diff --git a/.changeset/FN-7118-shared-task-read-tools.md b/.changeset/FN-7118-shared-task-read-tools.md index 42a84db8c2..2a2e6d97ca 100644 --- a/.changeset/FN-7118-shared-task-read-tools.md +++ b/.changeset/FN-7118-shared-task-read-tools.md @@ -4,4 +4,4 @@ summary: Permanent and custom agents can list, show, and search tasks during heartbeat runs. category: feature -dev: Adds shared read-only task tool factories (createTaskListTool/createTaskShowTool/createTaskSearchTool/createTaskReadTools), wires them into createSharedHeartbeatWorkTools, classifies fn_task_search/fn_task_get read-only, and adds cross-surface drift tests. +dev: Adds shared read-only task tool factories (createTaskListTool/createTaskShowTool/createTaskSearchTool/createTaskReadTools), wires them into createSharedHeartbeatWorkTools, classifies fn_task_search and the legacy task-get alias read-only, and adds cross-surface drift tests. diff --git a/.changeset/FN-7127-unify-task-show-tool-name.md b/.changeset/FN-7127-unify-task-show-tool-name.md new file mode 100644 index 0000000000..b102f44661 --- /dev/null +++ b/.changeset/FN-7127-unify-task-show-tool-name.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: The task detail tool is now named fn_task_show consistently across triage, planning, chat, and CLI surfaces. +category: internal +dev: Renames the legacy fn_task_get registration to canonical fn_task_show in createTriageTools (engine) and createPlanningBoardTools (dashboard), updates all prompt references and the FN-7118 cross-surface drift test, and retains fn_task_get in BOTH READONLY_FN_TOOLS and COORDINATION_EXEMPT_TOOLS as a deprecated recognition alias for backward-compatible action-gate classification and analytics. diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 0bbd97167c..8d7d47df7e 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -495,7 +495,7 @@ Use planning mode to turn a rough idea into a triage task through an interactive When supported by your configured runtime/model provider, planning sessions can also use builtin `WebSearch` and `WebFetch` tools for live context gathering. -Planning sessions also have read-only board tools: `fn_task_list` (list active backlog tasks) and `fn_task_get` (read full task details, including PROMPT.md) so interviews can avoid duplicate in-flight plans and anchor questions to existing work. `fn_task_list` output is bounded and falls back to a defensive formatter if the runtime task-list clamp helper is unavailable, so board reads return text instead of failing during ambient planning or heartbeat checks. `fn_task_list` also accepts `includeDeleted: true` to surface soft-deleted blockers when diagnosing stalled dependency chains, and `fn_task_show` now auto-falls back to include soft-deleted tasks with a `[SOFT-DELETED at ...]` marker. +Planning sessions also have read-only board tools: `fn_task_list` (list active backlog tasks) and `fn_task_show` (read full task details, including PROMPT.md) so interviews can avoid duplicate in-flight plans and anchor questions to existing work. `fn_task_list` output is bounded and falls back to a defensive formatter if the runtime task-list clamp helper is unavailable, so board reads return text instead of failing during ambient planning or heartbeat checks. `fn_task_list` also accepts `includeDeleted: true` to surface soft-deleted blockers when diagnosing stalled dependency chains, and `fn_task_show` now auto-falls back to include soft-deleted tasks with a `[SOFT-DELETED at ...]` marker. ```bash fn task plan [description] diff --git a/docs/missions.md b/docs/missions.md index bcedf7a5b0..98a6b696c4 100644 --- a/docs/missions.md +++ b/docs/missions.md @@ -244,7 +244,7 @@ The dashboard supports mission planning workflows where you can: - Persisted missions with `interviewState: "in_progress"` remain visible as interview-styled mission cards in the main mission list so planning work does not disappear after reloads - Resume in-progress mission interview sessions directly from separate transient session rows in the main missions list (`mission_interview` sessions in `generating`, `awaiting_input`, `error`, or `complete`) before a mission record is created; `complete` means the plan summary is ready for review/approval but has not been converted into a mission yet - Mission interview closes are non-destructive: the modal now uses a single close action for header close, backdrop click, and Escape. Closing preserves the in-progress `mission_interview` session, and Missions re-fetches project-scoped transient rows (including on the mobile stacked Missions view) so resume/retry remains discoverable without losing persisted `interviewState: "in_progress"` mission cards. Resume-launched interview modals also expose a **Send to background** action that performs the same non-destructive park without cancelling the session. Deletion remains an explicit sidebar action. -- Mission interview, milestone interview, and slice interview agents have read-only board visibility via `fn_task_list` and `fn_task_get`, so they can reference active backlog context and avoid duplicating in-flight tasks while asking planning questions +- Mission interview, milestone interview, and slice interview agents have read-only board visibility via `fn_task_list` and `fn_task_show`, so they can reference active backlog context and avoid duplicating in-flight tasks while asking planning questions ### Mission Interview Drafts diff --git a/packages/cli/skill/fusion/references/engine-tools.md b/packages/cli/skill/fusion/references/engine-tools.md index cc30327f2c..c38556d4ed 100644 --- a/packages/cli/skill/fusion/references/engine-tools.md +++ b/packages/cli/skill/fusion/references/engine-tools.md @@ -64,7 +64,7 @@ These tools are **not** part of the user-invokable extension surface. They are i |---|---|---| | `fn_task_list` | List active tasks during specification (duplicate check, discovery) | none | | `fn_task_search` | Keyword search tasks (including done/archived by default) for duplicate detection | `query` (string), `limit?` (number), `includeDone?` (boolean), `includeArchived?` (boolean) | -| `fn_task_get` | Fetch full task detail including PROMPT.md | `id` (string) | +| `fn_task_show` | Fetch full task detail including PROMPT.md | `id` (string) | | `fn_review_spec` | Spawn spec reviewer and return `APPROVE`/`REVISE`/`RETHINK`/`UNAVAILABLE` | none | ## Executor-only runtime tools (`executor.ts`) diff --git a/packages/core/src/__tests__/usage-events.test.ts b/packages/core/src/__tests__/usage-events.test.ts index f17c2aabbe..6dfc5a62ba 100644 --- a/packages/core/src/__tests__/usage-events.test.ts +++ b/packages/core/src/__tests__/usage-events.test.ts @@ -96,6 +96,7 @@ describe("usage_events", () => { ["semantic_search", "read"], ["fn_task_list", "read"], ["fn_task_show", "read"], + // FNXC:UsageAnalytics 2026-06-27-00:00: Keep legacy `fn_task_get` categorized as read-only so historical usage events remain comparable after live surfaces move to `fn_task_show`. ["fn_task_get", "read"], ["fn_task_search", "read"], ["fn_list_agents", "read"], diff --git a/packages/core/src/agent-prompts.ts b/packages/core/src/agent-prompts.ts index 64f20c0291..5f5ad1ba5f 100644 --- a/packages/core/src/agent-prompts.ts +++ b/packages/core/src/agent-prompts.ts @@ -372,12 +372,12 @@ If this task REMOVES existing functionality (deleting modules, settings, API end ## Duplicate check Before writing a spec, call \`fn_task_list\` to find existing active tasks, then call \`fn_task_search\` with 2-4 distinct keyword phrases from the task title and description (for example file paths, error symptoms, and symbol names). -For any likely match in \`done\` or \`archived\`, call \`fn_task_get\` to inspect details before deciding. +For any likely match in \`done\` or \`archived\`, call \`fn_task_show\` to inspect details before deciding. If an existing task already covers the same work, do NOT write a PROMPT.md. Instead write exactly: \`DUPLICATE: {existing-task-id}\` ## Dependency awareness -When adding a dependency in \`## Dependencies\`, first call \`fn_task_get\` for that task and read its PROMPT.md. +When adding a dependency in \`## Dependencies\`, first call \`fn_task_show\` for that task and read its PROMPT.md. Use that context to align file paths, APIs, assumptions, and completion expectations. If the dependency has no PROMPT.md yet, note that explicitly. ## Decision-only task flag (noCommitsExpected) @@ -610,13 +610,13 @@ tests. Manual verification is NOT a test. ## Duplicate check Before writing a spec, first call \`fn_task_list\` to see active tasks, then call \`fn_task_search\` with 2-4 distinct keyword phrases from the task title and description (for example file paths, error symptoms, and symbol names). -For any likely match in \`done\` or \`archived\`, call \`fn_task_get\` to inspect details before deciding. +For any likely match in \`done\` or \`archived\`, call \`fn_task_show\` to inspect details before deciding. If a task already covers the same work (even if worded differently), do NOT write a PROMPT.md. Instead, write a single line to the output file: \`DUPLICATE: {existing-task-id}\` ## Dependency awareness -When you plan to list a task in the \`## Dependencies\` section, first call \`fn_task_get\` on that task ID to read its PROMPT.md. +When you plan to list a task in the \`## Dependencies\` section, first call \`fn_task_show\` on that task ID to read its PROMPT.md. Use what you learn — file scope, APIs, patterns, completion criteria — to make the new spec accurate: reference the right paths, avoid conflicting assumptions, and describe what the dependency must deliver before this task starts. If the dependency task has no PROMPT.md yet (not yet specified), note that in the Dependencies section. @@ -656,7 +656,7 @@ For tasks you assess as Size M or L, consider whether splitting into 2-5 child t You have these extra tools during triage: - \`fn_task_list\` — list existing active tasks - \`fn_task_search\` — keyword search across tasks, including done and archived tasks -- \`fn_task_get\` — inspect a task and its PROMPT.md +- \`fn_task_show\` — inspect a task and its PROMPT.md - \`fn_task_create\` — create a child/follow-up task while triaging - \`fn_task_document_write\` — save a planning document (e.g., key="plan") - \`fn_task_document_read\` — read back a previously saved document @@ -744,7 +744,7 @@ If the task targets a different task ID (audit, forensic walk, historical reconc - Authoritative target-task artifacts live at the **project root**: \`/.fusion/tasks/{TARGET_ID}/\` (\`task.json\`, \`PROMPT.md\`, \`attachments/\`, agent logs). - Authoritative task DB rows live at the **project root** SQLite file: \`/.fusion/fusion.db\` (WAL mode). Read via \`TaskStore\` APIs; do not instruct direct SQL surgery. - \`.fusion/\` is gitignored, so a fresh worktree from \`main\` does **not** include \`.fusion/tasks/{TARGET_ID}/\` or \`.fusion/fusion.db\`. The running worktree's own \`.fusion/\` (if present) is scratch/session state for the running task only, not source of truth. -- Prefer \`fn_task_get\` / \`fn_task_list\` when the target task ID is known; fall back to project-root filesystem reads only when tools cannot provide needed evidence. +- Prefer \`fn_task_show\` / \`fn_task_list\` when the target task ID is known; fall back to project-root filesystem reads only when tools cannot provide needed evidence. `;; diff --git a/packages/dashboard/src/__tests__/milestone-slice-interview.test.ts b/packages/dashboard/src/__tests__/milestone-slice-interview.test.ts index d191d05c8b..8c06fcca2a 100644 --- a/packages/dashboard/src/__tests__/milestone-slice-interview.test.ts +++ b/packages/dashboard/src/__tests__/milestone-slice-interview.test.ts @@ -365,7 +365,7 @@ describe("milestone-slice-interview module", () => { const createFnAgentCallArg = await waitForCreateFnAgentOptions() as { customTools?: Array<{ name: string }> }; const customToolNames = createFnAgentCallArg.customTools?.map((tool) => tool.name) ?? []; expect(customToolNames).toContain("fn_task_list"); - expect(customToolNames).toContain("fn_task_get"); + expect(customToolNames).toContain("fn_task_show"); expect(session?.targetId).toBe("ms-123"); expect(session?.targetTitle).toBe("Launch Platform"); expect(session?.missionContext).toBe("Mission: Launch Platform v2"); diff --git a/packages/dashboard/src/__tests__/mission-interview.test.ts b/packages/dashboard/src/__tests__/mission-interview.test.ts index 02c2f40947..ce2253ea42 100644 --- a/packages/dashboard/src/__tests__/mission-interview.test.ts +++ b/packages/dashboard/src/__tests__/mission-interview.test.ts @@ -912,7 +912,7 @@ describe("mission-interview module", () => { expect(lastCall[0].builtinToolsAllowlist).toEqual(["WebSearch", "WebFetch"]); const customToolNames = (lastCall[0].customTools as Array<{ name: string }> | undefined)?.map((tool) => tool.name) ?? []; expect(customToolNames).toContain("fn_task_list"); - expect(customToolNames).toContain("fn_task_get"); + expect(customToolNames).toContain("fn_task_show"); }); it("uses override prompt when promptOverrides provided", async () => { diff --git a/packages/dashboard/src/__tests__/planning-board-tools.test.ts b/packages/dashboard/src/__tests__/planning-board-tools.test.ts index 875bc457e1..7c81e99d44 100644 --- a/packages/dashboard/src/__tests__/planning-board-tools.test.ts +++ b/packages/dashboard/src/__tests__/planning-board-tools.test.ts @@ -73,7 +73,7 @@ describe("createPlanningBoardTools", () => { expect(emptyResult.content[0]?.text).toBe("No active tasks."); }); - it("fn_task_get returns full details and not-found fallback", async () => { + it("fn_task_show returns full details and not-found fallback", async () => { const store = createStoreMock({ getTask: vi.fn(async (id: string) => ({ id, @@ -84,7 +84,7 @@ describe("createPlanningBoardTools", () => { })) as TaskStore["getTask"], }); - const taskGet = createPlanningBoardTools(store).find((tool) => tool.name === "fn_task_get"); + const taskGet = createPlanningBoardTools(store).find((tool) => tool.name === "fn_task_show"); expect(taskGet).toBeDefined(); const result = await taskGet!.execute("c3", { id: "FN-10" }); expect(result.content[0]?.text).toContain("ID: FN-10"); @@ -96,7 +96,7 @@ describe("createPlanningBoardTools", () => { const notFoundStore = createStoreMock(); const missingResult = await createPlanningBoardTools(notFoundStore) - .find((tool) => tool.name === "fn_task_get")! + .find((tool) => tool.name === "fn_task_show")! .execute("c4", { id: "FN-404" }); expect(missingResult.content[0]?.text).toBe("Task FN-404 not found."); }); diff --git a/packages/dashboard/src/milestone-slice-interview.ts b/packages/dashboard/src/milestone-slice-interview.ts index 313da4e026..3e4e7a3142 100644 --- a/packages/dashboard/src/milestone-slice-interview.ts +++ b/packages/dashboard/src/milestone-slice-interview.ts @@ -171,7 +171,7 @@ A milestone represents a major phase or deliverable within a larger mission. Eac ## Board tools - fn_task_list — list active tasks -- fn_task_get — read a task's full details and PROMPT.md +- fn_task_show — read a task's full details and PROMPT.md Use these to avoid duplicating an existing in-flight plan and to anchor your questions against current backlog context. ## Response Format @@ -220,7 +220,7 @@ A slice represents a focused work unit within a milestone that can be activated ## Board tools - fn_task_list — list active tasks -- fn_task_get — read a task's full details and PROMPT.md +- fn_task_show — read a task's full details and PROMPT.md Use these to avoid duplicating an existing in-flight plan and to anchor your questions against current backlog context. ## Response Format diff --git a/packages/dashboard/src/mission-interview.ts b/packages/dashboard/src/mission-interview.ts index 864a866241..c5cfe7ee6e 100644 --- a/packages/dashboard/src/mission-interview.ts +++ b/packages/dashboard/src/mission-interview.ts @@ -160,7 +160,7 @@ PREFER structured question types over free-text. This makes the interview faster ## Board tools - fn_task_list — list active tasks -- fn_task_get — read a task's full details and PROMPT.md +- fn_task_show — read a task's full details and PROMPT.md Use these to avoid duplicating an existing in-flight plan and to anchor your questions against current backlog context. ## Response Format diff --git a/packages/dashboard/src/planning-board-tools.ts b/packages/dashboard/src/planning-board-tools.ts index 9c7db2aca1..6da3c6a18a 100644 --- a/packages/dashboard/src/planning-board-tools.ts +++ b/packages/dashboard/src/planning-board-tools.ts @@ -83,8 +83,12 @@ export function createPlanningBoardTools(store: TaskStore): ToolDefinition[] { }, }; - const taskGet: ToolDefinition = { - name: "fn_task_get", + /** + * FNXC:AgentTooling 2026-06-27-00:00: + * Planning-board interviews must expose the task detail read tool as canonical `fn_task_show`, matching prompt text and the FN-7118 shared read-tool factory so every agent surface learns one model-visible show-tool name. + */ + const taskShow: ToolDefinition = { + name: "fn_task_show", label: "Get Task", description: "Get full details of a specific task including its PROMPT.md content. " + @@ -115,5 +119,5 @@ export function createPlanningBoardTools(store: TaskStore): ToolDefinition[] { }, }; - return [taskList, taskGet]; + return [taskList, taskShow]; } diff --git a/packages/dashboard/src/planning.ts b/packages/dashboard/src/planning.ts index d246c60b3f..ea512a7f35 100644 --- a/packages/dashboard/src/planning.ts +++ b/packages/dashboard/src/planning.ts @@ -215,7 +215,7 @@ When ready to complete, generate: ## Board tools - fn_task_list — list active tasks -- fn_task_get — read a task's full details and PROMPT.md +- fn_task_show — read a task's full details and PROMPT.md Use these to avoid duplicating an existing in-flight plan and to anchor your questions against current backlog context. ## Response Format diff --git a/packages/engine/src/__tests__/agent-task-read-tools.test.ts b/packages/engine/src/__tests__/agent-task-read-tools.test.ts index 0709a76abd..25a962c690 100644 --- a/packages/engine/src/__tests__/agent-task-read-tools.test.ts +++ b/packages/engine/src/__tests__/agent-task-read-tools.test.ts @@ -140,21 +140,31 @@ describe("shared task read tools", () => { } }); - it("pins per-surface task-read tool name parity", () => { + it("pins per-surface task-read tool name parity on canonical fn_task_show", () => { const triageProcessor = new TriageProcessor(createStore() as never, "/tmp/fn-test"); const triageNames = toolNames((triageProcessor as unknown as { createTriageTools: (opts: unknown) => Array<{ name: string }> }).createTriageTools({ parentTaskId: "FN-TRIAGE", allowTaskCreate: true, createdSubtasksRef: { current: [] }, })).filter((name) => name.startsWith("fn_task_") && name !== "fn_task_create"); - expect(triageNames).toEqual(["fn_task_list", "fn_task_search", "fn_task_get"]); - expect(toolNames(createPlanningBoardTools(createStore())).filter((name) => name.startsWith("fn_task_"))).toEqual([ - "fn_task_list", - "fn_task_get", - ]); + const surfaces = { + triage: triageNames, + planningBoard: toolNames(createPlanningBoardTools(createStore())).filter((name) => name.startsWith("fn_task_")), + cliExtension: extractRegisteredCliTaskReadNames(), + sharedFactory: toolNames(createTaskReadTools(createStore())), + }; - expect(extractRegisteredCliTaskReadNames()).toEqual(["fn_task_list", "fn_task_show"]); - expect(toolNames(createTaskReadTools(createStore()))).toEqual(["fn_task_list", "fn_task_show", "fn_task_search"]); + expect(surfaces).toEqual({ + triage: ["fn_task_list", "fn_task_search", "fn_task_show"], + planningBoard: ["fn_task_list", "fn_task_show"], + cliExtension: ["fn_task_list", "fn_task_show"], + sharedFactory: ["fn_task_list", "fn_task_show", "fn_task_search"], + }); + const deprecatedGetName = ["fn_task", "get"].join("_"); + for (const names of Object.values(surfaces)) { + expect(names).toContain("fn_task_show"); + expect(names).not.toContain(deprecatedGetName); + } }); }); diff --git a/packages/engine/src/__tests__/triage.test.ts b/packages/engine/src/__tests__/triage.test.ts index a69d71603c..542902147e 100644 --- a/packages/engine/src/__tests__/triage.test.ts +++ b/packages/engine/src/__tests__/triage.test.ts @@ -2286,7 +2286,7 @@ describe("taskCreate tool model inheritance", () => { expect(toolNames).toContain("fn_task_create"); expect(toolNames).toContain("fn_task_list"); expect(toolNames).toContain("fn_task_search"); - expect(toolNames).toContain("fn_task_get"); + expect(toolNames).toContain("fn_task_show"); expect(tools).toHaveLength(4); }); @@ -4494,7 +4494,7 @@ describe("TriageProcessor delegation tools", () => { }; } - it("createTriageTools returns fn_task_list, fn_task_search, fn_task_get, fn_task_create (no delegation tools — those are in customTools)", () => { + it("createTriageTools returns fn_task_list, fn_task_search, fn_task_show, fn_task_create (no delegation tools — those are in customTools)", () => { const store = createMockStore(); const processor = new TriageProcessor(store as any, "/tmp/root"); @@ -4507,7 +4507,7 @@ describe("TriageProcessor delegation tools", () => { const toolNames = tools.map((t: any) => t.name); expect(toolNames).toContain("fn_task_list"); expect(toolNames).toContain("fn_task_search"); - expect(toolNames).toContain("fn_task_get"); + expect(toolNames).toContain("fn_task_show"); expect(toolNames).toContain("fn_task_create"); // fn_list_agents and fn_delegate_task are added in customTools, not createTriageTools expect(toolNames).not.toContain("fn_list_agents"); diff --git a/packages/engine/src/agent-tools.ts b/packages/engine/src/agent-tools.ts index 2706a0d2e0..e8cb70cf3a 100644 --- a/packages/engine/src/agent-tools.ts +++ b/packages/engine/src/agent-tools.ts @@ -1044,7 +1044,10 @@ function formatTaskSummaryLine(task: { id: string; column: string; title?: strin /** * FNXC:AgentTooling 2026-06-27-14:05: - * Shared read-only task discovery factories must return host-safe text and be reusable by triage, chat/planning, and heartbeat surfaces. Heartbeat agents now receive task read tools through this single store-backed implementation instead of bespoke copies, while model-visible legacy `fn_task_get` surfaces remain separately pinned by drift tests. + * Shared read-only task discovery factories must return host-safe text and be reusable by triage, chat/planning, and heartbeat surfaces. Heartbeat agents now receive task read tools through this single store-backed implementation instead of bespoke copies. + * + * FNXC:AgentTooling 2026-06-27-00:00: + * Triage and planning-board surfaces now use canonical `fn_task_show`; deprecated `fn_task_get` survives only as a recognition alias in action-gate and analytics compatibility paths, not as a model-visible registered tool. */ export function createTaskListTool(store: TaskStore): ToolDefinition { return { diff --git a/packages/engine/src/gating-classifications.ts b/packages/engine/src/gating-classifications.ts index 3e779d6a1e..7e2c496200 100644 --- a/packages/engine/src/gating-classifications.ts +++ b/packages/engine/src/gating-classifications.ts @@ -118,8 +118,9 @@ export const READONLY_FN_TOOLS: ReadonlySet = new Set([ "fn_artifact_view", "fn_task_list", "fn_task_show", - // FNXC:ToolGovernance 2026-06-27-14:16: Task search and legacy task-get surfaces are read-only duplicate-discovery tools; classify them positively so heartbeat/triage calls never rely on the unknown-tool exempt fallback. + // FNXC:ToolGovernance 2026-06-27-14:16: Task search is a read-only duplicate-discovery tool; classify it positively so heartbeat/triage calls never rely on the unknown-tool exempt fallback. "fn_task_search", + // FNXC:ToolGovernance 2026-06-27-00:00: `fn_task_get` is a deprecated recognition-only alias. It is no longer registered as a live tool, but historical/in-flight calls must still classify as read-only instead of falling through to unknown-tool handling. "fn_task_get", "fn_task_create", "fn_task_document_write", @@ -172,7 +173,10 @@ export const COORDINATION_EXEMPT_TOOLS = [ "fn_task_document_read", /** * FNXC:ToolGovernance 2026-06-27-15:22: - * Task list/show/search/get are read-only discovery tools. Put them on the action-gate exempt registry, not only READONLY_FN_TOOLS, because evaluateAgentActionGate recognizes coordination exemptions directly and otherwise unknown fn_task_* reads silently fall through to exempt allow. + * Task list/show/search tools are read-only discovery tools. Put them on the action-gate exempt registry, not only READONLY_FN_TOOLS, because evaluateAgentActionGate recognizes coordination exemptions directly and otherwise unknown fn_task_* reads silently fall through to exempt allow. + * + * FNXC:ToolGovernance 2026-06-27-00:00: + * `fn_task_get` is no longer registered as a live tool, but it remains here as a deprecated recognition-only alias so stray in-flight legacy calls classify as known read-only coordination instead of relying on the unknown-tool fallback. */ "fn_task_list", "fn_task_show", diff --git a/packages/engine/src/triage.ts b/packages/engine/src/triage.ts index 4972cce5a3..4ada3420c2 100644 --- a/packages/engine/src/triage.ts +++ b/packages/engine/src/triage.ts @@ -1575,8 +1575,12 @@ export class TriageProcessor { }, }; - const taskGet: ToolDefinition = { - name: "fn_task_get", + /** + * FNXC:AgentTooling 2026-06-27-00:00: + * Triage must expose the task detail read tool as canonical `fn_task_show`, matching prompt text and the FN-7118 shared read-tool factory so every agent surface learns one model-visible show-tool name. + */ + const taskShow: ToolDefinition = { + name: "fn_task_show", label: "Get Task", description: "Get full details of a specific task including its PROMPT.md content. " + @@ -1605,7 +1609,7 @@ export class TriageProcessor { }; } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); - planLog.warn(`${options.parentTaskId}: fn_task_get lookup failed for ${params.id}: ${msg}`); + planLog.warn(`${options.parentTaskId}: fn_task_show lookup failed for ${params.id}: ${msg}`); return { content: [ { type: "text" as const, text: `Task ${params.id} not found.` }, @@ -1743,7 +1747,7 @@ export class TriageProcessor { }, }; - return [taskList, taskSearch, taskGet, taskCreate]; + return [taskList, taskSearch, taskShow, taskCreate]; } /**