Files
next-tjwater-agent/.opencode/tools/publish_task_report.ts
T
jiang 874bfba907
Generic Container CI/CD / test-build-publish (push) Successful in 56s
Agent CI/CD / build-test-publish-and-deploy (push) Successful in 56s
fix: harden report tools and guide investigation presentation
2026-11-02 15:23:34 +08:00

35 lines
4.1 KiB
TypeScript

import { tool } from "../tool.js";
import { getInternalBridgeConfig } from "../internalBridge.js";
import { taskPublicationReportSchema } from "./task-publication-schema.js";
import { taskReportSchema } from "../../src/product/investigation-report.js";
import catalog from "../../src/chat/answer-ui-catalog.json" with { type: "json" };
export default tool({
description: "Publish an evidence-backed investigation report. The host supplies fixed UI protocol versions and the default null stop_reason. For outcome=concluded omit stop_reason or use null, and keep every data_gaps.blocking false; use pending_items for external follow-up. For outcome=insufficient_data use stage=final, a nonempty stop_reason and an evidence-backed blocking gap, with no recommendations or pending_items. No todo or execution plan is required. An optional Mermaid diagram explains the investigation to people; it never schedules or completes work. Every node_refs node_id must exactly reuse an id declared in the Mermaid source; never create separate reference ids for the same nodes. Before proposing actions publish an interim concluded report; continue executable necessary analysis before finalizing with actual action references. Follow the investigation instructions for stopping: concluded classifies a supported finding, not completion of all analysis. Field-verification proposals and queued calculations do not justify early finalization. If a user can supply the remaining critical input, use ask_task_user before finalizing; the host renders saved questions in the right investigation report even before any report is published. A saved pending question needs no final report. Use final insufficient_data only when queries and applicable user clarification cannot fill critical gaps and there is no supported current judgment or concrete recommendation; include blocking gaps, no recommendations or pending items. Query failures are execution errors, not proof that data is absent. The run lifecycle endpoint settles execution independently of the diagram. Optional ui_blocks express existing results with Result, object comparisons with Table, real series with Chart, location links with MapLocation. Use ask_task_user for fixed task questions; do not generate FollowUpForm to collect investigation answers, because it routes input to left-side discussion rather than the task answer endpoint. Result status must reflect actual evidence; saving a synthetic record does not prove field action completion. Result never executes actions. Stack intent/density and Section role express presentation semantics; original required props remain required. Do not supply CSS or executable props. Report blocks are final results: set phase to final or omit it for legacy compatibility; process blocks cannot be published in reports. Each block references saved report evidence, has a unique block_id and a text fallback. Maximum 8 blocks / 400 KB total. Do not duplicate the conclusion or invent data to fill a layout. Component property schemas: " + JSON.stringify(catalog.props),
args: {
request_id: tool.schema.string().uuid().describe("Stable UUID idempotency key for this report revision"),
report: taskPublicationReportSchema,
evidence: tool.schema.array(tool.schema.object({
evidence_id: tool.schema.string(),
kind: tool.schema.literal("synthetic"),
summary: tool.schema.string(),
source_label: tool.schema.string(),
source_ref: tool.schema.string().optional(),
observed_at: tool.schema.string(),
})).default([]),
},
async execute(args, context) {
const report = taskReportSchema.parse(args.report);
const { baseUrl, internalToken } = getInternalBridgeConfig();
const response = await fetch(`${baseUrl}/internal/operational-task/artifacts`, {
method: "POST",
headers: { "Content-Type": "application/json", "x-agent-internal-token": internalToken },
signal: context.signal,
body: JSON.stringify({ session_id: context.sessionID, ...args, report }),
});
const text = await response.text();
if (!response.ok) throw new Error(`task report publish failed (${response.status}): ${text}`);
return text;
},
});