From ccddbaa25dbcc7757b759307bd044e69d82f2c18 Mon Sep 17 00:00:00 2001 From: Arvin Xu Date: Wed, 13 May 2026 01:13:04 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(builtin-tool):=20?= =?UTF-8?q?move=20sub-agent=20dispatch=20from=20`lobe-gtd`=20to=20`lobe-ag?= =?UTF-8?q?ent`=20(#14715)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️ refactor(builtin-tool): move sub-agent dispatch from lobe-gtd to lobe-agent Move the `execTask` / `execTasks` capability out of `packages/builtin-tool-gtd/` and into `packages/builtin-tool-lobe-agent/`, renaming the public APIs to `callSubAgent` / `callSubAgents`. The "subtask" naming inside GTD overlapped with the new lobe-task tool's task model and conflated planning with sub-agent dispatch. - API names: `execTask` → `callSubAgent`, `execTasks` → `callSubAgents` - TS types: `ExecTaskParams` → `CallSubAgentParams`, etc.; introduce `SubAgentTask` to replace `ExecTaskItem` - Client UI (Inspector / Render / Streaming) ported under `packages/builtin-tool-lobe-agent/src/client/` - Central registries (`packages/builtin-tools/src/{inspectors,renders,streamings}.ts`) updated to register lobe-agent - GTD `meta.description` and system role no longer mention async tasks; they point to lobe-agent for sub-agent dispatch - `isSubTask` filtering in `agentConfigResolver` now excludes `lobe-agent` (new owner of sub-agent dispatch) instead of `lobe-gtd` - i18n: new `builtins.lobe-agent.apiName.callSubAgent*` and `workflow.toolDisplayName.callSubAgent*` keys in default/zh-CN/en-US Kept the executor's emitted `state.type` values (`execTask` / `execTasks` / `execClientTask` / `execClientTasks`) unchanged so the agent-runtime instruction layer (`exec_task` / `exec_tasks` / `exec_client_task*`) and all downstream tests / heterogeneous executors (`builtin-tool-agent-management`, server `agentManagement` runtime) continue to work without modification. Co-Authored-By: Claude Opus 4.7 (1M context) * ♻️ refactor(chat): rename isSubTask flag to isSubAgent After moving sub-agent dispatch from lobe-gtd to lobe-agent, the flag name no longer matches what it controls. Rename `isSubTask` → `isSubAgent` across the chat / agent runtime layer and update related comments and test labels. - `agentConfigResolver` context field + filter helper - `streamingExecutor.internal_createAgentState` + `executeClientAgent` signatures and call sites - `createAgentExecutors` (exec_task / exec_client_task handlers) and `GroupOrchestrationExecutors` (batch_exec_async_tasks) - `chatService.createAssistantMessageStream` `resolvedAgentConfig` docs - Test descriptions and assertions in `agentConfigResolver.test.ts` and `streamingExecutor.test.ts` No behavior change — the flag's filter target (`lobe-agent` identifier) is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) * ♻️ refactor(agent-runtime): rename exec_task wire identifiers to exec_sub_agent Bring the agent-runtime "wire" naming in line with the lobe-agent callSubAgent / callSubAgents API rename. Three layers are renamed in lockstep to keep the bridge between tool executors and the runtime consistent: 1. Tool-emitted state.type discriminators - 'execTask' → 'execSubAgent' - 'execTasks' → 'execSubAgents' - 'execClientTask' → 'execClientSubAgent' - 'execClientTasks' → 'execClientSubAgents' 2. AgentInstruction.type and matching TS interfaces - 'exec_task' / 'exec_tasks' / 'exec_client_task' / 'exec_client_tasks' → 'exec_sub_agent' / 'exec_sub_agents' / 'exec_client_sub_agent' / 'exec_client_sub_agents' - AgentInstructionExecTask → AgentInstructionExecSubAgent (and the three siblings) - ExecTaskItem → SubAgentTask 3. AgentRuntimeContext.phase + matching payload types - 'task_result' → 'sub_agent_result' - 'tasks_batch_result' → 'sub_agents_batch_result' - TaskResultPayload → SubAgentResultPayload - TasksBatchResultPayload → SubAgentsBatchResultPayload Also renames the operation-type discriminator 'execClientTask' / 'execClientTasks' to 'execClientSubAgent' / 'execClientSubAgents' and updates its locale string in default / zh-CN / en-US. Tests / fixtures / mocks updated in lockstep: - packages/agent-runtime/src/agents/{GeneralChatAgent.ts,__tests__/...} - packages/builtin-tool-{lobe-agent,agent-management}/src/... - src/server/services/toolExecution/serverRuntimes/agentManagement.ts - packages/agent-mock/src/cases/builtins/todo-write-stress.ts (helper renamed to callSubAgent) - src/store/chat/agents/createAgentExecutors.ts + exec-task / exec-tasks tests + fixtures/mockInstructions.ts (createExecSubAgent[s]Instruction) - src/store/chat/slices/aiChat/actions/streamingExecutor.ts (phase check) - packages/conversation-flow/src/__tests__/fixtures/**/*.json (8 fixtures retargeted from lobe-gtd/execTask[s] to lobe-agent/callSubAgent[s] with the new state.type wire values) No behavior change — the agent runtime, executors and tests all go through the same code paths; only the strings on the wire change. Co-Authored-By: Claude Opus 4.7 (1M context) * ♻️ refactor(builtin-tool): absorb GTD tool (plan + todo) into lobe-agent Delete `packages/builtin-tool-gtd/` and fold its full surface — plan, todo, ExecutionRuntime, all client UI (Inspector / Render / Streaming / Intervention / SortableTodoList) and the system role — into `packages/builtin-tool-lobe-agent/`. Single `lobe-agent` identifier now owns: plan + todo management, sub-agent dispatch, and visual media analysis. Also restructures the lobe-agent package so the executor lives under `./client/` alongside the UI it ships with, and drops the dedicated `./executor` export — consumers go through `./client` for everything client-side. Package-level changes: - DELETE `packages/builtin-tool-gtd/` entirely. - `packages/builtin-tool-lobe-agent/` - Move `src/executor/` → `src/client/executor/`. Drop `./executor` from `package.json` exports; expose `lobeAgentExecutor` via `./client` only. - Rename `GTDExecutionRuntime` → `PlanExecutionRuntime` and place under `src/client/executor/PlanRuntime/`. Re-export from package root so the server runtime can consume it without pulling in client UI deps. - Extend `LobeAgentExecutor` with `createPlan` / `updatePlan` / `createTodos` / `updateTodos` / `clearTodos`, all delegated to the shared runtime. - Add Plan + Todo API entries to the manifest (with their original descriptions, humanIntervention, renderDisplayControl). - Move all GTD client UI verbatim: `Inspector/{ClearTodos,CreatePlan,CreateTodos,UpdatePlan,UpdateTodos}`, `Render/{CreatePlan,TodoList}`, `Streaming/CreatePlan`, `Intervention/{AddTodo,ClearTodos,CreatePlan}`, `components/SortableTodoList`. Register them in `LobeAgentInspectors / Renders / Streamings`, add new `LobeAgentInterventions`. - Merge GTD system role into lobe-agent's (`` plus the existing `` and `` sections). - `package.json`: pick up `@lobechat/prompts` dep and `@lobehub/editor` + `antd` + `lucide-react` peer-deps inherited from GTD. Central registries (`packages/builtin-tools/src/*`) and consumers: - Remove every `GTDManifest / Inspectors / Renders / Streamings / Interventions` import + registration; existing `LobeAgent*` registrations now cover them. - Replace `[GTDManifest.identifier]: GTDInterventions` with `[LobeAgentManifest.identifier]: LobeAgentInterventions`. - Drop `@lobechat/builtin-tool-gtd` workspace dep from `packages/builtin-tools/package.json`, `packages/builtin-agents/package.json` and root `package.json`. - Remove `gtdExecutor` from `src/store/tool/slices/builtin/executors/index.ts`; switch `lobeAgentExecutor` import to `/client`. - Replace `serverRuntimes/gtd.ts` with a service factory `serverRuntimes/lobeAgentPlan.ts` (`createServerPlanRuntimeService`). `serverRuntimes/lobeAgent.ts` instantiates `PlanExecutionRuntime` with that service so the registry exposes one runtime per `lobe-agent` identifier covering both visual analysis and plan/todo. - `services/chat/mecha/contextEngineering.ts`: gate plan/todo injection on `LobeAgentIdentifier` instead of `GTDIdentifier`. - `agentConfigResolver.test.ts`: switch fixture plugin IDs to `LobeAgentIdentifier`. - `packages/const/src/recommendedSkill.ts`: drop the standalone `lobe-gtd` recommendation — `lobe-agent` already covers it via `defaultToolIds`. i18n migration (default + zh-CN + en-US; other locales regenerate on `pnpm i18n`): - `builtins.lobe-gtd.*` → `builtins.lobe-agent.*` in `plugin.ts/json`. - `lobe-gtd.*` (tool namespace) → `lobe-agent.*` in `tool.ts/json`. - Remove `tools.builtins.lobe-gtd.{description,readme,title}` from `setting.ts/json` (lobe-agent has its own meta now). - Update all client component `t(...)` keys to the new namespace. Mocks / fixtures / tests: - `packages/agent-mock/src/cases/builtins/todo-write-stress.ts`: all `identifier: 'lobe-gtd'` → `'lobe-agent'`; helper comments updated. - `packages/types/src/stepContext.ts`: comment refers to `builtin-tool-lobe-agent` (the only consumer of `StepContextTodoItem`). - `packages/model-runtime/src/core/streams/google/google-ai.test.ts`: function-call names from `lobe-gtd____createPlan` etc. → `lobe-agent____*`. - `src/store/chat/slices/message/selectors/dbMessage.test.ts`: same. - `src/features/DevPanel/RenderGallery/fixtures/lobe-gtd.ts` deleted; its plan/todo fixtures are folded into `fixtures/lobe-agent.ts` alongside the existing `callSubAgent[s]` ones. - Replace `console.log` → `console.info` in moved client components to satisfy lobe-agent's stricter ESLint rules (GTD package allowed `console.log`; lobe-agent inherits the repo-wide `no-console` rule). No behavior change for end users: `lobe-agent` now owns all the APIs, identifiers, and UI that previously lived in `lobe-gtd`, but as a single consolidated package under a single tool identifier. Co-Authored-By: Claude Opus 4.7 (1M context) * ♻️ refactor(context-engine): drop residual GTD naming, rename to PlanInjector / TodoInjector Follow-up to 9ca5c9d (which absorbed the GTD tool package into lobe-agent). That commit moved the package surface but left the GTD vocabulary embedded in context-engine providers, types, metadata fields, XML tags, and a pile of comments. This change finishes the sweep so the only remaining GTD references are user-facing docs and the legitimate Productivity & GTD Coach methodology suggestion. context-engine - `GTDPlanInjector` → `PlanInjector`; types `GTDPlan`/`GTDPlanInjectorConfig` → `Plan`/`PlanInjectorConfig`; metadata `gtdPlanId`/`gtdPlanInjected` → `planId`/`planInjected`; XML tag `` → ``; debug channel `provider:GTDPlanInjector` → `provider:PlanInjector`. - `GTDTodoInjector` → `TodoInjector`; types `GTDTodoItem`/`GTDTodoList`/ `GTDTodoStatus`/`GTDTodoInjectorConfig` → `TodoItem`/`TodoList`/ `TodoStatus`/`TodoInjectorConfig`; metadata `gtdTodo*` → `todo*`; XML tag `` → ``, wrapper `gtd_todo_context` → `todo_context`; debug channel renamed similarly. - `MessagesEngineParams.gtd?: GTDConfig` → `planTodo?: PlanTodoConfig`; internal vars `isGTDPlanEnabled`/`isGTDTodoEnabled` → `isPlanEnabled`/`isTodoEnabled`. Re-exports updated in `providers/index.ts` and `engine/messages/{index,types}.ts`. prompts - `packages/prompts/src/prompts/gtd/` → `planTodo/` (only export was `formatTodoStateSummary`, which kept its name). Updated `prompts/index.ts` re-export. src/services - `contextEngineering.ts`: `GTDConfig` import → `PlanTodoConfig`; `isGTDEnabled`/`gtdConfig` → `isPlanTodoEnabled`/`planTodoConfig`; payload field `gtd` → `planTodo`; log message wording. Tests - `dbMessage.test.ts`: helper `createGTDToolMessage` → `createLobeAgentToolMessage`; `gtdMessage` → `lobeAgentMessage`; all `it` descriptions reworded to "lobe-agent" instead of "GTD". - `agentConfigResolver.test.ts`: test descriptions reworded. Comments / docs (no behavior change) - agent-runtime (`instruction.ts`, `runtime.ts`, `generalAgent.ts`, `messageSelectors.ts`), `types/{stepContext,tool/builtin}.ts`, `builtin-agents/group-supervisor`, `builtin-tool-claude-code/types.ts`, `builtin-tool-lobe-agent/Render/TodoList`, `createAgentExecutors.ts:1426`, `AssistantGroup/{constants,Fallback.test}`, `agent-mock/todo-write-stress`, `.agents/skills/builtin-tool/references/architecture.md`. Intentionally left alone - `docs/usage/agent/gtd.{mdx,zh-CN.mdx}` and other docs — user-facing product brand "GTD Tools". - `src/locales/default/suggestQuestions.ts` "Productivity & GTD Coach" — references the methodology, not the tool. - `ToolSystemRoleProvider.test.ts` `'gtd-tool'` fixture — generic test identifier, unrelated. - Translated locale files still carrying `lobe-gtd.*` keys — regenerated by `pnpm i18n` from the updated default namespace. Verified: `bun run type-check` passes; touched test files (dbMessage, agentConfigResolver) and full context-engine + prompts test suites pass. Co-Authored-By: Claude Opus 4.7 (1M context) * 🐛 fix(builtin-tool-lobe-agent): reset TodoList auto-save status to idle `performSave` (the debounced auto-save path) was leaving `saveStatus` stuck on 'saved' forever — `saveNow` had the 1.5s setTimeout-to-idle but the auto-save twin didn't, so the inline indicator never eased back to idle after a settle. Add the same idle-reset to performSave so both paths behave the same. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- .../builtin-tool/references/architecture.md | 2 +- locales/en-US/chat.json | 6 +- locales/en-US/plugin.json | 34 +- locales/en-US/setting.json | 3 - locales/en-US/tool.json | 90 ++-- locales/zh-CN/chat.json | 6 +- locales/zh-CN/plugin.json | 34 +- locales/zh-CN/setting.json | 3 - locales/zh-CN/tool.json | 90 ++-- package.json | 1 - .../src/cases/builtins/todo-write-stress.ts | 66 +-- .../src/agents/GeneralChatAgent.ts | 44 +- .../agents/__tests__/GeneralChatAgent.test.ts | 54 +-- .../agent-runtime/src/types/generalAgent.ts | 2 +- .../agent-runtime/src/types/instruction.ts | 111 ++--- packages/agent-runtime/src/types/runtime.ts | 2 +- .../src/utils/messageSelectors.ts | 4 +- packages/builtin-agents/package.json | 1 - .../src/agents/group-supervisor/index.ts | 2 +- .../src/executor.ts | 8 +- .../builtin-tool-claude-code/src/types.ts | 2 +- packages/builtin-tool-gtd/package.json | 27 -- .../src/client/Inspector/ExecTask/index.tsx | 60 --- .../src/client/Inspector/ExecTasks/index.tsx | 75 ---- .../src/client/Inspector/index.ts | 26 -- .../src/client/Render/ExecTasks/index.tsx | 64 --- .../src/client/Render/index.ts | 33 -- .../src/client/Streaming/ExecTasks/index.tsx | 77 ---- .../src/client/Streaming/index.ts | 24 - packages/builtin-tool-gtd/src/client/index.ts | 25 -- .../src/executor/index.test.ts | 421 ------------------ .../builtin-tool-gtd/src/executor/index.ts | 136 ------ packages/builtin-tool-gtd/src/index.ts | 3 - packages/builtin-tool-gtd/src/manifest.ts | 247 ---------- packages/builtin-tool-gtd/src/systemRole.ts | 216 --------- packages/builtin-tool-gtd/src/types.ts | 333 -------------- packages/builtin-tool-lobe-agent/package.json | 14 +- .../client/Inspector/CallSubAgent/index.tsx | 57 +++ .../client/Inspector/CallSubAgents/index.tsx | 75 ++++ .../src/client/Inspector/ClearTodos/index.tsx | 8 +- .../src/client/Inspector/CreatePlan/index.tsx | 6 +- .../client/Inspector/CreateTodos/index.tsx | 4 +- .../src/client/Inspector/UpdatePlan/index.tsx | 8 +- .../client/Inspector/UpdateTodos/index.tsx | 4 +- .../src/client/Inspector/index.ts | 26 ++ .../src/client/Intervention/AddTodo.tsx | 6 +- .../src/client/Intervention/ClearTodos.tsx | 8 +- .../src/client/Intervention/CreatePlan.tsx | 8 +- .../src/client/Intervention/index.ts | 12 +- .../src/client/Render/CallSubAgent}/index.tsx | 8 +- .../src/client/Render/CallSubAgents/index.tsx | 64 +++ .../src/client/Render/CreatePlan/PlanCard.tsx | 0 .../src/client/Render/CreatePlan/index.tsx | 0 .../src/client/Render/TodoList/index.tsx | 2 +- .../src/client/Render/index.ts | 32 ++ .../client/Streaming/CallSubAgent}/index.tsx | 8 +- .../client/Streaming/CallSubAgents/index.tsx | 79 ++++ .../src/client/Streaming/CreatePlan/index.tsx | 0 .../src/client/Streaming/index.ts | 22 + .../SortableTodoList/AddItemRow.tsx | 2 +- .../SortableTodoList/SortableItem.tsx | 0 .../SortableTodoList/TodoItemRow.tsx | 2 +- .../components/SortableTodoList/TodoList.tsx | 0 .../components/SortableTodoList/index.tsx | 4 +- .../SortableTodoList/store/actions.ts | 18 +- .../SortableTodoList/store/index.ts | 0 .../SortableTodoList/store/initialState.ts | 0 .../SortableTodoList/store/store.test.ts | 0 .../SortableTodoList/store/types.ts | 0 .../src/client/components/index.ts | 0 .../src/client/executor/PlanRuntime}/index.ts | 75 +--- .../src/{ => client}/executor/index.ts | 174 +++++++- .../src/client/executor/planTodoHelper.ts} | 2 +- .../src/client/index.ts | 41 ++ .../src/const.ts | 0 packages/builtin-tool-lobe-agent/src/index.ts | 7 + .../src/manifest.test.ts | 4 +- .../builtin-tool-lobe-agent/src/manifest.ts | 229 +++++++++- .../builtin-tool-lobe-agent/src/systemRole.ts | 211 ++++++++- packages/builtin-tool-lobe-agent/src/types.ts | 280 ++++++++++++ packages/builtin-tools/package.json | 1 - packages/builtin-tools/src/identifiers.ts | 2 - packages/builtin-tools/src/index.ts | 7 - packages/builtin-tools/src/inspectors.ts | 4 +- packages/builtin-tools/src/interventions.ts | 7 +- packages/builtin-tools/src/renders.ts | 4 +- packages/builtin-tools/src/streamings.ts | 4 +- packages/const/src/recommendedSkill.ts | 1 - .../src/engine/messages/MessagesEngine.ts | 20 +- .../src/engine/messages/index.ts | 8 +- .../src/engine/messages/types.ts | 22 +- .../src/engine/tools/ToolArgumentsRepairer.ts | 2 +- .../__tests__/ToolArgumentsRepairer.test.ts | 8 +- .../{GTDPlanInjector.ts => PlanInjector.ts} | 44 +- .../{GTDTodoInjector.ts => TodoInjector.ts} | 71 ++- .../context-engine/src/providers/index.ts | 8 +- .../tasks/multi-tasks-with-summary.json | 6 +- .../fixtures/inputs/tasks/simple.json | 10 +- .../tasks/single-task-with-tool-chain.json | 10 +- .../inputs/tasks/with-assistant-group.json | 6 +- .../fixtures/inputs/tasks/with-summary.json | 6 +- .../fixtures/outputs/tasks/simple.json | 16 +- .../tasks/single-task-with-tool-chain.json | 16 +- .../fixtures/outputs/tasks/with-summary.json | 12 +- .../src/__tests__/parse.test.ts | 2 +- .../src/core/streams/google/google-ai.test.ts | 8 +- packages/prompts/src/prompts/index.ts | 2 +- .../prompts/{gtd => planTodo}/index.test.ts | 0 .../src/prompts/{gtd => planTodo}/index.ts | 0 packages/types/src/stepContext.ts | 4 +- packages/types/src/tool/builtin.ts | 2 +- .../Detail/Intervention/Fallback.test.tsx | 2 +- .../Messages/AssistantGroup/constants.ts | 8 +- .../DevPanel/RenderGallery/fixtures/index.ts | 4 +- .../fixtures/{lobe-gtd.ts => lobe-agent.ts} | 48 +- src/locales/default/chat.ts | 6 +- src/locales/default/plugin.ts | 34 +- src/locales/default/setting.ts | 4 - src/locales/default/tool.ts | 90 ++-- .../serverRuntimes/agentManagement.ts | 2 +- .../toolExecution/serverRuntimes/index.ts | 2 - .../toolExecution/serverRuntimes/lobeAgent.ts | 23 + .../{gtd.ts => lobeAgentPlan.ts} | 35 +- src/services/chat/index.ts | 4 +- .../chat/mecha/agentConfigResolver.test.ts | 88 ++-- .../chat/mecha/agentConfigResolver.ts | 18 +- src/services/chat/mecha/contextEngineering.ts | 26 +- .../createGroupOrchestrationExecutors.ts | 4 +- .../createAgentExecutors/exec-task.test.ts | 74 +-- .../createAgentExecutors/exec-tasks.test.ts | 87 ++-- .../fixtures/mockInstructions.ts | 30 +- src/store/chat/agents/createAgentExecutors.ts | 216 ++++----- .../__tests__/streamingExecutor.test.ts | 24 +- .../aiChat/actions/streamingExecutor.ts | 22 +- .../message/selectors/dbMessage.test.ts | 49 +- .../slices/message/selectors/dbMessage.ts | 4 +- src/store/chat/slices/operation/types.ts | 6 +- src/store/chat/slices/plugin/action.test.ts | 10 +- src/store/chat/utils/messageMapKey.test.ts | 2 +- .../tool/slices/builtin/executors/index.ts | 4 +- 140 files changed, 2277 insertions(+), 2794 deletions(-) delete mode 100644 packages/builtin-tool-gtd/package.json delete mode 100644 packages/builtin-tool-gtd/src/client/Inspector/ExecTask/index.tsx delete mode 100644 packages/builtin-tool-gtd/src/client/Inspector/ExecTasks/index.tsx delete mode 100644 packages/builtin-tool-gtd/src/client/Inspector/index.ts delete mode 100644 packages/builtin-tool-gtd/src/client/Render/ExecTasks/index.tsx delete mode 100644 packages/builtin-tool-gtd/src/client/Render/index.ts delete mode 100644 packages/builtin-tool-gtd/src/client/Streaming/ExecTasks/index.tsx delete mode 100644 packages/builtin-tool-gtd/src/client/Streaming/index.ts delete mode 100644 packages/builtin-tool-gtd/src/client/index.ts delete mode 100644 packages/builtin-tool-gtd/src/executor/index.test.ts delete mode 100644 packages/builtin-tool-gtd/src/executor/index.ts delete mode 100644 packages/builtin-tool-gtd/src/index.ts delete mode 100644 packages/builtin-tool-gtd/src/manifest.ts delete mode 100644 packages/builtin-tool-gtd/src/systemRole.ts delete mode 100644 packages/builtin-tool-gtd/src/types.ts create mode 100644 packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgent/index.tsx create mode 100644 packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgents/index.tsx rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Inspector/ClearTodos/index.tsx (84%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Inspector/CreatePlan/index.tsx (85%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Inspector/CreateTodos/index.tsx (90%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Inspector/UpdatePlan/index.tsx (85%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Inspector/UpdateTodos/index.tsx (95%) create mode 100644 packages/builtin-tool-lobe-agent/src/client/Inspector/index.ts rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Intervention/AddTodo.tsx (85%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Intervention/ClearTodos.tsx (89%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Intervention/CreatePlan.tsx (95%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Intervention/index.ts (56%) rename packages/{builtin-tool-gtd/src/client/Render/ExecTask => builtin-tool-lobe-agent/src/client/Render/CallSubAgent}/index.tsx (83%) create mode 100644 packages/builtin-tool-lobe-agent/src/client/Render/CallSubAgents/index.tsx rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Render/CreatePlan/PlanCard.tsx (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Render/CreatePlan/index.tsx (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Render/TodoList/index.tsx (98%) create mode 100644 packages/builtin-tool-lobe-agent/src/client/Render/index.ts rename packages/{builtin-tool-gtd/src/client/Streaming/ExecTask => builtin-tool-lobe-agent/src/client/Streaming/CallSubAgent}/index.tsx (77%) create mode 100644 packages/builtin-tool-lobe-agent/src/client/Streaming/CallSubAgents/index.tsx rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/Streaming/CreatePlan/index.tsx (100%) create mode 100644 packages/builtin-tool-lobe-agent/src/client/Streaming/index.ts rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/AddItemRow.tsx (97%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/SortableItem.tsx (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/TodoItemRow.tsx (98%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/TodoList.tsx (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/index.tsx (95%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/store/actions.ts (87%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/store/index.ts (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/store/initialState.ts (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/store/store.test.ts (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/SortableTodoList/store/types.ts (100%) rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/client/components/index.ts (100%) rename packages/{builtin-tool-gtd/src/ExecutionRuntime => builtin-tool-lobe-agent/src/client/executor/PlanRuntime}/index.ts (82%) rename packages/builtin-tool-lobe-agent/src/{ => client}/executor/index.ts (55%) rename packages/{builtin-tool-gtd/src/executor/helper.ts => builtin-tool-lobe-agent/src/client/executor/planTodoHelper.ts} (96%) create mode 100644 packages/builtin-tool-lobe-agent/src/client/index.ts rename packages/{builtin-tool-gtd => builtin-tool-lobe-agent}/src/const.ts (100%) rename packages/context-engine/src/providers/{GTDPlanInjector.ts => PlanInjector.ts} (66%) rename packages/context-engine/src/providers/{GTDTodoInjector.ts => TodoInjector.ts} (57%) rename packages/prompts/src/prompts/{gtd => planTodo}/index.test.ts (100%) rename packages/prompts/src/prompts/{gtd => planTodo}/index.ts (100%) rename src/features/DevPanel/RenderGallery/fixtures/{lobe-gtd.ts => lobe-agent.ts} (97%) rename src/server/services/toolExecution/serverRuntimes/{gtd.ts => lobeAgentPlan.ts} (77%) diff --git a/.agents/skills/builtin-tool/references/architecture.md b/.agents/skills/builtin-tool/references/architecture.md index 7f7375d129..c1c837466c 100644 --- a/.agents/skills/builtin-tool/references/architecture.md +++ b/.agents/skills/builtin-tool/references/architecture.md @@ -213,7 +213,7 @@ The runtime hands every executor method an optional `BuiltinToolContext` as the | `operationId` | Operation lineage (use for cancellation, tracing) | | `scope` | `'task' \| 'agent' \| …` — toggles default behaviors | | `signal: AbortSignal` | Honor for long-running ops | -| `stepContext` | Cross-message runtime state (GTD todos, etc.) | +| `stepContext` | Cross-message runtime state (lobe-agent todos, etc.) | | `registerAfterCompletion(cb)` | Defer side-effects past message-update race | | `groupOrchestration` | Group orchestration callbacks | diff --git a/locales/en-US/chat.json b/locales/en-US/chat.json index ef06cc0809..e2ea475bda 100644 --- a/locales/en-US/chat.json +++ b/locales/en-US/chat.json @@ -314,7 +314,7 @@ "openInNewWindow": "Open in New Window", "operation.contextCompression": "Context too long, compressing history...", "operation.execAgentRuntime": "Preparing response", - "operation.execClientTask": "Executing task", + "operation.execClientSubAgent": "Running sub-agent", "operation.execHeterogeneousAgent": "{{name}} is running", "operation.execServerAgentRuntime": "Task is running in the server. You are safe to leave this page", "operation.heterogeneousAgentFallback": "External agent", @@ -772,6 +772,8 @@ "workflow.toolDisplayName.addPreferenceMemory": "Saved memory", "workflow.toolDisplayName.calculate": "Calculated", "workflow.toolDisplayName.callAgent": "Called an agent", + "workflow.toolDisplayName.callSubAgent": "Dispatched a sub-agent", + "workflow.toolDisplayName.callSubAgents": "Dispatched sub-agents", "workflow.toolDisplayName.clearTodos": "Cleared todos", "workflow.toolDisplayName.copyDocument": "Copied a document", "workflow.toolDisplayName.crawlMultiPages": "Crawled pages", @@ -786,8 +788,6 @@ "workflow.toolDisplayName.editTitle": "Edited title", "workflow.toolDisplayName.evaluate": "Evaluated expression", "workflow.toolDisplayName.execScript": "Executed a script", - "workflow.toolDisplayName.execTask": "Executed a task", - "workflow.toolDisplayName.execTasks": "Executed tasks", "workflow.toolDisplayName.execute": "Executed calculation", "workflow.toolDisplayName.executeCode": "Executed code", "workflow.toolDisplayName.finishOnboarding": "Finished onboarding", diff --git a/locales/en-US/plugin.json b/locales/en-US/plugin.json index 190690e53c..c5f5358e7c 100644 --- a/locales/en-US/plugin.json +++ b/locales/en-US/plugin.json @@ -72,6 +72,22 @@ "builtins.lobe-agent-marketplace.apiName.showAgentMarketplace": "Assemble agent team", "builtins.lobe-agent-marketplace.apiName.submitAgentPick": "Submit agent picks", "builtins.lobe-agent-marketplace.title": "Agent Marketplace", + "builtins.lobe-agent.apiName.callSubAgent": "Call sub-agent", + "builtins.lobe-agent.apiName.callSubAgent.completed": "Sub-agent dispatched: ", + "builtins.lobe-agent.apiName.callSubAgent.loading": "Dispatching sub-agent: ", + "builtins.lobe-agent.apiName.callSubAgents": "Call sub-agents", + "builtins.lobe-agent.apiName.clearTodos": "Clear todos", + "builtins.lobe-agent.apiName.clearTodos.modeAll": "all", + "builtins.lobe-agent.apiName.clearTodos.modeCompleted": "completed", + "builtins.lobe-agent.apiName.clearTodos.result": "Clear {{mode}} todos", + "builtins.lobe-agent.apiName.createPlan": "Create plan", + "builtins.lobe-agent.apiName.createPlan.result": "Create plan: {{goal}}", + "builtins.lobe-agent.apiName.createTodos": "Create todos", + "builtins.lobe-agent.apiName.updatePlan": "Update plan", + "builtins.lobe-agent.apiName.updatePlan.completed": "Completed", + "builtins.lobe-agent.apiName.updatePlan.modified": "Modified", + "builtins.lobe-agent.apiName.updateTodos": "Update todos", + "builtins.lobe-agent.title": "Lobe Agent", "builtins.lobe-claude-code.agent.instruction": "Instruction", "builtins.lobe-claude-code.agent.result": "Result", "builtins.lobe-claude-code.todoWrite.allDone": "All tasks completed", @@ -139,24 +155,6 @@ "builtins.lobe-group-management.inspector.executeAgentTasks.title": "Assigning tasks to:", "builtins.lobe-group-management.inspector.speak.title": "Designated Agent speaks:", "builtins.lobe-group-management.title": "Group Coordinator", - "builtins.lobe-gtd.apiName.clearTodos": "Clear todos", - "builtins.lobe-gtd.apiName.clearTodos.modeAll": "all", - "builtins.lobe-gtd.apiName.clearTodos.modeCompleted": "completed", - "builtins.lobe-gtd.apiName.clearTodos.result": "Clear {{mode}} todos", - "builtins.lobe-gtd.apiName.completeTodos": "Complete todos", - "builtins.lobe-gtd.apiName.createPlan": "Create plan", - "builtins.lobe-gtd.apiName.createPlan.result": "Create plan: {{goal}}", - "builtins.lobe-gtd.apiName.createTodos": "Create todos", - "builtins.lobe-gtd.apiName.execTask": "Execute task", - "builtins.lobe-gtd.apiName.execTask.completed": "Task created: ", - "builtins.lobe-gtd.apiName.execTask.loading": "Creating task: ", - "builtins.lobe-gtd.apiName.execTasks": "Execute tasks", - "builtins.lobe-gtd.apiName.removeTodos": "Delete todos", - "builtins.lobe-gtd.apiName.updatePlan": "Update plan", - "builtins.lobe-gtd.apiName.updatePlan.completed": "Completed", - "builtins.lobe-gtd.apiName.updatePlan.modified": "Modified", - "builtins.lobe-gtd.apiName.updateTodos": "Update todos", - "builtins.lobe-gtd.title": "Task Tools", "builtins.lobe-knowledge-base.apiName.readKnowledge": "Read Library content", "builtins.lobe-knowledge-base.apiName.searchKnowledgeBase": "Search Library", "builtins.lobe-knowledge-base.inspector.andMoreFiles": "and {{count}} more", diff --git a/locales/en-US/setting.json b/locales/en-US/setting.json index 63668f4104..5bf961a92e 100644 --- a/locales/en-US/setting.json +++ b/locales/en-US/setting.json @@ -934,9 +934,6 @@ "tools.builtins.lobe-group-agent-builder.title": "Group Agent Builder", "tools.builtins.lobe-group-management.description": "Orchestrate and manage multi-agent group conversations", "tools.builtins.lobe-group-management.title": "Group Management", - "tools.builtins.lobe-gtd.description": "Plan goals and track progress with GTD methodology", - "tools.builtins.lobe-gtd.readme": "Plan goals and track progress using GTD methodology. Create strategic plans, manage todo lists with status tracking, and execute long-running async tasks.", - "tools.builtins.lobe-gtd.title": "GTD Tools", "tools.builtins.lobe-knowledge-base.description": "Search uploaded documents and domain knowledge via semantic vector search — for persistent, reusable reference", "tools.builtins.lobe-knowledge-base.title": "Knowledge Base", "tools.builtins.lobe-local-system.description": "Access and manage local files, run shell commands on your desktop", diff --git a/locales/en-US/tool.json b/locales/en-US/tool.json index a155098d73..964bf0e16d 100644 --- a/locales/en-US/tool.json +++ b/locales/en-US/tool.json @@ -56,51 +56,51 @@ "dalle.generating": "Generating...", "dalle.images": "Images:", "dalle.prompt": "Prompt", - "lobe-gtd.actions.add": "Add", - "lobe-gtd.actions.clearCompleted": "Clear Completed", - "lobe-gtd.actions.placeholder": "Enter a to-do item...", - "lobe-gtd.addTodo.placeholder": "Add a todo item...", - "lobe-gtd.clearTodos.cleared": "{{count}} item(s) cleared", - "lobe-gtd.clearTodos.clearedCompleted": "{{count}} completed item(s) cleared", - "lobe-gtd.clearTodos.clearedCompleted_one": "{{count}} completed item cleared", - "lobe-gtd.clearTodos.clearedCompleted_other": "{{count}} completed items cleared", - "lobe-gtd.clearTodos.cleared_one": "{{count}} item cleared", - "lobe-gtd.clearTodos.cleared_other": "{{count}} items cleared", - "lobe-gtd.clearTodos.header": "Clear Todo Items", - "lobe-gtd.clearTodos.label": "Choose what to clear:", - "lobe-gtd.clearTodos.noItems": "No items to clear", - "lobe-gtd.clearTodos.option.all": "Clear all items (including pending)", - "lobe-gtd.clearTodos.option.completed": "Clear completed items only", - "lobe-gtd.clearTodos.remaining": "{{count}} item(s) remaining", - "lobe-gtd.clearTodos.remaining_one": "{{count}} item remaining", - "lobe-gtd.clearTodos.remaining_other": "{{count}} items remaining", - "lobe-gtd.completeTodos.completed": "{{count}} item(s) completed", - "lobe-gtd.completeTodos.completed_one": "{{count}} item completed", - "lobe-gtd.completeTodos.completed_other": "{{count}} items completed", - "lobe-gtd.createPlan.context.label": "Context (optional)", - "lobe-gtd.createPlan.context.placeholder": "Background, constraints, considerations...", - "lobe-gtd.createPlan.description.label": "Description", - "lobe-gtd.createPlan.description.placeholder": "Brief summary of the plan", - "lobe-gtd.createPlan.goal.label": "Goal", - "lobe-gtd.createPlan.goal.placeholder": "What do you want to achieve?", - "lobe-gtd.createTodos.created": "{{count}} to-do item(s) created", - "lobe-gtd.createTodos.created_one": "{{count}} to-do item created", - "lobe-gtd.createTodos.created_other": "{{count}} to-do items created", - "lobe-gtd.createTodos.total": "Total: {{count}} item(s)", - "lobe-gtd.createTodos.total_one": "Total: {{count}} item", - "lobe-gtd.createTodos.total_other": "Total: {{count}} items", - "lobe-gtd.removeTodos.removed": "{{count}} item(s) removed", - "lobe-gtd.removeTodos.removed_one": "{{count}} item removed", - "lobe-gtd.removeTodos.removed_other": "{{count}} items removed", - "lobe-gtd.status.done": "{{count}} completed", - "lobe-gtd.status.pending": "{{count}} pending", - "lobe-gtd.todoItem.placeholder": "Enter todo item...", - "lobe-gtd.todoList.empty": "To-do list is empty", - "lobe-gtd.todoList.items": "{{count}} item(s)", - "lobe-gtd.todoList.items_one": "{{count}} item", - "lobe-gtd.todoList.items_other": "{{count}} items", - "lobe-gtd.todoList.title": "To-Do List", - "lobe-gtd.updateTodos.updated": "To-do list updated", + "lobe-agent.actions.add": "Add", + "lobe-agent.actions.clearCompleted": "Clear Completed", + "lobe-agent.actions.placeholder": "Enter a to-do item...", + "lobe-agent.addTodo.placeholder": "Add a todo item...", + "lobe-agent.clearTodos.cleared": "{{count}} item(s) cleared", + "lobe-agent.clearTodos.clearedCompleted": "{{count}} completed item(s) cleared", + "lobe-agent.clearTodos.clearedCompleted_one": "{{count}} completed item cleared", + "lobe-agent.clearTodos.clearedCompleted_other": "{{count}} completed items cleared", + "lobe-agent.clearTodos.cleared_one": "{{count}} item cleared", + "lobe-agent.clearTodos.cleared_other": "{{count}} items cleared", + "lobe-agent.clearTodos.header": "Clear Todo Items", + "lobe-agent.clearTodos.label": "Choose what to clear:", + "lobe-agent.clearTodos.noItems": "No items to clear", + "lobe-agent.clearTodos.option.all": "Clear all items (including pending)", + "lobe-agent.clearTodos.option.completed": "Clear completed items only", + "lobe-agent.clearTodos.remaining": "{{count}} item(s) remaining", + "lobe-agent.clearTodos.remaining_one": "{{count}} item remaining", + "lobe-agent.clearTodos.remaining_other": "{{count}} items remaining", + "lobe-agent.completeTodos.completed": "{{count}} item(s) completed", + "lobe-agent.completeTodos.completed_one": "{{count}} item completed", + "lobe-agent.completeTodos.completed_other": "{{count}} items completed", + "lobe-agent.createPlan.context.label": "Context (optional)", + "lobe-agent.createPlan.context.placeholder": "Background, constraints, considerations...", + "lobe-agent.createPlan.description.label": "Description", + "lobe-agent.createPlan.description.placeholder": "Brief summary of the plan", + "lobe-agent.createPlan.goal.label": "Goal", + "lobe-agent.createPlan.goal.placeholder": "What do you want to achieve?", + "lobe-agent.createTodos.created": "{{count}} to-do item(s) created", + "lobe-agent.createTodos.created_one": "{{count}} to-do item created", + "lobe-agent.createTodos.created_other": "{{count}} to-do items created", + "lobe-agent.createTodos.total": "Total: {{count}} item(s)", + "lobe-agent.createTodos.total_one": "Total: {{count}} item", + "lobe-agent.createTodos.total_other": "Total: {{count}} items", + "lobe-agent.removeTodos.removed": "{{count}} item(s) removed", + "lobe-agent.removeTodos.removed_one": "{{count}} item removed", + "lobe-agent.removeTodos.removed_other": "{{count}} items removed", + "lobe-agent.status.done": "{{count}} completed", + "lobe-agent.status.pending": "{{count}} pending", + "lobe-agent.todoItem.placeholder": "Enter todo item...", + "lobe-agent.todoList.empty": "To-do list is empty", + "lobe-agent.todoList.items": "{{count}} item(s)", + "lobe-agent.todoList.items_one": "{{count}} item", + "lobe-agent.todoList.items_other": "{{count}} items", + "lobe-agent.todoList.title": "To-Do List", + "lobe-agent.updateTodos.updated": "To-do list updated", "lobe-knowledge-base.readKnowledge.meta.chars": "Character Count", "lobe-knowledge-base.readKnowledge.meta.lines": "Line Count", "localFiles.editFile.newString": "Replace with", diff --git a/locales/zh-CN/chat.json b/locales/zh-CN/chat.json index 0d3ad9c11b..aac6d6342c 100644 --- a/locales/zh-CN/chat.json +++ b/locales/zh-CN/chat.json @@ -314,7 +314,7 @@ "openInNewWindow": "在新窗口打开", "operation.contextCompression": "上下文过长,正在压缩历史记录……", "operation.execAgentRuntime": "准备响应中", - "operation.execClientTask": "执行任务中", + "operation.execClientSubAgent": "运行子代理中", "operation.execHeterogeneousAgent": "{{name}} 正在运行", "operation.execServerAgentRuntime": "任务正在服务器运行,您可以放心离开此页面", "operation.heterogeneousAgentFallback": "外部智能体", @@ -772,6 +772,8 @@ "workflow.toolDisplayName.addPreferenceMemory": "保存了记忆", "workflow.toolDisplayName.calculate": "完成了计算", "workflow.toolDisplayName.callAgent": "调用了助理", + "workflow.toolDisplayName.callSubAgent": "派发了子代理", + "workflow.toolDisplayName.callSubAgents": "派发了多个子代理", "workflow.toolDisplayName.clearTodos": "清空了待办", "workflow.toolDisplayName.copyDocument": "复制了文档", "workflow.toolDisplayName.crawlMultiPages": "抓取了多个页面", @@ -786,8 +788,6 @@ "workflow.toolDisplayName.editTitle": "编辑了标题", "workflow.toolDisplayName.evaluate": "求值了表达式", "workflow.toolDisplayName.execScript": "执行了脚本", - "workflow.toolDisplayName.execTask": "执行了任务", - "workflow.toolDisplayName.execTasks": "执行了任务", "workflow.toolDisplayName.execute": "执行了计算", "workflow.toolDisplayName.executeCode": "执行了代码", "workflow.toolDisplayName.finishOnboarding": "完成了引导", diff --git a/locales/zh-CN/plugin.json b/locales/zh-CN/plugin.json index b152b49d40..b090bbcf50 100644 --- a/locales/zh-CN/plugin.json +++ b/locales/zh-CN/plugin.json @@ -72,6 +72,22 @@ "builtins.lobe-agent-marketplace.apiName.showAgentMarketplace": "组建 Agent 团队", "builtins.lobe-agent-marketplace.apiName.submitAgentPick": "提交助手选择", "builtins.lobe-agent-marketplace.title": "助手市场", + "builtins.lobe-agent.apiName.callSubAgent": "调用子代理", + "builtins.lobe-agent.apiName.callSubAgent.completed": "已派发子代理:", + "builtins.lobe-agent.apiName.callSubAgent.loading": "正在派发子代理:", + "builtins.lobe-agent.apiName.callSubAgents": "调用多个子代理", + "builtins.lobe-agent.apiName.clearTodos": "清除待办", + "builtins.lobe-agent.apiName.clearTodos.modeAll": "全部", + "builtins.lobe-agent.apiName.clearTodos.modeCompleted": "已完成", + "builtins.lobe-agent.apiName.clearTodos.result": "清除{{mode}}待办", + "builtins.lobe-agent.apiName.createPlan": "创建计划", + "builtins.lobe-agent.apiName.createPlan.result": "创建计划:{{goal}}", + "builtins.lobe-agent.apiName.createTodos": "创建待办", + "builtins.lobe-agent.apiName.updatePlan": "更新计划", + "builtins.lobe-agent.apiName.updatePlan.completed": "已完成", + "builtins.lobe-agent.apiName.updatePlan.modified": "已修改", + "builtins.lobe-agent.apiName.updateTodos": "更新待办", + "builtins.lobe-agent.title": "Lobe Agent", "builtins.lobe-claude-code.agent.instruction": "指令", "builtins.lobe-claude-code.agent.result": "结果", "builtins.lobe-claude-code.todoWrite.allDone": "全部任务已完成", @@ -139,24 +155,6 @@ "builtins.lobe-group-management.inspector.executeAgentTasks.title": "分配任务给:", "builtins.lobe-group-management.inspector.speak.title": "指定 Agent 发言:", "builtins.lobe-group-management.title": "群组协调", - "builtins.lobe-gtd.apiName.clearTodos": "清除待办", - "builtins.lobe-gtd.apiName.clearTodos.modeAll": "全部", - "builtins.lobe-gtd.apiName.clearTodos.modeCompleted": "已完成", - "builtins.lobe-gtd.apiName.clearTodos.result": "清除{{mode}}待办", - "builtins.lobe-gtd.apiName.completeTodos": "完成待办", - "builtins.lobe-gtd.apiName.createPlan": "创建计划", - "builtins.lobe-gtd.apiName.createPlan.result": "创建计划:{{goal}}", - "builtins.lobe-gtd.apiName.createTodos": "创建待办", - "builtins.lobe-gtd.apiName.execTask": "执行任务", - "builtins.lobe-gtd.apiName.execTask.completed": "已创建任务:", - "builtins.lobe-gtd.apiName.execTask.loading": "创建任务中:", - "builtins.lobe-gtd.apiName.execTasks": "执行多个任务", - "builtins.lobe-gtd.apiName.removeTodos": "删除待办", - "builtins.lobe-gtd.apiName.updatePlan": "更新计划", - "builtins.lobe-gtd.apiName.updatePlan.completed": "已完成", - "builtins.lobe-gtd.apiName.updatePlan.modified": "已修改", - "builtins.lobe-gtd.apiName.updateTodos": "更新待办", - "builtins.lobe-gtd.title": "任务工具", "builtins.lobe-knowledge-base.apiName.readKnowledge": "读取资源库内容", "builtins.lobe-knowledge-base.apiName.searchKnowledgeBase": "搜索资源库", "builtins.lobe-knowledge-base.inspector.andMoreFiles": "还有 {{count}} 个", diff --git a/locales/zh-CN/setting.json b/locales/zh-CN/setting.json index 957ffef738..22ebdbc83b 100644 --- a/locales/zh-CN/setting.json +++ b/locales/zh-CN/setting.json @@ -934,9 +934,6 @@ "tools.builtins.lobe-group-agent-builder.title": "群组助手构建器", "tools.builtins.lobe-group-management.description": "编排并管理多助手群组对话", "tools.builtins.lobe-group-management.title": "群组管理", - "tools.builtins.lobe-gtd.description": "使用 GTD 方法规划目标并追踪进度", - "tools.builtins.lobe-gtd.readme": "使用 GTD 方法规划目标并追踪进度。创建战略计划、管理带状态跟踪的待办列表,并执行长时间运行的异步任务。", - "tools.builtins.lobe-gtd.title": "GTD 工具", "tools.builtins.lobe-knowledge-base.description": "通过语义向量检索搜索已上传的文档与领域知识 — 适用于持久、可复用的参考资料", "tools.builtins.lobe-knowledge-base.title": "知识库", "tools.builtins.lobe-local-system.description": "访问和管理本地文件,在桌面端运行 Shell 命令", diff --git a/locales/zh-CN/tool.json b/locales/zh-CN/tool.json index 3de23cee30..46729ddd47 100644 --- a/locales/zh-CN/tool.json +++ b/locales/zh-CN/tool.json @@ -56,51 +56,51 @@ "dalle.generating": "生成中...", "dalle.images": "图片:", "dalle.prompt": "提示词", - "lobe-gtd.actions.add": "添加", - "lobe-gtd.actions.clearCompleted": "清除已完成", - "lobe-gtd.actions.placeholder": "输入待办事项...", - "lobe-gtd.addTodo.placeholder": "添加待办事项...", - "lobe-gtd.clearTodos.cleared": "已清除 {{count}} 项", - "lobe-gtd.clearTodos.clearedCompleted": "已清除 {{count}} 项已完成事项", - "lobe-gtd.clearTodos.clearedCompleted_one": "已清除 {{count}} 项已完成事项", - "lobe-gtd.clearTodos.clearedCompleted_other": "已清除 {{count}} 项已完成事项", - "lobe-gtd.clearTodos.cleared_one": "已清除 {{count}} 项", - "lobe-gtd.clearTodos.cleared_other": "已清除 {{count}} 项", - "lobe-gtd.clearTodos.header": "清除待办事项", - "lobe-gtd.clearTodos.label": "请选择要清除的内容:", - "lobe-gtd.clearTodos.noItems": "无可清除事项", - "lobe-gtd.clearTodos.option.all": "清除所有事项(包括未完成)", - "lobe-gtd.clearTodos.option.completed": "仅清除已完成事项", - "lobe-gtd.clearTodos.remaining": "剩余 {{count}} 项", - "lobe-gtd.clearTodos.remaining_one": "剩余 {{count}} 项", - "lobe-gtd.clearTodos.remaining_other": "剩余 {{count}} 项", - "lobe-gtd.completeTodos.completed": "已完成 {{count}} 项", - "lobe-gtd.completeTodos.completed_one": "已完成 {{count}} 项", - "lobe-gtd.completeTodos.completed_other": "已完成 {{count}} 项", - "lobe-gtd.createPlan.context.label": "上下文(可选)", - "lobe-gtd.createPlan.context.placeholder": "背景、限制、注意事项等...", - "lobe-gtd.createPlan.description.label": "描述", - "lobe-gtd.createPlan.description.placeholder": "简要说明计划内容", - "lobe-gtd.createPlan.goal.label": "目标", - "lobe-gtd.createPlan.goal.placeholder": "你希望达成什么目标?", - "lobe-gtd.createTodos.created": "已创建 {{count}} 项待办事项", - "lobe-gtd.createTodos.created_one": "已创建 {{count}} 项待办事项", - "lobe-gtd.createTodos.created_other": "已创建 {{count}} 项待办事项", - "lobe-gtd.createTodos.total": "总计:{{count}} 项", - "lobe-gtd.createTodos.total_one": "总计:{{count}} 项", - "lobe-gtd.createTodos.total_other": "总计:{{count}} 项", - "lobe-gtd.removeTodos.removed": "已移除 {{count}} 项", - "lobe-gtd.removeTodos.removed_one": "已移除 {{count}} 项", - "lobe-gtd.removeTodos.removed_other": "已移除 {{count}} 项", - "lobe-gtd.status.done": "已完成 {{count}} 项", - "lobe-gtd.status.pending": "待完成 {{count}} 项", - "lobe-gtd.todoItem.placeholder": "输入待办事项...", - "lobe-gtd.todoList.empty": "待办事项列表为空", - "lobe-gtd.todoList.items": "{{count}} 项", - "lobe-gtd.todoList.items_one": "{{count}} 项", - "lobe-gtd.todoList.items_other": "{{count}} 项", - "lobe-gtd.todoList.title": "待办事项列表", - "lobe-gtd.updateTodos.updated": "待办事项已更新", + "lobe-agent.actions.add": "添加", + "lobe-agent.actions.clearCompleted": "清除已完成", + "lobe-agent.actions.placeholder": "输入待办事项...", + "lobe-agent.addTodo.placeholder": "添加待办事项...", + "lobe-agent.clearTodos.cleared": "已清除 {{count}} 项", + "lobe-agent.clearTodos.clearedCompleted": "已清除 {{count}} 项已完成事项", + "lobe-agent.clearTodos.clearedCompleted_one": "已清除 {{count}} 项已完成事项", + "lobe-agent.clearTodos.clearedCompleted_other": "已清除 {{count}} 项已完成事项", + "lobe-agent.clearTodos.cleared_one": "已清除 {{count}} 项", + "lobe-agent.clearTodos.cleared_other": "已清除 {{count}} 项", + "lobe-agent.clearTodos.header": "清除待办事项", + "lobe-agent.clearTodos.label": "请选择要清除的内容:", + "lobe-agent.clearTodos.noItems": "无可清除事项", + "lobe-agent.clearTodos.option.all": "清除所有事项(包括未完成)", + "lobe-agent.clearTodos.option.completed": "仅清除已完成事项", + "lobe-agent.clearTodos.remaining": "剩余 {{count}} 项", + "lobe-agent.clearTodos.remaining_one": "剩余 {{count}} 项", + "lobe-agent.clearTodos.remaining_other": "剩余 {{count}} 项", + "lobe-agent.completeTodos.completed": "已完成 {{count}} 项", + "lobe-agent.completeTodos.completed_one": "已完成 {{count}} 项", + "lobe-agent.completeTodos.completed_other": "已完成 {{count}} 项", + "lobe-agent.createPlan.context.label": "上下文(可选)", + "lobe-agent.createPlan.context.placeholder": "背景、限制、注意事项等...", + "lobe-agent.createPlan.description.label": "描述", + "lobe-agent.createPlan.description.placeholder": "简要说明计划内容", + "lobe-agent.createPlan.goal.label": "目标", + "lobe-agent.createPlan.goal.placeholder": "你希望达成什么目标?", + "lobe-agent.createTodos.created": "已创建 {{count}} 项待办事项", + "lobe-agent.createTodos.created_one": "已创建 {{count}} 项待办事项", + "lobe-agent.createTodos.created_other": "已创建 {{count}} 项待办事项", + "lobe-agent.createTodos.total": "总计:{{count}} 项", + "lobe-agent.createTodos.total_one": "总计:{{count}} 项", + "lobe-agent.createTodos.total_other": "总计:{{count}} 项", + "lobe-agent.removeTodos.removed": "已移除 {{count}} 项", + "lobe-agent.removeTodos.removed_one": "已移除 {{count}} 项", + "lobe-agent.removeTodos.removed_other": "已移除 {{count}} 项", + "lobe-agent.status.done": "已完成 {{count}} 项", + "lobe-agent.status.pending": "待完成 {{count}} 项", + "lobe-agent.todoItem.placeholder": "输入待办事项...", + "lobe-agent.todoList.empty": "待办事项列表为空", + "lobe-agent.todoList.items": "{{count}} 项", + "lobe-agent.todoList.items_one": "{{count}} 项", + "lobe-agent.todoList.items_other": "{{count}} 项", + "lobe-agent.todoList.title": "待办事项列表", + "lobe-agent.updateTodos.updated": "待办事项已更新", "lobe-knowledge-base.readKnowledge.meta.chars": "字符数", "lobe-knowledge-base.readKnowledge.meta.lines": "行数", "localFiles.editFile.newString": "替换为", diff --git a/package.json b/package.json index 77a52b2fbd..88680bec83 100644 --- a/package.json +++ b/package.json @@ -220,7 +220,6 @@ "@lobechat/builtin-tool-creds": "workspace:*", "@lobechat/builtin-tool-group-agent-builder": "workspace:*", "@lobechat/builtin-tool-group-management": "workspace:*", - "@lobechat/builtin-tool-gtd": "workspace:*", "@lobechat/builtin-tool-knowledge-base": "workspace:*", "@lobechat/builtin-tool-lobe-agent": "workspace:*", "@lobechat/builtin-tool-local-system": "workspace:*", diff --git a/packages/agent-mock/src/cases/builtins/todo-write-stress.ts b/packages/agent-mock/src/cases/builtins/todo-write-stress.ts index d5cb1e7d3f..7a8e7bd923 100644 --- a/packages/agent-mock/src/cases/builtins/todo-write-stress.ts +++ b/packages/agent-mock/src/cases/builtins/todo-write-stress.ts @@ -1,13 +1,13 @@ import { defineCase, errorStep, llmStep, toolStep } from '../../builders/defineCase'; // --------------------------------------------------------------------------- -// Helpers — all mapped to lobe-gtd +// Helpers — all mapped to lobe-agent // --------------------------------------------------------------------------- -/** lobe-gtd / createTodos */ +/** lobe-agent / createTodos */ const createTodos = (items: string[], durationMs = 60) => toolStep({ - identifier: 'lobe-gtd', + identifier: 'lobe-agent', apiName: 'createTodos', arguments: JSON.stringify({ adds: items }), result: { @@ -20,14 +20,14 @@ const createTodos = (items: string[], durationMs = 60) => durationMs, }); -/** lobe-gtd / updateTodos — batch operations */ +/** lobe-agent / updateTodos — batch operations */ const updateTodos = ( operations: Array<{ type: string; index?: number; newText?: string; status?: string }>, currentItems: Array<{ text: string; status: string }>, durationMs = 60, ) => toolStep({ - identifier: 'lobe-gtd', + identifier: 'lobe-agent', apiName: 'updateTodos', arguments: JSON.stringify({ operations }), result: { @@ -40,7 +40,7 @@ const updateTodos = ( durationMs, }); -/** lobe-gtd / createPlan */ +/** lobe-agent / createPlan */ const createPlan = ( goal: string, description: string, @@ -49,7 +49,7 @@ const createPlan = ( durationMs = 80, ) => toolStep({ - identifier: 'lobe-gtd', + identifier: 'lobe-agent', apiName: 'createPlan', arguments: JSON.stringify({ goal, description, context }), result: { @@ -66,14 +66,14 @@ const createPlan = ( durationMs, }); -/** lobe-gtd / updatePlan */ +/** lobe-agent / updatePlan */ const updatePlan = ( planId: string, set: { goal?: string; description?: string; context?: string; completed?: boolean }, durationMs = 60, ) => toolStep({ - identifier: 'lobe-gtd', + identifier: 'lobe-agent', apiName: 'updatePlan', arguments: JSON.stringify({ planId, ...set }), result: { @@ -90,16 +90,16 @@ const updatePlan = ( durationMs, }); -/** lobe-gtd / execTask */ -const execTask = (description: string, instruction: string, durationMs = 200) => +/** lobe-agent / callSubAgent */ +const callSubAgent = (description: string, instruction: string, durationMs = 200) => toolStep({ - identifier: 'lobe-gtd', - apiName: 'execTask', + identifier: 'lobe-agent', + apiName: 'callSubAgent', arguments: JSON.stringify({ description, instruction }), result: { parentMessageId: `mock-msg-task-${Date.now()}`, task: { description, instruction }, - type: 'execTask' as const, + type: 'execSubAgent' as const, }, durationMs, }); @@ -108,14 +108,14 @@ const execTask = (description: string, instruction: string, durationMs = 200) => const breathe = (text: string, durationMs = 250) => llmStep({ text, durationMs }); // --------------------------------------------------------------------------- -// The main case — ~200 lobe-gtd tool calls across 8 phases +// The main case — ~200 lobe-agent tool calls across 8 phases // --------------------------------------------------------------------------- export const todoWriteStress = defineCase({ id: 'todo-write-stress', name: 'TodoWrite × 200 (complex)', description: - '~200 GTD tool calls across 8 realistic phases: discovery, schema audit, store migration, ' + + '~200 lobe-agent tool calls across 8 realistic phases: discovery, schema audit, store migration, ' + 'TRPC refactor, i18n extraction, component rewrites, testing, and final verification.', tags: ['stress', 'todo', 'builtin'], @@ -137,8 +137,8 @@ export const todoWriteStress = defineCase({ text: '第一阶段:全面盘点现有代码结构。创建总体计划,再拆解为 15 个待办事项。', reasoning: '先创建一个顶层计划文档,再将盘点工作拆解为具体的 todo 项。', toolsCalling: [ - { id: 'tc-plan-1', identifier: 'lobe-gtd', apiName: 'createPlan', arguments: '{}' }, - { id: 'tc-todos-1', identifier: 'lobe-gtd', apiName: 'createTodos', arguments: '{}' }, + { id: 'tc-plan-1', identifier: 'lobe-agent', apiName: 'createPlan', arguments: '{}' }, + { id: 'tc-todos-1', identifier: 'lobe-agent', apiName: 'createTodos', arguments: '{}' }, ], durationMs: 600, }), @@ -242,7 +242,7 @@ export const todoWriteStress = defineCase({ status: k === i ? 'processing' : k < i ? 'completed' : 'todo', })), ), - execTask( + callSubAgent( `为 ${table} 表添加索引`, `检查 src/database/schemas/${table}.ts 的表结构,添加 createdAt 性能索引,生成迁移 SQL`, ), @@ -275,7 +275,7 @@ export const todoWriteStress = defineCase({ status: k === i ? 'processing' : k < i ? 'completed' : 'todo', })), ), - execTask( + callSubAgent( `为 ${table} 表添加索引`, `检查 src/database/schemas/${table}.ts 的表结构,添加 createdAt 性能索引,生成迁移 SQL`, ), @@ -343,7 +343,7 @@ export const todoWriteStress = defineCase({ [{ type: 'processing', index: 0 }], [{ text: `迁移 ${slice} store slice 到 SWR 模式`, status: 'processing' }], ), - execTask( + callSubAgent( `迁移 ${slice} store slice`, `重构 src/store/chat/slices/${slice}/index.ts,将数据获取逻辑迁移到 SWR + Zustand 模式`, ), @@ -482,7 +482,7 @@ export const todoWriteStress = defineCase({ { text: '修复 type-check 发现的类型问题', status: 'processing' }, ], ), - execTask('修复 TRPC 类型问题', '运行 bun run type-check,逐一修复类型错误直到通过'), + callSubAgent('修复 TRPC 类型问题', '运行 bun run type-check,逐一修复类型错误直到通过'), updateTodos( [{ type: 'complete', index: 1 }], [ @@ -523,7 +523,7 @@ export const todoWriteStress = defineCase({ [{ type: 'processing', index: 0 }], [{ text: `提取 ${ns} 命名空间的硬编码字符串`, status: 'processing' }], ), - execTask( + callSubAgent( `提取 ${ns} i18n keys`, `扫描 src/locales/default/${ns}.ts,将硬编码字符串替换为 i18n key`, ), @@ -540,7 +540,7 @@ export const todoWriteStress = defineCase({ [{ type: 'processing', index: 0 }], [{ text: `提取 ${ns} 命名空间的硬编码字符串`, status: 'processing' }], ), - execTask( + callSubAgent( `提取 ${ns} i18n keys`, `扫描 src/locales/default/${ns}.ts,将硬编码字符串替换为 i18n key`, ), @@ -560,7 +560,7 @@ export const todoWriteStress = defineCase({ [{ type: 'processing', index: 0 }], [{ text: '修复 i18n sync 重复 key 问题', status: 'processing' }], ), - execTask( + callSubAgent( '修复 i18n 重复 key', '检查 src/locales/zh-CN/agent.ts,合并重复的 confirmDelete key,重新运行 pnpm i18n', ), @@ -627,7 +627,7 @@ export const todoWriteStress = defineCase({ status: k === localIdx ? 'processing' : k < localIdx ? 'completed' : 'todo', })), ), - execTask( + callSubAgent( `迁移 ${comp} 样式`, `将 src/features/${comp}/index.tsx 中的 createStyles 替换为 createStaticStyles,使用 cssVar`, ), @@ -660,7 +660,7 @@ export const todoWriteStress = defineCase({ [{ type: 'processing', index: 0 }], [{ text: '验证迁移后的组件编译通过', status: 'processing' }], ), - execTask('编译验证', '运行 bun run type-check 确认迁移后的组件没有类型错误'), + callSubAgent('编译验证', '运行 bun run type-check 确认迁移后的组件没有类型错误'), updateTodos( [{ type: 'complete', index: 0 }], [{ text: '验证迁移后的组件编译通过', status: 'completed' }], @@ -693,7 +693,7 @@ export const todoWriteStress = defineCase({ status: k === i ? 'processing' : k < i ? 'completed' : 'todo', })), ), - execTask(`编写 ${target} 测试`, `为 ${target} 编写 vitest 测试用例,覆盖核心功能路径`), + callSubAgent(`编写 ${target} 测试`, `为 ${target} 编写 vitest 测试用例,覆盖核心功能路径`), updateTodos( [{ type: 'complete', index: i }], Array.from({ length: 4 }, (_, k) => ({ @@ -728,7 +728,7 @@ export const todoWriteStress = defineCase({ status: k === i ? 'processing' : k < i ? 'completed' : 'todo', })), ), - execTask(`${target}`, `执行 ${target} 相关的测试修复与验证工作`), + callSubAgent(`${target}`, `执行 ${target} 相关的测试修复与验证工作`), updateTodos( [{ type: 'complete', index: i }], Array.from({ length: 4 }, (_, k) => ({ @@ -768,7 +768,7 @@ export const todoWriteStress = defineCase({ status: k === i ? 'processing' : k < i ? 'completed' : 'todo', })), ), - execTask(`执行 ${task}`, `运行 ${task} 确认迁移无回归`), + callSubAgent(`执行 ${task}`, `运行 ${task} 确认迁移无回归`), updateTodos( [{ type: 'complete', index: i }], Array.from({ length: 5 }, (_, k) => ({ @@ -791,8 +791,8 @@ export const todoWriteStress = defineCase({ { text: '写迁移指南文档', status: 'processing' }, ], ), - execTask('更新 CI 配置', '修改 .github/workflows/ci.yml 添加并行 vitest shards'), - execTask('写迁移指南', '创建 docs/MIGRATION.md 记录所有迁移变更和操作步骤'), + callSubAgent('更新 CI 配置', '修改 .github/workflows/ci.yml 添加并行 vitest shards'), + callSubAgent('写迁移指南', '创建 docs/MIGRATION.md 记录所有迁移变更和操作步骤'), updateTodos( [ { type: 'complete', index: 0 }, @@ -810,7 +810,7 @@ export const todoWriteStress = defineCase({ // Done // ===================================================================== llmStep({ - text: '全部 8 个阶段完成。共执行约 200 个 GTD 工具调用,涵盖计划创建、待办管理、任务执行和错误恢复。迁移已通过 type-check、单测、E2E 和安全审计。', + text: '全部 8 个阶段完成。共执行约 200 个 lobe-agent 工具调用,涵盖计划创建、待办管理、任务执行和错误恢复。迁移已通过 type-check、单测、E2E 和安全审计。', reasoning: '确认所有 todo 已标记完成,所有 plan 已标记 completed,汇总执行统计。', durationMs: 600, }), diff --git a/packages/agent-runtime/src/agents/GeneralChatAgent.ts b/packages/agent-runtime/src/agents/GeneralChatAgent.ts index 144e399119..1d0eb01ae3 100644 --- a/packages/agent-runtime/src/agents/GeneralChatAgent.ts +++ b/packages/agent-runtime/src/agents/GeneralChatAgent.ts @@ -21,8 +21,8 @@ import { type GeneralAgentCompressionResultPayload, type GeneralAgentConfig, type HumanAbortPayload, - type TaskResultPayload, - type TasksBatchResultPayload, + type SubAgentResultPayload, + type SubAgentsBatchResultPayload, } from '../types'; import { shouldCompress } from '../utils/tokenCounter'; @@ -544,55 +544,57 @@ export class GeneralChatAgent implements Agent { const { data, parentMessageId, stop } = context.payload as GeneralAgentCallToolResultPayload; - // Check if this is a GTD async task request (only execTask/execTasks are passed here with stop=true) + // Check if this is a sub-agent dispatch request (lobe-agent.callSubAgent / + // callSubAgents and similarly-shaped tools emit state.type=execSubAgent* + // with stop=true so the runtime forks a sub-agent here). if (stop && data?.state) { const stateType = data.state.type; - // GTD async task (single) - if (stateType === 'execTask') { + // Server-side sub-agent (single) + if (stateType === 'execSubAgent') { const { parentMessageId: execParentId, task } = data.state as { parentMessageId: string; task: any; }; return { payload: { parentMessageId: execParentId, task }, - type: 'exec_task', + type: 'exec_sub_agent', }; } - // GTD async tasks (multiple) - if (stateType === 'execTasks') { + // Server-side sub-agents (multiple) + if (stateType === 'execSubAgents') { const { parentMessageId: execParentId, tasks } = data.state as { parentMessageId: string; tasks: any[]; }; return { payload: { parentMessageId: execParentId, tasks }, - type: 'exec_tasks', + type: 'exec_sub_agents', }; } - // GTD client-side async task (single, desktop only) - if (stateType === 'execClientTask') { + // Client-side sub-agent (single, desktop only) + if (stateType === 'execClientSubAgent') { const { parentMessageId: execParentId, task } = data.state as { parentMessageId: string; task: any; }; return { payload: { parentMessageId: execParentId, task }, - type: 'exec_client_task', + type: 'exec_client_sub_agent', }; } - // GTD client-side async tasks (multiple, desktop only) - if (stateType === 'execClientTasks') { + // Client-side sub-agents (multiple, desktop only) + if (stateType === 'execClientSubAgents') { const { parentMessageId: execParentId, tasks } = data.state as { parentMessageId: string; tasks: any[]; }; return { payload: { parentMessageId: execParentId, tasks }, - type: 'exec_client_tasks', + type: 'exec_client_sub_agents', }; } } @@ -662,9 +664,9 @@ export class GeneralChatAgent implements Agent { } as GeneralAgentCallLLMInstructionPayload); } - case 'task_result': { - // Single async task completed, continue to call LLM with result - const { parentMessageId } = context.payload as TaskResultPayload; + case 'sub_agent_result': { + // Single sub-agent completed, continue to call LLM with result + const { parentMessageId } = context.payload as SubAgentResultPayload; // Continue to call LLM with updated messages (task message is already in state) return this.toLLMCall({ @@ -676,9 +678,9 @@ export class GeneralChatAgent implements Agent { } as GeneralAgentCallLLMInstructionPayload); } - case 'tasks_batch_result': { - // Async tasks batch completed, continue to call LLM with results - const { parentMessageId } = context.payload as TasksBatchResultPayload; + case 'sub_agents_batch_result': { + // Sub-agents batch completed, continue to call LLM with results + const { parentMessageId } = context.payload as SubAgentsBatchResultPayload; if (context.stepContext?.hasQueuedMessages) { return { reason: 'queued_message_interrupt', type: 'finish' }; diff --git a/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts b/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts index 08a2fdb592..dd9232586d 100644 --- a/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +++ b/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts @@ -451,8 +451,8 @@ describe('GeneralChatAgent', () => { }); describe('tool_result phase', () => { - describe('GTD async tasks', () => { - it('should return exec_task for single async task (execTask)', async () => { + describe('Lobe Agent sub-agents (execSubAgent state)', () => { + it('should return exec_sub_agent for single sub-agent (execSubAgent)', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, operationId: 'test-session', @@ -465,7 +465,7 @@ describe('GeneralChatAgent', () => { stop: true, data: { state: { - type: 'execTask', + type: 'execSubAgent', parentMessageId: 'exec-parent-msg', task: { instruction: 'Do something async', timeout: 30000 }, }, @@ -475,7 +475,7 @@ describe('GeneralChatAgent', () => { const result = await agent.runner(context, state); expect(result).toEqual({ - type: 'exec_task', + type: 'exec_sub_agent', payload: { parentMessageId: 'exec-parent-msg', task: { instruction: 'Do something async', timeout: 30000 }, @@ -483,7 +483,7 @@ describe('GeneralChatAgent', () => { }); }); - it('should return exec_tasks for multiple async tasks (execTasks)', async () => { + it('should return exec_sub_agents for multiple sub-agents (execSubAgents)', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, operationId: 'test-session', @@ -500,7 +500,7 @@ describe('GeneralChatAgent', () => { stop: true, data: { state: { - type: 'execTasks', + type: 'execSubAgents', parentMessageId: 'exec-parent-msg', tasks, }, @@ -510,7 +510,7 @@ describe('GeneralChatAgent', () => { const result = await agent.runner(context, state); expect(result).toEqual({ - type: 'exec_tasks', + type: 'exec_sub_agents', payload: { parentMessageId: 'exec-parent-msg', tasks, @@ -518,7 +518,7 @@ describe('GeneralChatAgent', () => { }); }); - it('should return exec_client_task for single client-side async task (execClientTask)', async () => { + it('should return exec_client_sub_agent for single client-side sub-agent (execClientSubAgent)', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, operationId: 'test-session', @@ -531,7 +531,7 @@ describe('GeneralChatAgent', () => { stop: true, data: { state: { - type: 'execClientTask', + type: 'execClientSubAgent', parentMessageId: 'exec-parent-msg', task: { type: 'localFile', path: '/path/to/file' }, }, @@ -541,7 +541,7 @@ describe('GeneralChatAgent', () => { const result = await agent.runner(context, state); expect(result).toEqual({ - type: 'exec_client_task', + type: 'exec_client_sub_agent', payload: { parentMessageId: 'exec-parent-msg', task: { type: 'localFile', path: '/path/to/file' }, @@ -549,7 +549,7 @@ describe('GeneralChatAgent', () => { }); }); - it('should return exec_client_tasks for multiple client-side async tasks (execClientTasks)', async () => { + it('should return exec_client_sub_agents for multiple client-side sub-agents (execClientSubAgents)', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, operationId: 'test-session', @@ -566,7 +566,7 @@ describe('GeneralChatAgent', () => { stop: true, data: { state: { - type: 'execClientTasks', + type: 'execClientSubAgents', parentMessageId: 'exec-parent-msg', tasks, }, @@ -576,7 +576,7 @@ describe('GeneralChatAgent', () => { const result = await agent.runner(context, state); expect(result).toEqual({ - type: 'exec_client_tasks', + type: 'exec_client_sub_agents', payload: { parentMessageId: 'exec-parent-msg', tasks, @@ -584,7 +584,7 @@ describe('GeneralChatAgent', () => { }); }); - it('should not trigger exec_task when stop is false', async () => { + it('should not trigger exec_sub_agent when stop is false', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, operationId: 'test-session', @@ -600,10 +600,10 @@ describe('GeneralChatAgent', () => { }); const context = createMockContext('tool_result', { parentMessageId: 'tool-msg-1', - stop: false, // stop is false, should not trigger exec_task + stop: false, // stop is false, should not trigger exec_sub_agent data: { state: { - type: 'execTask', + type: 'execSubAgent', parentMessageId: 'exec-parent-msg', task: { instruction: 'Do something async' }, }, @@ -612,7 +612,7 @@ describe('GeneralChatAgent', () => { const result = await agent.runner(context, state); - // Should return call_llm instead of exec_task + // Should return call_llm instead of exec_sub_agent expect(result).toEqual({ type: 'call_llm', payload: { @@ -625,7 +625,7 @@ describe('GeneralChatAgent', () => { }); }); - it('should not trigger exec_task when data.state is undefined', async () => { + it('should not trigger exec_sub_agent when data.state is undefined', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, operationId: 'test-session', @@ -647,7 +647,7 @@ describe('GeneralChatAgent', () => { const result = await agent.runner(context, state); - // Should return call_llm instead of exec_task + // Should return call_llm instead of exec_sub_agent expect(result).toEqual({ type: 'call_llm', payload: { @@ -1502,7 +1502,7 @@ describe('GeneralChatAgent', () => { }); }); - describe('task_result phase (single task)', () => { + describe('sub_agent_result phase (single sub-agent)', () => { it('should return call_llm when task completed', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, @@ -1518,7 +1518,7 @@ describe('GeneralChatAgent', () => { ] as any, }); - const context = createMockContext('task_result', { + const context = createMockContext('sub_agent_result', { parentMessageId: 'task-parent-msg', result: { success: true, @@ -1557,7 +1557,7 @@ describe('GeneralChatAgent', () => { ] as any, }); - const context = createMockContext('task_result', { + const context = createMockContext('sub_agent_result', { parentMessageId: 'task-parent-msg', result: { success: false, @@ -1592,7 +1592,7 @@ describe('GeneralChatAgent', () => { ] as any, }); - const context = createMockContext('task_result', { + const context = createMockContext('sub_agent_result', { parentMessageId: 'task-parent-msg', }); @@ -1602,7 +1602,7 @@ describe('GeneralChatAgent', () => { }); }); - describe('tasks_batch_result phase (multiple tasks)', () => { + describe('sub_agents_batch_result phase (multiple sub-agents)', () => { it('should return call_llm when tasks completed', async () => { const agent = new GeneralChatAgent({ agentConfig: { maxSteps: 100 }, @@ -1619,7 +1619,7 @@ describe('GeneralChatAgent', () => { ] as any, }); - const context = createMockContext('tasks_batch_result', { + const context = createMockContext('sub_agents_batch_result', { parentMessageId: 'task-parent-msg', results: [ { success: true, taskMessageId: 'task-1', threadId: 'thread-1', result: 'Task 1 result' }, @@ -1664,7 +1664,7 @@ describe('GeneralChatAgent', () => { ] as any, }); - const context = createMockContext('tasks_batch_result', { + const context = createMockContext('sub_agents_batch_result', { parentMessageId: 'task-parent-msg', results: [ { success: true, taskMessageId: 'task-1', threadId: 'thread-1', result: 'Task 1 result' }, @@ -1710,7 +1710,7 @@ describe('GeneralChatAgent', () => { ] as any, }); - const context = createMockContext('tasks_batch_result', { + const context = createMockContext('sub_agents_batch_result', { parentMessageId: 'task-parent-msg', }); diff --git a/packages/agent-runtime/src/types/generalAgent.ts b/packages/agent-runtime/src/types/generalAgent.ts index 75f11dff31..4be58010f3 100644 --- a/packages/agent-runtime/src/types/generalAgent.ts +++ b/packages/agent-runtime/src/types/generalAgent.ts @@ -34,7 +34,7 @@ export interface GeneralAgentCallToolResultPayload { executionTime: number; isSuccess: boolean; parentMessageId: string; - /** Whether tool requested to stop execution (e.g., group management speak/delegate, GTD async tasks) */ + /** Whether tool requested to stop execution (e.g., group management speak/delegate, lobe-agent async sub-agents) */ stop?: boolean; toolCall: ChatToolPayload; toolCallId: string; diff --git a/packages/agent-runtime/src/types/instruction.ts b/packages/agent-runtime/src/types/instruction.ts index cdfc5a468f..8f99183b3e 100644 --- a/packages/agent-runtime/src/types/instruction.ts +++ b/packages/agent-runtime/src/types/instruction.ts @@ -35,8 +35,8 @@ export interface AgentRuntimeContext { | 'llm_result' | 'tool_result' | 'tools_batch_result' - | 'task_result' - | 'tasks_batch_result' + | 'sub_agent_result' + | 'sub_agents_batch_result' | 'human_response' | 'human_approved_tool' | 'human_abort' @@ -53,7 +53,7 @@ export interface AgentRuntimeContext { /** * Step context computed at the beginning of each step - * Contains dynamic state like GTD todos that changes between steps + * Contains dynamic state like lobe-agent todos that changes between steps * Computed by AgentRuntime and passed to Context Engine and Tool Executors */ stepContext?: RuntimeStepContext; @@ -148,27 +148,28 @@ export interface HumanAbortPayload { } /** - * Task definition for exec_tasks instruction + * Sub-agent definition for exec_sub_agents instruction */ -export interface ExecTaskItem { - /** Brief description of what this task does (shown in UI) */ +export interface SubAgentTask { + /** Brief description of what this sub-agent does (shown in UI) */ description: string; /** Whether to inherit context messages from parent conversation */ inheritMessages?: boolean; - /** Detailed instruction/prompt for the task execution */ + /** Detailed instruction/prompt for the sub-agent execution */ instruction: string; /** - * Whether to execute the task on the client side (desktop only). - * When true and running on desktop, the task will be executed locally - * with access to local tools (file system, shell commands, etc.). + * Whether to execute the sub-agent on the client side (desktop only). + * When true and running on desktop, the sub-agent runs locally with + * access to local tools (file system, shell commands, etc.). * - * IMPORTANT: This MUST be set to true when the task requires: + * IMPORTANT: This MUST be set to true when the sub-agent requires: * - Reading/writing local files via `local-system` tool * - Executing shell commands * - Any other desktop-only local tool operations * - * If not specified or false, the task runs on the server (default behavior). - * On non-desktop platforms (web), this flag is ignored and tasks always run on server. + * If not specified or false, the sub-agent runs on the server (default behavior). + * On non-desktop platforms (web), this flag is ignored and sub-agents always + * run on the server. */ runInClient?: boolean; /** Timeout in milliseconds (optional, default 30 minutes) */ @@ -176,43 +177,43 @@ export interface ExecTaskItem { } /** - * Payload for task_result phase (single task) + * Payload for sub_agent_result phase (single sub-agent) */ -export interface TaskResultPayload { +export interface SubAgentResultPayload { /** Parent message ID */ parentMessageId: string; - /** Result from executed task */ + /** Result from executed sub-agent */ result: { - /** Error message if task failed */ + /** Error message if sub-agent failed */ error?: string; - /** Task result content */ + /** Sub-agent result content */ result?: string; - /** Whether the task completed successfully */ + /** Whether the sub-agent completed successfully */ success: boolean; - /** Task message ID */ + /** Sub-agent message ID */ taskMessageId: string; - /** Thread ID where the task was executed */ + /** Thread ID where the sub-agent was executed */ threadId: string; }; } /** - * Payload for tasks_batch_result phase (multiple tasks) + * Payload for sub_agents_batch_result phase (multiple sub-agents) */ -export interface TasksBatchResultPayload { +export interface SubAgentsBatchResultPayload { /** Parent message ID */ parentMessageId: string; - /** Results from executed tasks */ + /** Results from executed sub-agents */ results: Array<{ - /** Error message if task failed */ + /** Error message if sub-agent failed */ error?: string; - /** Task result content */ + /** Sub-agent result content */ result?: string; - /** Whether the task completed successfully */ + /** Whether the sub-agent completed successfully */ success: boolean; - /** Task message ID */ + /** Sub-agent message ID */ taskMessageId: string; - /** Thread ID where the task was executed */ + /** Thread ID where the sub-agent was executed */ threadId: string; }>; } @@ -272,46 +273,46 @@ export interface AgentInstructionResolveAbortedTools extends AgentInstructionBas type: 'resolve_aborted_tools'; } -// ─ Task ────────────────────────────────────────────────── +// ─ Sub-Agent ───────────────────────────────────────────── -export interface AgentInstructionExecTask extends AgentInstructionBase { +export interface AgentInstructionExecSubAgent extends AgentInstructionBase { payload: { - /** Parent message ID (tool message that triggered the task) */ + /** Parent message ID (tool message that dispatched the sub-agent) */ parentMessageId: string; - /** Task to execute */ - task: ExecTaskItem; + /** Sub-agent to execute */ + task: SubAgentTask; }; - type: 'exec_task'; + type: 'exec_sub_agent'; } -export interface AgentInstructionExecTasks extends AgentInstructionBase { +export interface AgentInstructionExecSubAgents extends AgentInstructionBase { payload: { - /** Parent message ID (tool message that triggered the tasks) */ + /** Parent message ID (tool message that dispatched the sub-agents) */ parentMessageId: string; - /** Array of tasks to execute */ - tasks: ExecTaskItem[]; + /** Array of sub-agents to execute */ + tasks: SubAgentTask[]; }; - type: 'exec_tasks'; + type: 'exec_sub_agents'; } -export interface AgentInstructionExecClientTask extends AgentInstructionBase { +export interface AgentInstructionExecClientSubAgent extends AgentInstructionBase { payload: { - /** Parent message ID (tool message that triggered the task) */ + /** Parent message ID (tool message that dispatched the sub-agent) */ parentMessageId: string; - /** Task to execute */ - task: ExecTaskItem; + /** Sub-agent to execute */ + task: SubAgentTask; }; - type: 'exec_client_task'; + type: 'exec_client_sub_agent'; } -export interface AgentInstructionExecClientTasks extends AgentInstructionBase { +export interface AgentInstructionExecClientSubAgents extends AgentInstructionBase { payload: { - /** Parent message ID (tool message that triggered the tasks) */ + /** Parent message ID (tool message that dispatched the sub-agents) */ parentMessageId: string; - /** Array of tasks to execute */ - tasks: ExecTaskItem[]; + /** Array of sub-agents to execute */ + tasks: SubAgentTask[]; }; - type: 'exec_client_tasks'; + type: 'exec_client_sub_agents'; } // ─ Human Interaction ───────────────────────────────────── @@ -372,11 +373,11 @@ export type AgentInstruction = | AgentInstructionCallTool | AgentInstructionCallToolsBatch | AgentInstructionResolveAbortedTools - // Task - | AgentInstructionExecTask - | AgentInstructionExecTasks - | AgentInstructionExecClientTask - | AgentInstructionExecClientTasks + // Sub-Agent + | AgentInstructionExecSubAgent + | AgentInstructionExecSubAgents + | AgentInstructionExecClientSubAgent + | AgentInstructionExecClientSubAgents // Human Interaction | AgentInstructionRequestHumanPrompt | AgentInstructionRequestHumanSelect diff --git a/packages/agent-runtime/src/types/runtime.ts b/packages/agent-runtime/src/types/runtime.ts index 1f1381b42e..675d848bf0 100644 --- a/packages/agent-runtime/src/types/runtime.ts +++ b/packages/agent-runtime/src/types/runtime.ts @@ -7,7 +7,7 @@ export type InstructionExecutor = ( state: AgentState, /** * Runtime context for this step - * Contains stepContext with dynamic state like GTD todos + * Contains stepContext with dynamic state like lobe-agent todos */ context?: AgentRuntimeContext, ) => Promise<{ diff --git a/packages/agent-runtime/src/utils/messageSelectors.ts b/packages/agent-runtime/src/utils/messageSelectors.ts index f4e2cf002c..194d922547 100644 --- a/packages/agent-runtime/src/utils/messageSelectors.ts +++ b/packages/agent-runtime/src/utils/messageSelectors.ts @@ -25,9 +25,9 @@ export interface MessageVisitorOptions { * if (id) return { activeDeviceId: id }; * }, { role: 'tool' }); * - * // Find latest GTD todos + * // Find latest lobe-agent todos * const todos = findInMessages(messages, (msg) => { - * if (msg.plugin?.identifier === GTDIdentifier) return msg.pluginState?.todos; + * if (msg.plugin?.identifier === LobeAgentIdentifier) return msg.pluginState?.todos; * }, { role: 'tool' }); * ``` */ diff --git a/packages/builtin-agents/package.json b/packages/builtin-agents/package.json index 428ae6f3e8..e899b6d260 100644 --- a/packages/builtin-agents/package.json +++ b/packages/builtin-agents/package.json @@ -9,7 +9,6 @@ "@lobechat/builtin-tool-agent-management": "workspace:*", "@lobechat/builtin-tool-group-agent-builder": "workspace:*", "@lobechat/builtin-tool-group-management": "workspace:*", - "@lobechat/builtin-tool-gtd": "workspace:*", "@lobechat/builtin-tool-notebook": "workspace:*", "@lobechat/builtin-tool-task": "workspace:*", "@lobechat/builtin-tool-user-interaction": "workspace:*", diff --git a/packages/builtin-agents/src/agents/group-supervisor/index.ts b/packages/builtin-agents/src/agents/group-supervisor/index.ts index 319eaac534..531ad66a7c 100644 --- a/packages/builtin-agents/src/agents/group-supervisor/index.ts +++ b/packages/builtin-agents/src/agents/group-supervisor/index.ts @@ -26,7 +26,7 @@ const resolveSystemRole = (ctx: GroupSupervisorContext): string => { * Tools: * - GroupManagement: orchestration (speak, broadcast, executeAgentTask, etc.) * - GroupAgentBuilder: member management (searchAgent, inviteAgent, createAgent, etc.) - * - GTD: task tracking + * - LobeAgent: task tracking (plan + todos) */ export const GROUP_SUPERVISOR: BuiltinAgentDefinition = { runtime: (ctx) => { diff --git a/packages/builtin-tool-agent-management/src/executor.ts b/packages/builtin-tool-agent-management/src/executor.ts index 6c9e7e4bd6..bbfbf8a136 100644 --- a/packages/builtin-tool-agent-management/src/executor.ts +++ b/packages/builtin-tool-agent-management/src/executor.ts @@ -119,7 +119,7 @@ class AgentManagementExecutor extends BaseExecutor>( - ({ args, partialArgs, isArgumentsStreaming, isLoading }) => { - const { t } = useTranslation('plugin'); - - const description = args?.description || partialArgs?.description; - - // Arguments are still streaming and no description yet - if (isArgumentsStreaming) { - if (!description) - return ( -
- {t('builtins.lobe-gtd.apiName.execTask')} -
- ); - - return ( -
- {t('builtins.lobe-gtd.apiName.execTask.loading')} - {description} -
- ); - } - - // When description is available, show different text based on loading state - if (description) { - return ( -
- - {isLoading - ? t('builtins.lobe-gtd.apiName.execTask.loading') - : t('builtins.lobe-gtd.apiName.execTask.completed')} - - {description} -
- ); - } - - // fallback - return ( -
- {t('builtins.lobe-gtd.apiName.execTask')} -
- ); - }, -); - -ExecTaskInspector.displayName = 'ExecTaskInspector'; - -export default ExecTaskInspector; diff --git a/packages/builtin-tool-gtd/src/client/Inspector/ExecTasks/index.tsx b/packages/builtin-tool-gtd/src/client/Inspector/ExecTasks/index.tsx deleted file mode 100644 index 64e1bae586..0000000000 --- a/packages/builtin-tool-gtd/src/client/Inspector/ExecTasks/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -'use client'; - -import type { BuiltinInspectorProps } from '@lobechat/types'; -import { Icon } from '@lobehub/ui'; -import { createStaticStyles, cx } from 'antd-style'; -import { ListTodo } from 'lucide-react'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; - -import { highlightTextStyles, shinyTextStyles } from '@/styles'; - -import type { ExecTasksParams, ExecTasksState } from '../../../types'; - -const styles = createStaticStyles(({ css, cssVar }) => ({ - count: css` - flex-shrink: 0; - margin-inline-start: 4px; - color: ${cssVar.colorTextSecondary}; - `, - description: css` - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - `, - root: css` - overflow: hidden; - display: flex; - gap: 4px; - align-items: center; - `, - title: css` - flex-shrink: 0; - color: ${cssVar.colorText}; - `, -})); - -export const ExecTasksInspector = memo>( - ({ args, partialArgs, isArgumentsStreaming }) => { - const { t } = useTranslation('plugin'); - - const tasks = args?.tasks || partialArgs?.tasks || []; - const count = tasks.length; - const firstTask = tasks[0]; - - if (isArgumentsStreaming && count === 0) { - return ( -
- {t('builtins.lobe-gtd.apiName.execTasks')} -
- ); - } - - return ( -
- - {t('builtins.lobe-gtd.apiName.execTasks')}: - - {firstTask?.description && ( - - {firstTask.description} - - )} - {count > 1 && ( - - {count} - - )} -
- ); - }, -); - -ExecTasksInspector.displayName = 'ExecTasksInspector'; - -export default ExecTasksInspector; diff --git a/packages/builtin-tool-gtd/src/client/Inspector/index.ts b/packages/builtin-tool-gtd/src/client/Inspector/index.ts deleted file mode 100644 index b147d614c4..0000000000 --- a/packages/builtin-tool-gtd/src/client/Inspector/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { BuiltinInspector } from '@lobechat/types'; - -import { GTDApiName } from '../../types'; -import { ClearTodosInspector } from './ClearTodos'; -import { CreatePlanInspector } from './CreatePlan'; -import { CreateTodosInspector } from './CreateTodos'; -import { ExecTaskInspector } from './ExecTask'; -import { ExecTasksInspector } from './ExecTasks'; -import { UpdatePlanInspector } from './UpdatePlan'; -import { UpdateTodosInspector } from './UpdateTodos'; - -/** - * GTD Inspector Components Registry - * - * Inspector components customize the title/header area - * of tool calls in the conversation UI. - */ -export const GTDInspectors: Record = { - [GTDApiName.clearTodos]: ClearTodosInspector as BuiltinInspector, - [GTDApiName.createPlan]: CreatePlanInspector as BuiltinInspector, - [GTDApiName.createTodos]: CreateTodosInspector as BuiltinInspector, - [GTDApiName.execTask]: ExecTaskInspector as BuiltinInspector, - [GTDApiName.execTasks]: ExecTasksInspector as BuiltinInspector, - [GTDApiName.updatePlan]: UpdatePlanInspector as BuiltinInspector, - [GTDApiName.updateTodos]: UpdateTodosInspector as BuiltinInspector, -}; diff --git a/packages/builtin-tool-gtd/src/client/Render/ExecTasks/index.tsx b/packages/builtin-tool-gtd/src/client/Render/ExecTasks/index.tsx deleted file mode 100644 index 46088ebb2d..0000000000 --- a/packages/builtin-tool-gtd/src/client/Render/ExecTasks/index.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client'; - -import type { BuiltinRenderProps } from '@lobechat/types'; -import { Block, Text } from '@lobehub/ui'; -import { createStaticStyles } from 'antd-style'; -import { memo } from 'react'; - -import type { ExecTasksParams, ExecTasksState } from '../../../types'; - -const styles = createStaticStyles(({ css, cssVar }) => ({ - index: css` - flex-shrink: 0; - font-size: 12px; - color: ${cssVar.colorTextQuaternary}; - `, - - taskItem: css` - display: flex; - gap: 8px; - align-items: flex-start; - - padding-block: 12px; - padding-inline: 12px; - border-block-end: 1px dashed ${cssVar.colorBorderSecondary}; - - &:last-child { - border-block-end: none; - } - `, -})); - -export const ExecTasksRender = memo>( - ({ pluginState }) => { - const { tasks } = pluginState || {}; - - if (!tasks || tasks.length === 0) return null; - - return ( - - {tasks.map((task, index) => ( -
-
{index + 1}.
-
- {task.description && ( - - {task.description} - - )} - {task.instruction && ( - - {task.instruction} - - )} -
-
- ))} -
- ); - }, -); - -ExecTasksRender.displayName = 'ExecTasksRender'; - -export default ExecTasksRender; diff --git a/packages/builtin-tool-gtd/src/client/Render/index.ts b/packages/builtin-tool-gtd/src/client/Render/index.ts deleted file mode 100644 index ba32cf7dc0..0000000000 --- a/packages/builtin-tool-gtd/src/client/Render/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { GTDApiName } from '../../types'; -import CreatePlan from './CreatePlan'; -import ExecTaskRender from './ExecTask'; -import ExecTasksRender from './ExecTasks'; -import TodoListRender from './TodoList'; - -/** - * GTD Tool Render Components Registry - * - * All todo operations use the same TodoList render component - * which displays the current state of the todo list. - * Plan operations use the CreatePlan render component. - */ -export const GTDRenders = { - // All todo operations render the same TodoList UI - [GTDApiName.clearTodos]: TodoListRender, - [GTDApiName.createTodos]: TodoListRender, - [GTDApiName.updateTodos]: TodoListRender, - - // Plan operations render the PlanCard UI - [GTDApiName.createPlan]: CreatePlan, - [GTDApiName.updatePlan]: CreatePlan, - - // Async task operations - [GTDApiName.execTask]: ExecTaskRender, - [GTDApiName.execTasks]: ExecTasksRender, -}; - -export { default as CreatePlan, PlanCard } from './CreatePlan'; -export { default as ExecTaskRender } from './ExecTask'; -export { default as ExecTasksRender } from './ExecTasks'; -export type { TodoListRenderState } from './TodoList'; -export { default as TodoListRender, TodoListUI } from './TodoList'; diff --git a/packages/builtin-tool-gtd/src/client/Streaming/ExecTasks/index.tsx b/packages/builtin-tool-gtd/src/client/Streaming/ExecTasks/index.tsx deleted file mode 100644 index 7ef25e5327..0000000000 --- a/packages/builtin-tool-gtd/src/client/Streaming/ExecTasks/index.tsx +++ /dev/null @@ -1,77 +0,0 @@ -'use client'; - -import type { BuiltinStreamingProps } from '@lobechat/types'; -import { Block, Markdown } from '@lobehub/ui'; -import { createStaticStyles } from 'antd-style'; -import { memo } from 'react'; - -import type { ExecTasksParams } from '../../../types'; - -const styles = createStaticStyles(({ css, cssVar }) => ({ - index: css` - flex-shrink: 0; - font-size: 12px; - color: ${cssVar.colorTextQuaternary}; - `, - instruction: css` - font-size: 12px; - line-height: 1.5; - color: ${cssVar.colorTextTertiary}; - `, - taskContent: css` - display: flex; - flex: 1; - flex-direction: column; - gap: 2px; - - min-width: 0; - `, - taskItem: css` - display: flex; - gap: 8px; - align-items: flex-start; - - padding-block: 10px; - padding-inline: 12px; - border-block-end: 1px dashed ${cssVar.colorBorderSecondary}; - - &:last-child { - border-block-end: none; - } - `, - title: css` - font-size: 13px; - line-height: 1.4; - color: ${cssVar.colorText}; - `, -})); - -export const ExecTasksStreaming = memo>(({ args }) => { - const { tasks } = args || {}; - - if (!tasks || tasks.length === 0) return null; - - return ( - - {tasks.map((task, index) => ( -
-
{index + 1}.
-
- {task.description &&
{task.description}
} - {task.instruction && ( -
- - {task.instruction} - -
- )} -
-
- ))} -
- ); -}); - -ExecTasksStreaming.displayName = 'ExecTasksStreaming'; - -export default ExecTasksStreaming; diff --git a/packages/builtin-tool-gtd/src/client/Streaming/index.ts b/packages/builtin-tool-gtd/src/client/Streaming/index.ts deleted file mode 100644 index 8b549bef18..0000000000 --- a/packages/builtin-tool-gtd/src/client/Streaming/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { BuiltinStreaming } from '@lobechat/types'; - -import { GTDApiName } from '../../types'; -import { CreatePlanStreaming } from './CreatePlan'; -import { ExecTaskStreaming } from './ExecTask'; -import { ExecTasksStreaming } from './ExecTasks'; - -/** - * GTD Streaming Components Registry - * - * Streaming components render tool calls while they are - * still executing, allowing real-time feedback to users. - */ -export const GTDStreamings: Record = { - [GTDApiName.createPlan]: CreatePlanStreaming as BuiltinStreaming, - [GTDApiName.execTask]: ExecTaskStreaming as BuiltinStreaming, - [GTDApiName.execTasks]: ExecTasksStreaming as BuiltinStreaming, -}; - - - -export {CreatePlanStreaming} from './CreatePlan'; -export {ExecTaskStreaming} from './ExecTask'; -export {ExecTasksStreaming} from './ExecTasks'; \ No newline at end of file diff --git a/packages/builtin-tool-gtd/src/client/index.ts b/packages/builtin-tool-gtd/src/client/index.ts deleted file mode 100644 index 18b5fecfa8..0000000000 --- a/packages/builtin-tool-gtd/src/client/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Inspector components (customized tool call headers) -export { GTDInspectors } from './Inspector'; - -// Render components (read-only snapshots) -export type { TodoListRenderState } from './Render'; -export { GTDRenders, TodoListRender, TodoListUI } from './Render'; - -// Streaming components (real-time tool execution feedback) -export { - CreatePlanStreaming, - ExecTasksStreaming, - ExecTaskStreaming, - GTDStreamings, -} from './Streaming'; - -// Intervention components (interactive editing) -export { AddTodoIntervention, ClearTodosIntervention, GTDInterventions } from './Intervention'; - -// Reusable components -export type { SortableTodoListProps, TodoListItem } from './components'; -export { SortableTodoList } from './components'; - -// Re-export types and manifest for convenience -export { GTDManifest } from '../manifest'; -export * from '../types'; diff --git a/packages/builtin-tool-gtd/src/executor/index.test.ts b/packages/builtin-tool-gtd/src/executor/index.test.ts deleted file mode 100644 index b5c24242b3..0000000000 --- a/packages/builtin-tool-gtd/src/executor/index.test.ts +++ /dev/null @@ -1,421 +0,0 @@ -import type { BuiltinToolContext } from '@lobechat/types'; -import { describe, expect, it } from 'vitest'; - -import { gtdExecutor } from './index'; - -describe('GTDExecutor', () => { - const createMockContext = (pluginState?: Record): BuiltinToolContext => ({ - messageId: 'test-message-id', - operationId: 'test-operation-id', - pluginState, - }); - - describe('createTodos', () => { - it('should add items to empty todo list using adds (AI input)', async () => { - const ctx = createMockContext(); - - const result = await gtdExecutor.createTodos({ adds: ['Buy milk', 'Call mom'] }, ctx); - - expect(result.success).toBe(true); - expect(result.content).toContain('Added 2 items'); - expect(result.content).toContain('Buy milk'); - expect(result.content).toContain('Call mom'); - expect(result.state?.todos.items).toHaveLength(2); - expect(result.state?.todos.items[0].text).toBe('Buy milk'); - expect(result.state?.todos.items[0].status).toBe('todo'); - expect(result.state?.todos.items[1].text).toBe('Call mom'); - }); - - it('should add items using items (user-edited format)', async () => { - const ctx = createMockContext(); - - const result = await gtdExecutor.createTodos( - { - items: [ - { text: 'Buy milk', status: 'todo' }, - { text: 'Call mom', status: 'completed' }, - ], - }, - ctx, - ); - - expect(result.success).toBe(true); - expect(result.content).toContain('Added 2 items'); - expect(result.state?.todos.items).toHaveLength(2); - expect(result.state?.todos.items[0].text).toBe('Buy milk'); - expect(result.state?.todos.items[0].status).toBe('todo'); - expect(result.state?.todos.items[1].text).toBe('Call mom'); - expect(result.state?.todos.items[1].status).toBe('completed'); - }); - - it('should append items to existing todo list', async () => { - const ctx = createMockContext({ - todos: { - items: [{ text: 'Existing task', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.createTodos({ adds: ['New task'] }, ctx); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(2); - expect(result.state?.todos.items[0].text).toBe('Existing task'); - expect(result.state?.todos.items[1].text).toBe('New task'); - }); - - it('should return error when no items provided', async () => { - const ctx = createMockContext(); - - const result = await gtdExecutor.createTodos({ adds: [] }, ctx); - - expect(result.success).toBe(false); - expect(result.content).toContain('No items provided'); - }); - - it('should add single item with correct singular grammar', async () => { - const ctx = createMockContext(); - - const result = await gtdExecutor.createTodos({ adds: ['Single task'] }, ctx); - - expect(result.success).toBe(true); - expect(result.content).toContain('Added 1 item'); - expect(result.content).not.toContain('items'); - }); - - it('should prioritize items over adds when both provided', async () => { - const ctx = createMockContext(); - - const result = await gtdExecutor.createTodos( - { - adds: ['AI task'], - items: [{ text: 'User edited task', status: 'completed' }], - }, - ctx, - ); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(1); - expect(result.state?.todos.items[0].text).toBe('User edited task'); - expect(result.state?.todos.items[0].status).toBe('completed'); - }); - }); - - describe('updateTodos', () => { - it('should add new items via operations', async () => { - const ctx = createMockContext({ - todos: { - items: [{ text: 'Existing task', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.updateTodos( - { - operations: [{ type: 'add', text: 'New task' }], - }, - ctx, - ); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(2); - expect(result.state?.todos.items[1].text).toBe('New task'); - }); - - it('should update item text via operations', async () => { - const ctx = createMockContext({ - todos: { - items: [{ text: 'Old task', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.updateTodos( - { - operations: [{ type: 'update', index: 0, newText: 'Updated task' }], - }, - ctx, - ); - - expect(result.success).toBe(true); - expect(result.state?.todos.items[0].text).toBe('Updated task'); - }); - - it('should complete items via operations', async () => { - const ctx = createMockContext({ - todos: { - items: [{ text: 'Task', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.updateTodos( - { - operations: [{ type: 'complete', index: 0 }], - }, - ctx, - ); - - expect(result.success).toBe(true); - expect(result.state?.todos.items[0].status).toBe('completed'); - }); - - it('should remove items via operations', async () => { - const ctx = createMockContext({ - todos: { - items: [ - { text: 'Task 1', status: 'todo' }, - { text: 'Task 2', status: 'todo' }, - ], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.updateTodos( - { - operations: [{ type: 'remove', index: 0 }], - }, - ctx, - ); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(1); - expect(result.state?.todos.items[0].text).toBe('Task 2'); - }); - - it('should return error when no operations provided', async () => { - const ctx = createMockContext(); - - const result = await gtdExecutor.updateTodos({ operations: [] }, ctx); - - expect(result.success).toBe(false); - expect(result.content).toContain('No operations provided'); - }); - - it('should handle complete operations with out-of-range indices gracefully', async () => { - // Test case: 5 items (indices 0-4), operations reference index 5 (out of range) and index 2 (valid) - const ctx = createMockContext({ - createdItems: ['Task A', 'Task B', 'Task C', 'Task D', 'Task E'], - todos: { - items: [ - { status: 'todo', text: 'Task A' }, - { status: 'todo', text: 'Task B' }, - { status: 'todo', text: 'Task C' }, - { status: 'todo', text: 'Task D' }, - { status: 'todo', text: 'Task E' }, - ], - updatedAt: '2025-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.updateTodos( - { - operations: [ - { index: 5, type: 'complete' }, // out of range - { index: 2, type: 'complete' }, // valid - ], - }, - ctx, - ); - - expect(result.success).toBe(true); - // Should have all 5 items preserved - expect(result.state?.todos.items).toHaveLength(5); - // Index 5 is out of range (0-4), so should be skipped - // Index 2 should be completed - expect(result.state?.todos.items[2].status).toBe('completed'); - // Other items should remain uncompleted - expect(result.state?.todos.items[0].status).toBe('todo'); - expect(result.state?.todos.items[1].status).toBe('todo'); - expect(result.state?.todos.items[3].status).toBe('todo'); - expect(result.state?.todos.items[4].status).toBe('todo'); - }); - }); - - describe('clearTodos', () => { - it('should clear all items when mode is "all"', async () => { - const ctx = createMockContext({ - todos: { - items: [ - { text: 'Task 1', status: 'todo' }, - { text: 'Task 2', status: 'completed' }, - ], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.clearTodos({ mode: 'all' }, ctx); - - expect(result.success).toBe(true); - expect(result.content).toContain('Cleared all 2 items'); - expect(result.state?.todos.items).toHaveLength(0); - }); - - it('should clear only completed items when mode is "completed"', async () => { - const ctx = createMockContext({ - todos: { - items: [ - { text: 'Task 1', status: 'todo' }, - { text: 'Task 2', status: 'completed' }, - { text: 'Task 3', status: 'completed' }, - ], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.clearTodos({ mode: 'completed' }, ctx); - - expect(result.success).toBe(true); - expect(result.content).toContain('Cleared 2 completed items'); - // New format shows "1 pending" instead of "1 item remaining" - expect(result.content).toContain('1 pending'); - expect(result.state?.todos.items).toHaveLength(1); - expect(result.state?.todos.items[0].text).toBe('Task 1'); - }); - - it('should handle empty todo list', async () => { - const ctx = createMockContext({ - todos: { items: [], updatedAt: '2024-01-01T00:00:00.000Z' }, - }); - - const result = await gtdExecutor.clearTodos({ mode: 'all' }, ctx); - - expect(result.success).toBe(true); - expect(result.content).toContain('already empty'); - }); - - it('should handle no completed items to clear', async () => { - const ctx = createMockContext({ - todos: { - items: [{ text: 'Task 1', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }); - - const result = await gtdExecutor.clearTodos({ mode: 'completed' }, ctx); - - expect(result.success).toBe(true); - expect(result.content).toContain('No completed items to clear'); - expect(result.state?.todos.items).toHaveLength(1); - }); - }); - - describe('stepContext priority', () => { - it('should prioritize stepContext.todos over pluginState.todos', async () => { - // Create context with both stepContext and pluginState - const ctx: BuiltinToolContext = { - messageId: 'test-message-id', - operationId: 'test-operation-id', - pluginState: { - todos: { - items: [{ text: 'Old task from pluginState', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }, - stepContext: { - todos: { - items: [{ text: 'New task from stepContext', status: 'completed' }], - updatedAt: '2024-06-01T00:00:00.000Z', - }, - }, - }; - - // createTodos should use stepContext.todos as base - const result = await gtdExecutor.createTodos({ adds: ['Another task'] }, ctx); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(2); - // First item should be from stepContext, not pluginState - expect(result.state?.todos.items[0].text).toBe('New task from stepContext'); - expect(result.state?.todos.items[0].status).toBe('completed'); - expect(result.state?.todos.items[1].text).toBe('Another task'); - }); - - it('should fallback to pluginState.todos when stepContext.todos is undefined', async () => { - const ctx: BuiltinToolContext = { - messageId: 'test-message-id', - operationId: 'test-operation-id', - pluginState: { - todos: { - items: [{ text: 'Task from pluginState', status: 'todo' }], - updatedAt: '2024-01-01T00:00:00.000Z', - }, - }, - stepContext: { - // No todos in stepContext - }, - }; - - const result = await gtdExecutor.createTodos({ adds: ['New task'] }, ctx); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(2); - expect(result.state?.todos.items[0].text).toBe('Task from pluginState'); - expect(result.state?.todos.items[1].text).toBe('New task'); - }); - - it('should start with empty todos when both stepContext and pluginState are empty', async () => { - const ctx: BuiltinToolContext = { - messageId: 'test-message-id', - operationId: 'test-operation-id', - stepContext: {}, - }; - - const result = await gtdExecutor.createTodos({ adds: ['First task'] }, ctx); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(1); - expect(result.state?.todos.items[0].text).toBe('First task'); - }); - - it('should work with stepContext.todos for clearTodos', async () => { - const ctx: BuiltinToolContext = { - messageId: 'test-message-id', - operationId: 'test-operation-id', - stepContext: { - todos: { - items: [ - { text: 'Task 1', status: 'completed' }, - { text: 'Task 2', status: 'todo' }, - ], - updatedAt: '2024-06-01T00:00:00.000Z', - }, - }, - }; - - const result = await gtdExecutor.clearTodos({ mode: 'completed' }, ctx); - - expect(result.success).toBe(true); - expect(result.state?.todos.items).toHaveLength(1); - expect(result.state?.todos.items[0].text).toBe('Task 2'); - }); - }); - - describe('executor metadata', () => { - it('should have correct identifier', () => { - expect(gtdExecutor.identifier).toBe('lobe-gtd'); - }); - - it('should support all APIs', () => { - expect(gtdExecutor.hasApi('createTodos')).toBe(true); - expect(gtdExecutor.hasApi('updateTodos')).toBe(true); - expect(gtdExecutor.hasApi('clearTodos')).toBe(true); - expect(gtdExecutor.hasApi('createPlan')).toBe(true); - expect(gtdExecutor.hasApi('updatePlan')).toBe(true); - expect(gtdExecutor.hasApi('execTask')).toBe(true); - expect(gtdExecutor.hasApi('execTasks')).toBe(true); - }); - - it('should return correct API names', () => { - const apiNames = gtdExecutor.getApiNames(); - expect(apiNames).toContain('createTodos'); - expect(apiNames).toContain('updateTodos'); - expect(apiNames).toContain('clearTodos'); - expect(apiNames).toContain('createPlan'); - expect(apiNames).toContain('updatePlan'); - expect(apiNames).toContain('execTask'); - expect(apiNames).toContain('execTasks'); - expect(apiNames).toHaveLength(7); - }); - }); -}); diff --git a/packages/builtin-tool-gtd/src/executor/index.ts b/packages/builtin-tool-gtd/src/executor/index.ts deleted file mode 100644 index 858511f78a..0000000000 --- a/packages/builtin-tool-gtd/src/executor/index.ts +++ /dev/null @@ -1,136 +0,0 @@ -import type { BuiltinToolContext, BuiltinToolResult } from '@lobechat/types'; -import { BaseExecutor } from '@lobechat/types'; - -import { notebookService } from '@/services/notebook'; -import { useNotebookStore } from '@/store/notebook'; - -import { - GTDExecutionRuntime, - type GTDRuntimeContext, - type GTDRuntimeService, - type PlanDocument, -} from '../ExecutionRuntime'; -import { GTDIdentifier } from '../manifest'; -import type { - ClearTodosParams, - CreatePlanParams, - CreateTodosParams, - ExecTaskParams, - ExecTasksParams, - UpdatePlanParams, - UpdateTodosParams, -} from '../types'; -import { GTDApiName } from '../types'; -import { getTodosFromContext } from './helper'; - -const PLAN_DOC_TYPE = 'agent/plan'; - -/** - * Normalize a document payload returned by notebookService / useNotebookStore - * into the `PlanDocument` shape expected by GTDExecutionRuntime. - */ -const normalizePlanDoc = (doc: { - content?: string | null; - createdAt: Date | string; - description?: string | null; - id: string; - metadata?: Record | null; - title?: string | null; - updatedAt: Date | string; -}): PlanDocument => ({ - content: doc.content ?? null, - createdAt: typeof doc.createdAt === 'string' ? new Date(doc.createdAt) : doc.createdAt, - description: doc.description ?? null, - id: doc.id, - metadata: doc.metadata ?? null, - title: doc.title ?? null, - updatedAt: typeof doc.updatedAt === 'string' ? new Date(doc.updatedAt) : doc.updatedAt, -}); - -/** - * Client-side implementation of the GTD runtime service. - * Routes user-facing plan CRUD through useNotebookStore (so SWR caches refresh), - * and keeps silent metadata writes (todos sync) on the raw notebookService. - */ -const clientGTDService: GTDRuntimeService = { - createPlan: async ({ topicId, goal, description, content }) => { - const doc = await useNotebookStore.getState().createDocument({ - content, - description, - title: goal, - topicId, - type: PLAN_DOC_TYPE, - }); - return normalizePlanDoc(doc); - }, - - findPlanById: async (id) => { - const doc = await notebookService.getDocument(id); - return doc ? normalizePlanDoc(doc) : null; - }, - - findPlanByTopic: async (topicId) => { - const result = await notebookService.listDocuments({ topicId, type: PLAN_DOC_TYPE }); - const first = result.data[0]; - return first ? normalizePlanDoc(first) : null; - }, - - updatePlan: async (id, { goal, description, content }, topicId) => { - const doc = await useNotebookStore - .getState() - .updateDocument({ content, description, id, title: goal }, topicId ?? ''); - if (!doc) throw new Error(`Plan not found after update: ${id}`); - return normalizePlanDoc(doc); - }, - - updatePlanMetadata: async (id, metadata) => { - await notebookService.updateDocument({ id, metadata }); - }, -}; - -const GTDApiNameEnum = { - clearTodos: GTDApiName.clearTodos, - createPlan: GTDApiName.createPlan, - createTodos: GTDApiName.createTodos, - execTask: GTDApiName.execTask, - execTasks: GTDApiName.execTasks, - updatePlan: GTDApiName.updatePlan, - updateTodos: GTDApiName.updateTodos, -} as const; - -const toRuntimeContext = (ctx: BuiltinToolContext): GTDRuntimeContext => ({ - currentTodos: getTodosFromContext(ctx), - messageId: ctx.messageId, - signal: ctx.signal, - topicId: ctx.topicId ?? undefined, -}); - -class GTDExecutor extends BaseExecutor { - readonly identifier = GTDIdentifier; - protected readonly apiEnum = GTDApiNameEnum; - - private runtime = new GTDExecutionRuntime(clientGTDService); - - createTodos = (params: CreateTodosParams, ctx: BuiltinToolContext): Promise => - this.runtime.createTodos(params, toRuntimeContext(ctx)); - - updateTodos = (params: UpdateTodosParams, ctx: BuiltinToolContext): Promise => - this.runtime.updateTodos(params, toRuntimeContext(ctx)); - - clearTodos = (params: ClearTodosParams, ctx: BuiltinToolContext): Promise => - this.runtime.clearTodos(params, toRuntimeContext(ctx)); - - createPlan = (params: CreatePlanParams, ctx: BuiltinToolContext): Promise => - this.runtime.createPlan(params, toRuntimeContext(ctx)); - - updatePlan = (params: UpdatePlanParams, ctx: BuiltinToolContext): Promise => - this.runtime.updatePlan(params, toRuntimeContext(ctx)); - - execTask = (params: ExecTaskParams, ctx: BuiltinToolContext): Promise => - this.runtime.execTask(params, toRuntimeContext(ctx)); - - execTasks = (params: ExecTasksParams, ctx: BuiltinToolContext): Promise => - this.runtime.execTasks(params, toRuntimeContext(ctx)); -} - -export const gtdExecutor = new GTDExecutor(); diff --git a/packages/builtin-tool-gtd/src/index.ts b/packages/builtin-tool-gtd/src/index.ts deleted file mode 100644 index 95ce02e077..0000000000 --- a/packages/builtin-tool-gtd/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './manifest'; -export * from './systemRole'; -export * from './types'; diff --git a/packages/builtin-tool-gtd/src/manifest.ts b/packages/builtin-tool-gtd/src/manifest.ts deleted file mode 100644 index 3ace391ee5..0000000000 --- a/packages/builtin-tool-gtd/src/manifest.ts +++ /dev/null @@ -1,247 +0,0 @@ -import type { BuiltinToolManifest } from '@lobechat/types'; - -import { isDesktop } from './const'; -import { systemPrompt } from './systemRole'; -import { GTDApiName } from './types'; - -export const GTDIdentifier = 'lobe-gtd'; - -export const GTDManifest: BuiltinToolManifest = { - api: [ - // ==================== Planning ==================== - { - description: - 'Create a high-level plan document. Plans define the strategic direction (the "what" and "why"), while todos handle the actionable steps.', - name: GTDApiName.createPlan, - humanIntervention: 'required', - renderDisplayControl: 'expand', - parameters: { - properties: { - goal: { - description: 'The main goal or objective to achieve (used as document title).', - type: 'string', - }, - description: { - description: 'A brief summary of the plan (1-2 sentences).', - type: 'string', - }, - context: { - description: - 'Detailed context, constraints, background information, or strategic considerations relevant to the goal.', - type: 'string', - }, - }, - required: ['goal', 'description', 'context'], - type: 'object', - }, - }, - { - description: - 'Update an existing plan document. Only use this when the goal fundamentally changes. Plans should remain stable once created - do not update plans just because details change.', - name: GTDApiName.updatePlan, - parameters: { - properties: { - planId: { - description: - 'The document ID of the plan to update (e.g., "docs_xxx"). This ID is returned in the createPlan response. Do NOT use the goal text as planId.', - type: 'string', - }, - goal: { - description: 'Updated goal (document title).', - type: 'string', - }, - description: { - description: 'Updated brief summary.', - type: 'string', - }, - context: { - description: 'Updated detailed context.', - type: 'string', - }, - }, - required: ['planId'], - type: 'object', - }, - }, - - // ==================== Quick Todo ==================== - { - description: 'Create new todo items. Pass an array of text strings.', - name: GTDApiName.createTodos, - humanIntervention: 'required', - parameters: { - properties: { - adds: { - description: 'Array of todo item texts to create.', - items: { type: 'string' }, - type: 'array', - }, - }, - required: ['adds'], - type: 'object', - }, - }, - { - description: `Update todo items with batch operations. Each operation type requires specific fields: -- "add": requires "text" (the todo text to add) -- "update": requires "index", optional "newText" and/or "status" -- "remove": requires "index" only -- "complete": requires "index" only (marks item as completed) -- "processing": requires "index" only (marks item as in progress)`, - name: GTDApiName.updateTodos, - renderDisplayControl: 'expand', - parameters: { - properties: { - operations: { - description: - 'Array of update operations. IMPORTANT: For "complete", "processing" and "remove" operations, only pass "type" and "index" - no other fields needed.', - items: { - properties: { - type: { - description: - 'Operation type. "add" needs text, "update" needs index + optional newText/status, "remove", "complete" and "processing" need index only.', - enum: ['add', 'update', 'remove', 'complete', 'processing'], - type: 'string', - }, - text: { - description: 'Required for "add" only: the text to add.', - type: 'string', - }, - index: { - description: - 'Required for "update", "remove", "complete", "processing": the item index (0-based).', - type: 'number', - }, - newText: { - description: 'Optional for "update" only: the new text.', - type: 'string', - }, - status: { - description: - 'Optional for "update" only: set status (todo, processing, completed).', - enum: ['todo', 'processing', 'completed'], - type: 'string', - }, - }, - required: ['type'], - type: 'object', - }, - type: 'array', - }, - }, - required: ['operations'], - type: 'object', - }, - }, - { - description: 'Clear todo items. Can clear only completed items or all items.', - name: GTDApiName.clearTodos, - humanIntervention: 'always', - renderDisplayControl: 'expand', - parameters: { - properties: { - mode: { - description: '"completed" clears only done items, "all" clears the entire list.', - enum: ['completed', 'all'], - type: 'string', - }, - }, - required: ['mode'], - type: 'object', - }, - }, - - // ==================== Async Tasks ==================== - { - description: - 'Execute a single long-running async task. The task runs in an isolated context and can take significant time to complete. Use this for a single complex operation that requires extended processing.', - name: GTDApiName.execTask, - parameters: { - properties: { - description: { - description: 'Brief description of what this task does (shown in UI).', - type: 'string', - }, - instruction: { - description: 'Detailed instruction/prompt for the task execution.', - type: 'string', - }, - inheritMessages: { - description: - 'Whether to inherit context messages from the parent conversation. Default is false.', - type: 'boolean', - }, - ...(isDesktop && { - runInClient: { - description: - 'Whether to run on the desktop client (for local file/shell access). MUST be true when task requires local-system tools. Default is false (server execution).', - type: 'boolean', - }, - }), - timeout: { - description: 'Optional timeout in milliseconds. Default is 30 minutes.', - type: 'number', - }, - }, - required: ['description', 'instruction'], - type: 'object', - }, - }, - { - description: - 'Execute one or more long-running async tasks. Each task runs in an isolated context and can take significant time to complete. Use this for complex operations that require extended processing.', - name: GTDApiName.execTasks, - parameters: { - properties: { - tasks: { - description: 'Array of tasks to execute asynchronously.', - items: { - properties: { - description: { - description: 'Brief description of what this task does (shown in UI).', - type: 'string', - }, - instruction: { - description: 'Detailed instruction/prompt for the task execution.', - type: 'string', - }, - inheritMessages: { - description: - 'Whether to inherit context messages from the parent conversation. Default is false.', - type: 'boolean', - }, - ...(isDesktop && { - runInClient: { - description: - 'Whether to run on the desktop client (for local file/shell access). MUST be true when task requires local-system tools. Default is false (server execution).', - type: 'boolean', - }, - }), - timeout: { - description: 'Optional timeout in milliseconds. Default is 30 minutes.', - type: 'number', - }, - }, - required: ['description', 'instruction'], - type: 'object', - }, - type: 'array', - }, - }, - required: ['tasks'], - type: 'object', - }, - }, - ], - identifier: GTDIdentifier, - meta: { - avatar: '✅', - description: - 'Plan and track one-time goals, manage todo checklists, and run background tasks. For tasks that need to be done once or tracked manually — NOT for tasks that should repeat automatically on a schedule (use lobe-cron for daily/weekly/recurring automation).', - title: 'GTD Tools', - }, - systemRole: systemPrompt, - type: 'builtin', -}; - -export { GTDApiName } from './types'; diff --git a/packages/builtin-tool-gtd/src/systemRole.ts b/packages/builtin-tool-gtd/src/systemRole.ts deleted file mode 100644 index 209991af11..0000000000 --- a/packages/builtin-tool-gtd/src/systemRole.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { isDesktop } from './const'; - -const runInClientSection = ` - -**IMPORTANT: When to use \`runInClient: true\` for async tasks** - -The \`runInClient\` parameter controls WHERE the async task executes: -- \`runInClient: false\` (default): Task runs on the **server** - suitable for web searches, API calls, general research -- \`runInClient: true\`: Task runs on the **desktop client** - required for local system access - -**MUST set \`runInClient: true\` when the task involves:** -- Reading or writing local files (via \`local-system\` tool) -- Executing shell commands on the user's machine -- Accessing local directories or file system -- Any operation that requires desktop-only local tools - -**Keep \`runInClient: false\` (or omit) when:** -- Task only needs web searches or API calls -- Task processes data that doesn't require local file access -- Task can be fully completed with server-side capabilities - -**Note:** \`runInClient\` only has effect on the **desktop app**. On web platform, tasks always run on the server regardless of this setting. - -**Examples:** -- "Research Python best practices" → \`runInClient: false\` (web search only) -- "Organize files in my Downloads folder" → \`runInClient: true\` (local file access required) -- "Read the project README and summarize it" → \`runInClient: true\` (local file read required) -- "Find trending tech news" → \`runInClient: false\` (web search only) -- "Create a new directory structure for my project" → \`runInClient: true\` (local shell/file required) - -`; - -export const systemPrompt = `You have GTD (Getting Things Done) tools to help manage plans, todos and tasks effectively. These tools support three levels of task management: - -- **Plan**: A high-level strategic document describing goals, context, and overall direction. Plans do NOT contain actionable steps - they define the "what" and "why". **Plans should be stable once created** - they represent the overarching objective that rarely changes. -- **Todo**: The concrete execution list with actionable items. Todos define the "how" - specific tasks to accomplish the plan. **Todos are dynamic** - they can be added, updated, completed, and removed as work progresses. -- **Task**: Long-running async operations that execute in isolated contexts. Tasks are for complex, multi-step operations that require extended processing time. **Tasks run independently** - they can inherit context but execute separately from the main conversation. - - -**Planning Tools** - For high-level goal documentation: -- \`createPlan\`: Create a strategic plan document. **Required params: goal, description (brief summary), context** - all three must be provided -- \`updatePlan\`: Update plan details (only planId is required) - -**Todo Tools** - For actionable execution items: -- \`createTodos\`: Create new todo items from text array -- \`updateTodos\`: Batch update todos (add, update, remove, complete, processing operations) -- \`clearTodos\`: Clear completed or all items - -**Todo Status Workflow:** todo → processing → completed (use "processing" when actively working on an item) - -**Async Task Tools** - For long-running background tasks: -- \`execTask\`: Execute a single async task. **Required params: description (brief UI label), instruction (detailed prompt)** - both must be provided -- \`execTasks\`: Execute multiple async tasks in parallel. Each task requires **description** and **instruction** - - - -**CRITICAL: Most tasks do NOT need GTD tools. Only use them for complex, multi-step projects.** - -**DO NOT use GTD tools for:** -- Simple one-step tasks (rename a file, send a message, search something) -- Quick questions or lookups -- Tasks that can be completed immediately with a single action -- Any request that doesn't require tracking progress over time - -**ONLY use GTD tools when ALL of these are true:** -1. The task has multiple distinct steps that need tracking -2. The user explicitly wants to plan or organize something -3. Progress needs to be tracked over time (not completed in one response) - -**When GTD tools ARE appropriate:** -1. **First**, use \`createPlan\` to document the goal and relevant context -2. **Then**, use \`createTodos\` to break down the plan into actionable steps - -**Examples:** -- ❌ "Rename this file" → Just do it, no GTD needed -- ❌ "What's the weather?" → Just answer, no GTD needed -- ❌ "Help me write an email" → Just write it, no GTD needed -- ✅ "Help me plan a trip to Japan" → Use createPlan + createTodos -- ✅ "I want to learn Python, create a study plan" → Use createPlan + createTodos -- ✅ "Help me organize my project tasks" → Use createTodos (user explicitly wants organization) - - - -**Use Plans when:** -- User explicitly asks to "plan", "organize", or "break down" a complex goal -- The project spans multiple sessions or days -- There's significant context, constraints, or background worth documenting -- The task has 5+ distinct steps that benefit from strategic organization - -**Use Todos when:** -- Breaking down a plan into actionable steps (after creating a plan) -- User explicitly requests a checklist or task list -- Tracking progress on a multi-step project - -**DO NOT use Plans/Todos when:** -- The task can be done in one action (rename, delete, send, search, etc.) -- The user just wants something done, not organized -- The task will be completed in this single conversation -- The user wants a task to repeat automatically on a schedule (daily/weekly/hourly) — use **lobe-cron** instead. Keywords like "daily task", "routine", "recurring", "every day/morning/week", "set as daily", "make it regular" all indicate scheduled automation, not GTD todo management. - -**Use Async Tasks when:** -- **The request requires gathering external information**: User wants you to research, investigate, or find information that you don't already know. This requires web searches, reading multiple sources, and synthesizing information. -- **The task involves multiple steps**: The request cannot be answered in one simple response - it requires searching, reading, analyzing, and summarizing. -- **Quality depends on thorough investigation**: A superficial answer would be insufficient; the user expects comprehensive, well-researched results. -- **Independent execution is beneficial**: The task can run separately while freeing up the main conversation. - -**How to identify async task scenarios:** -Ask yourself: "Can I answer this well from my existing knowledge, or does this require actively gathering new information?" -- If you need to search the web, read articles, or investigate → Use async task -- If you can answer directly from knowledge → Just respond - -Use \`execTask\` for a single task, \`execTasks\` for multiple parallel tasks. - -**Example scenarios:** -- User asks about best restaurants in a city → execTask (needs current info from reviews, searches) -- User wants research on a topic → execTask (multi-step: search, read, analyze, summarize) -- User asks to compare products/services → execTask (needs to gather data from multiple sources) -- User asks a factual question you know → Just answer directly -- User wants multiple independent analyses → execTasks (parallel execution) - -${isDesktop ? runInClientSection : ''} - -- **Plan first, then todos**: Always start with a plan unless explicitly told otherwise -- **Separate concerns**: Plans describe goals; Todos list actions -- **Actionable todos**: Each todo should be a concrete, completable task -- **Context in plans**: Use plan's context field to capture constraints and background -- **Regular cleanup**: Clear completed todos to keep the list focused -- **Track progress**: Use todo completion to measure plan progress - - - -When using \`updateTodos\`, each operation type requires specific fields: - -**Todo Status:** -- \`todo\`: Not started yet -- \`processing\`: Currently in progress -- \`completed\`: Done - -**Minimal required fields per operation type:** -- \`{ "type": "add", "text": "todo text" }\` - only type + text -- \`{ "type": "complete", "index": 0 }\` - only type + index (marks as completed) -- \`{ "type": "processing", "index": 0 }\` - only type + index (marks as in progress) -- \`{ "type": "remove", "index": 0 }\` - only type + index -- \`{ "type": "update", "index": 0, "newText": "..." }\` - type + index + optional newText/status - -**Example - mark item 0 as processing, item 1 as complete:** -\`\`\`json -{ - "operations": [ - { "type": "processing", "index": 0 }, - { "type": "complete", "index": 1 } - ] -} -\`\`\` - -**DO NOT** add extra fields like \`"status": "completed"\` for complete/processing operations - they are ignored. - - - -**IMPORTANT: Keep todos focused on major stages, not detailed sub-tasks.** - -- **Limit to 5-10 items**: A todo list should contain around 5-10 major milestones or stages, not 20+ detailed tasks. -- **Think in phases**: Group related tasks into higher-level stages (e.g., "Plan itinerary" instead of listing every city separately). -- **Use hierarchical numbering** when more detail is needed: Use "1.", "2.", "2.1", "2.2", "3." format to show parent-child relationships. - -**Good example** (Japan trip - 7 items, stage-focused): -- 1. Determine travel dates and duration -- 2. Handle visa and documentation -- 3. Book flights and accommodation -- 4. Plan city itineraries -- 5. Arrange local transportation -- 6. Prepare for departure -- 7. Final confirmation before trip - -**Bad example** (20+ detailed items): -- Book Tokyo hotel -- Book Kyoto hotel -- Book Osaka hotel -- Buy Suica card -- Download Google Maps -- Download translation app -- ... (too granular!) - -**When user needs more detail**, use hierarchical numbering: -- 1. Determine travel dates -- 2. Plan itinerary -- 2.1 Tokyo attractions (3 days) -- 2.2 Kyoto attractions (2 days) -- 2.3 Osaka attractions (2 days) -- 3. Handle bookings -- 3.1 Flights -- 3.2 Hotels -- 3.3 JR Pass -- 4. Departure preparation - - - -**IMPORTANT: Plans should remain stable once created. Each conversation has only ONE plan.** - -- **Do NOT update plans** when details change (dates, locations, preferences). Instead, update the todos to reflect new information. -- **Only use updatePlan** when the user's goal fundamentally changes (e.g., destination changes from Japan to Korea). -- When user provides more specific information (like exact dates or preferences), **update or add todos** - not the plan. - -Example: -- User: "Plan a trip to Japan" → Create plan with goal "Japan Trip" -- User: "I want to go in February" → Update todos to include February-specific tasks, NOT update the plan -- User: "Actually I want to go to Korea instead" → Use updatePlan to change the goal to "Korea Trip" (fundamental goal change) - - - -When working with GTD tools: -- Confirm actions: "Created plan: [goal]" or "Added [n] todo items" -- Show progress: "Completed [n] items, [m] remaining" -- Be concise: Brief confirmations, not verbose explanations -- **NEVER repeat the todo list in your response** - Users can already see the todos in the UI component. Do not list or enumerate the todo items in your text output. -`; diff --git a/packages/builtin-tool-gtd/src/types.ts b/packages/builtin-tool-gtd/src/types.ts deleted file mode 100644 index 34a14c06dd..0000000000 --- a/packages/builtin-tool-gtd/src/types.ts +++ /dev/null @@ -1,333 +0,0 @@ -/** - * API names for GTD (Getting Things Done) tool - * - * GTD Tools help users and agents manage tasks effectively. - * These tools can be used by: - * - LobeAI default assistant for user task management - * - Group Supervisor for multi-agent task orchestration - * - * MVP version focuses on Plan and Todo functionality. - * Task management will be added in future iterations. - */ -export const GTDApiName = { - // ==================== Quick Todo ==================== - /** Clear completed or all todos */ - clearTodos: 'clearTodos', - - // ==================== Planning ==================== - /** Create a structured plan by breaking down a goal into actionable steps */ - createPlan: 'createPlan', - - /** Create new todo items */ - createTodos: 'createTodos', - - // ==================== Async Tasks ==================== - /** Execute a single async task */ - execTask: 'execTask', - - /** Execute one or more async tasks */ - execTasks: 'execTasks', - - /** Update an existing plan */ - updatePlan: 'updatePlan', - - /** Update todo items with batch operations (add, update, remove, complete, processing) */ - updateTodos: 'updateTodos', -} as const; - -export type GTDApiNameType = (typeof GTDApiName)[keyof typeof GTDApiName]; - -// ==================== Todo Item ==================== - -/** Status of a todo item */ -export type TodoStatus = 'todo' | 'processing' | 'completed'; - -export interface TodoItem { - /** Status of the todo item */ - status: TodoStatus; - /** The todo item text */ - text: string; -} - -/** Get the next status in the cycle: todo → processing → completed → todo */ -export const getNextTodoStatus = (current: TodoStatus): TodoStatus => { - const cycle: TodoStatus[] = ['todo', 'processing', 'completed']; - const index = cycle.indexOf(current); - return cycle[(index + 1) % cycle.length]; -}; - -export interface TodoList { - items: TodoItem[]; - updatedAt: string; -} - -/** Alias for TodoList, used for state storage in Plan metadata */ -export type TodoState = TodoList; - -// ==================== Todo Params ==================== - -/** - * Create new todo items - * - AI input: { adds: string[] } - array of text strings from AI - * - After user edit: { items: TodoItem[] } - saved format with TodoItem objects - */ -export interface CreateTodosParams { - /** Array of text strings from AI */ - adds?: string[]; - /** Array of TodoItem objects (saved format after user edit) */ - items?: TodoItem[]; -} - -/** - * Update operation types for batch updates - */ -export type TodoUpdateOperationType = 'add' | 'update' | 'remove' | 'complete' | 'processing'; - -/** - * Single update operation - */ -export interface TodoUpdateOperation { - /** For 'update', 'remove', 'complete', 'processing': the index of the item (0-based) */ - index?: number; - /** For 'update': the new text */ - newText?: string; - /** For 'update': the new status */ - status?: TodoStatus; - /** For 'add': the text to add */ - text?: string; - /** Operation type */ - type: TodoUpdateOperationType; -} - -/** - * Update todo list with batch operations - * Supports: add, update, remove, complete, processing - */ -export interface UpdateTodosParams { - /** Array of update operations to apply */ - operations: TodoUpdateOperation[]; -} - -/** - * Clear todo items - */ -export interface ClearTodosParams { - /** Clear mode: 'completed' only clears done items, 'all' clears everything */ - mode: 'completed' | 'all'; -} - -// ==================== Todo State Types for Render ==================== - -export interface CreateTodosState { - /** Items that were created */ - createdItems: string[]; - /** Current todo list after creation */ - todos: TodoList; -} - -export interface UpdateTodosState { - /** Operations that were applied */ - appliedOperations: TodoUpdateOperation[]; - /** Current todo list after update */ - todos: TodoList; -} - -export interface CompleteTodosState { - /** Indices that were completed */ - completedIndices: number[]; - /** Current todo list after completion */ - todos: TodoList; -} - -export interface RemoveTodosState { - /** Indices that were removed */ - removedIndices: number[]; - /** Current todo list after removal */ - todos: TodoList; -} - -export interface ClearTodosState { - /** Number of items cleared */ - clearedCount: number; - /** Mode used for clearing */ - mode: 'completed' | 'all'; - /** Current todo list after clearing */ - todos: TodoList; -} - -// ==================== Planning Params ==================== - -/** - * Create a high-level plan document - * Plans define the strategic direction (what and why), not actionable steps - * - * Field mapping to Document: - * - goal -> document.title - * - description -> document.description - * - context -> document.content - */ -export interface CreatePlanParams { - /** Detailed context, background, constraints (maps to document.content) */ - context?: string; - /** Brief summary of the plan (maps to document.description) */ - description: string; - /** The main goal or objective to achieve (maps to document.title) */ - goal: string; -} - -export interface UpdatePlanParams { - /** Mark plan as completed */ - completed?: boolean; - /** Updated context (maps to document.content) */ - context?: string; - /** Updated description (maps to document.description) */ - description?: string; - /** Updated goal (maps to document.title) */ - goal?: string; - /** Plan ID to update */ - planId: string; -} - -// ==================== Plan Result Types ==================== - -/** - * A high-level plan document - * Contains goal and context, but no steps (steps are managed via Todos) - * - * Field mapping to Document: - * - goal -> document.title - * - description -> document.description - * - context -> document.content - */ -export interface Plan { - /** Whether the plan is completed */ - completed: boolean; - /** Detailed context, background, constraints (maps to document.content) */ - context?: string; - /** Creation timestamp */ - createdAt: string; - /** Brief summary of the plan (maps to document.description) */ - description: string; - /** The main goal or objective (maps to document.title) */ - goal: string; - /** Unique plan identifier */ - id: string; - /** Last update timestamp */ - updatedAt: string; -} - -// ==================== Plan State Types for Render ==================== - -export interface CreatePlanState { - /** The created plan document */ - plan: Plan; -} - -export interface UpdatePlanState { - /** The updated plan document */ - plan: Plan; -} - -// ==================== Async Tasks Types ==================== - -/** - * Single task item for execution - */ -export interface ExecTaskItem { - /** Brief description of what this task does (shown in UI) */ - description: string; - /** Whether to inherit context messages from parent conversation */ - inheritMessages?: boolean; - /** Detailed instruction/prompt for the task execution */ - instruction: string; - /** - * Whether to execute the task on the client side (desktop only). - * When true and running on desktop, the task will be executed locally - * with access to local tools (file system, shell commands, etc.). - * - * MUST be true when task requires local-system tools. - */ - runInClient?: boolean; - /** Timeout in milliseconds (optional, default 30 minutes) */ - timeout?: number; -} - -/** - * Parameters for execTask API - * Execute a single async task - */ -export interface ExecTaskParams { - /** Brief description of what this task does (shown in UI) */ - description: string; - /** Whether to inherit context messages from parent conversation */ - inheritMessages?: boolean; - /** Detailed instruction/prompt for the task execution */ - instruction: string; - /** - * Whether to execute the task on the client side (desktop only). - * When true and running on desktop, the task will be executed locally - * with access to local tools (file system, shell commands, etc.). - * - * MUST be true when task requires local-system tools. - */ - runInClient?: boolean; - /** Timeout in milliseconds (optional, default 30 minutes) */ - timeout?: number; -} - -/** - * Parameters for execTasks API - * Execute one or more async tasks - */ -export interface ExecTasksParams { - /** Array of tasks to execute */ - tasks: ExecTaskItem[]; -} - -/** - * State returned after triggering exec_task (server-side) - */ -export interface ExecTaskState { - /** Parent message ID (tool message) */ - parentMessageId: string; - /** The task definition that was triggered */ - task: ExecTaskItem; - /** Type identifier for render component */ - type: 'execTask'; -} - -/** - * State returned after triggering exec_tasks (server-side) - */ -export interface ExecTasksState { - /** Parent message ID (tool message) */ - parentMessageId: string; - /** Array of task definitions that were triggered */ - tasks: ExecTaskItem[]; - /** Type identifier for render component */ - type: 'execTasks'; -} - -/** - * State returned after triggering exec_client_task (client-side, desktop only) - */ -export interface ExecClientTaskState { - /** Parent message ID (tool message) */ - parentMessageId: string; - /** The task definition that was triggered */ - task: ExecTaskItem; - /** Type identifier for render component */ - type: 'execClientTask'; -} - -/** - * State returned after triggering exec_client_tasks (client-side, desktop only) - */ -export interface ExecClientTasksState { - /** Parent message ID (tool message) */ - parentMessageId: string; - /** Array of task definitions that were triggered */ - tasks: ExecTaskItem[]; - /** Type identifier for render component */ - type: 'execClientTasks'; -} diff --git a/packages/builtin-tool-lobe-agent/package.json b/packages/builtin-tool-lobe-agent/package.json index 52839bab11..5b8aa146f2 100644 --- a/packages/builtin-tool-lobe-agent/package.json +++ b/packages/builtin-tool-lobe-agent/package.json @@ -4,7 +4,7 @@ "private": true, "exports": { ".": "./src/index.ts", - "./executor": "./src/executor/index.ts" + "./client": "./src/client/index.ts" }, "main": "./src/index.ts", "scripts": { @@ -12,7 +12,19 @@ "test:coverage": "vitest --coverage --silent='passed-only'", "test:update": "vitest -u" }, + "dependencies": { + "@lobechat/const": "workspace:*", + "@lobechat/prompts": "workspace:*" + }, "devDependencies": { "@lobechat/types": "workspace:*" + }, + "peerDependencies": { + "@lobehub/editor": "^4", + "@lobehub/ui": "^5", + "antd": "^6", + "antd-style": "*", + "lucide-react": "*", + "react": "*" } } diff --git a/packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgent/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgent/index.tsx new file mode 100644 index 0000000000..65592bf8d3 --- /dev/null +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgent/index.tsx @@ -0,0 +1,57 @@ +'use client'; + +import type { BuiltinInspectorProps } from '@lobechat/types'; +import { cx } from 'antd-style'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { highlightTextStyles, inspectorTextStyles, shinyTextStyles } from '@/styles'; + +import type { CallSubAgentParams, CallSubAgentState } from '../../../types'; + +export const CallSubAgentInspector = memo< + BuiltinInspectorProps +>(({ args, partialArgs, isArgumentsStreaming, isLoading }) => { + const { t } = useTranslation('plugin'); + + const description = args?.description || partialArgs?.description; + + if (isArgumentsStreaming) { + if (!description) + return ( +
+ {t('builtins.lobe-agent.apiName.callSubAgent')} +
+ ); + + return ( +
+ {t('builtins.lobe-agent.apiName.callSubAgent.loading')} + {description} +
+ ); + } + + if (description) { + return ( +
+ + {isLoading + ? t('builtins.lobe-agent.apiName.callSubAgent.loading') + : t('builtins.lobe-agent.apiName.callSubAgent.completed')} + + {description} +
+ ); + } + + return ( +
+ {t('builtins.lobe-agent.apiName.callSubAgent')} +
+ ); +}); + +CallSubAgentInspector.displayName = 'CallSubAgentInspector'; + +export default CallSubAgentInspector; diff --git a/packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgents/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgents/index.tsx new file mode 100644 index 0000000000..6b0592d49d --- /dev/null +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/CallSubAgents/index.tsx @@ -0,0 +1,75 @@ +'use client'; + +import type { BuiltinInspectorProps } from '@lobechat/types'; +import { Icon } from '@lobehub/ui'; +import { createStaticStyles, cx } from 'antd-style'; +import { ListTodo } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { highlightTextStyles, shinyTextStyles } from '@/styles'; + +import type { CallSubAgentsParams, CallSubAgentsState } from '../../../types'; + +const styles = createStaticStyles(({ css, cssVar }) => ({ + count: css` + flex-shrink: 0; + margin-inline-start: 4px; + color: ${cssVar.colorTextSecondary}; + `, + description: css` + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + `, + root: css` + overflow: hidden; + display: flex; + gap: 4px; + align-items: center; + `, + title: css` + flex-shrink: 0; + color: ${cssVar.colorText}; + `, +})); + +export const CallSubAgentsInspector = memo< + BuiltinInspectorProps +>(({ args, partialArgs, isArgumentsStreaming }) => { + const { t } = useTranslation('plugin'); + + const tasks = args?.tasks || partialArgs?.tasks || []; + const count = tasks.length; + const firstTask = tasks[0]; + + if (isArgumentsStreaming && count === 0) { + return ( +
+ {t('builtins.lobe-agent.apiName.callSubAgents')} +
+ ); + } + + return ( +
+ + {t('builtins.lobe-agent.apiName.callSubAgents')}: + + {firstTask?.description && ( + + {firstTask.description} + + )} + {count > 1 && ( + + {count} + + )} +
+ ); +}); + +CallSubAgentsInspector.displayName = 'CallSubAgentsInspector'; + +export default CallSubAgentsInspector; diff --git a/packages/builtin-tool-gtd/src/client/Inspector/ClearTodos/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/ClearTodos/index.tsx similarity index 84% rename from packages/builtin-tool-gtd/src/client/Inspector/ClearTodos/index.tsx rename to packages/builtin-tool-lobe-agent/src/client/Inspector/ClearTodos/index.tsx index 25b1cfde01..312ccdc66b 100644 --- a/packages/builtin-tool-gtd/src/client/Inspector/ClearTodos/index.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/ClearTodos/index.tsx @@ -26,15 +26,15 @@ export const ClearTodosInspector = memo - {t('builtins.lobe-gtd.apiName.clearTodos')} + {t('builtins.lobe-agent.apiName.clearTodos')} ); } const modeLabel = mode === 'all' - ? t('builtins.lobe-gtd.apiName.clearTodos.modeAll') - : t('builtins.lobe-gtd.apiName.clearTodos.modeCompleted'); + ? t('builtins.lobe-agent.apiName.clearTodos.modeAll') + : t('builtins.lobe-agent.apiName.clearTodos.modeCompleted'); return (
}} - i18nKey="builtins.lobe-gtd.apiName.clearTodos.result" + i18nKey="builtins.lobe-agent.apiName.clearTodos.result" ns="plugin" values={{ mode: modeLabel }} /> diff --git a/packages/builtin-tool-gtd/src/client/Inspector/CreatePlan/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/CreatePlan/index.tsx similarity index 85% rename from packages/builtin-tool-gtd/src/client/Inspector/CreatePlan/index.tsx rename to packages/builtin-tool-lobe-agent/src/client/Inspector/CreatePlan/index.tsx index 3c95767bdf..6904ce18d5 100644 --- a/packages/builtin-tool-gtd/src/client/Inspector/CreatePlan/index.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/CreatePlan/index.tsx @@ -18,7 +18,7 @@ export const CreatePlanInspector = memo - {t('builtins.lobe-gtd.apiName.createPlan')} + {t('builtins.lobe-agent.apiName.createPlan')}
); } @@ -30,12 +30,12 @@ export const CreatePlanInspector = memo }} - i18nKey="builtins.lobe-gtd.apiName.createPlan.result" + i18nKey="builtins.lobe-agent.apiName.createPlan.result" ns="plugin" values={{ goal }} /> ) : ( - {t('builtins.lobe-gtd.apiName.createPlan')} + {t('builtins.lobe-agent.apiName.createPlan')} )} ); diff --git a/packages/builtin-tool-gtd/src/client/Inspector/CreateTodos/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/CreateTodos/index.tsx similarity index 90% rename from packages/builtin-tool-gtd/src/client/Inspector/CreateTodos/index.tsx rename to packages/builtin-tool-lobe-agent/src/client/Inspector/CreateTodos/index.tsx index c44a4d4b65..8dbcfea93c 100644 --- a/packages/builtin-tool-gtd/src/client/Inspector/CreateTodos/index.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/CreateTodos/index.tsx @@ -30,14 +30,14 @@ export const CreateTodosInspector = memo< if (isArgumentsStreaming && count === 0) { return (
- {t('builtins.lobe-gtd.apiName.createTodos')} + {t('builtins.lobe-agent.apiName.createTodos')}
); } return (
- {t('builtins.lobe-gtd.apiName.createTodos')} + {t('builtins.lobe-agent.apiName.createTodos')} {count > 0 && ( diff --git a/packages/builtin-tool-gtd/src/client/Inspector/UpdatePlan/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/UpdatePlan/index.tsx similarity index 85% rename from packages/builtin-tool-gtd/src/client/Inspector/UpdatePlan/index.tsx rename to packages/builtin-tool-lobe-agent/src/client/Inspector/UpdatePlan/index.tsx index a8ffe2528e..9b2233a06b 100644 --- a/packages/builtin-tool-gtd/src/client/Inspector/UpdatePlan/index.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/UpdatePlan/index.tsx @@ -29,24 +29,24 @@ export const UpdatePlanInspector = memo - {t('builtins.lobe-gtd.apiName.updatePlan')} + {t('builtins.lobe-agent.apiName.updatePlan')}
); } return (
- {t('builtins.lobe-gtd.apiName.updatePlan')} + {t('builtins.lobe-agent.apiName.updatePlan')} {completed && ( - {t('builtins.lobe-gtd.apiName.updatePlan.completed')} + {t('builtins.lobe-agent.apiName.updatePlan.completed')} )} {hasUpdates && !completed && ( - {t('builtins.lobe-gtd.apiName.updatePlan.modified')} + {t('builtins.lobe-agent.apiName.updatePlan.modified')} )}
diff --git a/packages/builtin-tool-gtd/src/client/Inspector/UpdateTodos/index.tsx b/packages/builtin-tool-lobe-agent/src/client/Inspector/UpdateTodos/index.tsx similarity index 95% rename from packages/builtin-tool-gtd/src/client/Inspector/UpdateTodos/index.tsx rename to packages/builtin-tool-lobe-agent/src/client/Inspector/UpdateTodos/index.tsx index e5b3cb1115..b191466216 100644 --- a/packages/builtin-tool-gtd/src/client/Inspector/UpdateTodos/index.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/UpdateTodos/index.tsx @@ -62,7 +62,7 @@ export const UpdateTodosInspector = memo< if (isArgumentsStreaming && !hasOperations) { return (
- {t('builtins.lobe-gtd.apiName.updateTodos')} + {t('builtins.lobe-agent.apiName.updateTodos')}
); } @@ -103,7 +103,7 @@ export const UpdateTodosInspector = memo< return (
- {t('builtins.lobe-gtd.apiName.updateTodos')} + {t('builtins.lobe-agent.apiName.updateTodos')} {statsParts.length > 0 && ( <> {statsParts.map((part, index) => ( diff --git a/packages/builtin-tool-lobe-agent/src/client/Inspector/index.ts b/packages/builtin-tool-lobe-agent/src/client/Inspector/index.ts new file mode 100644 index 0000000000..adf7f1a697 --- /dev/null +++ b/packages/builtin-tool-lobe-agent/src/client/Inspector/index.ts @@ -0,0 +1,26 @@ +import type { BuiltinInspector } from '@lobechat/types'; + +import { LobeAgentApiName } from '../../types'; +import { CallSubAgentInspector } from './CallSubAgent'; +import { CallSubAgentsInspector } from './CallSubAgents'; +import { ClearTodosInspector } from './ClearTodos'; +import { CreatePlanInspector } from './CreatePlan'; +import { CreateTodosInspector } from './CreateTodos'; +import { UpdatePlanInspector } from './UpdatePlan'; +import { UpdateTodosInspector } from './UpdateTodos'; + +/** + * Lobe Agent Inspector Components Registry + * + * Inspector components customize the title/header area + * of tool calls in the conversation UI. + */ +export const LobeAgentInspectors: Record = { + [LobeAgentApiName.callSubAgent]: CallSubAgentInspector as BuiltinInspector, + [LobeAgentApiName.callSubAgents]: CallSubAgentsInspector as BuiltinInspector, + [LobeAgentApiName.clearTodos]: ClearTodosInspector as BuiltinInspector, + [LobeAgentApiName.createPlan]: CreatePlanInspector as BuiltinInspector, + [LobeAgentApiName.createTodos]: CreateTodosInspector as BuiltinInspector, + [LobeAgentApiName.updatePlan]: UpdatePlanInspector as BuiltinInspector, + [LobeAgentApiName.updateTodos]: UpdateTodosInspector as BuiltinInspector, +}; diff --git a/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx b/packages/builtin-tool-lobe-agent/src/client/Intervention/AddTodo.tsx similarity index 85% rename from packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx rename to packages/builtin-tool-lobe-agent/src/client/Intervention/AddTodo.tsx index d1ae2c8832..ea4e065f6f 100644 --- a/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Intervention/AddTodo.tsx @@ -21,9 +21,9 @@ const AddTodoIntervention = memo>( const handleSave = useCallback( async (items: TodoItem[]) => { - console.log('[AddTodoIntervention] handleSave called with', items.length, 'items'); + console.info('[AddTodoIntervention] handleSave called with', items.length, 'items'); await onArgsChange?.({ items }); - console.log('[AddTodoIntervention] onArgsChange completed'); + console.info('[AddTodoIntervention] onArgsChange completed'); }, [onArgsChange], ); @@ -32,7 +32,7 @@ const AddTodoIntervention = memo>( diff --git a/packages/builtin-tool-gtd/src/client/Intervention/ClearTodos.tsx b/packages/builtin-tool-lobe-agent/src/client/Intervention/ClearTodos.tsx similarity index 89% rename from packages/builtin-tool-gtd/src/client/Intervention/ClearTodos.tsx rename to packages/builtin-tool-lobe-agent/src/client/Intervention/ClearTodos.tsx index 6bd717b7dc..78da56c9b9 100644 --- a/packages/builtin-tool-gtd/src/client/Intervention/ClearTodos.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Intervention/ClearTodos.tsx @@ -55,20 +55,20 @@ const ClearTodosIntervention = memo>( - {t('lobe-gtd.clearTodos.header')} + {t('lobe-agent.clearTodos.header')} - {t('lobe-gtd.clearTodos.label')} + {t('lobe-agent.clearTodos.label')} - {t('lobe-gtd.clearTodos.option.completed')} + {t('lobe-agent.clearTodos.option.completed')} - {t('lobe-gtd.clearTodos.option.all')} + {t('lobe-agent.clearTodos.option.all')} diff --git a/packages/builtin-tool-gtd/src/client/Intervention/CreatePlan.tsx b/packages/builtin-tool-lobe-agent/src/client/Intervention/CreatePlan.tsx similarity index 95% rename from packages/builtin-tool-gtd/src/client/Intervention/CreatePlan.tsx rename to packages/builtin-tool-lobe-agent/src/client/Intervention/CreatePlan.tsx index cc189ca613..aadf83fbf7 100644 --- a/packages/builtin-tool-gtd/src/client/Intervention/CreatePlan.tsx +++ b/packages/builtin-tool-lobe-agent/src/client/Intervention/CreatePlan.tsx @@ -143,7 +143,7 @@ const CreatePlanIntervention = memo>(