import final_answer from "../tools/final_answer.js"; import present_answer from "../tools/present_answer.js"; import locate_features from "../tools/locate_features.js"; import zoom_to_map from "../tools/zoom_to_map.js"; import show_chart from "../tools/show_chart.js"; import view_history from "../tools/view_history.js"; import { Plugin, Rpc } from "@opencode/plugin"; import { z } from "zod"; import { resolve } from "node:path"; import { registerSessionSandbox } from "../session-sandbox.js"; import { registerMcpPolicy } from "../mcp-policy.js"; import { registerTaskAgentPolicy } from "../task-agent-policy.js"; import { AGENT_MESSAGE_TOOLS, registerAgentMessagePolicy } from "../agent-message-policy.js"; import { checkOpencodeModels } from "../model-check.js"; import { DEFAULT_SESSION_WORKSPACE_ROOT } from "../../src/runtime/conversationWorkspace.js"; import add_task_human_evidence from "../tools/add_task_human_evidence.js"; import clear_scada_analysis from "../tools/clear_scada_analysis.js"; import memory_manager from "../tools/memory_manager.js"; import propose_task_action from "../tools/propose_task_action.js"; import publish_execution_plan from "../tools/publish_execution_plan.js"; import publish_task_report from "../tools/publish_task_report.js"; import publish_task_progress from "../tools/publish_task_progress.js"; import publish_task_presentation from "../tools/publish_task_presentation.js"; import render_scada_analysis from "../tools/render_scada_analysis.js"; import request_task_data_access from "../tools/request_task_data_access.js"; import skill_manager from "../tools/skill_manager.js"; import send_task_message from "../tools/send_task_message.js"; import reply_agent_message from "../tools/reply_agent_message.js"; const businessTools = { final_answer, present_answer, locate_features, zoom_to_map, show_chart, view_history, add_task_human_evidence, clear_scada_analysis, memory_manager, propose_task_action, publish_execution_plan, publish_task_report, publish_task_progress, publish_task_presentation, render_scada_analysis, request_task_data_access, skill_manager, send_task_message, reply_agent_message, }; export default Plugin.define({ id: "tjwater.tools", async setup(ctx) { await registerSessionSandbox(ctx); await ctx.tool.transform((editor) => { for (const [name, definition] of Object.entries(businessTools)) { const object = z.object(definition.args); const input = (AGENT_MESSAGE_TOOLS as readonly string[]).includes(name) ? object.strict() : object; editor.add({ name, description: definition.description, input, options: { codemode: false, permission: name }, async execute(args, context) { // Validate again at the execution boundary, retaining domain refinements. const parsed = input.parse(args); const content = await definition.execute(parsed as never, { sessionID: context.sessionID, callID: context.id, signal: context.signal, }); return { content }; }, }); } }); const todoItem = z.object({ id: z.string().optional(), content: z.string(), status: z.enum(["pending", "in_progress", "completed", "cancelled"]), priority: z.enum(["low", "medium", "high"]).optional(), }); await ctx.tool.transform((editor) => { editor.remove("todoread"); editor.add({ name: "todowrite", description: "Update the current session's task checklist.", input: z.object({ todos: z.array(todoItem) }), options: { codemode: false, permission: "todowrite" }, async execute({ todos }, context) { await ctx.storage.set(`todos/${context.sessionID}`, todos); return { content: JSON.stringify(todos) }; }, }); }); const mcpReport = await registerMcpPolicy(ctx); await registerTaskAgentPolicy(ctx); await registerAgentMessagePolicy(ctx); await ctx.rpc.register(Rpc.define({ id: "tjwater.tools", methods: { read_todos: { input: z.object({ session_id: z.string().min(1).max(128) }).strict(), output: z.array(todoItem), }, check_models: { input: z.object({ models: z.array(z.object({ id: z.string(), provider_id: z.string(), model_id: z.string(), wire_id: z.string(), requires_tools: z.boolean() }).strict()).min(1).max(1000) }).strict(), output: z.object({ models: z.array(z.object({ id: z.string(), model_id: z.string(), status: z.enum(["valid", "not_registered", "not_enabled", "no_tools", "wire_id_mismatch", "not_advertised", "unchecked"]) })), providers: z.array(z.object({ id: z.string(), status: z.enum(["checked", "not_registered", "unsupported_catalog", "catalog_unavailable", "catalog_invalid", "credentials_unavailable"]), http_status: z.number().int().optional() })), }), }, list: { input: z.object({}), output: z.array(z.object({ id: z.string(), direct: z.boolean(), sandboxed: z.boolean(), workspaceRoot: z.string().optional() })), }, mcp: { input: z.object({}), output: z.object({ configuration_errors: z.array(z.string()), servers: z.array(z.object({ name: z.string(), type: z.enum(["local", "remote"]), status: z.enum(["connected", "pending", "disabled", "failed", "needs_auth"]), configured_protocol: z.enum(["legacy", "auto", "2026-07-28"]), tools: z.array(z.string()), })), }), }, }, events: {}, }), { read_todos: async (input) => z.array(todoItem).parse(await ctx.storage.get(`todos/${input.session_id}`) ?? []), check_models: (input, context) => checkOpencodeModels(ctx, input, context.signal), mcp: mcpReport, list: async () => (await ctx.tool.list()).map((tool) => ({ id: tool.id, direct: tool.options?.codemode === false, sandboxed: tool.id === "shell" && tool.description.includes("Landlock + seccomp"), ...(tool.id === "shell" ? { workspaceRoot: resolve(process.env.TJWATER_AGENT_WORKSPACE_ROOT ?? DEFAULT_SESSION_WORKSPACE_ROOT) } : {}), })), }); }, });