antechamber 0.2.21 → 0.2.23
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 +19 -0
- package/README.md +12 -0
- package/dist/commands/setup.js +9 -0
- package/dist/monitor-sessions.d.ts +4 -0
- package/dist/monitor-sessions.js +29 -3
- package/dist/pi-event-translation.d.ts +1 -1
- package/dist/pi-event-translation.js +25 -3
- package/dist/session-history.js +17 -18
- package/dist/tool-map.d.ts +5 -0
- package/dist/tool-map.js +41 -7
- package/extensions/omo-compat/README.md +41 -0
- package/extensions/omo-compat/icon.svg +1 -0
- package/extensions/omo-compat/package.json +28 -0
- package/extensions/omo-dag/package.json +1 -1
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project uses [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.23] - 2026-10-17
|
|
11
|
+
|
|
12
|
+
- feat(monitors): show matched lines in monitor sessions (#32)
|
|
13
|
+
|
|
14
|
+
## [0.2.22] - 2026-10-17
|
|
15
|
+
|
|
16
|
+
- fix(tools): stream live bash and eval output into OpenChamber cards (#29)
|
|
17
|
+
|
|
10
18
|
## [0.2.21] - 2026-10-17
|
|
11
19
|
|
|
12
20
|
### Fixed
|
|
@@ -29,6 +37,17 @@ and this project uses [Semantic Versioning](https://semver.org/).
|
|
|
29
37
|
- Report the real agent startup failure on macOS instead of `kill EPERM`. When OmO exited while a session was being
|
|
30
38
|
created, cleanup signalled its not yet reaped process group, macOS answered EPERM, and OpenChamber showed "Failed
|
|
31
39
|
to create session" with the original error hidden.
|
|
40
|
+
- Show live bash and eval output in OpenChamber 1.24, and display eval and terminal controls as shell cards with
|
|
41
|
+
their final results retained after history reload. A failed cell shows as a failed card.
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- OmO Compatibility, a second bundled OpenChamber extension (1.24 or newer) with no code or permissions. It heads
|
|
46
|
+
eval cards with `JS Eval` or `Python Eval` and the cell's summary.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- Show the lines an OmO monitor matched in its monitor session, as they fire.
|
|
32
51
|
|
|
33
52
|
## [0.2.18] - 2026-10-17
|
|
34
53
|
|
package/README.md
CHANGED
|
@@ -234,6 +234,18 @@ OpenChamber clones the repository root, which is antechamber itself, not the
|
|
|
234
234
|
extension, and refuses it as an invalid manifest. Details:
|
|
235
235
|
[extensions/omo-dag/README.md](extensions/omo-dag/README.md).
|
|
236
236
|
|
|
237
|
+
## OpenChamber extension: OmO Compatibility
|
|
238
|
+
|
|
239
|
+
`extensions/omo-compat` is a second, code-free extension for OpenChamber 1.24
|
|
240
|
+
or newer. It tells OpenChamber how to display OmO tool calls that antechamber
|
|
241
|
+
maps onto OpenChamber's cards; today it heads eval cells with `JS Eval` or
|
|
242
|
+
`Python Eval` and the cell's summary. Add it the same way as OmO Graph: the
|
|
243
|
+
folder `antechamber setup` prints (`.../extensions/omo-compat`, no build
|
|
244
|
+
needed), or the release archive
|
|
245
|
+
`https://github.com/eliottness/antechamber/releases/latest/download/antechamber-omo-compat.zip`.
|
|
246
|
+
It asks for no permissions. Details:
|
|
247
|
+
[extensions/omo-compat/README.md](extensions/omo-compat/README.md).
|
|
248
|
+
|
|
237
249
|
## Configuration
|
|
238
250
|
|
|
239
251
|
Connector settings use the `ANTECHAMBER_` prefix; the deprecated `OCPI_`
|
package/dist/commands/setup.js
CHANGED
|
@@ -18,6 +18,11 @@ function omoGraphExtensionDir(ctx) {
|
|
|
18
18
|
const built = ["package.json", "panel/main.js", "service/main.js"].every((file) => ctx.fs.existsSync(join(dir, file)));
|
|
19
19
|
return built ? dir : undefined;
|
|
20
20
|
}
|
|
21
|
+
/** The bundled OmO Compatibility extension folder; it is a manifest only, so it needs no build. */
|
|
22
|
+
function omoCompatExtensionDir(ctx) {
|
|
23
|
+
const dir = resolve(dirname(ctx.cliPath), "..", "extensions", "omo-compat");
|
|
24
|
+
return ctx.fs.existsSync(join(dir, "package.json")) ? dir : undefined;
|
|
25
|
+
}
|
|
21
26
|
/** Plan all inputs before applying changes; dependencies are injected for hermetic tests. */
|
|
22
27
|
export function setup(options, ctx = createContext()) {
|
|
23
28
|
const lines = [];
|
|
@@ -174,5 +179,9 @@ export function setup(options, ctx = createContext()) {
|
|
|
174
179
|
if (extension !== undefined) {
|
|
175
180
|
report(`Optional OmO Graph extension: in OpenChamber, Settings \u2192 Extensions \u2192 Add \u2192 Folder: ${extension}`);
|
|
176
181
|
}
|
|
182
|
+
const compat = omoCompatExtensionDir(ctx);
|
|
183
|
+
if (compat !== undefined) {
|
|
184
|
+
report(`Optional OmO Compatibility extension (eval card headers): Settings \u2192 Extensions \u2192 Add \u2192 Folder: ${compat}`);
|
|
185
|
+
}
|
|
177
186
|
return lines;
|
|
178
187
|
}
|
|
@@ -3,6 +3,8 @@ import type { OCEvent, OCMessageWithParts } from "./types.js";
|
|
|
3
3
|
/** Names OmO's terminal extension passes to `pi.rpc.emit` (core/extensions/builtin/monitor-state-event.js). */
|
|
4
4
|
export declare const MONITOR_STATE_EVENT = "terminal_monitor_state";
|
|
5
5
|
export declare const MONITOR_ENDED_EVENT = "terminal_monitor_ended";
|
|
6
|
+
/** customType of the custom message OmO sends with a watch's matched lines (raw RPC capture of installed omo-ai 5.1.33, 2026-10-17). */
|
|
7
|
+
export declare const MONITOR_NOTIFICATION = "senpi-monitor:notification";
|
|
6
8
|
export interface MonitorSnapshot {
|
|
7
9
|
id: string;
|
|
8
10
|
description: string;
|
|
@@ -33,6 +35,8 @@ export declare class MonitorSessions {
|
|
|
33
35
|
owns(id: string): boolean;
|
|
34
36
|
messages(id: string): OCMessageWithParts[];
|
|
35
37
|
observe(parent: ManagedSession, ev: Record<string, unknown>): void;
|
|
38
|
+
/** A hidden `senpi-monitor:notification` custom message: append its lines to each watch it names. */
|
|
39
|
+
notify(parent: ManagedSession, message: Record<string, unknown>): void;
|
|
36
40
|
/** The agent process is gone: OmO's in-process watches died with it. */
|
|
37
41
|
stopParent(parentID: string): void;
|
|
38
42
|
/** Forget a deleted child, or every child of a deleted parent. */
|
package/dist/monitor-sessions.js
CHANGED
|
@@ -8,6 +8,10 @@ import { ocIdFor } from "./session-store.js";
|
|
|
8
8
|
/** Names OmO's terminal extension passes to `pi.rpc.emit` (core/extensions/builtin/monitor-state-event.js). */
|
|
9
9
|
export const MONITOR_STATE_EVENT = "terminal_monitor_state";
|
|
10
10
|
export const MONITOR_ENDED_EVENT = "terminal_monitor_ended";
|
|
11
|
+
/** customType of the custom message OmO sends with a watch's matched lines (raw RPC capture of installed omo-ai 5.1.33, 2026-10-17). */
|
|
12
|
+
export const MONITOR_NOTIFICATION = "senpi-monitor:notification";
|
|
13
|
+
/** Matched lines kept per watch; older lines are dropped. */
|
|
14
|
+
const MAX_EVENT_LINES = 200;
|
|
11
15
|
function record(value) {
|
|
12
16
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
13
17
|
}
|
|
@@ -95,6 +99,27 @@ export class MonitorSessions {
|
|
|
95
99
|
else if (ev.name === MONITOR_ENDED_EVENT)
|
|
96
100
|
this.applyEnded(parent, ev.data);
|
|
97
101
|
}
|
|
102
|
+
/** A hidden `senpi-monitor:notification` custom message: append its lines to each watch it names. */
|
|
103
|
+
notify(parent, message) {
|
|
104
|
+
if (typeof message.content !== "string" || !record(message.details) || !Array.isArray(message.details.monitors))
|
|
105
|
+
return;
|
|
106
|
+
const lines = message.content
|
|
107
|
+
.replaceAll(/<\/?system-reminder>/g, "")
|
|
108
|
+
.replace(/^Monitor event\([^\n]*?\):\s?/, "")
|
|
109
|
+
.split("\n")
|
|
110
|
+
.filter((line) => line.trim() !== "");
|
|
111
|
+
if (lines.length === 0)
|
|
112
|
+
return;
|
|
113
|
+
for (const entry of message.details.monitors) {
|
|
114
|
+
if (!record(entry) || typeof entry.id !== "string")
|
|
115
|
+
continue;
|
|
116
|
+
const watch = this.watches.get(this.childID(parent, entry.id));
|
|
117
|
+
if (!watch)
|
|
118
|
+
continue;
|
|
119
|
+
watch.lines = [...watch.lines, ...lines].slice(-MAX_EVENT_LINES);
|
|
120
|
+
this.publish(watch);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
98
123
|
/** The agent process is gone: OmO's in-process watches died with it. */
|
|
99
124
|
stopParent(parentID) {
|
|
100
125
|
for (const watch of this.watches.values()) {
|
|
@@ -193,14 +218,14 @@ export class MonitorSessions {
|
|
|
193
218
|
hasPendingInteraction: () => false,
|
|
194
219
|
hasRunningChildren: () => false,
|
|
195
220
|
};
|
|
196
|
-
const watch = { session, monitor };
|
|
221
|
+
const watch = { session, monitor, lines: [] };
|
|
197
222
|
this.watches.set(id, watch);
|
|
198
223
|
this.sessions.set(id, session);
|
|
199
224
|
this.emit(session.info.directory, { type: "session.created", properties: { info: session.info } });
|
|
200
225
|
this.publish(watch);
|
|
201
226
|
}
|
|
202
227
|
publish(watch) {
|
|
203
|
-
const { session, monitor, ending } = watch;
|
|
228
|
+
const { session, monitor, ending, lines } = watch;
|
|
204
229
|
const directory = session.info.directory;
|
|
205
230
|
const sessionID = session.info.id;
|
|
206
231
|
const base = sessionID.replace(/^ses_/, "");
|
|
@@ -208,7 +233,8 @@ export class MonitorSessions {
|
|
|
208
233
|
const started = monitor.startedAtMs;
|
|
209
234
|
const command = monitor.command ?? monitor.description;
|
|
210
235
|
const input = { command, description: monitor.description };
|
|
211
|
-
const
|
|
236
|
+
const summary = monitorSummary(monitor, ending);
|
|
237
|
+
const output = lines.length > 0 ? `${summary}\n\n${lines.join("\n")}` : summary;
|
|
212
238
|
const tool = {
|
|
213
239
|
id: `prt_${base}_tool`,
|
|
214
240
|
sessionID,
|
|
@@ -3,7 +3,7 @@ import type { OCAssistantMessage, OCMessageWithParts, OCModelRef, OCEvent, OCSes
|
|
|
3
3
|
import type { ManagedSession } from "./sessions.js";
|
|
4
4
|
import type { SessionStore } from "./session-store.js";
|
|
5
5
|
import type { SubagentBridge } from "./subagents.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type MonitorSessions } from "./monitor-sessions.js";
|
|
7
7
|
import { type TodoUpdated } from "./todo-bridge.js";
|
|
8
8
|
export interface PiUsage {
|
|
9
9
|
input?: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Pi message/part translation and the live event bridge, with explicit manager services. */
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
import {
|
|
3
|
+
import { MONITOR_NOTIFICATION } from "./monitor-sessions.js";
|
|
4
|
+
import { applyProviderToolResults, finishProviderToolParts, mapTool, providerToolParts, resultMetadata, resultText, toolFailed, } from "./tool-map.js";
|
|
4
5
|
import { TodoBridge } from "./todo-bridge.js";
|
|
5
6
|
import { readSessionTree, recordTurn } from "./session-tree.js";
|
|
6
7
|
import { touchedFiles } from "./session-diff.js";
|
|
@@ -408,6 +409,22 @@ export class PiEventTranslator {
|
|
|
408
409
|
const part = typeof ev.toolCallId === "string" ? s.toolByCallId.get(ev.toolCallId) : undefined;
|
|
409
410
|
if (part === undefined || part.state.status !== "running")
|
|
410
411
|
return;
|
|
412
|
+
const partial = ev.partialResult;
|
|
413
|
+
let output = resultText(partial !== null && typeof partial === "object" && "content" in partial ? partial.content : undefined);
|
|
414
|
+
if (ev.toolName === "eval") {
|
|
415
|
+
// raw RPC capture of installed omo-ai 5.1.33 / senpi runtime, 2026-10-17:
|
|
416
|
+
// eval prefixes cumulative stdout with status lines, unlike its final result.
|
|
417
|
+
const header = /^\d+\/(\d+) cells? (?:running|complete)\b[^\n]*(?:\n|$)/.exec(output);
|
|
418
|
+
if (header !== null) {
|
|
419
|
+
output = output.slice(header[0].length);
|
|
420
|
+
if (header[1] === "1")
|
|
421
|
+
output = output.replace(/^\[1\] \S+ [^\n]* (?:running|complete)(?:\r?\n|$)/, "");
|
|
422
|
+
}
|
|
423
|
+
if (/^waiting for the \w+ kernel to be ready$/.test(output.trim()))
|
|
424
|
+
output = "";
|
|
425
|
+
}
|
|
426
|
+
if (output.trim() !== "")
|
|
427
|
+
part.state.metadata = { ...part.state.metadata, output };
|
|
411
428
|
this.emitPart(s, part);
|
|
412
429
|
return;
|
|
413
430
|
}
|
|
@@ -427,6 +444,11 @@ export class PiEventTranslator {
|
|
|
427
444
|
case "message_start": {
|
|
428
445
|
if (this.reconcileUser(s, ev))
|
|
429
446
|
return;
|
|
447
|
+
const custom = ev.message;
|
|
448
|
+
if (custom?.role === "custom" && custom.customType === MONITOR_NOTIFICATION) {
|
|
449
|
+
this.services.monitors.notify(s, custom);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
430
452
|
const msg = ev.message;
|
|
431
453
|
if (msg?.role !== "assistant")
|
|
432
454
|
return; // user message already recorded at prompt()
|
|
@@ -774,7 +796,7 @@ export class PiEventTranslator {
|
|
|
774
796
|
if (!part || callID === undefined)
|
|
775
797
|
continue;
|
|
776
798
|
s.toolByCallId.delete(callID);
|
|
777
|
-
s.todoBridge?.finish(part, tr
|
|
799
|
+
s.todoBridge?.finish(part, toolFailed(tr));
|
|
778
800
|
const text = resultText(tr.content);
|
|
779
801
|
const startedAt = part.state.status !== "pending" ? part.state.time.start : Date.now();
|
|
780
802
|
const input = part.state.input ?? {};
|
|
@@ -785,7 +807,7 @@ export class PiEventTranslator {
|
|
|
785
807
|
const title = part.state.status === "running" || part.state.status === "completed"
|
|
786
808
|
? (part.state.title ?? part.tool)
|
|
787
809
|
: part.tool;
|
|
788
|
-
if (tr
|
|
810
|
+
if (toolFailed(tr)) {
|
|
789
811
|
part.state = {
|
|
790
812
|
status: "error",
|
|
791
813
|
input,
|
package/dist/session-history.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Reconstruct OpenCode history from pi JSONL session files. */
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
|
-
import { applyProviderToolResults, finishProviderToolParts, mapTool, providerToolParts, resultMetadata, resultText, } from "./tool-map.js";
|
|
3
|
+
import { applyProviderToolResults, finishProviderToolParts, mapTool, providerToolParts, resultMetadata, resultText, toolFailed, } from "./tool-map.js";
|
|
4
4
|
import { TodoBridge } from "./todo-bridge.js";
|
|
5
5
|
import { userMessageModel } from "./thinking-levels.js";
|
|
6
6
|
import { contextMessageID } from "./prompt-parts.js";
|
|
@@ -396,23 +396,22 @@ export function parsePiSessionText(s, agentName, raw) {
|
|
|
396
396
|
const title = part.state.status === "running" || part.state.status === "completed"
|
|
397
397
|
? (part.state.title ?? part.tool)
|
|
398
398
|
: part.tool;
|
|
399
|
-
part.state =
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
};
|
|
399
|
+
part.state = toolFailed(m)
|
|
400
|
+
? {
|
|
401
|
+
status: "error",
|
|
402
|
+
input,
|
|
403
|
+
error: text !== "" ? text : `tool ${part.tool} failed`,
|
|
404
|
+
metadata,
|
|
405
|
+
time: { start: startedAt, end: created },
|
|
406
|
+
}
|
|
407
|
+
: {
|
|
408
|
+
status: "completed",
|
|
409
|
+
input,
|
|
410
|
+
output: text,
|
|
411
|
+
title,
|
|
412
|
+
metadata,
|
|
413
|
+
time: { start: startedAt, end: created },
|
|
414
|
+
};
|
|
416
415
|
}
|
|
417
416
|
// system / custom entries are not rendered
|
|
418
417
|
}
|
package/dist/tool-map.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export interface ToolResult {
|
|
|
15
15
|
type ToolMapper = (args: Record<string, unknown>, result?: ToolResult) => MappedTool;
|
|
16
16
|
/** Mutable registry: todos 6/7 can assign handlers for `todo` and `task`. */
|
|
17
17
|
export declare const toolMappers: Record<string, ToolMapper>;
|
|
18
|
+
/**
|
|
19
|
+
* A failed result. Codemode leaves a failed eval cell's top-level isError false and sets
|
|
20
|
+
* details.isError instead (senpi-codemode src/tool/render-result.ts:42).
|
|
21
|
+
*/
|
|
22
|
+
export declare function toolFailed(result: ToolResult): boolean;
|
|
18
23
|
/** Text blocks only; images and structured details are not tool output text. */
|
|
19
24
|
export declare function resultText(content: unknown): string;
|
|
20
25
|
/** Only edit cards need patch metadata; write cards already preview input.content. */
|
package/dist/tool-map.js
CHANGED
|
@@ -5,6 +5,25 @@ function generic(tool, input) {
|
|
|
5
5
|
const hint = [input.summary, input.description, input.query, input.url, input.path, input.command].find((value) => typeof value === "string" && value !== "");
|
|
6
6
|
return { tool, input, title: (hint ?? tool).slice(0, 60) };
|
|
7
7
|
}
|
|
8
|
+
function terminalTool(name, args) {
|
|
9
|
+
const target = typeof args.bash_id === "string" ? ` ${args.bash_id}` : args.all === true ? " all" : "";
|
|
10
|
+
let command = `${name}${target}`;
|
|
11
|
+
if (name === "bash_input") {
|
|
12
|
+
if (typeof args.input === "string")
|
|
13
|
+
command += ` ${JSON.stringify(args.input)}`;
|
|
14
|
+
if (Array.isArray(args.keys)) {
|
|
15
|
+
const keys = args.keys.filter((key) => typeof key === "string").join(" ");
|
|
16
|
+
if (keys !== "")
|
|
17
|
+
command += ` ${keys}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (name === "bash_resize" && typeof args.cols === "number" && typeof args.rows === "number") {
|
|
21
|
+
command += ` ${args.cols}x${args.rows}`;
|
|
22
|
+
}
|
|
23
|
+
return { tool: "bash", input: { command, description: command }, title: command.slice(0, 60) };
|
|
24
|
+
}
|
|
25
|
+
/** Display names for codemode's kernel ids. */
|
|
26
|
+
const EVAL_LANGUAGES = { js: "JS", py: "Python" };
|
|
8
27
|
/** Mutable registry: todos 6/7 can assign handlers for `todo` and `task`. */
|
|
9
28
|
export const toolMappers = {
|
|
10
29
|
read: (args) => typeof args.path === "string"
|
|
@@ -40,13 +59,21 @@ export const toolMappers = {
|
|
|
40
59
|
title: args.command.slice(0, 60),
|
|
41
60
|
}
|
|
42
61
|
: generic("bash", args),
|
|
43
|
-
eval: (args) =>
|
|
44
|
-
?
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
eval: (args) => {
|
|
63
|
+
const language = typeof args.language === "string" && args.language !== "" ? args.language : "js";
|
|
64
|
+
const summary = typeof args.summary === "string" && args.summary !== "" ? args.summary : "eval";
|
|
65
|
+
const name = `${EVAL_LANGUAGES[language] ?? language.toUpperCase()} Eval`;
|
|
66
|
+
const command = typeof args.code === "string" && args.code !== ""
|
|
67
|
+
? args.code
|
|
68
|
+
: ["eval", args.action, args.cell_id].filter((value) => typeof value === "string").join(" ");
|
|
69
|
+
// Read by the OmO Compatibility extension's `bash` header rule; plain shell cards lack them and keep the default header.
|
|
70
|
+
const metadata = { evalTitle: name, evalSubtitle: summary };
|
|
71
|
+
return { tool: "bash", input: { command, description: `${name}: ${summary}` }, title: summary, metadata };
|
|
72
|
+
},
|
|
73
|
+
bash_output: (args) => terminalTool("bash_output", args),
|
|
74
|
+
bash_input: (args) => terminalTool("bash_input", args),
|
|
75
|
+
kill_bash: (args) => terminalTool("kill_bash", args),
|
|
76
|
+
bash_resize: (args) => terminalTool("bash_resize", args),
|
|
50
77
|
ask_user_question: (args) => {
|
|
51
78
|
if (!Array.isArray(args.questions) || !args.questions.every(record))
|
|
52
79
|
return generic("ask_user_question", args);
|
|
@@ -67,6 +94,13 @@ export const toolMappers = {
|
|
|
67
94
|
return { tool: "task", input, title: typeof input.description === "string" ? input.description : "task" };
|
|
68
95
|
},
|
|
69
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* A failed result. Codemode leaves a failed eval cell's top-level isError false and sets
|
|
99
|
+
* details.isError instead (senpi-codemode src/tool/render-result.ts:42).
|
|
100
|
+
*/
|
|
101
|
+
export function toolFailed(result) {
|
|
102
|
+
return result.isError === true || (record(result.details) && result.details.isError === true);
|
|
103
|
+
}
|
|
70
104
|
/** Text blocks only; images and structured details are not tool output text. */
|
|
71
105
|
export function resultText(content) {
|
|
72
106
|
if (!Array.isArray(content))
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# OmO Compatibility
|
|
2
|
+
|
|
3
|
+
An OpenChamber extension that ships with antechamber. It changes how OpenChamber
|
|
4
|
+
displays some OmO tool calls, using only the display rules OpenChamber lets an
|
|
5
|
+
extension declare. It has no panel, page, service or permissions.
|
|
6
|
+
|
|
7
|
+
What it does today:
|
|
8
|
+
|
|
9
|
+
- **Eval cell headers.** OpenChamber 1.24 streams live output only for shell
|
|
10
|
+
cards, so antechamber shows OmO eval cells as shell cards. With this extension
|
|
11
|
+
their header reads `JS Eval` (or `Python Eval`) and the cell's summary instead
|
|
12
|
+
of "Shell Command" and the first line of code. Other shell cards keep their
|
|
13
|
+
normal header.
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- OpenChamber **1.24 or newer** (the first release with `contributes.tools`).
|
|
18
|
+
- antechamber as OpenChamber's backend. Without it the rules match nothing and
|
|
19
|
+
change nothing.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
In OpenChamber, open **Settings → Extensions → Add**:
|
|
24
|
+
|
|
25
|
+
- **Folder**, when OpenChamber runs on the machine where antechamber is
|
|
26
|
+
installed. `antechamber setup` prints the path:
|
|
27
|
+
`$(npm root -g)/antechamber/extensions/omo-compat` for an npm install, or
|
|
28
|
+
`<checkout>/extensions/omo-compat` from a source checkout. It needs no build.
|
|
29
|
+
- **URL**, from anywhere:
|
|
30
|
+
`https://github.com/eliottness/antechamber/releases/latest/download/antechamber-omo-compat.zip`.
|
|
31
|
+
Every GitHub release attaches this archive.
|
|
32
|
+
|
|
33
|
+
There is nothing to approve and no rail icon. Reload open chats after
|
|
34
|
+
installing so their cards pick up the new header.
|
|
35
|
+
|
|
36
|
+
For a server you reach over HTTP:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
curl -sX POST "$OC/api/guests" -H 'content-type: application/json' \
|
|
40
|
+
-d '{"path":"/abs/path/to/extensions/omo-compat"}'
|
|
41
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><title>OmO Compatibility</title><path d="M8 7 3 12l5 5"/><path d="m16 7 5 5-5 5"/><path d="M14 4l-4 16"/></svg>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "antechamber-omo-compat",
|
|
3
|
+
"version": "0.2.23",
|
|
4
|
+
"description": "OpenChamber extension: displays OmO tool calls the way OmO means them when OpenChamber runs on antechamber",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"openchamber": {
|
|
9
|
+
"apiVersion": 1,
|
|
10
|
+
"engines": {
|
|
11
|
+
"openchamber": ">=1.24.0"
|
|
12
|
+
},
|
|
13
|
+
"contributes": {
|
|
14
|
+
"panel": {
|
|
15
|
+
"id": "omo-compat",
|
|
16
|
+
"name": "OmO Compatibility",
|
|
17
|
+
"icon": "icon.svg"
|
|
18
|
+
},
|
|
19
|
+
"tools": [
|
|
20
|
+
{
|
|
21
|
+
"match": "bash",
|
|
22
|
+
"title": "{metadata.evalTitle}",
|
|
23
|
+
"subtitle": "{metadata.evalSubtitle}"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antechamber",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"description": "OpenCode-compatible HTTP/SSE server that lets OpenChamber drive the pi coding agent (and OmO) over RPC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
"extensions/omo-dag/service/main.js",
|
|
36
36
|
"extensions/omo-dag/README.md",
|
|
37
37
|
"extensions/omo-dag/docs/DESIGN.md",
|
|
38
|
+
"extensions/omo-compat/package.json",
|
|
39
|
+
"extensions/omo-compat/icon.svg",
|
|
40
|
+
"extensions/omo-compat/README.md",
|
|
38
41
|
"README.md",
|
|
39
42
|
"LICENSE",
|
|
40
43
|
"CHANGELOG.md"
|