antechamber 0.2.25 → 0.2.26
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 +11 -0
- package/dist/subagents.d.ts +4 -3
- package/dist/subagents.js +29 -6
- package/dist/tool-map.d.ts +9 -2
- package/dist/tool-map.js +77 -14
- package/extensions/omo-compat/README.md +4 -0
- package/extensions/omo-compat/package.json +11 -1
- package/extensions/omo-dag/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project uses [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.26] - 2026-10-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Name a subagent card for an `agent()` call made inside eval after its agent type (for example "Explore Agent"),
|
|
15
|
+
and describe it with the call's label, the task's summary, or the first line of its prompt, instead of a bare "agent".
|
|
16
|
+
- Show subagents an eval cell starts with `tool.task(...)` as subagent cards that open their session, live and after
|
|
17
|
+
reloading history, including ones started in the background.
|
|
18
|
+
- Show an `agent()` call that OmO refused (for example one with no agent type) as a failed subagent card. OmO
|
|
19
|
+
records it as a success but starts no task.
|
|
20
|
+
|
|
10
21
|
## [0.2.25] - 2026-10-17
|
|
11
22
|
|
|
12
23
|
- feat(tools): show subagents and monitors started inside eval (#30)
|
package/dist/subagents.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SessionStore } from "./session-store.js";
|
|
2
|
-
import { type ToolResult } from "./tool-map.js";
|
|
2
|
+
import { type EvalAgent, type ToolResult } from "./tool-map.js";
|
|
3
3
|
import type { ManagedSession } from "./sessions.js";
|
|
4
4
|
import type { OCEvent, OCMessageWithParts, OCToolPart } from "./types.js";
|
|
5
5
|
export declare function stripTaskSuffix(text: string): string;
|
|
@@ -17,9 +17,10 @@ export declare function findTaskBySession(sessionId: string): {
|
|
|
17
17
|
/**
|
|
18
18
|
* The session of a subagent an eval cell started with `agent()`. The recorded call keeps only its
|
|
19
19
|
* arguments, so the task record is found by parent, prompt and label: the oldest one created since
|
|
20
|
-
* the cell started and not yet claimed by an earlier call of the same cell.
|
|
20
|
+
* the cell started and not yet claimed by an earlier call of the same cell. `null` means the parent
|
|
21
|
+
* was searched and no record matched; `undefined` means it could not be searched.
|
|
21
22
|
*/
|
|
22
|
-
export declare function evalAgentSession(parentPiId: string | undefined, args: Record<string, unknown>, claimed: Set<string>, after: number):
|
|
23
|
+
export declare function evalAgentSession(parentPiId: string | undefined, args: Record<string, unknown>, claimed: Set<string>, after: number): EvalAgent | null | undefined;
|
|
23
24
|
export declare function findTask(id: string, parentPiId: string): {
|
|
24
25
|
path: string;
|
|
25
26
|
data: Record<string, unknown>;
|
package/dist/subagents.js
CHANGED
|
@@ -193,10 +193,23 @@ export function findTaskBySession(sessionId) {
|
|
|
193
193
|
}
|
|
194
194
|
return undefined;
|
|
195
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Whether a recorded argument names a task record's value. Codemode caps recorded strings at 512 code
|
|
198
|
+
* points and ends a cut one with "…" (call-capture.ts), and a schema agent() call sends its prompt with
|
|
199
|
+
* JSON instructions appended (agent-bridge.ts toTaskParams), so both match as prefixes.
|
|
200
|
+
*/
|
|
201
|
+
function recordedMatch(recorded, stored) {
|
|
202
|
+
if (typeof stored !== "string")
|
|
203
|
+
return false;
|
|
204
|
+
if (stored === recorded)
|
|
205
|
+
return true;
|
|
206
|
+
return recorded.endsWith("…") ? stored.startsWith(recorded.slice(0, -1)) : stored.startsWith(`${recorded}\n\n`);
|
|
207
|
+
}
|
|
196
208
|
/**
|
|
197
209
|
* The session of a subagent an eval cell started with `agent()`. The recorded call keeps only its
|
|
198
210
|
* arguments, so the task record is found by parent, prompt and label: the oldest one created since
|
|
199
|
-
* the cell started and not yet claimed by an earlier call of the same cell.
|
|
211
|
+
* the cell started and not yet claimed by an earlier call of the same cell. `null` means the parent
|
|
212
|
+
* was searched and no record matched; `undefined` means it could not be searched.
|
|
200
213
|
*/
|
|
201
214
|
export function evalAgentSession(parentPiId, args, claimed, after) {
|
|
202
215
|
if (parentPiId === undefined || typeof args.prompt !== "string")
|
|
@@ -209,21 +222,31 @@ export function evalAgentSession(parentPiId, args, claimed, after) {
|
|
|
209
222
|
if (data?.parent_session_id !== parentPiId)
|
|
210
223
|
continue;
|
|
211
224
|
const spec = record(data.spawn_spec) ? data.spawn_spec : {};
|
|
212
|
-
if (
|
|
225
|
+
if (!recordedMatch(args.prompt, spec.prompt))
|
|
213
226
|
continue;
|
|
214
|
-
if (typeof args.label === "string" && data.name
|
|
227
|
+
if (typeof args.label === "string" && !recordedMatch(args.label, data.name))
|
|
215
228
|
continue;
|
|
216
229
|
const created = typeof data.created_at === "string" ? Date.parse(data.created_at) : Number.NaN;
|
|
217
230
|
// The cell's start is taken when its card opens, a moment after OmO starts it.
|
|
218
231
|
if (!Number.isFinite(created) || created < after - 5_000)
|
|
219
232
|
continue;
|
|
220
233
|
if (best === undefined || created < best.created)
|
|
221
|
-
best = { id, created };
|
|
234
|
+
best = { id, created, data };
|
|
222
235
|
}
|
|
223
236
|
if (best === undefined)
|
|
224
|
-
return
|
|
237
|
+
return null;
|
|
225
238
|
claimed.add(best.id);
|
|
226
|
-
|
|
239
|
+
const text = (value) => (typeof value === "string" && value !== "" ? value : undefined);
|
|
240
|
+
// OmO names an unlabelled task after its id, which says nothing.
|
|
241
|
+
const name = text(best.data.name);
|
|
242
|
+
const summary = text(best.data.task_summary);
|
|
243
|
+
const agentType = text(best.data.agent_type);
|
|
244
|
+
return {
|
|
245
|
+
sessionID: ocIdFor(best.id),
|
|
246
|
+
...(name !== undefined && name !== best.id ? { name } : {}),
|
|
247
|
+
...(summary !== undefined ? { summary } : {}),
|
|
248
|
+
...(agentType !== undefined ? { agentType } : {}),
|
|
249
|
+
};
|
|
227
250
|
}
|
|
228
251
|
export function findTask(id, parentPiId) {
|
|
229
252
|
if (!taskId(id))
|
package/dist/tool-map.d.ts
CHANGED
|
@@ -32,8 +32,15 @@ export declare function mapTool(omoName: string, args: unknown, result?: ToolRes
|
|
|
32
32
|
export interface NestedSessions {
|
|
33
33
|
/** The monitor child session for a recorded `monitor` call. */
|
|
34
34
|
monitor?: (args: Record<string, unknown>) => string | undefined;
|
|
35
|
-
/** The subagent
|
|
36
|
-
agent?: (args: Record<string, unknown>, claimed: Set<string>, after: number) =>
|
|
35
|
+
/** The subagent a recorded `agent()` call started; `claimed` keeps repeated calls apart. */
|
|
36
|
+
agent?: (args: Record<string, unknown>, claimed: Set<string>, after: number) => EvalAgent | null | undefined;
|
|
37
|
+
}
|
|
38
|
+
/** The task record behind an `agent()` call made inside eval. */
|
|
39
|
+
export interface EvalAgent {
|
|
40
|
+
sessionID: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
summary?: string;
|
|
43
|
+
agentType?: string;
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
39
46
|
* Finished eval calls, from the raw RPC capture of installed omo-ai 5.1.33 / senpi runtime, 2026-10-17.
|
package/dist/tool-map.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ocIdFor } from "./session-store.js";
|
|
1
2
|
function record(value) {
|
|
2
3
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3
4
|
}
|
|
@@ -134,13 +135,41 @@ export function mapTool(omoName, args, result) {
|
|
|
134
135
|
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
135
136
|
};
|
|
136
137
|
}
|
|
137
|
-
/**
|
|
138
|
-
function
|
|
138
|
+
/** "Explore Agent" for an agent type or category, "Subagent" when there is none. */
|
|
139
|
+
function agentTitle(type) {
|
|
140
|
+
return type === "subagent" ? "Subagent" : `${type.charAt(0).toUpperCase()}${type.slice(1)} Agent`;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The task id OmO puts in a `task` result: "[task_id: st_x - " when it waited, "(st_x, running" in the
|
|
144
|
+
* background. The preview is capped at 160 code points, so only an id followed by its delimiter is whole.
|
|
145
|
+
*/
|
|
146
|
+
const TASK_ID = /\[task_id: (st_[A-Za-z0-9_-]+) - |\((st_[A-Za-z0-9_-]+), running\b/;
|
|
147
|
+
/** The prompt's first line, cut at a word boundary near 60 characters. */
|
|
148
|
+
function shortPrompt(prompt) {
|
|
149
|
+
const line = prompt
|
|
150
|
+
.split("\n")
|
|
151
|
+
.find((text) => text.trim() !== "")
|
|
152
|
+
?.trim();
|
|
153
|
+
if (line === undefined || line.length <= 60)
|
|
154
|
+
return line;
|
|
155
|
+
const cut = line.slice(0, 60);
|
|
156
|
+
const space = cut.lastIndexOf(" ");
|
|
157
|
+
return `${(space > 30 ? cut.slice(0, space) : cut).trimEnd()}…`;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* A subagent-style card, as OpenChamber draws `task`: it opens `sessionID` when there is one.
|
|
161
|
+
* `agentTitle`/`agentSubtitle` feed the OmO Compatibility extension's `task` header rule.
|
|
162
|
+
*/
|
|
163
|
+
function nestedSubagent(heading, input, sessionID) {
|
|
139
164
|
return {
|
|
140
165
|
tool: "task",
|
|
141
|
-
input: { description, prompt, subagent_type: type },
|
|
142
|
-
title: description.slice(0, 60),
|
|
143
|
-
metadata:
|
|
166
|
+
input: { description: input.description, prompt: input.prompt, subagent_type: input.type },
|
|
167
|
+
title: input.description.slice(0, 60),
|
|
168
|
+
metadata: {
|
|
169
|
+
agentTitle: heading.title,
|
|
170
|
+
agentSubtitle: heading.subtitle,
|
|
171
|
+
...(sessionID !== undefined ? { sessionID } : {}),
|
|
172
|
+
},
|
|
144
173
|
};
|
|
145
174
|
}
|
|
146
175
|
/**
|
|
@@ -154,8 +183,9 @@ export function nestedToolParts(parent, details, sessions = {}) {
|
|
|
154
183
|
const start = parent.state.status === "pending" ? 0 : parent.state.time.start;
|
|
155
184
|
const claimed = new Set();
|
|
156
185
|
details.toolCalls.forEach((entry, index) => {
|
|
186
|
+
let failure;
|
|
157
187
|
if (!record(entry) ||
|
|
158
|
-
(entry.name !== "monitor" && entry.name !== "__agent__") ||
|
|
188
|
+
(entry.name !== "monitor" && entry.name !== "__agent__" && entry.name !== "task") ||
|
|
159
189
|
typeof entry.ok !== "boolean" ||
|
|
160
190
|
typeof entry.durationMs !== "number" ||
|
|
161
191
|
!Number.isFinite(entry.durationMs) ||
|
|
@@ -169,14 +199,44 @@ export function nestedToolParts(parent, details, sessions = {}) {
|
|
|
169
199
|
return; // nothing to open; the cell's code already shows the call
|
|
170
200
|
const command = typeof args.command === "string" ? args.command : "";
|
|
171
201
|
const label = typeof args.description === "string" && args.description !== "" ? args.description : command;
|
|
172
|
-
mapped = nestedSubagent(`Monitor: ${label}`, command, "monitor", sessionID);
|
|
202
|
+
mapped = nestedSubagent({ title: "Monitor", subtitle: label }, { description: `Monitor: ${label}`, prompt: command, type: "monitor" }, sessionID);
|
|
203
|
+
}
|
|
204
|
+
else if (entry.name === "task") {
|
|
205
|
+
const text = (value) => (typeof value === "string" && value !== "" ? value : undefined);
|
|
206
|
+
const prompt = text(args.prompt) ?? "";
|
|
207
|
+
const match = typeof entry.resultPreview === "string" ? TASK_ID.exec(entry.resultPreview) : null;
|
|
208
|
+
const taskID = match?.[1] ?? match?.[2];
|
|
209
|
+
if (taskID !== undefined)
|
|
210
|
+
claimed.add(taskID);
|
|
211
|
+
// A long reply pushes the id out of the preview; the task record still names the session.
|
|
212
|
+
const sessionID = !entry.ok
|
|
213
|
+
? undefined
|
|
214
|
+
: taskID !== undefined
|
|
215
|
+
? ocIdFor(taskID)
|
|
216
|
+
: (sessions.agent?.({ prompt, ...(text(args.name) ? { label: args.name } : {}) }, claimed, start) ??
|
|
217
|
+
undefined)?.sessionID;
|
|
218
|
+
const description = text(args.task_summary) ?? text(args.description) ?? shortPrompt(prompt) ?? "subagent";
|
|
219
|
+
const type = text(args.subagent_type) ?? text(args.category) ?? "subagent";
|
|
220
|
+
mapped = nestedSubagent({ title: agentTitle(type), subtitle: description }, { description, prompt, type }, sessionID);
|
|
173
221
|
}
|
|
174
222
|
else {
|
|
175
223
|
const prompt = typeof args.prompt === "string" ? args.prompt : "";
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
|
|
224
|
+
const found = entry.ok ? sessions.agent?.(args, claimed, start) : undefined;
|
|
225
|
+
const text = (value) => (typeof value === "string" && value !== "" ? value : undefined);
|
|
226
|
+
const description = text(args.label) ??
|
|
227
|
+
text(args.description) ??
|
|
228
|
+
found?.summary ??
|
|
229
|
+
found?.name ??
|
|
230
|
+
shortPrompt(prompt) ??
|
|
231
|
+
"subagent";
|
|
232
|
+
const type = text(args.agent) ?? found?.agentType ?? "subagent";
|
|
233
|
+
mapped = nestedSubagent({
|
|
234
|
+
title: agentTitle(type),
|
|
235
|
+
subtitle: description,
|
|
236
|
+
}, { description, prompt, type }, found?.sessionID);
|
|
237
|
+
// OmO writes the task record before agent() returns, but records a refused spawn as ok with no record.
|
|
238
|
+
if (entry.ok && found === null)
|
|
239
|
+
failure = "OmO started no subagent for this call (agent() needs an agent type or a category)";
|
|
180
240
|
}
|
|
181
241
|
const key = typeof entry.callId === "string" ? `id:${encodeURIComponent(entry.callId)}` : `index:${index}`;
|
|
182
242
|
const callID = `${encodeURIComponent(parent.callID)}:${key}`;
|
|
@@ -187,19 +247,22 @@ export function nestedToolParts(parent, details, sessions = {}) {
|
|
|
187
247
|
metadata: { ...mapped.metadata, nested: true, parentCallID: parent.callID, durationMs: entry.durationMs },
|
|
188
248
|
time: { start, end: start + entry.durationMs },
|
|
189
249
|
};
|
|
250
|
+
const failed = !entry.ok || failure !== undefined;
|
|
190
251
|
parts.push({
|
|
191
252
|
id: `prt_${parent.sessionID}_nested_${callID}`,
|
|
192
253
|
sessionID: parent.sessionID,
|
|
193
254
|
messageID: parent.messageID,
|
|
194
255
|
type: "tool",
|
|
195
256
|
callID: `nested:${callID}`,
|
|
196
|
-
|
|
197
|
-
|
|
257
|
+
// OpenChamber 1.24 never styles a task card as failed or shows its error (ToolPart.tsx isTaskTool),
|
|
258
|
+
// and a failed spawn has no session to open, so it goes out as a plain card that does both.
|
|
259
|
+
tool: failed && mapped.tool === "task" ? "agent" : mapped.tool,
|
|
260
|
+
state: !failed
|
|
198
261
|
? { ...state, status: "completed" }
|
|
199
262
|
: {
|
|
200
263
|
...state,
|
|
201
264
|
status: "error",
|
|
202
|
-
error: typeof entry.error === "string" && entry.error !== "" ? entry.error : "failed",
|
|
265
|
+
error: failure ?? (typeof entry.error === "string" && entry.error !== "" ? entry.error : "failed"),
|
|
203
266
|
},
|
|
204
267
|
});
|
|
205
268
|
});
|
|
@@ -6,6 +6,10 @@ extension declare. It has no panel, page, service or permissions.
|
|
|
6
6
|
|
|
7
7
|
What it does today:
|
|
8
8
|
|
|
9
|
+
- **Subagent card headers.** A subagent an eval cell started with `agent()` is shown as a `task` card. Its header
|
|
10
|
+
reads the agent type and a short description (the call's label, the task's summary, or the prompt's first line)
|
|
11
|
+
instead of the generic "Agent Task".
|
|
12
|
+
|
|
9
13
|
- **Eval cell headers.** OpenChamber 1.24 streams live output only for shell
|
|
10
14
|
cards, so antechamber shows OmO eval cells as shell cards. With this extension
|
|
11
15
|
their header reads `JS Eval` (or `Python Eval`) and the cell's summary instead
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antechamber-omo-compat",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.26",
|
|
4
4
|
"description": "OpenChamber extension: displays OmO tool calls the way OmO means them when OpenChamber runs on antechamber",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -21,6 +21,16 @@
|
|
|
21
21
|
"match": "bash",
|
|
22
22
|
"title": "{metadata.evalTitle}",
|
|
23
23
|
"subtitle": "{metadata.evalSubtitle}"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"match": "task",
|
|
27
|
+
"title": "{metadata.agentTitle}",
|
|
28
|
+
"subtitle": "{metadata.agentSubtitle}"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"match": "agent",
|
|
32
|
+
"title": "{metadata.agentTitle}",
|
|
33
|
+
"subtitle": "{metadata.agentSubtitle}"
|
|
24
34
|
}
|
|
25
35
|
]
|
|
26
36
|
}
|