feat(agent): add typed server API tools

This commit is contained in:
2026-07-15 10:44:07 +08:00
parent f3f873e3c4
commit 8a21908785
30 changed files with 3119 additions and 15 deletions
+5 -1
View File
@@ -2,7 +2,7 @@ import { describe, expect, it } from "bun:test";
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { FRONTEND_ACTION_TOOLS, frontendActionCallIdPlugin } from "../../.opencode/plugins/frontend-action-call-id.js";
import { FRONTEND_ACTION_TOOLS, frontendActionCallIdPlugin, server } from "../../.opencode/plugins/frontend-action-call-id.js";
import { frontendActionRegistry } from "../../src/frontendAction/registry.js";
const frontendActionToolNames = () => readdirSync(".opencode/tools")
@@ -17,6 +17,10 @@ describe("frontend action call ID plugin", () => {
expect(config.plugin).toContain("./.opencode/plugins/frontend-action-call-id.ts");
});
it("exposes the server export required by OpenCode", () => {
expect(server).toBe(frontendActionCallIdPlugin);
});
it("overwrites forged IDs only for allowlisted tools", async () => {
const hooks = await frontendActionCallIdPlugin({} as never);
const before = hooks["tool.execute.before"];
+43
View File
@@ -44,4 +44,47 @@ describe("FrontendActionCoordinator", () => {
coordinator.registerSink("s", () => undefined);
expect(() => coordinator.request({ sessionId: "s", toolCallId: "c", name: "unknown", params: {} })).toThrow("unknown frontend action");
});
it("requires a valid time range when opening history data", async () => {
const coordinator = new FrontendActionCoordinator();
let emitted: FrontendActionRequest | undefined;
coordinator.registerSink("s", (request) => { emitted = request; });
expect(() => coordinator.request({
sessionId: "s",
toolCallId: "c",
name: "view_history",
params: { feature_infos: [["node-1", "junction"]], data_type: "realtime" },
})).toThrow("invalid frontend action params");
expect(() => coordinator.request({
sessionId: "s",
toolCallId: "c",
name: "view_history",
params: {
feature_infos: [["node-1", "junction"]],
data_type: "realtime",
start_time: "2026-07-14T00:00:00Z",
end_time: "2026-07-14T00:00:00Z",
},
})).toThrow("invalid frontend action params");
const pending = coordinator.request({
sessionId: "s",
toolCallId: "c",
name: "view_history",
params: {
feature_infos: [["node-1", "junction"]],
data_type: "realtime",
start_time: "2026-07-14T00:00:00Z",
end_time: "2026-07-14T01:00:00Z",
},
});
if (!emitted) throw new Error("request was not emitted");
coordinator.submitResult("s", {
version: "frontend-action-result@1",
actionId: emitted.actionId,
status: "succeeded",
output: { component: "HistoryPanel", rendered: true, itemCount: 1 },
completedAt: Date.now(),
});
await expect(pending).resolves.toMatchObject({ status: "succeeded" });
});
});