antechamber 0.1.0 → 0.2.0
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/CHANGELOG.md +51 -0
- package/README.md +17 -14
- package/bin/opencode-antechamber +10 -1
- package/bin/opencode-pi +11 -1
- package/dist/approvals.d.ts +4 -1
- package/dist/approvals.js +51 -33
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.js +1 -1
- package/dist/commands/context.d.ts +0 -1
- package/dist/commands/context.js +1 -1
- package/dist/commands/doctor.d.ts +3 -2
- package/dist/commands/serve.d.ts +2 -1
- package/dist/commands/setup.d.ts +2 -3
- package/dist/commands/setup.js +16 -4
- package/dist/http.d.ts +8 -1
- package/dist/http.js +42 -19
- package/dist/pi-event-translation.d.ts +21 -3
- package/dist/pi-event-translation.js +317 -65
- package/dist/pi-rpc.d.ts +26 -2
- package/dist/pi-rpc.js +102 -29
- package/dist/prompt-parts.d.ts +40 -0
- package/dist/prompt-parts.js +157 -0
- package/dist/route-services.d.ts +45 -2
- package/dist/route-services.js +70 -3
- package/dist/routes-v1.js +110 -65
- package/dist/routes-v2.js +376 -73
- package/dist/server.d.ts +9 -1
- package/dist/server.js +109 -9
- package/dist/session-commands.d.ts +20 -15
- package/dist/session-commands.js +61 -11
- package/dist/session-diff.d.ts +1 -1
- package/dist/session-diff.js +10 -2
- package/dist/session-history.js +113 -42
- package/dist/session-hosts.js +2 -2
- package/dist/session-store.d.ts +8 -4
- package/dist/session-store.js +183 -33
- package/dist/session-tree.d.ts +9 -2
- package/dist/session-tree.js +51 -63
- package/dist/sessions.d.ts +34 -6
- package/dist/sessions.js +340 -146
- package/dist/sse.d.ts +16 -6
- package/dist/sse.js +77 -21
- package/dist/subagents.d.ts +5 -0
- package/dist/subagents.js +86 -69
- package/dist/tool-map.d.ts +3 -2
- package/dist/types.d.ts +164 -1
- package/dist/v2.d.ts +18 -4
- package/dist/v2.js +141 -50
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/extensions/omo-dag/README.md +2 -0
- package/extensions/omo-dag/docs/DESIGN.md +10 -1
- package/extensions/omo-dag/panel/index.html +1 -1
- package/extensions/omo-dag/panel/main.js +60 -60
- package/extensions/omo-dag/service/main.js +72 -8
- package/package.json +1 -1
package/dist/types.d.ts
CHANGED
|
@@ -12,14 +12,42 @@ export interface OCSession {
|
|
|
12
12
|
projectID: string;
|
|
13
13
|
directory: string;
|
|
14
14
|
parentID?: string;
|
|
15
|
+
parentMessageID?: string;
|
|
16
|
+
agent?: string;
|
|
17
|
+
model?: {
|
|
18
|
+
id: string;
|
|
19
|
+
providerID: string;
|
|
20
|
+
variant?: string;
|
|
21
|
+
};
|
|
22
|
+
metadata?: Record<string, unknown>;
|
|
23
|
+
outcome?: "succeeded" | "failed" | "interrupted";
|
|
24
|
+
slug?: string;
|
|
25
|
+
path?: string;
|
|
26
|
+
summary?: {
|
|
27
|
+
additions: number;
|
|
28
|
+
deletions: number;
|
|
29
|
+
files: number;
|
|
30
|
+
};
|
|
31
|
+
tokens?: {
|
|
32
|
+
input: number;
|
|
33
|
+
output: number;
|
|
34
|
+
reasoning: number;
|
|
35
|
+
cache: {
|
|
36
|
+
read: number;
|
|
37
|
+
write: number;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
15
40
|
title: string;
|
|
16
41
|
version: string;
|
|
17
42
|
revert?: {
|
|
18
43
|
messageID: string;
|
|
19
44
|
};
|
|
45
|
+
/** USD spent by this session's own assistant messages; OpenChamber adds child sessions via parentID. */
|
|
46
|
+
cost?: number;
|
|
20
47
|
time: {
|
|
21
48
|
created: number;
|
|
22
49
|
updated: number;
|
|
50
|
+
idle?: number;
|
|
23
51
|
compacting?: number;
|
|
24
52
|
/** Epoch ms — presence marks the session archived (SDK v2 session.update). */
|
|
25
53
|
archived?: number;
|
|
@@ -34,6 +62,10 @@ export interface OCUserMessage {
|
|
|
34
62
|
};
|
|
35
63
|
agent: string;
|
|
36
64
|
model: OCModelRef;
|
|
65
|
+
/** No-reply context admitted without a turn (v2 lists it as `type: "synthetic"`). */
|
|
66
|
+
synthetic?: boolean;
|
|
67
|
+
/** Client metadata sent with the prompt (OpenChamber 2.x). */
|
|
68
|
+
metadata?: Record<string, unknown>;
|
|
37
69
|
}
|
|
38
70
|
export interface OCAssistantMessage {
|
|
39
71
|
id: string;
|
|
@@ -68,6 +100,8 @@ export interface OCAssistantMessage {
|
|
|
68
100
|
message: string;
|
|
69
101
|
};
|
|
70
102
|
};
|
|
103
|
+
/** Marks a compaction summary (OpenCode `AssistantMessage.summary`). */
|
|
104
|
+
summary?: boolean;
|
|
71
105
|
}
|
|
72
106
|
export type OCMessage = OCUserMessage | OCAssistantMessage;
|
|
73
107
|
export interface OCTextPart {
|
|
@@ -144,7 +178,42 @@ export interface OCToolPart {
|
|
|
144
178
|
tool: string;
|
|
145
179
|
state: OCToolState;
|
|
146
180
|
}
|
|
147
|
-
|
|
181
|
+
/** OpenChamber renders a user message holding this part as `/compact`. */
|
|
182
|
+
export interface OCCompactionPart {
|
|
183
|
+
id: string;
|
|
184
|
+
sessionID: string;
|
|
185
|
+
messageID: string;
|
|
186
|
+
type: "compaction";
|
|
187
|
+
auto: boolean;
|
|
188
|
+
}
|
|
189
|
+
export type OCPromptPart = ({
|
|
190
|
+
type: "text";
|
|
191
|
+
text: string;
|
|
192
|
+
synthetic?: boolean;
|
|
193
|
+
} | {
|
|
194
|
+
type: "file";
|
|
195
|
+
mime: string;
|
|
196
|
+
url: string;
|
|
197
|
+
filename?: string;
|
|
198
|
+
} | {
|
|
199
|
+
type: "agent";
|
|
200
|
+
name: string;
|
|
201
|
+
source?: {
|
|
202
|
+
value: string;
|
|
203
|
+
start: number;
|
|
204
|
+
end: number;
|
|
205
|
+
};
|
|
206
|
+
}) & {
|
|
207
|
+
id?: string;
|
|
208
|
+
};
|
|
209
|
+
export type OCInputPart = OCPromptPart & {
|
|
210
|
+
id: string;
|
|
211
|
+
sessionID: string;
|
|
212
|
+
messageID: string;
|
|
213
|
+
};
|
|
214
|
+
export type OCPart = OCTextPart | OCReasoningPart | OCToolPart | OCCompactionPart | Exclude<OCInputPart, {
|
|
215
|
+
type: "text";
|
|
216
|
+
}>;
|
|
148
217
|
export interface OCMessageWithParts {
|
|
149
218
|
info: OCMessage;
|
|
150
219
|
parts: OCPart[];
|
|
@@ -169,6 +238,15 @@ export type OCEvent = {
|
|
|
169
238
|
delivery: "steer" | "queue";
|
|
170
239
|
payload: {
|
|
171
240
|
text: string;
|
|
241
|
+
files?: Array<Record<string, unknown>>;
|
|
242
|
+
agents?: Array<Record<string, unknown>>;
|
|
243
|
+
metadata?: Record<string, unknown>;
|
|
244
|
+
};
|
|
245
|
+
} | {
|
|
246
|
+
type: "synthetic";
|
|
247
|
+
payload: {
|
|
248
|
+
text: string;
|
|
249
|
+
metadata?: Record<string, unknown>;
|
|
172
250
|
};
|
|
173
251
|
};
|
|
174
252
|
};
|
|
@@ -197,6 +275,79 @@ export type OCEvent = {
|
|
|
197
275
|
properties: {
|
|
198
276
|
info: OCSession;
|
|
199
277
|
};
|
|
278
|
+
} | {
|
|
279
|
+
type: "session.revert.staged";
|
|
280
|
+
properties: {
|
|
281
|
+
sessionID: string;
|
|
282
|
+
revert: {
|
|
283
|
+
messageID: string;
|
|
284
|
+
};
|
|
285
|
+
};
|
|
286
|
+
} | {
|
|
287
|
+
type: "session.revert.cleared";
|
|
288
|
+
properties: {
|
|
289
|
+
sessionID: string;
|
|
290
|
+
};
|
|
291
|
+
} | {
|
|
292
|
+
type: "session.revert.committed";
|
|
293
|
+
properties: {
|
|
294
|
+
sessionID: string;
|
|
295
|
+
to: string;
|
|
296
|
+
};
|
|
297
|
+
} | {
|
|
298
|
+
type: "session.compaction.started";
|
|
299
|
+
properties: {
|
|
300
|
+
sessionID: string;
|
|
301
|
+
reason: string;
|
|
302
|
+
inputID: string;
|
|
303
|
+
};
|
|
304
|
+
} | {
|
|
305
|
+
type: "session.compaction.ended";
|
|
306
|
+
properties: {
|
|
307
|
+
sessionID: string;
|
|
308
|
+
reason: string;
|
|
309
|
+
inputID: string;
|
|
310
|
+
text: string;
|
|
311
|
+
recent: string;
|
|
312
|
+
};
|
|
313
|
+
} | {
|
|
314
|
+
type: "session.compaction.failed";
|
|
315
|
+
properties: {
|
|
316
|
+
sessionID: string;
|
|
317
|
+
reason: string;
|
|
318
|
+
inputID: string;
|
|
319
|
+
error: {
|
|
320
|
+
name: string;
|
|
321
|
+
data: {
|
|
322
|
+
message: string;
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
} | {
|
|
327
|
+
type: "session.shell.started" | "session.shell.ended";
|
|
328
|
+
properties: {
|
|
329
|
+
sessionID: string;
|
|
330
|
+
shell: {
|
|
331
|
+
id: string;
|
|
332
|
+
command: string;
|
|
333
|
+
cwd: string;
|
|
334
|
+
shell: string;
|
|
335
|
+
file: string;
|
|
336
|
+
status: "running" | "exited" | "timeout" | "killed";
|
|
337
|
+
exit?: number;
|
|
338
|
+
metadata: Record<string, unknown>;
|
|
339
|
+
time: {
|
|
340
|
+
started: number;
|
|
341
|
+
completed?: number;
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
output?: {
|
|
345
|
+
output: string;
|
|
346
|
+
cursor: number;
|
|
347
|
+
size: number;
|
|
348
|
+
truncated: boolean;
|
|
349
|
+
};
|
|
350
|
+
};
|
|
200
351
|
} | {
|
|
201
352
|
type: "session.deleted";
|
|
202
353
|
properties: {
|
|
@@ -241,6 +392,15 @@ export type OCEvent = {
|
|
|
241
392
|
part: OCPart;
|
|
242
393
|
delta?: string;
|
|
243
394
|
};
|
|
395
|
+
} | {
|
|
396
|
+
type: "message.part.delta";
|
|
397
|
+
properties: {
|
|
398
|
+
sessionID: string;
|
|
399
|
+
messageID: string;
|
|
400
|
+
partID: string;
|
|
401
|
+
field: "text";
|
|
402
|
+
delta: string;
|
|
403
|
+
};
|
|
244
404
|
} | {
|
|
245
405
|
type: "permission.asked";
|
|
246
406
|
properties: {
|
|
@@ -320,12 +480,15 @@ export interface OCProject {
|
|
|
320
480
|
vcs?: "git";
|
|
321
481
|
time: {
|
|
322
482
|
created: number;
|
|
483
|
+
updated?: number;
|
|
323
484
|
initialized?: number;
|
|
324
485
|
};
|
|
486
|
+
sandboxes?: string[];
|
|
325
487
|
}
|
|
326
488
|
/** Incoming prompt body for POST /session/{id}/message and /prompt_async */
|
|
327
489
|
export interface OCPromptBody {
|
|
328
490
|
messageID?: string;
|
|
491
|
+
delivery?: "steer" | "queue";
|
|
329
492
|
model?: OCModelRef;
|
|
330
493
|
agent?: string;
|
|
331
494
|
noReply?: boolean;
|
package/dist/v2.d.ts
CHANGED
|
@@ -92,7 +92,7 @@ interface CatalogProviderLike {
|
|
|
92
92
|
name: string;
|
|
93
93
|
models: Record<string, CatalogModelLike>;
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
interface CatalogLike {
|
|
96
96
|
providers: CatalogProviderLike[];
|
|
97
97
|
defaults: Record<string, string>;
|
|
98
98
|
/** The model the agent reported as active (see catalog.ts). */
|
|
@@ -108,6 +108,7 @@ export declare function defaultV2Model(cat: CatalogLike): V2Model | undefined;
|
|
|
108
108
|
export interface V2Session {
|
|
109
109
|
id: string;
|
|
110
110
|
parentID?: string;
|
|
111
|
+
parentMessageID?: string;
|
|
111
112
|
projectID: string;
|
|
112
113
|
agent: string;
|
|
113
114
|
model?: {
|
|
@@ -127,6 +128,12 @@ export interface V2Session {
|
|
|
127
128
|
location: {
|
|
128
129
|
directory: string;
|
|
129
130
|
};
|
|
131
|
+
directory: string;
|
|
132
|
+
metadata?: Record<string, unknown>;
|
|
133
|
+
outcome?: OCSession["outcome"];
|
|
134
|
+
revert?: {
|
|
135
|
+
messageID: string;
|
|
136
|
+
};
|
|
130
137
|
}
|
|
131
138
|
export declare function toV2Session(info: OCSession, opts?: {
|
|
132
139
|
model?: OCModelRef | undefined;
|
|
@@ -139,8 +146,11 @@ export interface V2Message {
|
|
|
139
146
|
completed?: number;
|
|
140
147
|
streamed?: number;
|
|
141
148
|
};
|
|
142
|
-
type: "user" | "assistant";
|
|
149
|
+
type: "user" | "assistant" | "synthetic";
|
|
143
150
|
text?: string;
|
|
151
|
+
files?: Array<Record<string, unknown>>;
|
|
152
|
+
agents?: Array<Record<string, unknown>>;
|
|
153
|
+
metadata?: Record<string, unknown>;
|
|
144
154
|
agent?: string;
|
|
145
155
|
model?: {
|
|
146
156
|
id: string;
|
|
@@ -153,8 +163,6 @@ export interface V2Message {
|
|
|
153
163
|
tokens?: V2Tokens;
|
|
154
164
|
error?: OCAssistantMessage["error"];
|
|
155
165
|
}
|
|
156
|
-
/** v2 user message (list + prompt response): the UI reads `.text`. */
|
|
157
|
-
export declare function toV2UserMessage(info: OCMessageWithParts): V2Message;
|
|
158
166
|
/**
|
|
159
167
|
* v2 assistant message: parts become `content` blocks. The UI rebuilds
|
|
160
168
|
* text/reasoning part ids from per-type indices into this array.
|
|
@@ -162,6 +170,11 @@ export declare function toV2UserMessage(info: OCMessageWithParts): V2Message;
|
|
|
162
170
|
export declare function toV2AssistantMessage(info: OCMessageWithParts): V2Message;
|
|
163
171
|
export declare function toV2Message(info: OCMessageWithParts): V2Message;
|
|
164
172
|
export interface V2Envelope {
|
|
173
|
+
durable?: {
|
|
174
|
+
aggregateID: string;
|
|
175
|
+
seq: number;
|
|
176
|
+
version: number;
|
|
177
|
+
};
|
|
165
178
|
id: string;
|
|
166
179
|
created: number;
|
|
167
180
|
type: string;
|
|
@@ -177,6 +190,7 @@ export interface V2Envelope {
|
|
|
177
190
|
*/
|
|
178
191
|
export declare class V2EventTranslator {
|
|
179
192
|
private sessions;
|
|
193
|
+
private sequences;
|
|
180
194
|
translate(directory: string, ev: OCEvent): V2Envelope[];
|
|
181
195
|
private onStatus;
|
|
182
196
|
private onMessageUpdated;
|
package/dist/v2.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { randomUUID } from "node:crypto";
|
|
25
25
|
import { getAgentName } from "./agent-name.js";
|
|
26
26
|
import { questionFormID, toQuestionForm } from "./question-forms.js";
|
|
27
|
+
import { v2PromptAttachments } from "./prompt-parts.js";
|
|
27
28
|
function genId(prefix) {
|
|
28
29
|
return `${prefix}_${randomUUID().replaceAll("-", "")}`;
|
|
29
30
|
}
|
|
@@ -89,35 +90,51 @@ export function toV2Session(info, opts = {}) {
|
|
|
89
90
|
id: info.id,
|
|
90
91
|
projectID: info.projectID,
|
|
91
92
|
agent: opts.agent ?? getAgentName(),
|
|
92
|
-
cost: 0,
|
|
93
|
-
tokens: zeroTokens(),
|
|
93
|
+
cost: info.cost ?? 0,
|
|
94
|
+
tokens: info.tokens ?? zeroTokens(),
|
|
94
95
|
time: {
|
|
95
96
|
created: info.time.created,
|
|
96
97
|
updated: info.time.updated,
|
|
98
|
+
...(info.time.idle !== undefined ? { idle: info.time.idle } : {}),
|
|
97
99
|
...(info.time.archived !== undefined ? { archived: info.time.archived } : {}),
|
|
98
100
|
},
|
|
99
101
|
title: info.title,
|
|
100
102
|
subpath: subpathOf(info.directory),
|
|
101
103
|
location: { directory: info.directory },
|
|
104
|
+
directory: info.directory,
|
|
105
|
+
...(info.metadata !== undefined ? { metadata: info.metadata } : {}),
|
|
106
|
+
...(info.outcome !== undefined ? { outcome: info.outcome } : {}),
|
|
107
|
+
...(info.revert !== undefined ? { revert: info.revert } : {}),
|
|
102
108
|
};
|
|
103
109
|
if (info.parentID !== undefined)
|
|
104
110
|
session.parentID = info.parentID;
|
|
111
|
+
if (info.parentMessageID !== undefined)
|
|
112
|
+
session.parentMessageID = info.parentMessageID;
|
|
105
113
|
if (opts.model !== undefined) {
|
|
106
|
-
session.model = {
|
|
114
|
+
session.model = {
|
|
115
|
+
id: opts.model.modelID,
|
|
116
|
+
providerID: opts.model.providerID,
|
|
117
|
+
variant: info.model?.variant ?? "default",
|
|
118
|
+
};
|
|
107
119
|
}
|
|
108
120
|
return session;
|
|
109
121
|
}
|
|
110
122
|
/** v2 user message (list + prompt response): the UI reads `.text`. */
|
|
111
|
-
|
|
112
|
-
const text = info.parts
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
function toV2UserMessage(info) {
|
|
124
|
+
const text = info.parts.map((p) => (p.type === "text" ? p.text : p.type === "compaction" ? "/compact" : "")).join("");
|
|
125
|
+
const user = info.info;
|
|
126
|
+
const metadata = user.metadata !== undefined ? { metadata: user.metadata } : {};
|
|
127
|
+
// Admitted no-reply context lists as OpenCode's synthetic item, not as a user turn.
|
|
128
|
+
if (user.synthetic)
|
|
129
|
+
return { id: user.id, time: { created: user.time.created }, type: "synthetic", text, ...metadata };
|
|
130
|
+
const inputs = info.parts.flatMap((part) => (part.type === "file" || part.type === "agent" ? [part] : []));
|
|
116
131
|
return {
|
|
117
|
-
id:
|
|
118
|
-
time: { created:
|
|
132
|
+
id: user.id,
|
|
133
|
+
time: { created: user.time.created },
|
|
119
134
|
type: "user",
|
|
120
135
|
text,
|
|
136
|
+
...v2PromptAttachments(inputs),
|
|
137
|
+
...metadata,
|
|
121
138
|
};
|
|
122
139
|
}
|
|
123
140
|
/**
|
|
@@ -126,7 +143,7 @@ export function toV2UserMessage(info) {
|
|
|
126
143
|
*/
|
|
127
144
|
export function toV2AssistantMessage(info) {
|
|
128
145
|
const i = info.info;
|
|
129
|
-
const model = { id: i.modelID, providerID: i.providerID };
|
|
146
|
+
const model = { id: i.modelID, providerID: i.providerID, variant: "default" };
|
|
130
147
|
const content = [];
|
|
131
148
|
for (const part of info.parts) {
|
|
132
149
|
if (part.type === "text") {
|
|
@@ -142,13 +159,16 @@ export function toV2AssistantMessage(info) {
|
|
|
142
159
|
},
|
|
143
160
|
});
|
|
144
161
|
}
|
|
145
|
-
else {
|
|
162
|
+
else if (part.type === "tool") {
|
|
146
163
|
content.push(toolContent(part));
|
|
147
164
|
}
|
|
148
165
|
}
|
|
149
166
|
const msg = { id: i.id, time: { created: i.time.created }, type: "assistant", content };
|
|
150
167
|
if (i.time.completed !== undefined)
|
|
151
168
|
msg.time.completed = i.time.completed;
|
|
169
|
+
const streamed = info.parts.flatMap((part) => part.type === "text" || part.type === "reasoning" ? (part.time?.start === undefined ? [] : [part.time.start]) : []);
|
|
170
|
+
if (streamed.length > 0)
|
|
171
|
+
msg.time.streamed = Math.min(...streamed);
|
|
152
172
|
msg.agent = i.mode;
|
|
153
173
|
msg.model = model;
|
|
154
174
|
if (i.finish !== undefined)
|
|
@@ -217,10 +237,19 @@ export function toV2Message(info) {
|
|
|
217
237
|
*/
|
|
218
238
|
export class V2EventTranslator {
|
|
219
239
|
sessions = new Map();
|
|
240
|
+
sequences = new Map();
|
|
220
241
|
translate(directory, ev) {
|
|
221
242
|
switch (ev.type) {
|
|
222
243
|
case "session.inbox.enqueued":
|
|
223
244
|
case "session.inbox.delivered":
|
|
245
|
+
case "session.revert.staged":
|
|
246
|
+
case "session.revert.cleared":
|
|
247
|
+
case "session.revert.committed":
|
|
248
|
+
case "session.compaction.started":
|
|
249
|
+
case "session.compaction.ended":
|
|
250
|
+
case "session.compaction.failed":
|
|
251
|
+
case "session.shell.started":
|
|
252
|
+
case "session.shell.ended":
|
|
224
253
|
return [this.frame(directory, ev.type, ev.properties)];
|
|
225
254
|
case "message.removed":
|
|
226
255
|
return [
|
|
@@ -238,12 +267,22 @@ export class V2EventTranslator {
|
|
|
238
267
|
location: { directory: info.directory },
|
|
239
268
|
subpath: subpathOf(info.directory),
|
|
240
269
|
title: info.title,
|
|
270
|
+
agent: info.agent ?? getAgentName(),
|
|
271
|
+
...(info.parentID !== undefined ? { parentID: info.parentID } : {}),
|
|
272
|
+
...(info.parentMessageID !== undefined ? { parentMessageID: info.parentMessageID } : {}),
|
|
273
|
+
...(info.metadata !== undefined ? { metadata: info.metadata } : {}),
|
|
241
274
|
}),
|
|
242
275
|
];
|
|
243
276
|
}
|
|
244
277
|
case "session.updated": {
|
|
245
278
|
const info = ev.properties.info;
|
|
246
|
-
return [
|
|
279
|
+
return [
|
|
280
|
+
this.frame(directory, "session.renamed", { sessionID: info.id, title: info.title }),
|
|
281
|
+
...(info.metadata !== undefined
|
|
282
|
+
? [this.frame(directory, "session.metadata.updated", { sessionID: info.id, metadata: info.metadata })]
|
|
283
|
+
: []),
|
|
284
|
+
this.frame(directory, "session.agent.selected", { sessionID: info.id, agent: info.agent ?? getAgentName() }),
|
|
285
|
+
];
|
|
247
286
|
}
|
|
248
287
|
case "session.diff":
|
|
249
288
|
return [this.frame(directory, "session.diff", ev.properties)];
|
|
@@ -260,7 +299,21 @@ export class V2EventTranslator {
|
|
|
260
299
|
const frames = [];
|
|
261
300
|
if (st?.step && !st.step.ended)
|
|
262
301
|
frames.push(...this.finalizeStep(directory, st.step));
|
|
263
|
-
|
|
302
|
+
if (st?.executionEnded) {
|
|
303
|
+
// session.error already published the execution's terminal frame.
|
|
304
|
+
}
|
|
305
|
+
else if (st?.step?.error?.name === "MessageAbortedError") {
|
|
306
|
+
frames.push(this.frame(directory, "session.execution.interrupted", { sessionID, reason: "user" }));
|
|
307
|
+
}
|
|
308
|
+
else if (st?.step?.finish === "error") {
|
|
309
|
+
frames.push(this.frame(directory, "session.execution.failed", {
|
|
310
|
+
sessionID,
|
|
311
|
+
error: st.step.error ?? { name: "UnknownError", data: { message: "Provider error" } },
|
|
312
|
+
}));
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
frames.push(this.frame(directory, "session.execution.succeeded", { sessionID }));
|
|
316
|
+
}
|
|
264
317
|
frames.push(this.frame(directory, "session.idle", { sessionID }));
|
|
265
318
|
this.sessions.delete(sessionID);
|
|
266
319
|
return frames;
|
|
@@ -268,24 +321,20 @@ export class V2EventTranslator {
|
|
|
268
321
|
case "session.error": {
|
|
269
322
|
const { sessionID, error } = ev.properties;
|
|
270
323
|
const frames = [];
|
|
271
|
-
const st = sessionID !== undefined ? this.
|
|
324
|
+
const st = sessionID !== undefined ? this.state(sessionID) : undefined;
|
|
272
325
|
if (sessionID !== undefined && st?.step && !st.step.ended) {
|
|
273
|
-
st.step.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
assistantMessageID: st.step.messageID,
|
|
277
|
-
finish: st.step.finish ?? "error",
|
|
278
|
-
error: error ?? { name: "UnknownError", data: { message: "session error" } },
|
|
279
|
-
cost: st.step.cost,
|
|
280
|
-
tokens: st.step.tokens,
|
|
281
|
-
}));
|
|
282
|
-
this.sessions.delete(sessionID);
|
|
326
|
+
st.step.finish = "error";
|
|
327
|
+
st.step.error = error ?? { name: "UnknownError", data: { message: "session error" } };
|
|
328
|
+
frames.push(...this.finalizeStep(directory, st.step));
|
|
283
329
|
}
|
|
284
|
-
if (sessionID !== undefined) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
330
|
+
if (sessionID !== undefined && st !== undefined && !st.executionEnded) {
|
|
331
|
+
st.executionEnded = true;
|
|
332
|
+
frames.push(error?.name === "MessageAbortedError"
|
|
333
|
+
? this.frame(directory, "session.execution.interrupted", { sessionID, reason: "user" })
|
|
334
|
+
: this.frame(directory, "session.execution.failed", {
|
|
335
|
+
sessionID,
|
|
336
|
+
error: error ?? { name: "UnknownError", data: { message: "session error" } },
|
|
337
|
+
}));
|
|
289
338
|
}
|
|
290
339
|
return frames;
|
|
291
340
|
}
|
|
@@ -293,6 +342,20 @@ export class V2EventTranslator {
|
|
|
293
342
|
return this.onMessageUpdated(directory, ev.properties.info);
|
|
294
343
|
case "message.part.updated":
|
|
295
344
|
return this.onPartUpdated(directory, ev.properties.part, ev.properties.delta);
|
|
345
|
+
case "message.part.delta": {
|
|
346
|
+
const { sessionID, messageID, partID, delta } = ev.properties;
|
|
347
|
+
const part = this.state(sessionID).parts.get(partID);
|
|
348
|
+
if (part === undefined || delta === "")
|
|
349
|
+
return [];
|
|
350
|
+
return [
|
|
351
|
+
this.frame(directory, `session.${part.kind}.delta`, {
|
|
352
|
+
sessionID,
|
|
353
|
+
assistantMessageID: messageID,
|
|
354
|
+
ordinal: part.ordinal,
|
|
355
|
+
delta,
|
|
356
|
+
}),
|
|
357
|
+
];
|
|
358
|
+
}
|
|
296
359
|
case "model.changed": {
|
|
297
360
|
const { sessionID, model, previous } = ev.properties;
|
|
298
361
|
return [
|
|
@@ -305,20 +368,10 @@ export class V2EventTranslator {
|
|
|
305
368
|
}
|
|
306
369
|
case "permission.asked": {
|
|
307
370
|
const p = ev.properties;
|
|
308
|
-
return [
|
|
309
|
-
this.frame(directory, "permission.v2.asked", {
|
|
310
|
-
id: p.id,
|
|
311
|
-
sessionID: p.sessionID,
|
|
312
|
-
action: p.permission,
|
|
313
|
-
resources: p.patterns,
|
|
314
|
-
save: p.always,
|
|
315
|
-
metadata: p.metadata,
|
|
316
|
-
...(p.tool ? { source: { type: "tool", ...p.tool } } : {}),
|
|
317
|
-
}),
|
|
318
|
-
];
|
|
371
|
+
return [this.frame(directory, "permission.asked", p)];
|
|
319
372
|
}
|
|
320
373
|
case "permission.replied":
|
|
321
|
-
return [this.frame(directory, "permission.
|
|
374
|
+
return [this.frame(directory, "permission.replied", ev.properties)];
|
|
322
375
|
case "question.asked":
|
|
323
376
|
return [this.frame(directory, "form.created", { form: toQuestionForm(ev.properties) })];
|
|
324
377
|
case "question.replied":
|
|
@@ -371,6 +424,9 @@ export class V2EventTranslator {
|
|
|
371
424
|
};
|
|
372
425
|
if (info.finish !== undefined)
|
|
373
426
|
step.finish = info.finish;
|
|
427
|
+
if (info.finish === "error") {
|
|
428
|
+
step.error = info.error ?? { name: "UnknownError", data: { message: "Provider error" } };
|
|
429
|
+
}
|
|
374
430
|
st.step = step;
|
|
375
431
|
frames.push(this.frame(directory, "session.step.started", {
|
|
376
432
|
sessionID: info.sessionID,
|
|
@@ -384,6 +440,9 @@ export class V2EventTranslator {
|
|
|
384
440
|
st.step.tokens = info.tokens;
|
|
385
441
|
if (info.finish !== undefined)
|
|
386
442
|
st.step.finish = info.finish;
|
|
443
|
+
if (info.finish === "error") {
|
|
444
|
+
st.step.error = info.error ?? { name: "UnknownError", data: { message: "Provider error" } };
|
|
445
|
+
}
|
|
387
446
|
if (!st.step.streamed) {
|
|
388
447
|
st.step.streamed = true;
|
|
389
448
|
frames.push(this.frame(directory, "session.step.streamed", { sessionID: info.sessionID, assistantMessageID: info.id }));
|
|
@@ -402,16 +461,37 @@ export class V2EventTranslator {
|
|
|
402
461
|
st.ended = true;
|
|
403
462
|
return [
|
|
404
463
|
this.frame(directory, "session.usage.updated", { sessionID: st.sessionID, cost: st.cost, tokens: st.tokens }),
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
464
|
+
st.finish === "error"
|
|
465
|
+
? this.frame(directory, "session.step.failed", {
|
|
466
|
+
sessionID: st.sessionID,
|
|
467
|
+
assistantMessageID: st.messageID,
|
|
468
|
+
rawFinish: st.finish,
|
|
469
|
+
error: st.error ?? { name: "UnknownError", data: { message: "Provider error" } },
|
|
470
|
+
cost: st.cost,
|
|
471
|
+
tokens: st.tokens,
|
|
472
|
+
})
|
|
473
|
+
: this.frame(directory, "session.step.ended", {
|
|
474
|
+
sessionID: st.sessionID,
|
|
475
|
+
assistantMessageID: st.messageID,
|
|
476
|
+
...(st.finish !== undefined ? { finish: st.finish } : {}),
|
|
477
|
+
cost: st.cost,
|
|
478
|
+
tokens: st.tokens,
|
|
479
|
+
}),
|
|
412
480
|
];
|
|
413
481
|
}
|
|
414
482
|
onPartUpdated(directory, part, delta) {
|
|
483
|
+
if (part.type === "file" || part.type === "agent")
|
|
484
|
+
return [];
|
|
485
|
+
if (part.type === "compaction")
|
|
486
|
+
// Like shell turns, the server creates this user turn; there is no optimistic prompt.
|
|
487
|
+
return [
|
|
488
|
+
this.frame(directory, "session.prompted", {
|
|
489
|
+
sessionID: part.sessionID,
|
|
490
|
+
messageID: part.messageID,
|
|
491
|
+
prompt: { text: "/compact" },
|
|
492
|
+
delivery: "queue",
|
|
493
|
+
}),
|
|
494
|
+
];
|
|
415
495
|
return part.type === "tool" ? this.onToolPart(directory, part) : this.onTextPart(directory, part, delta);
|
|
416
496
|
}
|
|
417
497
|
onTextPart(directory, part, delta) {
|
|
@@ -540,7 +620,18 @@ export class V2EventTranslator {
|
|
|
540
620
|
return st;
|
|
541
621
|
}
|
|
542
622
|
frame(directory, type, data) {
|
|
543
|
-
|
|
623
|
+
const aggregateID = typeof data.sessionID === "string" ? data.sessionID : undefined;
|
|
624
|
+
const seq = aggregateID === undefined ? undefined : (this.sequences.get(aggregateID) ?? 0) + 1;
|
|
625
|
+
if (aggregateID !== undefined && seq !== undefined)
|
|
626
|
+
this.sequences.set(aggregateID, seq);
|
|
627
|
+
return {
|
|
628
|
+
id: genId("evt"),
|
|
629
|
+
created: Date.now(),
|
|
630
|
+
type,
|
|
631
|
+
location: { directory },
|
|
632
|
+
data,
|
|
633
|
+
...(aggregateID !== undefined && seq !== undefined ? { durable: { aggregateID, seq, version: 1 } } : {}),
|
|
634
|
+
};
|
|
544
635
|
}
|
|
545
636
|
}
|
|
546
637
|
function safeJson(value) {
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const ADAPTER_VERSION: string;
|
|
2
|
-
export declare const OPENCODE_API_VERSION = "2.0.
|
|
2
|
+
export declare const OPENCODE_API_VERSION = "2.0.20";
|
package/dist/version.js
CHANGED
|
@@ -10,4 +10,4 @@ if (typeof manifest !== "object" ||
|
|
|
10
10
|
export const ADAPTER_VERSION = manifest.version;
|
|
11
11
|
// OpenChamber parses --version as an OpenCode version and requires major 2.
|
|
12
12
|
// This API contract version must not follow the npm package version.
|
|
13
|
-
export const OPENCODE_API_VERSION = "2.0.
|
|
13
|
+
export const OPENCODE_API_VERSION = "2.0.20";
|
|
@@ -25,6 +25,8 @@ sessions on OmO.
|
|
|
25
25
|
- **Pan and zoom.** Drag the background, and scroll or pinch to zoom. `0`
|
|
26
26
|
fits the graph; the target button centres on the current or first running
|
|
27
27
|
agent.
|
|
28
|
+
- Very large runs are sent within a bounded response size. When tasks are
|
|
29
|
+
omitted to fit that limit, the panel shows the omitted-node count.
|
|
28
30
|
|
|
29
31
|
The panel docks in the right rail. The same page is also available full
|
|
30
32
|
screen from the sidebar's Extension pages menu.
|
|
@@ -28,6 +28,14 @@ does that in ~2 ms with an mtime cache and returns one JSON document.
|
|
|
28
28
|
2. **Connector registry**: `<stateDir>/sessions.json`, mapping OpenChamber
|
|
29
29
|
session ids to OmO session ids and titles.
|
|
30
30
|
|
|
31
|
+
Task discovery reads regular `.json` files and skips directories and symlinks.
|
|
32
|
+
The service resolves configured root spellings before using them as cache
|
|
33
|
+
keys; its recency-updated task-store cache holds at most 32 root sets. Graph
|
|
34
|
+
responses are capped at 240,000 serialized characters. If the full graph
|
|
35
|
+
exceeds that bound, the service keeps the root and a valid task prefix, removes
|
|
36
|
+
edges to omitted tasks, and returns `truncated.omittedNodes`; the panel
|
|
37
|
+
validates that field and displays the count.
|
|
38
|
+
|
|
31
39
|
The connector names sub-agent sessions `ses_<md5(task_id)>` and root sessions
|
|
32
40
|
`ses_<md5(piSessionId)>` (`ocIdFor` in `src/session-store.ts`). The graph
|
|
33
41
|
uses the same function, so a node's `sessionId` is exactly the id
|
|
@@ -59,7 +67,8 @@ uses the same function, so a node's `sessionId` is exactly the id
|
|
|
59
67
|
|
|
60
68
|
## Layout (`src/layout.ts`)
|
|
61
69
|
|
|
62
|
-
Columns are fixed-width
|
|
70
|
+
Columns are fixed-width, and panel CSS dimensions come from the same card-size
|
|
71
|
+
constants used by the layout. Within a column, cards stack in the order of their
|
|
63
72
|
parents' rows, then by creation time, so a fan-out stays next to the card
|
|
64
73
|
that launched it. The orchestrator is centred on its direct children. Edges
|
|
65
74
|
leave a card's right side and enter the left side as horizontal cubic
|