@te-river/opencode-team-mode 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -15
- package/README.zh-CN.md +67 -18
- package/dist/host/note.d.ts +7 -0
- package/dist/host/note.d.ts.map +1 -0
- package/dist/host/note.js +31 -0
- package/dist/host/note.js.map +1 -0
- package/dist/host/v1.d.ts +14 -0
- package/dist/host/v1.d.ts.map +1 -0
- package/dist/host/v1.js +340 -0
- package/dist/host/v1.js.map +1 -0
- package/dist/host/v2-browser-gate.d.ts +45 -0
- package/dist/host/v2-browser-gate.d.ts.map +1 -0
- package/dist/host/v2-browser-gate.js +319 -0
- package/dist/host/v2-browser-gate.js.map +1 -0
- package/dist/host/v2-capabilities.d.ts +78 -0
- package/dist/host/v2-capabilities.d.ts.map +1 -0
- package/dist/host/v2-capabilities.js +173 -0
- package/dist/host/v2-capabilities.js.map +1 -0
- package/dist/host/v2-client.d.ts +53 -0
- package/dist/host/v2-client.d.ts.map +1 -0
- package/dist/host/v2-client.js +193 -0
- package/dist/host/v2-client.js.map +1 -0
- package/dist/host/v2-events.d.ts +56 -0
- package/dist/host/v2-events.d.ts.map +1 -0
- package/dist/host/v2-events.js +158 -0
- package/dist/host/v2-events.js.map +1 -0
- package/dist/host/v2-guard.d.ts +101 -0
- package/dist/host/v2-guard.d.ts.map +1 -0
- package/dist/host/v2-guard.js +199 -0
- package/dist/host/v2-guard.js.map +1 -0
- package/dist/host/v2-offload.d.ts +148 -0
- package/dist/host/v2-offload.d.ts.map +1 -0
- package/dist/host/v2-offload.js +288 -0
- package/dist/host/v2-offload.js.map +1 -0
- package/dist/host/v2-permissions.d.ts +123 -0
- package/dist/host/v2-permissions.d.ts.map +1 -0
- package/dist/host/v2-permissions.js +190 -0
- package/dist/host/v2-permissions.js.map +1 -0
- package/dist/host/v2-probe.d.ts +85 -0
- package/dist/host/v2-probe.d.ts.map +1 -0
- package/dist/host/v2-probe.js +268 -0
- package/dist/host/v2-probe.js.map +1 -0
- package/dist/host/v2-scope.d.ts +51 -0
- package/dist/host/v2-scope.d.ts.map +1 -0
- package/dist/host/v2-scope.js +58 -0
- package/dist/host/v2-scope.js.map +1 -0
- package/dist/host/v2-session-client.d.ts +105 -0
- package/dist/host/v2-session-client.d.ts.map +1 -0
- package/dist/host/v2-session-client.js +390 -0
- package/dist/host/v2-session-client.js.map +1 -0
- package/dist/host/v2-session.d.ts +85 -0
- package/dist/host/v2-session.d.ts.map +1 -0
- package/dist/host/v2-session.js +171 -0
- package/dist/host/v2-session.js.map +1 -0
- package/dist/host/v2-subagent.d.ts +157 -0
- package/dist/host/v2-subagent.d.ts.map +1 -0
- package/dist/host/v2-subagent.js +286 -0
- package/dist/host/v2-subagent.js.map +1 -0
- package/dist/host/v2-tool.d.ts +67 -0
- package/dist/host/v2-tool.d.ts.map +1 -0
- package/dist/host/v2-tool.js +209 -0
- package/dist/host/v2-tool.js.map +1 -0
- package/dist/host/v2-transcript.d.ts +73 -0
- package/dist/host/v2-transcript.d.ts.map +1 -0
- package/dist/host/v2-transcript.js +151 -0
- package/dist/host/v2-transcript.js.map +1 -0
- package/dist/host/v2-types.d.ts +229 -0
- package/dist/host/v2-types.d.ts.map +1 -0
- package/dist/host/v2-types.js +17 -0
- package/dist/host/v2-types.js.map +1 -0
- package/dist/host/v2.d.ts +42 -0
- package/dist/host/v2.d.ts.map +1 -0
- package/dist/host/v2.js +853 -0
- package/dist/host/v2.js.map +1 -0
- package/dist/index.d.ts +23 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -366
- package/dist/index.js.map +1 -1
- package/dist/prompts/lead.d.ts +1 -1
- package/dist/prompts/lead.d.ts.map +1 -1
- package/dist/prompts/lead.js +456 -426
- package/dist/prompts/lead.js.map +1 -1
- package/dist/prompts/shared.d.ts +2 -2
- package/dist/prompts/shared.d.ts.map +1 -1
- package/dist/prompts/shared.js +38 -11
- package/dist/prompts/shared.js.map +1 -1
- package/dist/prompts/specialists.d.ts +2 -2
- package/dist/prompts/specialists.d.ts.map +1 -1
- package/dist/prompts/specialists.js +7 -6
- package/dist/prompts/specialists.js.map +1 -1
- package/dist/task-offload.d.ts +16 -0
- package/dist/task-offload.d.ts.map +1 -1
- package/dist/task-offload.js +51 -0
- package/dist/task-offload.js.map +1 -1
- package/dist/tm/browser.d.ts.map +1 -1
- package/dist/tm/browser.js +41 -10
- package/dist/tm/browser.js.map +1 -1
- package/dist/tm/dispatch.d.ts +86 -1
- package/dist/tm/dispatch.d.ts.map +1 -1
- package/dist/tm/dispatch.js +360 -39
- package/dist/tm/dispatch.js.map +1 -1
- package/dist/tm/dupe-guard.d.ts +16 -3
- package/dist/tm/dupe-guard.d.ts.map +1 -1
- package/dist/tm/dupe-guard.js +27 -7
- package/dist/tm/dupe-guard.js.map +1 -1
- package/dist/tm/index.d.ts +40 -1
- package/dist/tm/index.d.ts.map +1 -1
- package/dist/tm/index.js +40 -11
- package/dist/tm/index.js.map +1 -1
- package/dist/tm/ledger.d.ts +114 -0
- package/dist/tm/ledger.d.ts.map +1 -0
- package/dist/tm/ledger.js +308 -0
- package/dist/tm/ledger.js.map +1 -0
- package/dist/tm/perm-ask.d.ts +1 -3
- package/dist/tm/perm-ask.d.ts.map +1 -1
- package/dist/tm/perm-ask.js +10 -1
- package/dist/tm/perm-ask.js.map +1 -1
- package/dist/tm/preview.d.ts +55 -0
- package/dist/tm/preview.d.ts.map +1 -1
- package/dist/tm/preview.js +225 -0
- package/dist/tm/preview.js.map +1 -1
- package/dist/tm/search.d.ts.map +1 -1
- package/dist/tm/search.js +40 -10
- package/dist/tm/search.js.map +1 -1
- package/dist/tm/serp-loop.d.ts +45 -0
- package/dist/tm/serp-loop.d.ts.map +1 -0
- package/dist/tm/serp-loop.js +80 -0
- package/dist/tm/serp-loop.js.map +1 -0
- package/dist/tm/stats.d.ts +29 -0
- package/dist/tm/stats.d.ts.map +1 -1
- package/dist/tm/stats.js +278 -4
- package/dist/tm/stats.js.map +1 -1
- package/dist/tm/webfetch.d.ts +4 -0
- package/dist/tm/webfetch.d.ts.map +1 -1
- package/dist/tm/webfetch.js +75 -8
- package/dist/tm/webfetch.js.map +1 -1
- package/docs/installation-v2.md +445 -0
- package/docs/installation.md +12 -0
- package/docs/research/agent-data-exchange.md +117 -0
- package/docs/research/browser-pane.md +89 -0
- package/docs/research/host-http-api.md +132 -0
- package/docs/research/host-subagent-injection.md +187 -0
- package/docs/research/plugin-loader-contract.md +261 -0
- package/docs/research/v2-builtin-tools.md +447 -0
- package/docs/v2-port-notes.md +413 -0
- package/index.js +7 -0
- package/package.json +64 -61
- package/scripts/gen-v2-config.mjs +304 -0
- package/scripts/lib/config-surgery.cjs +239 -0
- package/scripts/lib/fake-ctx.mjs +169 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1 tool definitions -> v2 tool registrations.
|
|
3
|
+
*
|
|
4
|
+
* Two shapes have to be translated, and both translations are load-bearing:
|
|
5
|
+
*
|
|
6
|
+
* 1. THE RESULT. v1 tools answer `{output: string, attachments?: [...]}`. A
|
|
7
|
+
* live probe measured what the v2 host does with that: every tool that
|
|
8
|
+
* returned a bare `output` without declaring an `output` schema came back as
|
|
9
|
+
* "Tool result declared output without an output schema". So the v2 adapter
|
|
10
|
+
* answers with `content` parts instead — text plus `file` entries, which is
|
|
11
|
+
* also the first time tm_browser's screenshot attachment has had a host
|
|
12
|
+
* contract we can VERIFY rather than assume (the v1 capability row for it is
|
|
13
|
+
* still 未验证).
|
|
14
|
+
* 2. THE CONTEXT. Our tools read `{directory, sessionID, agent, ask}` off the
|
|
15
|
+
* per-call ctx. v2's ToolContext carries `{sessionID, agent, messageID, id,
|
|
16
|
+
* progress}` and NO directory and NO ask bridge. Directory comes from the
|
|
17
|
+
* boot location; the missing ask bridge is left missing on purpose, because
|
|
18
|
+
* `askFnOf` then reports "unavailable" and every governed call fails CLOSED
|
|
19
|
+
* rather than pretending somebody approved it.
|
|
20
|
+
*/
|
|
21
|
+
import type { ToolDefinition } from "../types.js";
|
|
22
|
+
import type { V2ToolContext, V2ToolInfo, V2ToolResult } from "./v2-types.js";
|
|
23
|
+
/**
|
|
24
|
+
* `args` is a ZodRawShape (see `src/tm/args-schema.ts`) — but it is a
|
|
25
|
+
* *descriptor* when zod could not be loaded, and it may already be a JSON
|
|
26
|
+
* Schema. `exact:false` means the model gets no parameter guidance for this
|
|
27
|
+
* tool, which the caller reports instead of hiding: a tool the model cannot
|
|
28
|
+
* call correctly is a tool that is broken, whatever the code says.
|
|
29
|
+
*/
|
|
30
|
+
export declare function inputSchemaFor(args: unknown): Promise<{
|
|
31
|
+
schema: Record<string, unknown>;
|
|
32
|
+
exact: boolean;
|
|
33
|
+
source: string;
|
|
34
|
+
note?: string;
|
|
35
|
+
}>;
|
|
36
|
+
/** The per-execute literal our pipelines expect. */
|
|
37
|
+
export declare function v2ToolCtx(ctx: V2ToolContext, directory: string): Record<string, unknown>;
|
|
38
|
+
export declare function v2Result(res: unknown): V2ToolResult;
|
|
39
|
+
export interface V2ToolBinding {
|
|
40
|
+
readonly tool: V2ToolInfo;
|
|
41
|
+
readonly inputExact: boolean;
|
|
42
|
+
/** How the schema was obtained: "zod" | "json-schema" | "descriptor" |
|
|
43
|
+
* "permissive". `exact` alone cannot tell a translated zod shape from a
|
|
44
|
+
* regex read of a descriptor string, and the boot log must not claim the
|
|
45
|
+
* two are the same fact. */
|
|
46
|
+
readonly inputSource: string;
|
|
47
|
+
readonly note?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Wrap one v1 ToolDefinition. `execute` may be absent on exotic hosts; a tool
|
|
51
|
+
* that cannot run must not be registered at all, because the model would spend
|
|
52
|
+
* a round on it and get nothing.
|
|
53
|
+
*/
|
|
54
|
+
export declare function bindV2Tool(name: string, def: ToolDefinition, directory: string,
|
|
55
|
+
/** Every call to OUR tool tells the host-scope resolver which sessions belong to
|
|
56
|
+
* Team (#22) — the one fact about a session we can learn from the inside. */
|
|
57
|
+
onCall?: (agent: unknown, sessionID: unknown) => void,
|
|
58
|
+
/** `codemodeDirect: true` sends `options:{codemode:false}`, which the 2.0.16
|
|
59
|
+
* binary uses as the visibility switch: without it a registered tool reaches the
|
|
60
|
+
* model ONLY inside the Code Mode catalog, with its description cut to the first
|
|
61
|
+
* line — so every governance sentence we wrote below that line never arrives.
|
|
62
|
+
* Off by default because the cost is the whole definition set riding every
|
|
63
|
+
* request; the number is measured, not argued (see TM_V2_CODEMODE). */
|
|
64
|
+
opts?: {
|
|
65
|
+
codemodeDirect?: boolean;
|
|
66
|
+
}): Promise<V2ToolBinding | null>;
|
|
67
|
+
//# sourceMappingURL=v2-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-tool.d.ts","sourceRoot":"","sources":["../../src/host/v2-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAoC,MAAM,aAAa,CAAA;AACnF,OAAO,KAAK,EAAa,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAkFvF;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgC7F;AAED,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWxF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAcnD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B;;;iCAG6B;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,cAAc,EACnB,SAAS,EAAE,MAAM;AACjB;8EAC8E;AAC9E,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI;AACrD;;;;;wEAKwE;AACxE,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAkB/B"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1 tool definitions -> v2 tool registrations.
|
|
3
|
+
*
|
|
4
|
+
* Two shapes have to be translated, and both translations are load-bearing:
|
|
5
|
+
*
|
|
6
|
+
* 1. THE RESULT. v1 tools answer `{output: string, attachments?: [...]}`. A
|
|
7
|
+
* live probe measured what the v2 host does with that: every tool that
|
|
8
|
+
* returned a bare `output` without declaring an `output` schema came back as
|
|
9
|
+
* "Tool result declared output without an output schema". So the v2 adapter
|
|
10
|
+
* answers with `content` parts instead — text plus `file` entries, which is
|
|
11
|
+
* also the first time tm_browser's screenshot attachment has had a host
|
|
12
|
+
* contract we can VERIFY rather than assume (the v1 capability row for it is
|
|
13
|
+
* still 未验证).
|
|
14
|
+
* 2. THE CONTEXT. Our tools read `{directory, sessionID, agent, ask}` off the
|
|
15
|
+
* per-call ctx. v2's ToolContext carries `{sessionID, agent, messageID, id,
|
|
16
|
+
* progress}` and NO directory and NO ask bridge. Directory comes from the
|
|
17
|
+
* boot location; the missing ask bridge is left missing on purpose, because
|
|
18
|
+
* `askFnOf` then reports "unavailable" and every governed call fails CLOSED
|
|
19
|
+
* rather than pretending somebody approved it.
|
|
20
|
+
*/
|
|
21
|
+
/** zod is a peer the host ships, never a dependency we require: the same
|
|
22
|
+
* variable-specifier trick `args-schema.ts` uses for the arg schemas. */
|
|
23
|
+
async function loadZod() {
|
|
24
|
+
try {
|
|
25
|
+
const spec = "zod";
|
|
26
|
+
const mod = (await import(spec));
|
|
27
|
+
const z = (mod.z ?? mod.default?.z);
|
|
28
|
+
return z && typeof z.object === "function" ? z : null;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** A descriptor entry: `{ key: { descriptor: "name: type (…) — guidance" } }`.
|
|
35
|
+
* Three tools ship this shape (tm_join / tm_pty / tm_stats) because their args
|
|
36
|
+
* are built without zod, and feeding it to `z.object()` throws
|
|
37
|
+
* `undefined is not an object (evaluating 'schema._zod.def')` — measured live,
|
|
38
|
+
* where those three reached the model with NO parameter guidance at all.
|
|
39
|
+
* The descriptor's leading `name: type` is parseable, and the whole string is
|
|
40
|
+
* the guidance, so translating it is strictly better than a permissive schema. */
|
|
41
|
+
const DESCRIPTOR_HEAD = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([\s\S]*)$/;
|
|
42
|
+
/** `typed` is what follows the `name:` in the descriptor — the type is read off
|
|
43
|
+
* its first token. Passing the whole line instead would read the parameter
|
|
44
|
+
* NAME plus its colon (`action:`), which matches no type shape at all, so every
|
|
45
|
+
* descriptor would collapse to `string` and the enum/array/number guidance
|
|
46
|
+
* would be silently lost. `full` stays the description verbatim: the guidance
|
|
47
|
+
* after the type is the part the model actually needs. */
|
|
48
|
+
function descriptorToProperty(full, typed) {
|
|
49
|
+
const head = (typed.trim().match(/^[^\s(,]+/) ?? [""])[0];
|
|
50
|
+
let type = "string";
|
|
51
|
+
let enumValues;
|
|
52
|
+
if (/^[A-Za-z][\w.]*\[\]$/.test(head)) {
|
|
53
|
+
type = "array";
|
|
54
|
+
}
|
|
55
|
+
else if (/^\d+$/.test(head) || /^(number|int|integer)/i.test(head)) {
|
|
56
|
+
type = "number";
|
|
57
|
+
}
|
|
58
|
+
else if (/^(true|false|boolean)$/i.test(head)) {
|
|
59
|
+
type = "boolean";
|
|
60
|
+
}
|
|
61
|
+
else if (/^[A-Za-z0-9_|-]*\|[A-Za-z0-9_|-]+$/.test(head)) {
|
|
62
|
+
enumValues = head.split("|").filter(Boolean);
|
|
63
|
+
type = "string";
|
|
64
|
+
}
|
|
65
|
+
const prop = { type };
|
|
66
|
+
if (type === "array")
|
|
67
|
+
prop.items = { type: "string" };
|
|
68
|
+
if (enumValues)
|
|
69
|
+
prop.enum = enumValues;
|
|
70
|
+
prop.description = full.trim();
|
|
71
|
+
return prop;
|
|
72
|
+
}
|
|
73
|
+
function fromDescriptors(shape) {
|
|
74
|
+
const properties = {};
|
|
75
|
+
const required = [];
|
|
76
|
+
let seen = 0;
|
|
77
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
78
|
+
const text = typeof value === "string"
|
|
79
|
+
? `${key}: ${value}`
|
|
80
|
+
: typeof value?.descriptor === "string"
|
|
81
|
+
? String(value.descriptor)
|
|
82
|
+
: null;
|
|
83
|
+
if (!text)
|
|
84
|
+
continue;
|
|
85
|
+
seen++;
|
|
86
|
+
const m = text.match(DESCRIPTOR_HEAD);
|
|
87
|
+
properties[key] = m
|
|
88
|
+
? descriptorToProperty(text, m[2] ?? "")
|
|
89
|
+
: { type: "string", description: text };
|
|
90
|
+
// `(required)` is explicit in the fallback schemas; `(optional` marks the
|
|
91
|
+
// rest. Anything unmarked stays optional — execute() coerces raw args
|
|
92
|
+
// itself, and a wrong `required` makes the host reject a valid call.
|
|
93
|
+
if (/\(required\)/i.test(text) && !/optional/i.test(text))
|
|
94
|
+
required.push(key);
|
|
95
|
+
}
|
|
96
|
+
if (!seen || seen !== Object.keys(shape).length)
|
|
97
|
+
return null;
|
|
98
|
+
const schema = { type: "object", properties, additionalProperties: false };
|
|
99
|
+
if (required.length)
|
|
100
|
+
schema.required = required;
|
|
101
|
+
return { schema, required };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* `args` is a ZodRawShape (see `src/tm/args-schema.ts`) — but it is a
|
|
105
|
+
* *descriptor* when zod could not be loaded, and it may already be a JSON
|
|
106
|
+
* Schema. `exact:false` means the model gets no parameter guidance for this
|
|
107
|
+
* tool, which the caller reports instead of hiding: a tool the model cannot
|
|
108
|
+
* call correctly is a tool that is broken, whatever the code says.
|
|
109
|
+
*/
|
|
110
|
+
export async function inputSchemaFor(args) {
|
|
111
|
+
if (args && typeof args === "object") {
|
|
112
|
+
const shape = args;
|
|
113
|
+
if (typeof shape.type === "string" && (shape.properties || shape.additionalProperties !== undefined)) {
|
|
114
|
+
return { schema: shape, exact: true, source: "json-schema" };
|
|
115
|
+
}
|
|
116
|
+
const descriptors = fromDescriptors(shape);
|
|
117
|
+
if (descriptors) {
|
|
118
|
+
return { schema: descriptors.schema, exact: true, source: "descriptor" };
|
|
119
|
+
}
|
|
120
|
+
const z = await loadZod();
|
|
121
|
+
const toJSONSchema = z?.toJSONSchema;
|
|
122
|
+
if (z && toJSONSchema) {
|
|
123
|
+
try {
|
|
124
|
+
const schema = toJSONSchema(z.object(shape));
|
|
125
|
+
return { schema, exact: true, source: "zod" };
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return {
|
|
129
|
+
schema: { type: "object", additionalProperties: true },
|
|
130
|
+
exact: false,
|
|
131
|
+
source: "permissive",
|
|
132
|
+
note: `zod 形状转换失败:${err?.message ?? String(err)}`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
schema: { type: "object", additionalProperties: true },
|
|
139
|
+
exact: false,
|
|
140
|
+
source: "permissive",
|
|
141
|
+
note: "宿主未提供 zod,参数表退化为不限形状",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/** The per-execute literal our pipelines expect. */
|
|
145
|
+
export function v2ToolCtx(ctx, directory) {
|
|
146
|
+
const c = (ctx ?? {});
|
|
147
|
+
return {
|
|
148
|
+
// A future host may carry a per-call directory (sessions CAN move); honor it
|
|
149
|
+
// when present instead of pinning the boot value.
|
|
150
|
+
directory: typeof c.directory === "string" && c.directory ? c.directory : directory,
|
|
151
|
+
sessionID: String(c.sessionID ?? ""),
|
|
152
|
+
agent: String(c.agent ?? ""),
|
|
153
|
+
// NOTE: no `ask` on purpose — see the header. Adding a stub that resolves
|
|
154
|
+
// would be the self-allowing this codebase refuses.
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function v2Result(res) {
|
|
158
|
+
// `ToolResult` is a union: most tm_* answers are already plain strings.
|
|
159
|
+
if (typeof res === "string")
|
|
160
|
+
return { content: [{ type: "text", text: res }] };
|
|
161
|
+
const out = (res ?? {});
|
|
162
|
+
const text = typeof out.output === "string" ? out.output : String(out.output ?? "");
|
|
163
|
+
const content = [{ type: "text", text }];
|
|
164
|
+
for (const att of (out.attachments ?? [])) {
|
|
165
|
+
if (!att || typeof att.url !== "string" || !att.url)
|
|
166
|
+
continue;
|
|
167
|
+
content.push({ type: "file", uri: att.url, mime: att.mime, name: att.filename });
|
|
168
|
+
}
|
|
169
|
+
const metadata = out.metadata;
|
|
170
|
+
return metadata && typeof metadata === "object"
|
|
171
|
+
? { content, metadata }
|
|
172
|
+
: { content };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Wrap one v1 ToolDefinition. `execute` may be absent on exotic hosts; a tool
|
|
176
|
+
* that cannot run must not be registered at all, because the model would spend
|
|
177
|
+
* a round on it and get nothing.
|
|
178
|
+
*/
|
|
179
|
+
export async function bindV2Tool(name, def, directory,
|
|
180
|
+
/** Every call to OUR tool tells the host-scope resolver which sessions belong to
|
|
181
|
+
* Team (#22) — the one fact about a session we can learn from the inside. */
|
|
182
|
+
onCall,
|
|
183
|
+
/** `codemodeDirect: true` sends `options:{codemode:false}`, which the 2.0.16
|
|
184
|
+
* binary uses as the visibility switch: without it a registered tool reaches the
|
|
185
|
+
* model ONLY inside the Code Mode catalog, with its description cut to the first
|
|
186
|
+
* line — so every governance sentence we wrote below that line never arrives.
|
|
187
|
+
* Off by default because the cost is the whole definition set riding every
|
|
188
|
+
* request; the number is measured, not argued (see TM_V2_CODEMODE). */
|
|
189
|
+
opts = {}) {
|
|
190
|
+
if (typeof def?.execute !== "function")
|
|
191
|
+
return null;
|
|
192
|
+
const { schema, exact, source, note } = await inputSchemaFor(def.args);
|
|
193
|
+
const tool = {
|
|
194
|
+
name,
|
|
195
|
+
description: String(def.description ?? ""),
|
|
196
|
+
input: schema,
|
|
197
|
+
...(opts.codemodeDirect ? { options: { codemode: false } } : {}),
|
|
198
|
+
async execute(args, ctx) {
|
|
199
|
+
onCall?.(ctx?.agent, ctx?.sessionID);
|
|
200
|
+
// Our tools are defensive about raw model args already (they coerce
|
|
201
|
+
// string booleans and JSON-array strings themselves), so nothing is
|
|
202
|
+
// normalized here beyond a guaranteed object.
|
|
203
|
+
const res = await def.execute?.((args ?? {}), v2ToolCtx(ctx, directory));
|
|
204
|
+
return v2Result(res);
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
return { tool, inputExact: exact, inputSource: source, note };
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=v2-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-tool.js","sourceRoot":"","sources":["../../src/host/v2-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a CHILD session's own messages — in process, with no credential.
|
|
3
|
+
*
|
|
4
|
+
* This is the answer to the HTTP-API decision (task #32). The host's own API
|
|
5
|
+
* (`docs/research/host-http-api.md`) does expose `GET /api/session/{id}/message`, and using
|
|
6
|
+
* it would have meant reading the Basic-auth password out of
|
|
7
|
+
* `<global-config>/service.json` — a secret that would then live in this plugin's memory,
|
|
8
|
+
* in every error string the fetch layer can produce, and in any log line that quotes a
|
|
9
|
+
* request. The user's condition for going there was "prove it cannot leak".
|
|
10
|
+
*
|
|
11
|
+
* Measured instead, on a live 2.0.18 with a plugin that only inspects its own ctx (zero
|
|
12
|
+
* model tokens, `--model nope/nope`): the plugin ctx carries a full `session` domain —
|
|
13
|
+
*
|
|
14
|
+
* hook create get switchAgent switchModel prompt generate command synthetic interrupt
|
|
15
|
+
* update move wait context
|
|
16
|
+
*
|
|
17
|
+
* and `ctx.session.context({ sessionID })` returns the session's message array. On the child
|
|
18
|
+
* session of a real background dispatch that array had 5 items shaped
|
|
19
|
+
* `{id, time:{created}, text, type}`. `ctx.session.get({sessionID})` returns
|
|
20
|
+
* `{id, parentID, projectID, agent, model, outcome, tokens, title, location}`.
|
|
21
|
+
*
|
|
22
|
+
* So the capability was in front of us the whole time and the password was never needed:
|
|
23
|
+
* nothing here opens a socket, reads a credential file, or can be redirected to a port that
|
|
24
|
+
* is not our own host process. That is a stronger guarantee than "we will keep the secret
|
|
25
|
+
* safe" — there is no secret.
|
|
26
|
+
*
|
|
27
|
+
* The one thing this MUST still earn is scope. `session.context` will answer for ANY session
|
|
28
|
+
* id handed to it, including the user's unrelated `build`/`plan` sessions, which makes it a
|
|
29
|
+
* private-content oracle if used carelessly. Therefore: parentage is verified with
|
|
30
|
+
* `session.get` FIRST, and a session that is not the caller's own child is refused without
|
|
31
|
+
* being read. The refusal is counted (`refused`) so "we did not look" stays distinguishable
|
|
32
|
+
* from "we looked and were denied". Text bodies are never written to the trajectory — ids,
|
|
33
|
+
* item counts and the chosen message's TYPE only, per R6.
|
|
34
|
+
*/
|
|
35
|
+
export interface V2TranscriptReport {
|
|
36
|
+
/** read() calls made */
|
|
37
|
+
attempted: number;
|
|
38
|
+
/** calls that returned a non-empty body */
|
|
39
|
+
resolved: number;
|
|
40
|
+
/** calls refused because session.get said the child is not the caller's */
|
|
41
|
+
refused: number;
|
|
42
|
+
/** calls where the parentage check itself could not answer (no seam, host error) */
|
|
43
|
+
unverifiable: number;
|
|
44
|
+
lastError?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface V2TranscriptResult {
|
|
47
|
+
text: string;
|
|
48
|
+
/** how many messages the host handed back */
|
|
49
|
+
items: number;
|
|
50
|
+
/** the `type` of the message the body was taken from, when it had one */
|
|
51
|
+
pickedType?: string;
|
|
52
|
+
/** why there is no body — names the seam that failed, never a guess */
|
|
53
|
+
error?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface V2TranscriptReader {
|
|
56
|
+
read: (sessionID: string, callerSessionID: string) => Promise<V2TranscriptResult>;
|
|
57
|
+
report: V2TranscriptReport;
|
|
58
|
+
/** Whether this host gives the seam at all — the caller says so out loud when not. */
|
|
59
|
+
active: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** The child's ANSWER is the last non-user message that carries text. Taking the last,
|
|
62
|
+
* rather than concatenating the transcript, is the whole point: the lead asked for the
|
|
63
|
+
* report, and the earlier turns are the work it does not want to pay tokens for. The type
|
|
64
|
+
* of the chosen item is returned so the reply can say where the text came from instead of
|
|
65
|
+
* implying it read the whole session. */
|
|
66
|
+
export declare function pickChildReply(items: unknown[]): {
|
|
67
|
+
text: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
};
|
|
70
|
+
export declare function createV2TranscriptReader(ctx: unknown): V2TranscriptReader;
|
|
71
|
+
/** One line for tm_stats: what the reader was asked for and what it could say. */
|
|
72
|
+
export declare function transcriptSummary(r: V2TranscriptReport): string;
|
|
73
|
+
//# sourceMappingURL=v2-transcript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-transcript.d.ts","sourceRoot":"","sources":["../../src/host/v2-transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAA;IACf,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjF,MAAM,EAAE,kBAAkB,CAAA;IAC1B,sFAAsF;IACtF,MAAM,EAAE,OAAO,CAAA;CAChB;AAkCD;;;;0CAI0C;AAC1C,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAQhF;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CA2DzE;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAO/D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a CHILD session's own messages — in process, with no credential.
|
|
3
|
+
*
|
|
4
|
+
* This is the answer to the HTTP-API decision (task #32). The host's own API
|
|
5
|
+
* (`docs/research/host-http-api.md`) does expose `GET /api/session/{id}/message`, and using
|
|
6
|
+
* it would have meant reading the Basic-auth password out of
|
|
7
|
+
* `<global-config>/service.json` — a secret that would then live in this plugin's memory,
|
|
8
|
+
* in every error string the fetch layer can produce, and in any log line that quotes a
|
|
9
|
+
* request. The user's condition for going there was "prove it cannot leak".
|
|
10
|
+
*
|
|
11
|
+
* Measured instead, on a live 2.0.18 with a plugin that only inspects its own ctx (zero
|
|
12
|
+
* model tokens, `--model nope/nope`): the plugin ctx carries a full `session` domain —
|
|
13
|
+
*
|
|
14
|
+
* hook create get switchAgent switchModel prompt generate command synthetic interrupt
|
|
15
|
+
* update move wait context
|
|
16
|
+
*
|
|
17
|
+
* and `ctx.session.context({ sessionID })` returns the session's message array. On the child
|
|
18
|
+
* session of a real background dispatch that array had 5 items shaped
|
|
19
|
+
* `{id, time:{created}, text, type}`. `ctx.session.get({sessionID})` returns
|
|
20
|
+
* `{id, parentID, projectID, agent, model, outcome, tokens, title, location}`.
|
|
21
|
+
*
|
|
22
|
+
* So the capability was in front of us the whole time and the password was never needed:
|
|
23
|
+
* nothing here opens a socket, reads a credential file, or can be redirected to a port that
|
|
24
|
+
* is not our own host process. That is a stronger guarantee than "we will keep the secret
|
|
25
|
+
* safe" — there is no secret.
|
|
26
|
+
*
|
|
27
|
+
* The one thing this MUST still earn is scope. `session.context` will answer for ANY session
|
|
28
|
+
* id handed to it, including the user's unrelated `build`/`plan` sessions, which makes it a
|
|
29
|
+
* private-content oracle if used carelessly. Therefore: parentage is verified with
|
|
30
|
+
* `session.get` FIRST, and a session that is not the caller's own child is refused without
|
|
31
|
+
* being read. The refusal is counted (`refused`) so "we did not look" stays distinguishable
|
|
32
|
+
* from "we looked and were denied". Text bodies are never written to the trajectory — ids,
|
|
33
|
+
* item counts and the chosen message's TYPE only, per R6.
|
|
34
|
+
*/
|
|
35
|
+
/** Unwrap whatever envelope the host puts on a result object. */
|
|
36
|
+
function unwrap(raw) {
|
|
37
|
+
if (!raw || typeof raw !== "object")
|
|
38
|
+
return null;
|
|
39
|
+
const rec = raw;
|
|
40
|
+
for (const cand of [rec, rec.data, rec.result, rec.session]) {
|
|
41
|
+
if (cand && typeof cand === "object")
|
|
42
|
+
return cand;
|
|
43
|
+
}
|
|
44
|
+
return rec;
|
|
45
|
+
}
|
|
46
|
+
/** The text one message item carries, across the shapes the host has been seen to use:
|
|
47
|
+
* a bare `text` (measured on 2.0.18), `parts[]` (the persisted message shape), and
|
|
48
|
+
* `content[]` (the tool-result shape). Never descends into a tool payload. */
|
|
49
|
+
function itemText(raw) {
|
|
50
|
+
if (!raw || typeof raw !== "object")
|
|
51
|
+
return null;
|
|
52
|
+
const it = raw;
|
|
53
|
+
const type = String(it.type ?? it.role ?? "");
|
|
54
|
+
const direct = it.text;
|
|
55
|
+
if (typeof direct === "string" && direct.trim())
|
|
56
|
+
return { text: direct, type };
|
|
57
|
+
for (const key of ["parts", "content"]) {
|
|
58
|
+
const arr = it[key];
|
|
59
|
+
if (!Array.isArray(arr))
|
|
60
|
+
continue;
|
|
61
|
+
const texts = arr
|
|
62
|
+
.map((p) => (p && typeof p === "object" ? p.text : undefined))
|
|
63
|
+
.filter((t) => typeof t === "string" && t.trim().length > 0);
|
|
64
|
+
if (texts.length)
|
|
65
|
+
return { text: texts.join(String.fromCharCode(10)), type };
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/** The child's ANSWER is the last non-user message that carries text. Taking the last,
|
|
70
|
+
* rather than concatenating the transcript, is the whole point: the lead asked for the
|
|
71
|
+
* report, and the earlier turns are the work it does not want to pay tokens for. The type
|
|
72
|
+
* of the chosen item is returned so the reply can say where the text came from instead of
|
|
73
|
+
* implying it read the whole session. */
|
|
74
|
+
export function pickChildReply(items) {
|
|
75
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
76
|
+
const t = itemText(items[i]);
|
|
77
|
+
if (!t)
|
|
78
|
+
continue;
|
|
79
|
+
if (/^user$/i.test(t.type))
|
|
80
|
+
continue;
|
|
81
|
+
return { text: t.text, type: t.type || undefined };
|
|
82
|
+
}
|
|
83
|
+
return { text: "" };
|
|
84
|
+
}
|
|
85
|
+
export function createV2TranscriptReader(ctx) {
|
|
86
|
+
const report = { attempted: 0, resolved: 0, refused: 0, unverifiable: 0 };
|
|
87
|
+
const session = ctx?.session;
|
|
88
|
+
const getContext = session?.context;
|
|
89
|
+
const get = session?.get;
|
|
90
|
+
const active = typeof getContext === "function";
|
|
91
|
+
const call = async (fn, arg) => await fn.call(session, arg);
|
|
92
|
+
const read = async (sessionID, callerSessionID) => {
|
|
93
|
+
report.attempted++;
|
|
94
|
+
if (!active || typeof getContext !== "function") {
|
|
95
|
+
return { text: "", items: 0, error: "这个宿主没给 ctx.session.context" };
|
|
96
|
+
}
|
|
97
|
+
if (!sessionID || !callerSessionID)
|
|
98
|
+
return { text: "", items: 0, error: "缺少会话 id,无法核验归属" };
|
|
99
|
+
// Scope FIRST. A reader that takes whatever id it is handed is a private-content oracle,
|
|
100
|
+
// and "the user approved the API" does not extend to their unrelated sessions.
|
|
101
|
+
if (typeof get !== "function") {
|
|
102
|
+
report.unverifiable++;
|
|
103
|
+
return { text: "", items: 0, error: "宿主没给 ctx.session.get,无法核验子会话归属,因此没有读取正文" };
|
|
104
|
+
}
|
|
105
|
+
let parentID;
|
|
106
|
+
try {
|
|
107
|
+
const rec = unwrap(await call(get, { sessionID }));
|
|
108
|
+
const p = rec?.parentID ?? rec?.parent_id;
|
|
109
|
+
parentID = typeof p === "string" && p ? p : undefined;
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
report.unverifiable++;
|
|
113
|
+
report.lastError = String(err?.message ?? err).slice(0, 160);
|
|
114
|
+
return { text: "", items: 0, error: `归属核验失败:${report.lastError ?? "宿主未回应"}` };
|
|
115
|
+
}
|
|
116
|
+
if (!parentID) {
|
|
117
|
+
report.unverifiable++;
|
|
118
|
+
return { text: "", items: 0, error: "宿主回答里没有 parentID,无法确认这个会话是你的子会话,因此没有读取正文" };
|
|
119
|
+
}
|
|
120
|
+
if (parentID !== callerSessionID) {
|
|
121
|
+
report.refused++;
|
|
122
|
+
return { text: "", items: 0, error: "这个会话不是你的子会话(宿主给的 parentID 不匹配),我没有读它" };
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const raw = await call(getContext, { sessionID });
|
|
126
|
+
const arr = Array.isArray(raw) ? raw : Array.isArray(raw?.data) ? raw.data : null;
|
|
127
|
+
if (!arr) {
|
|
128
|
+
report.lastError = "context 返回值不是数组";
|
|
129
|
+
return { text: "", items: 0, error: report.lastError };
|
|
130
|
+
}
|
|
131
|
+
const picked = pickChildReply(arr);
|
|
132
|
+
if (picked.text)
|
|
133
|
+
report.resolved++;
|
|
134
|
+
return { text: picked.text, items: arr.length, pickedType: picked.type };
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
report.lastError = String(err?.message ?? err).slice(0, 160);
|
|
138
|
+
return { text: "", items: 0, error: `ctx.session.context 失败:${report.lastError}` };
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
return { read, report, active };
|
|
142
|
+
}
|
|
143
|
+
/** One line for tm_stats: what the reader was asked for and what it could say. */
|
|
144
|
+
export function transcriptSummary(r) {
|
|
145
|
+
if (!r.attempted)
|
|
146
|
+
return "子会话正文读取:没被调用过(缝在场,没数据)";
|
|
147
|
+
return (`子会话正文读取:尝试 ${r.attempted} · 拿到正文 ${r.resolved} · ` +
|
|
148
|
+
`归属不符拒绝 ${r.refused} · 无法核验 ${r.unverifiable}` +
|
|
149
|
+
(r.lastError ? ` · 最后错误:${r.lastError}` : ""));
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=v2-transcript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-transcript.js","sourceRoot":"","sources":["../../src/host/v2-transcript.ts"],"names":[],"mappings":"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"}
|