@canonmsg/codex-plugin 0.19.1 → 0.19.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/dist/adapter.d.ts +1 -0
- package/dist/app-server-adapter.d.ts +3 -0
- package/dist/app-server-adapter.js +38 -2
- package/dist/host.js +37 -3
- package/dist/turn-activity.d.ts +10 -0
- package/dist/turn-activity.js +8 -0
- package/package.json +4 -4
package/dist/adapter.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ export declare class CodexAppServerAdapter {
|
|
|
39
39
|
private skillsCache;
|
|
40
40
|
private messageTextByItem;
|
|
41
41
|
private planText;
|
|
42
|
+
private traceTurnEpochMs;
|
|
42
43
|
constructor(opts: {
|
|
43
44
|
cwd: string;
|
|
44
45
|
threadId?: string | null;
|
|
@@ -96,4 +97,6 @@ export declare class CodexAppServerAdapter {
|
|
|
96
97
|
private clearActiveTurn;
|
|
97
98
|
private sendRequest;
|
|
98
99
|
private write;
|
|
100
|
+
private trace;
|
|
101
|
+
private traceLine;
|
|
99
102
|
}
|
|
@@ -31,6 +31,7 @@ export class CodexAppServerAdapter {
|
|
|
31
31
|
skillsCache = null;
|
|
32
32
|
messageTextByItem = new Map();
|
|
33
33
|
planText = '';
|
|
34
|
+
traceTurnEpochMs = null;
|
|
34
35
|
constructor(opts) {
|
|
35
36
|
this.cwd = opts.cwd;
|
|
36
37
|
this.threadId = opts.threadId ?? null;
|
|
@@ -117,6 +118,8 @@ export class CodexAppServerAdapter {
|
|
|
117
118
|
this.interrupted = false;
|
|
118
119
|
this.messageTextByItem.clear();
|
|
119
120
|
this.planText = '';
|
|
121
|
+
this.traceTurnEpochMs = Date.now();
|
|
122
|
+
this.trace('turn/run begin');
|
|
120
123
|
try {
|
|
121
124
|
if (this.threadId && this.loadedThreadId !== this.threadId) {
|
|
122
125
|
const resumed = await this.sendRequest('thread/resume', {
|
|
@@ -158,9 +161,11 @@ export class CodexAppServerAdapter {
|
|
|
158
161
|
this.currentTurnReject = reject;
|
|
159
162
|
});
|
|
160
163
|
turnPromise.catch(() => { });
|
|
164
|
+
const turnInput = await this.buildTurnInput(prompt, imagePaths);
|
|
165
|
+
this.trace('turn/start sent');
|
|
161
166
|
const turnStarted = await this.sendRequest('turn/start', {
|
|
162
167
|
threadId: this.threadId,
|
|
163
|
-
input:
|
|
168
|
+
input: turnInput,
|
|
164
169
|
...(this.model ? { model: this.model } : {}),
|
|
165
170
|
...this.sandboxPolicyPayload(_extraAddDirs),
|
|
166
171
|
collaborationMode: {
|
|
@@ -172,6 +177,7 @@ export class CodexAppServerAdapter {
|
|
|
172
177
|
},
|
|
173
178
|
},
|
|
174
179
|
});
|
|
180
|
+
this.trace('turn/start ack');
|
|
175
181
|
const turn = turnStarted.turn;
|
|
176
182
|
if (this.currentTurnResolve) {
|
|
177
183
|
this.currentTurnId = readString(turn, 'id') ?? null;
|
|
@@ -322,6 +328,7 @@ export class CodexAppServerAdapter {
|
|
|
322
328
|
const message = parseJson(line);
|
|
323
329
|
if (!message)
|
|
324
330
|
return;
|
|
331
|
+
this.traceLine(line, message);
|
|
325
332
|
if ('id' in message && ('result' in message || 'error' in message) && !('method' in message)) {
|
|
326
333
|
const id = Number(message.id);
|
|
327
334
|
const pending = this.pending.get(id);
|
|
@@ -395,7 +402,7 @@ export class CodexAppServerAdapter {
|
|
|
395
402
|
this.messageTextByItem.set(itemId, next);
|
|
396
403
|
this.currentFinalMessage = this.joinedAgentMessageText() ?? this.currentFinalMessage;
|
|
397
404
|
if (next.trim())
|
|
398
|
-
this.currentOnEvent?.({ type: 'message', text: next, itemId });
|
|
405
|
+
this.currentOnEvent?.({ type: 'message', text: next, delta, itemId });
|
|
399
406
|
return;
|
|
400
407
|
}
|
|
401
408
|
if (method === 'turn/plan/updated') {
|
|
@@ -467,6 +474,7 @@ export class CodexAppServerAdapter {
|
|
|
467
474
|
return;
|
|
468
475
|
}
|
|
469
476
|
if (method === 'turn/completed') {
|
|
477
|
+
this.trace('turn/completed notification');
|
|
470
478
|
const turn = params.turn;
|
|
471
479
|
const status = turn?.status;
|
|
472
480
|
if (isRecord(status) && status.type === 'failed') {
|
|
@@ -530,6 +538,7 @@ export class CodexAppServerAdapter {
|
|
|
530
538
|
this.currentErrorText = null;
|
|
531
539
|
this.messageTextByItem.clear();
|
|
532
540
|
this.planText = '';
|
|
541
|
+
this.traceTurnEpochMs = null;
|
|
533
542
|
}
|
|
534
543
|
sendRequest(method, params) {
|
|
535
544
|
const id = this.requestSeq++;
|
|
@@ -549,6 +558,33 @@ export class CodexAppServerAdapter {
|
|
|
549
558
|
throw new Error('Codex app-server is not running');
|
|
550
559
|
this.child.stdin.write(`${JSON.stringify(message)}\n`);
|
|
551
560
|
}
|
|
561
|
+
trace(message) {
|
|
562
|
+
if (!isCodexTraceEnabled())
|
|
563
|
+
return;
|
|
564
|
+
const elapsedMs = this.traceTurnEpochMs === null ? 0 : Date.now() - this.traceTurnEpochMs;
|
|
565
|
+
console.error(`[canon-codex-trace] +${elapsedMs}ms ${message}`);
|
|
566
|
+
}
|
|
567
|
+
traceLine(line, message) {
|
|
568
|
+
if (!isCodexTraceEnabled())
|
|
569
|
+
return;
|
|
570
|
+
const method = typeof message.method === 'string' ? message.method : null;
|
|
571
|
+
if (!method) {
|
|
572
|
+
const id = 'id' in message ? ` id=${String(message.id)}` : '';
|
|
573
|
+
this.trace(`line bytes=${line.length} response${id}`);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (method === 'item/agentMessage/delta') {
|
|
577
|
+
const params = isRecord(message.params) ? message.params : {};
|
|
578
|
+
const itemId = readString(params, 'itemId') ?? 'agent-message';
|
|
579
|
+
const delta = readRawString(params, 'delta') ?? '';
|
|
580
|
+
this.trace(`line bytes=${line.length} method=${method} itemId=${itemId} deltaLen=${delta.length}`);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
this.trace(`line bytes=${line.length} method=${method}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function isCodexTraceEnabled() {
|
|
587
|
+
return process.env.CANON_CODEX_TRACE_EVENTS === '1';
|
|
552
588
|
}
|
|
553
589
|
function parseJson(line) {
|
|
554
590
|
try {
|
package/dist/host.js
CHANGED
|
@@ -26,7 +26,7 @@ import { detectCodexCliVersion } from './codex-cli-version.js';
|
|
|
26
26
|
import { buildCodexModelGuardMessage, formatCodexTurnFailure, isRecoverableCodexThreadError, } from './error-format.js';
|
|
27
27
|
import { attachCodexControlNotifications } from './control-channel.js';
|
|
28
28
|
import { runCli } from './cli-entry.js';
|
|
29
|
-
import { beginCommandBlock, claimCommandBlock, createCommandBlockTracker, hasSpeechSegmentText,
|
|
29
|
+
import { beginCommandBlock, applyCodexMessageToStreamingOutput, claimCommandBlock, createCommandBlockTracker, hasSpeechSegmentText, } from './turn-activity.js';
|
|
30
30
|
const HELP = `canon-codex — run a local Codex agent host for Canon
|
|
31
31
|
|
|
32
32
|
USAGE
|
|
@@ -108,6 +108,35 @@ const CODEX_RUNTIME_CAPABILITIES = {
|
|
|
108
108
|
supportsQueue: true,
|
|
109
109
|
supportsNonFinalPermanentMessages: false,
|
|
110
110
|
};
|
|
111
|
+
function isCodexTraceEnabled() {
|
|
112
|
+
return process.env.CANON_CODEX_TRACE_EVENTS === '1';
|
|
113
|
+
}
|
|
114
|
+
function createCodexTracePort(port) {
|
|
115
|
+
if (!isCodexTraceEnabled())
|
|
116
|
+
return port;
|
|
117
|
+
return new Proxy(port, {
|
|
118
|
+
get(target, property, receiver) {
|
|
119
|
+
if (property !== 'publishStreaming') {
|
|
120
|
+
return Reflect.get(target, property, receiver);
|
|
121
|
+
}
|
|
122
|
+
return async (input) => {
|
|
123
|
+
const startedAt = Date.now();
|
|
124
|
+
const textLength = typeof input.text === 'string' ? input.text.length : 0;
|
|
125
|
+
console.error(`[canon-codex-trace] publishStreaming sent conversation=${input.conversationId} turn=${input.turnId ?? input.messageId ?? 'unknown'} textLen=${textLength}`);
|
|
126
|
+
try {
|
|
127
|
+
const result = await target.publishStreaming(input);
|
|
128
|
+
console.error(`[canon-codex-trace] publishStreaming ack conversation=${input.conversationId} ackMs=${Date.now() - startedAt}`);
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
133
|
+
console.error(`[canon-codex-trace] publishStreaming error conversation=${input.conversationId} ackMs=${Date.now() - startedAt} error=${message}`);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
111
140
|
// This host process resolves and locks exactly one agent profile. The lock
|
|
112
141
|
// handle returned by resolveCanonAgent is held here so the top-level runCli
|
|
113
142
|
// error handler (outside main's scope) can release it on a failed start —
|
|
@@ -554,7 +583,7 @@ export async function main() {
|
|
|
554
583
|
});
|
|
555
584
|
// The BridgeClient's zod-derived result shapes mirror the core wire types
|
|
556
585
|
// structurally; the port pins the strong types the host machinery uses.
|
|
557
|
-
const port = bridge.client;
|
|
586
|
+
const port = createCodexTracePort(bridge.client);
|
|
558
587
|
bridge.client.onProtocolError((error) => {
|
|
559
588
|
console.error(`[canon-codex] Bridge protocol error: ${error.message}`);
|
|
560
589
|
});
|
|
@@ -976,7 +1005,12 @@ export async function main() {
|
|
|
976
1005
|
session.turnState = 'streaming';
|
|
977
1006
|
writers.writeTurn();
|
|
978
1007
|
writers.stopVisibleWorkSignal();
|
|
979
|
-
writers.streamingOutput
|
|
1008
|
+
applyCodexMessageToStreamingOutput(writers.streamingOutput, {
|
|
1009
|
+
turnId: session.currentTurnId,
|
|
1010
|
+
itemId: event.itemId,
|
|
1011
|
+
text: event.text,
|
|
1012
|
+
delta: event.delta,
|
|
1013
|
+
});
|
|
980
1014
|
return;
|
|
981
1015
|
}
|
|
982
1016
|
if (event.type === 'plan.updated') {
|
package/dist/turn-activity.d.ts
CHANGED
|
@@ -24,6 +24,16 @@ export declare function createCommandBlockTracker(): CommandBlockTracker;
|
|
|
24
24
|
* only owns the codex id scheme.
|
|
25
25
|
*/
|
|
26
26
|
export declare function textSegmentBlockId(turnId: string | null | undefined, itemId?: string): string;
|
|
27
|
+
export interface CodexTextSegmentOutput {
|
|
28
|
+
appendTextSegmentDelta(id: string, delta: string): void;
|
|
29
|
+
replaceTextSegmentSnapshot(id: string, text: string): void;
|
|
30
|
+
}
|
|
31
|
+
export declare function applyCodexMessageToStreamingOutput(output: CodexTextSegmentOutput, input: {
|
|
32
|
+
turnId: string | null | undefined;
|
|
33
|
+
itemId?: string;
|
|
34
|
+
text: string;
|
|
35
|
+
delta?: string;
|
|
36
|
+
}): void;
|
|
27
37
|
export declare function beginCommandBlock(tracker: CommandBlockTracker, input: {
|
|
28
38
|
turnId: string | null | undefined;
|
|
29
39
|
command: string;
|
package/dist/turn-activity.js
CHANGED
|
@@ -27,6 +27,14 @@ function normalizeOptionalString(value) {
|
|
|
27
27
|
export function textSegmentBlockId(turnId, itemId) {
|
|
28
28
|
return `message:${turnId ?? 'turn'}:${normalizeOptionalString(itemId) ?? 'latest'}`;
|
|
29
29
|
}
|
|
30
|
+
export function applyCodexMessageToStreamingOutput(output, input) {
|
|
31
|
+
const segmentId = textSegmentBlockId(input.turnId, input.itemId);
|
|
32
|
+
if (input.delta !== undefined) {
|
|
33
|
+
output.appendTextSegmentDelta(segmentId, input.delta);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
output.replaceTextSegmentSnapshot(segmentId, input.text);
|
|
37
|
+
}
|
|
30
38
|
function nextCommandBlockId(tracker, turnId, itemId) {
|
|
31
39
|
const stableTurnId = turnId ?? 'turn';
|
|
32
40
|
if (itemId)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/codex-plugin",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.2",
|
|
4
4
|
"description": "Canon host integration for Codex CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"prepack": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@canonmsg/agent-host": "^0.
|
|
33
|
-
"@canonmsg/agent-sdk": "^3.4.
|
|
32
|
+
"@canonmsg/agent-host": "^0.4.0",
|
|
33
|
+
"@canonmsg/agent-sdk": "^3.4.4",
|
|
34
34
|
"@canonmsg/backend-contracts": "^1.8.1",
|
|
35
35
|
"@canonmsg/bridge": "^0.2.1",
|
|
36
|
-
"@canonmsg/core": "^3.
|
|
36
|
+
"@canonmsg/core": "^3.2.0",
|
|
37
37
|
"@canonmsg/framework": "^0.2.1"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|