@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,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The v2 session read seam, shaped like the v1 client the collect path expects (#8).
|
|
3
|
+
*
|
|
4
|
+
* `tm_join` collects a child in two ways: it looks the child up in its own registry
|
|
5
|
+
* (children THIS plugin process created — and since `babfcb8` also the host's `subagent`
|
|
6
|
+
* children), and otherwise it asks the host. That ask was written against v1's SDK client
|
|
7
|
+
* (`client.session.get({path:{id}})`), and on a live host it never once resolved.
|
|
8
|
+
*
|
|
9
|
+
* Why it failed, read out of 2.0.18 rather than guessed (both quotes are from the embedded
|
|
10
|
+
* JS): the plugin-facing wrapper is a schema decode plus a single-object call —
|
|
11
|
+
*
|
|
12
|
+
* te = (schema, fn) => (input) => decode(schema, input ?? {}) → fn(decoded)
|
|
13
|
+
* get: te(N["session.get"], a.session.get)
|
|
14
|
+
*
|
|
15
|
+
* and the host's own call sites are flat:
|
|
16
|
+
*
|
|
17
|
+
* await e.session.get({ sessionID: n })
|
|
18
|
+
* await e.message.list({ sessionID: n, limit: 200, cursor: r })
|
|
19
|
+
*
|
|
20
|
+
* So our adapter had TWO bugs: the key (`path.id` / `id` instead of `sessionID`) and the
|
|
21
|
+
* arity (every shape was passed as a one-element ARRAY, which no `te`-wrapped method
|
|
22
|
+
* accepts). A decode failure looks exactly like "the host has no such method", which is
|
|
23
|
+
* how this stayed wrong for a whole release cycle.
|
|
24
|
+
*
|
|
25
|
+
* What this surface does NOT give, stated rather than discovered later:
|
|
26
|
+
* · no `children` method, so adoption from the host's session tree is still impossible on
|
|
27
|
+
* v2 — only an explicitly named id can be claimed, which is what the lead's prompt says.
|
|
28
|
+
* · no `message`/`messages` domain on the plugin ctx (the host's internal `message.list`
|
|
29
|
+
* is the SDK client, not this surface). `context` is the only candidate that could
|
|
30
|
+
* carry a child's reply, so it is tried, and its outcome — including the NAMES of the
|
|
31
|
+
* keys it returned — is recorded. Key names are safe; a message body is not written to
|
|
32
|
+
* the trajectory by this file.
|
|
33
|
+
* · the HTTP API does expose `GET /api/session/{id}/message` (136 distinct routes were
|
|
34
|
+
* enumerated from a scanned window of the binary, and none of them is a todo list —
|
|
35
|
+
* which settles the `tm_ledger` question: there is no host todo resource to read), but
|
|
36
|
+
* reaching it needs the basic-auth password from
|
|
37
|
+
* `~/.config/opencode/service.json`. A plugin reading the user's credential file to
|
|
38
|
+
* call back into the host is a new trust boundary, so it is NOT done here; it is
|
|
39
|
+
* recorded as the option with its cost attached. See
|
|
40
|
+
* `docs/research/host-http-api.md`.
|
|
41
|
+
*/
|
|
42
|
+
/** Measured first, then the v1 spellings kept as fallbacks for an older 2.x build. Each
|
|
43
|
+
* builder returns the ARGUMENT OBJECT — `te`-wrapped methods take one object, not an
|
|
44
|
+
* array, and that alone is why every previous shape failed. */
|
|
45
|
+
const SHAPES = [
|
|
46
|
+
["sessionID", (id) => ({ sessionID: id })],
|
|
47
|
+
["path", (id) => ({ path: { id } })],
|
|
48
|
+
["flat", (id) => ({ id })],
|
|
49
|
+
];
|
|
50
|
+
function idOf(opts) {
|
|
51
|
+
const o = (opts ?? {});
|
|
52
|
+
return String(o.path?.id ?? o.query?.id ?? o.sessionID ?? o.id ?? "");
|
|
53
|
+
}
|
|
54
|
+
function unwrap(value) {
|
|
55
|
+
if (!value || typeof value !== "object")
|
|
56
|
+
return undefined;
|
|
57
|
+
const rec = value;
|
|
58
|
+
// `{data}` and `{result}` are both envelopes on this surface; reading a field off the
|
|
59
|
+
// wrapper yields undefined, which then reads as "not my child" and refuses a child that is.
|
|
60
|
+
for (const cand of [rec, rec.data, rec.result, rec.session]) {
|
|
61
|
+
if (cand && typeof cand === "object" && (("parentID" in cand) || ("parent_id" in cand) || ("id" in cand))) {
|
|
62
|
+
return cand;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return rec;
|
|
66
|
+
}
|
|
67
|
+
/** The message-kind values the host writes on its discriminator field — the members of the
|
|
68
|
+
* published union `Session.Message.Info`. Anything else on `type` is a PART kind and must
|
|
69
|
+
* never be read as a message kind. */
|
|
70
|
+
const MESSAGE_KINDS = ["user", "assistant", "system", "synthetic", "skill", "shell", "compaction", "idle"];
|
|
71
|
+
/** The PART kinds the host writes inside a message's `content` bag. A TOP-LEVEL item
|
|
72
|
+
* carrying one of these on `type` with no `role` is a part, not a message (the shape
|
|
73
|
+
* `{type:"tool", content:[{type:"text",…}]}` exists): renaming its bag to `parts` would
|
|
74
|
+
* hand a tool output to the collect path as an unroled assistant candidate. */
|
|
75
|
+
const PART_KINDS = ["text", "reasoning", "tool"];
|
|
76
|
+
/** The discriminator field's own value, lower-cased — "" only when the field is ABSENT
|
|
77
|
+
* (or not a string). "Present but unknown" and "absent" are two different facts, and
|
|
78
|
+
* downstream can only tell them apart if the seam keeps them apart. */
|
|
79
|
+
function rawKind(value) {
|
|
80
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
81
|
+
}
|
|
82
|
+
function messageKind(value) {
|
|
83
|
+
const s = rawKind(value);
|
|
84
|
+
return MESSAGE_KINDS.includes(s) ? s : "";
|
|
85
|
+
}
|
|
86
|
+
/** Which kind of message an item is. The OpenAPI contract puts the discriminator on `type`;
|
|
87
|
+
* the plugin ctx measured on 2.0.20 puts it on `role` — so BOTH are read, a recognised
|
|
88
|
+
* kind first (`role` before `type`), exactly as before.
|
|
89
|
+
*
|
|
90
|
+
* A value that is PRESENT but not a known message kind is carried through verbatim
|
|
91
|
+
* (lower-cased) instead of dropped to "". This INVERTS the previous rule — "an
|
|
92
|
+
* unrecognised value yields "" and the caller leaves the role OFF instead of guessing
|
|
93
|
+
* one" — because that rule was false where it mattered: `lastAssistantMessage` skips on
|
|
94
|
+
* `if (role && role !== "assistant")`, so an EMPTY role IS an assistant candidate,
|
|
95
|
+
* exactly equivalent to guessing "assistant". A host that spelled the discriminator a
|
|
96
|
+
* value outside MESSAGE_KINDS would have had its item delivered as the child's report
|
|
97
|
+
* while the comment claimed the opposite (and while AGENTS.md's "keeps an EMPTY role …
|
|
98
|
+
* rather than guessing" described downstream semantics under which leaving it empty was
|
|
99
|
+
* the guess). Carrying the raw value makes the skip real: unknown kind ⇒ not delivered.
|
|
100
|
+
* Only when BOTH fields are absent — a bare Part[] item — does the role stay unset,
|
|
101
|
+
* which is the shape the collect path reads by the item's own `type:"text"`. */
|
|
102
|
+
function roleOfMessage(rec) {
|
|
103
|
+
const roleRaw = rawKind(rec.role);
|
|
104
|
+
const typeRaw = rawKind(rec.type);
|
|
105
|
+
return messageKind(roleRaw) || messageKind(typeRaw) || roleRaw || typeRaw;
|
|
106
|
+
}
|
|
107
|
+
/** Copy the host's own timestamps, and ONLY those. `time.completed` IS the settle verdict
|
|
108
|
+
* (AGENTS.md), so it is never invented: 2.0.20's plugin ctx carries no `time` field at all,
|
|
109
|
+
* and tm_join then settles from `event` / `injection` / 推定 — which is what it prints. */
|
|
110
|
+
function timeOfMessage(rec) {
|
|
111
|
+
const t = rec.time;
|
|
112
|
+
if (!t || typeof t !== "object")
|
|
113
|
+
return undefined;
|
|
114
|
+
const src = t;
|
|
115
|
+
const out = {};
|
|
116
|
+
const created = Number(src.created);
|
|
117
|
+
if (Number.isFinite(created))
|
|
118
|
+
out.created = created;
|
|
119
|
+
const completed = Number(src.completed);
|
|
120
|
+
if (Number.isFinite(completed))
|
|
121
|
+
out.completed = completed;
|
|
122
|
+
return Object.keys(out).length ? out : undefined;
|
|
123
|
+
}
|
|
124
|
+
/** The `{info,…}` envelope for a message item, carrying ONLY what the host actually wrote. */
|
|
125
|
+
function infoOfMessage(rec, role) {
|
|
126
|
+
const time = timeOfMessage(rec);
|
|
127
|
+
return {
|
|
128
|
+
...(role ? { role } : {}),
|
|
129
|
+
...(time ? { time } : {}),
|
|
130
|
+
// an errored assistant turn carries its reason on the item itself in these shapes;
|
|
131
|
+
// without the copy, "no reply" reads as "the agent had nothing to say"
|
|
132
|
+
...(rec.error == null ? {} : { error: rec.error }),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/** Turn the host's context items into the `{info,parts}` shape the collect path already
|
|
136
|
+
* understands — HERE, at the seam that knows the shape, so nothing downstream has to guess.
|
|
137
|
+
* Three shapes are in the wild and all three are measurements, not version numbers:
|
|
138
|
+
* · 2.0.18 `[L]`: a FLAT item per message, `{id, time:{created}, text, type}`.
|
|
139
|
+
* · 2.0.20 `[L][D]`: a MESSAGE whose body is `content: (Text|Reasoning|Tool)[]` and whose
|
|
140
|
+
* kind is on `role` — the name-level probe recorded `{keys:["content","id","metadata",
|
|
141
|
+
* "role"]}`. The previous version of this function passed that item through untouched
|
|
142
|
+
* ("already message-shaped"), `lastAssistantMessage` found no `parts` and no `text` on
|
|
143
|
+
* it, and the seam answered while the body was dropped AGAIN — which is why 正文来源=
|
|
144
|
+
* never printed on 2.0.20 (A1).
|
|
145
|
+
* · v1's `[{info,parts[]}]`: passed through untouched, so a host that changes back needs
|
|
146
|
+
* no change here.
|
|
147
|
+
* Only the bag is renamed and the envelope added: the elements are already v1 part shapes
|
|
148
|
+
* (`{type:"text", text}`), and reasoning/tool parts stay exactly as the host wrote them.
|
|
149
|
+
* An empty `content` normalises to empty parts — this function MOVES text, it never
|
|
150
|
+
* manufactures any. */
|
|
151
|
+
export function normaliseContextMessages(list) {
|
|
152
|
+
if (!Array.isArray(list))
|
|
153
|
+
return list;
|
|
154
|
+
return list.map((item) => {
|
|
155
|
+
if (!item || typeof item !== "object")
|
|
156
|
+
return item;
|
|
157
|
+
const rec = item;
|
|
158
|
+
if (rec.info || Array.isArray(rec.parts))
|
|
159
|
+
return item;
|
|
160
|
+
if (Array.isArray(rec.content)) {
|
|
161
|
+
// A PART item (no `role`, `type` a part kind) is not a message: renaming its bag to
|
|
162
|
+
// `parts` would make it an unroled assistant candidate downstream, i.e. a TOOL OUTPUT
|
|
163
|
+
// delivered as the child's report — while passing it through untouched was the SAFE
|
|
164
|
+
// case, because the collect path reads a part's own `type` and skips `tool`.
|
|
165
|
+
if (!rawKind(rec.role) && PART_KINDS.includes(rawKind(rec.type)))
|
|
166
|
+
return item;
|
|
167
|
+
return { info: infoOfMessage(rec, roleOfMessage(rec)), parts: rec.content };
|
|
168
|
+
}
|
|
169
|
+
const text = rec.text;
|
|
170
|
+
if (typeof text !== "string" || !text.trim())
|
|
171
|
+
return item;
|
|
172
|
+
// 2.0.18's flat item: a recognised role word is read from either field; anything else
|
|
173
|
+
// (the measured answer items carry `type:"text"`, a PART kind) falls to "assistant",
|
|
174
|
+
// which is the behaviour that shipped and that the 2.0.18 probe pinned. This branch
|
|
175
|
+
// deliberately keeps the fallback the content[] branch above no longer needs: a flat
|
|
176
|
+
// item's `type` is the PART kind of its own body, not a message discriminator, so
|
|
177
|
+
// carrying the raw value here would skip the real 2.0.18 replies.
|
|
178
|
+
return {
|
|
179
|
+
info: infoOfMessage(rec, messageKind(rec.role) || messageKind(rec.type) || "assistant"),
|
|
180
|
+
parts: [{ type: "text", text }],
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/** WHY a body came back empty, in names and counts only — never a value, a path, or a
|
|
185
|
+
* snippet of text (the R6 口径 binds a diagnostic). tm_join writes this onto the
|
|
186
|
+
* `child_body_missing` trajectory line so the three conclusions stay distinguishable:
|
|
187
|
+
* a real body (`child_body`), a seam that answered with nothing readable in it
|
|
188
|
+
* (`items=2 keys=[content+id+metadata+role] content=1 kinds=[tool] text=0`), and a seam
|
|
189
|
+
* that did not answer at all (`no-context-method`). Without it, "we read it" and "we could
|
|
190
|
+
* not read it" print the same row — goal #6's failure shape. */
|
|
191
|
+
export function contextShapeEvidence(list) {
|
|
192
|
+
if (list === undefined || list === null)
|
|
193
|
+
return "no-list";
|
|
194
|
+
if (!Array.isArray(list))
|
|
195
|
+
return `not-array(${typeof list})`;
|
|
196
|
+
if (list.length === 0)
|
|
197
|
+
return "items=0";
|
|
198
|
+
const last = list[list.length - 1];
|
|
199
|
+
if (!last || typeof last !== "object")
|
|
200
|
+
return `items=${list.length} last=${last === null ? "null" : typeof last}`;
|
|
201
|
+
const rec = last;
|
|
202
|
+
const keys = Object.keys(rec).slice(0, 12).join("+");
|
|
203
|
+
const bag = Array.isArray(rec.content) ? "content" : Array.isArray(rec.parts) ? "parts" : "";
|
|
204
|
+
if (bag) {
|
|
205
|
+
const arr = rec[bag];
|
|
206
|
+
const kinds = Array.from(new Set(arr.map((p) => (p && typeof p === "object" ? String(p.type ?? "?") : typeof p))))
|
|
207
|
+
.slice(0, 6)
|
|
208
|
+
.join("+");
|
|
209
|
+
let withText = 0;
|
|
210
|
+
for (const p of arr) {
|
|
211
|
+
const t = p?.text;
|
|
212
|
+
if (typeof t === "string" && t.trim())
|
|
213
|
+
withText++;
|
|
214
|
+
}
|
|
215
|
+
return `items=${list.length} keys=[${keys}] ${bag}=${arr.length} kinds=[${kinds}] text=${withText}`;
|
|
216
|
+
}
|
|
217
|
+
if (typeof rec.text === "string")
|
|
218
|
+
return `items=${list.length} keys=[${keys}] textlen=${rec.text.length}`;
|
|
219
|
+
return `items=${list.length} keys=[${keys}] nobag`;
|
|
220
|
+
}
|
|
221
|
+
/** The one name this bridge has for itself, so a reply credits the seam that answered and a
|
|
222
|
+
* refusal names the seam that did not — never the v1 endpoint this host does not have. */
|
|
223
|
+
const SEAM = "ctx.session.context";
|
|
224
|
+
export function createV2SessionReader(ctx) {
|
|
225
|
+
const report = {
|
|
226
|
+
attempted: 0, resolved: 0, failedShapes: [], contextTried: 0, contextOk: 0, contextKeys: [],
|
|
227
|
+
interruptTried: 0, interruptConfirmed: 0, interruptRefused: 0, interruptUnknown: 0, interruptKeys: [],
|
|
228
|
+
};
|
|
229
|
+
const domain = ctx?.session;
|
|
230
|
+
const call = async (method, arg) => {
|
|
231
|
+
const fn = domain?.[method];
|
|
232
|
+
if (typeof fn !== "function")
|
|
233
|
+
return undefined;
|
|
234
|
+
// Property access on the domain, never a captured reference: a detached `get` loses
|
|
235
|
+
// its receiver and the host's client throws (the dispatch.ts §10 rule).
|
|
236
|
+
return await fn.call(domain, arg);
|
|
237
|
+
};
|
|
238
|
+
const client = {
|
|
239
|
+
session: {
|
|
240
|
+
get: async (opts) => {
|
|
241
|
+
const id = idOf(opts);
|
|
242
|
+
report.attempted++;
|
|
243
|
+
if (!id || !id.startsWith("ses"))
|
|
244
|
+
return { data: undefined };
|
|
245
|
+
const tried = [];
|
|
246
|
+
for (const [shape, build] of SHAPES) {
|
|
247
|
+
try {
|
|
248
|
+
const raw = await call("get", build(id));
|
|
249
|
+
const rec = unwrap(raw);
|
|
250
|
+
if (rec) {
|
|
251
|
+
report.resolved++;
|
|
252
|
+
report.usedShape = shape;
|
|
253
|
+
report.failedShapes = [];
|
|
254
|
+
const parent = rec.parentID ?? rec.parent_id;
|
|
255
|
+
return { data: { id, parentID: typeof parent === "string" ? parent : undefined, raw: rec } };
|
|
256
|
+
}
|
|
257
|
+
tried.push(shape);
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
tried.push(shape);
|
|
261
|
+
report.lastError = String(err?.message ?? err).slice(0, 160);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
report.failedShapes = tried;
|
|
265
|
+
return { data: undefined };
|
|
266
|
+
},
|
|
267
|
+
/** The reply path: `ctx.session.context({sessionID})` is the in-process seam that
|
|
268
|
+
* answers for a child's messages. Measured on 2.0.18 it returns an ARRAY of flat
|
|
269
|
+
* `{id, time:{created}, text, type}` items; measured on 2.0.20 it returns items of
|
|
270
|
+
* `{id, role, metadata, content:[…]}` — the shape the published
|
|
271
|
+
* `Session.Message.Info` contract describes, with the kind on `role` instead of the
|
|
272
|
+
* documented `type`. Neither is v1's `[{info:{role},parts:[…]}]`, and both were the
|
|
273
|
+
* reason `tm_join` said it could not read a reply that was sitting right there:
|
|
274
|
+
* `lastAssistantMessage` tolerates an unknown shape by returning NO text, so the call
|
|
275
|
+
* succeeded and the body was silently dropped. Both shapes are therefore NORMALISED
|
|
276
|
+
* here, at the seam that knows them, so the collect path stays single-shaped — and
|
|
277
|
+
* every answer carries WHICH seam it came from plus the SHAPE it saw, because a reply
|
|
278
|
+
* that credits "session.messages" (a v1 endpoint this host does not have) is a claim
|
|
279
|
+
* about the host nobody measured, and a missing body with no shape on it is the same
|
|
280
|
+
* claim in the other direction. */
|
|
281
|
+
messages: async (opts) => {
|
|
282
|
+
const id = idOf(opts);
|
|
283
|
+
if (!id)
|
|
284
|
+
return { data: undefined, via: SEAM, shape: "no-id" };
|
|
285
|
+
if (typeof domain?.context !== "function") {
|
|
286
|
+
// The seam is ABSENT, which is a different fact from "it answered with nothing".
|
|
287
|
+
report.contextError = domain ? "ctx.session has no context method" : "ctx has no session domain";
|
|
288
|
+
return { data: undefined, via: SEAM, shape: domain ? "no-context-method" : "no-session-domain" };
|
|
289
|
+
}
|
|
290
|
+
report.contextTried++;
|
|
291
|
+
try {
|
|
292
|
+
const raw = await call("context", { sessionID: id });
|
|
293
|
+
const rec = unwrap(raw);
|
|
294
|
+
if (!rec)
|
|
295
|
+
return { data: undefined, via: SEAM, shape: `seam-answered-${raw === null ? "null" : typeof raw}` };
|
|
296
|
+
report.contextOk++;
|
|
297
|
+
report.contextKeys = Array.isArray(rec) ? ["array"] : Object.keys(rec).slice(0, 24);
|
|
298
|
+
const list = Array.isArray(rec) ? rec : (rec.messages ?? rec.data ?? rec);
|
|
299
|
+
const seen = contextShapeEvidence(list);
|
|
300
|
+
report.contextShape = seen;
|
|
301
|
+
return { data: normaliseContextMessages(list), via: SEAM, shape: seen };
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
report.contextError = String(err?.message ?? err).slice(0, 160);
|
|
305
|
+
return { data: undefined, via: SEAM, shape: "context-threw" };
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
/** #33 — the STOP path. `tm_join { cancel: true }` was written against v1's
|
|
309
|
+
* `client.session.abort`, and this bridge never wrapped it, so on 2.x every
|
|
310
|
+
* background child was un-stoppable by the lead (the host gives no dialog and
|
|
311
|
+
* no card for a child the plugin observed rather than created).
|
|
312
|
+
*
|
|
313
|
+
* What the host DOES give a plugin is `ctx.session.interrupt`, and its contract
|
|
314
|
+
* is quoted from the v2 API page rather than inferred:
|
|
315
|
+
*
|
|
316
|
+
* POST /api/session/{sessionID}/interrupt
|
|
317
|
+
* "Returns interrupted=true when an active execution was interrupted and
|
|
318
|
+
* false for the idle no-op."
|
|
319
|
+
*
|
|
320
|
+
* That one sentence is why this seam must not collapse into a boolean: `false`
|
|
321
|
+
* is a real answer meaning "nothing was running", not "the stop failed", and a
|
|
322
|
+
* reply that called it 已停止 would be goal #6's overstated claim. Three
|
|
323
|
+
* outcomes therefore survive to the caller, plus the two failure cases (no
|
|
324
|
+
* seam, host threw):
|
|
325
|
+
* stopped — `interrupted === true`, the host stopped an active execution
|
|
326
|
+
* idle — `interrupted === false`, documented no-op
|
|
327
|
+
* unknown — the call answered but carried no `interrupted` boolean
|
|
328
|
+
* no-seam — this host's ctx has no `interrupt`
|
|
329
|
+
* threw — the host refused; its own message rides back
|
|
330
|
+
*
|
|
331
|
+
* The shape is `session.interrupt({sessionID})` — the same flat object `get` and
|
|
332
|
+
* `context` take (the rule AGENTS.md records for every `te`-wrapped method), and
|
|
333
|
+
* the v1 `{path:{id}}` spellings are NOT retried here because a wrong key on THIS
|
|
334
|
+
* method is not a decode failure but an interrupt of the wrong session.
|
|
335
|
+
*
|
|
336
|
+
* `resume` is deliberately never sent: `resume=true` continues pending steering
|
|
337
|
+
* input after the interrupt, which is the opposite of what a caller who asked to
|
|
338
|
+
* cancel a runaway child wants.
|
|
339
|
+
*
|
|
340
|
+
* Privacy: the key NAMES the host returned are recorded; the value text is not
|
|
341
|
+
* (R6 binds a diagnostic). */
|
|
342
|
+
interrupt: async (opts) => {
|
|
343
|
+
const id = idOf(opts);
|
|
344
|
+
report.interruptTried++;
|
|
345
|
+
if (!id || typeof domain?.interrupt !== "function")
|
|
346
|
+
return { data: { outcome: "no-seam" } };
|
|
347
|
+
// Property access on the domain, never a captured reference (see `call`).
|
|
348
|
+
const fn = domain.interrupt;
|
|
349
|
+
try {
|
|
350
|
+
const raw = await fn.call(domain, { sessionID: id });
|
|
351
|
+
const rec = unwrap(raw);
|
|
352
|
+
report.interruptKeys = rec ? Object.keys(rec).slice(0, 16) : ["(non-object)"];
|
|
353
|
+
// `interrupted` can ride the returned object or one of the envelopes `unwrap`
|
|
354
|
+
// recognises (`{data}` / `{result}` / `{session}`) — reading only the outer one
|
|
355
|
+
// turns a real stop into `unknown`, and `unknown` reads as "we could not tell".
|
|
356
|
+
const carriers = [rec, raw?.data, raw?.result];
|
|
357
|
+
let flag;
|
|
358
|
+
for (const cand of carriers) {
|
|
359
|
+
const v = cand?.interrupted;
|
|
360
|
+
if (typeof v === "boolean") {
|
|
361
|
+
flag = v;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (flag === true)
|
|
366
|
+
report.interruptConfirmed++;
|
|
367
|
+
else if (flag === false)
|
|
368
|
+
report.interruptRefused++;
|
|
369
|
+
else
|
|
370
|
+
report.interruptUnknown++;
|
|
371
|
+
const note = carriers
|
|
372
|
+
.map((c) => c?.message)
|
|
373
|
+
.find((m) => typeof m === "string");
|
|
374
|
+
return {
|
|
375
|
+
data: {
|
|
376
|
+
outcome: flag === true ? "stopped" : flag === false ? "idle" : "unknown",
|
|
377
|
+
...(note ? { message: note } : {}),
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
report.interruptError = String(err?.message ?? err).slice(0, 160);
|
|
383
|
+
return { data: { outcome: "threw", message: report.interruptError } };
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
return { client, report };
|
|
389
|
+
}
|
|
390
|
+
//# sourceMappingURL=v2-session-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-session-client.js","sourceRoot":"","sources":["../../src/host/v2-session-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The v2 session-request layer (goal #4 and #6 of the product).
|
|
3
|
+
*
|
|
4
|
+
* Three things that v1 could only approximate, because 1.18.x gave a plugin one
|
|
5
|
+
* mutable slot before execution and no way to touch an assembled request:
|
|
6
|
+
*
|
|
7
|
+
* 1. the tool surface. v1's whitelist was enforced by permission DENY, which
|
|
8
|
+
* stops a call but leaves the tool's description and schema in EVERY request
|
|
9
|
+
* — the model pays ~9.5K tokens for thirteen governed tools plus the native
|
|
10
|
+
* catalog it is forbidden to use. `session.hook("context")` can `delete
|
|
11
|
+
* event.tools.<name>`, so the whitelist finally decides what the model sees.
|
|
12
|
+
* 2. `temperature`. It is a documented legacy agent field on v2 (and the
|
|
13
|
+
* runner "preserves these values but does not yet send them"), so the
|
|
14
|
+
* all-agents-0.2 invariant has to be set on the outgoing request instead.
|
|
15
|
+
* 3. the blackboard root. v1 appended the resolved path to the team prompt at
|
|
16
|
+
* config time; a v2 agent is a config FILE, which cannot carry a
|
|
17
|
+
* per-workspace path, so it goes on the request.
|
|
18
|
+
*
|
|
19
|
+
* Everything here is additive and reversible: each hook returns a disposable
|
|
20
|
+
* registration, and nothing is claimed that the host did not hand us.
|
|
21
|
+
*/
|
|
22
|
+
import type { V2Registration, V2Context } from "./v2-types.js";
|
|
23
|
+
/** Sentinel for "this role may not browse at all" — it removes the host's whole
|
|
24
|
+
* browser catalog (45 `browser_*` tools on 2.0.16), not just our own door.
|
|
25
|
+
* Leaving them in would hand back, at the request layer, exactly the surface the
|
|
26
|
+
* whitelist exists to withhold. */
|
|
27
|
+
export declare const BROWSER_CATALOG = "browser_*";
|
|
28
|
+
/**
|
|
29
|
+
* The tools one agent must never be offered. Only a literal `deny` removes:
|
|
30
|
+
* the `{ "*": "ask" }` object form means "callable, gated", and deleting such a
|
|
31
|
+
* tool would silently drop a capability the matrix grants with a dialog.
|
|
32
|
+
*
|
|
33
|
+
* `read`/`grep`/`glob` are exempted by name (`V2_LADDER_ACTIONS`), which is the
|
|
34
|
+
* other half of the `tm_read`/`tm_grep`/`tm_bash` retirement: v1 denied the
|
|
35
|
+
* native file tools because the governed aliases existed, and on v2 those
|
|
36
|
+
* aliases are not registered, so honouring the deny here would leave a role with
|
|
37
|
+
* no way to open a file at all. Nothing is lost by letting them ride — the path
|
|
38
|
+
* scope P2 enforced in code is the host's own `external_directory` action, which
|
|
39
|
+
* was observed live answering `effect:"ask"` with a real `permission.asked`
|
|
40
|
+
* behind it, i.e. a dialog instead of a hard throw.
|
|
41
|
+
*/
|
|
42
|
+
export declare function toolsToRemove(permission: Record<string, unknown> | undefined | null): string[];
|
|
43
|
+
/** Built once per agent id so the hook body stays a set lookup on a hot path. */
|
|
44
|
+
export declare function removalPlan(agents: Record<string, {
|
|
45
|
+
permission?: Record<string, unknown>;
|
|
46
|
+
}>): Map<string, Set<string>>;
|
|
47
|
+
export interface SessionLayerInput {
|
|
48
|
+
/** 0 disables the temperature write entirely (the host's model default wins). */
|
|
49
|
+
temperature: number | false;
|
|
50
|
+
/** The resolved blackboard addendum, or "" when there is nothing to say. */
|
|
51
|
+
note: string;
|
|
52
|
+
/** Which agent ids receive the note — v1 gave it to the lead only. */
|
|
53
|
+
noteAgents: string[];
|
|
54
|
+
plan: Map<string, Set<string>>;
|
|
55
|
+
/** Team-scope isolation (#22). `session.context` fires for EVERY agent on the
|
|
56
|
+
* host, so temperature, the board note and the compaction survival list are
|
|
57
|
+
* writes to somebody else's request unless the agent is one of ours. The tool
|
|
58
|
+
* trim is already keyed by agent (a foreign role is not in the plan, so nothing
|
|
59
|
+
* is deleted); this closes the other three. */
|
|
60
|
+
scope?: import("./v2-scope.js").TeamScope;
|
|
61
|
+
}
|
|
62
|
+
export interface SessionLayerReport {
|
|
63
|
+
temperature: number | false;
|
|
64
|
+
removed: Record<string, number>;
|
|
65
|
+
notePushed: boolean;
|
|
66
|
+
compactionLines: number;
|
|
67
|
+
/** Did a `tm_*` name ever appear in an assembled request's own tool surface?
|
|
68
|
+
* This is the only evidence that direct delivery happened: `options.codemode:false`
|
|
69
|
+
* is what WE send, and a live 2.0.16 session proved the host still put every
|
|
70
|
+
* `tm_*` in the Code Mode catalog ("They cannot be called directly…") while the
|
|
71
|
+
* model's own callable list was nine native tools. Reporting the sent flag as if it
|
|
72
|
+
* were the outcome is the overstated claim this product exists to refuse. */
|
|
73
|
+
tmInRequestSurface: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Register the request-layer hooks. Returns the registrations (so the caller
|
|
77
|
+
* can dispose them) and a live report object — the counts are read off what the
|
|
78
|
+
* hooks actually did, not off what the matrix intends, because "we trimmed the
|
|
79
|
+
* surface" is a claim the user can only check against the request.
|
|
80
|
+
*/
|
|
81
|
+
export declare function applyV2SessionLayer(ctx: V2Context, input: SessionLayerInput): Promise<{
|
|
82
|
+
registrations: V2Registration[];
|
|
83
|
+
report: SessionLayerReport;
|
|
84
|
+
}>;
|
|
85
|
+
//# sourceMappingURL=v2-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-session.d.ts","sourceRoot":"","sources":["../../src/host/v2-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAoB,SAAS,EAAE,MAAM,eAAe,CAAA;AAUhF;;;oCAGoC;AACpC,eAAO,MAAM,eAAe,cAAc,CAAA;AAI1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAyB9F;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,GAC/D,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAI1B;AAKD,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,WAAW,EAAE,MAAM,GAAG,KAAK,CAAA;IAC3B,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAC9B;;;;oDAIgD;IAChD,KAAK,CAAC,EAAE,OAAO,eAAe,EAAE,SAAS,CAAA;CAC1C;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,GAAG,KAAK,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,UAAU,EAAE,OAAO,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB;;;;;kFAK8E;IAC9E,kBAAkB,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC;IAAE,aAAa,EAAE,cAAc,EAAE,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAgF1E"}
|