@canonmsg/codex-plugin 0.18.10 → 0.18.11
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/app-server-adapter.d.ts +1 -0
- package/dist/app-server-adapter.js +9 -0
- package/dist/control-channel.d.ts +10 -3
- package/dist/control-channel.js +10 -2
- package/dist/host.d.ts +20 -1
- package/dist/host.js +45 -1
- package/package.json +1 -1
|
@@ -64,6 +64,7 @@ export declare class CodexAppServerAdapter {
|
|
|
64
64
|
setReasoningEffort(effort: string | null): void;
|
|
65
65
|
isRunning(): boolean;
|
|
66
66
|
interrupt(): Promise<void>;
|
|
67
|
+
compactThread(): Promise<void>;
|
|
67
68
|
close(): void;
|
|
68
69
|
runTurn(prompt: string, onEvent: (event: CodexEvent) => void, onLog?: (line: string) => void, imagePaths?: readonly string[], _extraAddDirs?: readonly string[], options?: CodexRunTurnOptions): Promise<CodexTurnResult>;
|
|
69
70
|
private resolveApprovalPolicy;
|
|
@@ -83,6 +83,15 @@ export class CodexAppServerAdapter {
|
|
|
83
83
|
turnId: this.currentTurnId,
|
|
84
84
|
}).catch(() => { });
|
|
85
85
|
}
|
|
86
|
+
async compactThread() {
|
|
87
|
+
if (!this.threadId) {
|
|
88
|
+
throw new Error('No Codex thread to compact');
|
|
89
|
+
}
|
|
90
|
+
await this.ensureStarted();
|
|
91
|
+
await this.sendRequest('thread/compact/start', {
|
|
92
|
+
threadId: this.threadId,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
86
95
|
close() {
|
|
87
96
|
this.child?.kill('SIGTERM');
|
|
88
97
|
this.child = null;
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* codex host characterization profile (the "codex host profile" describe
|
|
6
6
|
* block in core's control-poller.test.ts is the contract):
|
|
7
7
|
*
|
|
8
|
-
* - Keys: `session` + `signal
|
|
9
|
-
* conversation, conversations polled one
|
|
8
|
+
* - Keys: `session` + `signal`, plus `primitive` when a primitive handler is
|
|
9
|
+
* configured; read sequentially per conversation, conversations polled one
|
|
10
|
+
* at a time.
|
|
10
11
|
* - Cadence: immediate first cycle, then active/idle delays + jitter with
|
|
11
12
|
* the activity probe sampled BEFORE the cycle runs.
|
|
12
13
|
* - Session controls are always consumed once newer (default consume), even
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
* - Dedupe is primed eagerly via `poller.baseline([conversationId])` at
|
|
16
17
|
* session creation — the second legacy poll site.
|
|
17
18
|
*/
|
|
18
|
-
import { ControlChannelPoller, type ControlChannelRTDB, type ControlHandlerResult, type ControlPollerError, type ControlSessionEvent, type ControlSignalEvent } from '@canonmsg/core';
|
|
19
|
+
import { ControlChannelPoller, type ControlChannelRTDB, type ControlHandlerResult, type ControlPollerError, type ControlPrimitiveEvent, type ControlSessionEvent, type ControlSignalEvent } from '@canonmsg/core';
|
|
19
20
|
export declare const CONTROL_POLL_MS = 2000;
|
|
20
21
|
export declare const IDLE_CONTROL_POLL_MS = 10000;
|
|
21
22
|
export declare const CONTROL_POLL_JITTER_MS = 1000;
|
|
@@ -38,6 +39,12 @@ export interface CodexControlChannelInput {
|
|
|
38
39
|
* node in place; thrown errors also leave it (consumeOnError stays false).
|
|
39
40
|
*/
|
|
40
41
|
onSignal: (event: ControlSignalEvent) => Promise<ControlHandlerResult> | ControlHandlerResult;
|
|
42
|
+
/**
|
|
43
|
+
* Handles a newer `/primitive` node. Primitive commands are consumed by
|
|
44
|
+
* default after the handler resolves or throws, matching core's command
|
|
45
|
+
* semantics so one failed command cannot replay forever.
|
|
46
|
+
*/
|
|
47
|
+
onPrimitive?: (event: ControlPrimitiveEvent) => Promise<ControlHandlerResult> | ControlHandlerResult;
|
|
41
48
|
onError?: (error: ControlPollerError) => void;
|
|
42
49
|
/** Injectable jitter source (tests). */
|
|
43
50
|
random?: () => number;
|
package/dist/control-channel.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* codex host characterization profile (the "codex host profile" describe
|
|
6
6
|
* block in core's control-poller.test.ts is the contract):
|
|
7
7
|
*
|
|
8
|
-
* - Keys: `session` + `signal
|
|
9
|
-
* conversation, conversations polled one
|
|
8
|
+
* - Keys: `session` + `signal`, plus `primitive` when a primitive handler is
|
|
9
|
+
* configured; read sequentially per conversation, conversations polled one
|
|
10
|
+
* at a time.
|
|
10
11
|
* - Cadence: immediate first cycle, then active/idle delays + jitter with
|
|
11
12
|
* the activity probe sampled BEFORE the cycle runs.
|
|
12
13
|
* - Session controls are always consumed once newer (default consume), even
|
|
@@ -41,6 +42,13 @@ export function createCodexControlPoller(input) {
|
|
|
41
42
|
signal: {
|
|
42
43
|
handle: input.onSignal,
|
|
43
44
|
},
|
|
45
|
+
...(input.onPrimitive
|
|
46
|
+
? {
|
|
47
|
+
primitive: {
|
|
48
|
+
handle: input.onPrimitive,
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
: {}),
|
|
44
52
|
},
|
|
45
53
|
...(input.onError ? { onError: input.onError } : {}),
|
|
46
54
|
...(input.random ? { random: input.random } : {}),
|
package/dist/host.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { type CanonRuntimeCommandDescriptor, type ExecutionEnvironmentMode } from '@canonmsg/core';
|
|
2
|
+
import { type CanonRuntimeCommandDescriptor, type CanonRuntimeDescriptor, type CanonRuntimePresentationPolicy, type ExecutionEnvironmentMode, type WorkspaceOption, type CanonWorkspaceRootMetadata } from '@canonmsg/core';
|
|
3
3
|
import { type CodexSkillMetadata } from './app-server-adapter.js';
|
|
4
4
|
interface HostSessionState {
|
|
5
5
|
lastError?: string;
|
|
@@ -51,5 +51,24 @@ export declare const CODEX_EFFORT_OPTIONS: readonly [{
|
|
|
51
51
|
}];
|
|
52
52
|
export declare const CODEX_SESSION_CONFIG_FIELDS: readonly ["permissionMode", "effort"];
|
|
53
53
|
export declare function buildCodexSkillCommands(skills: ReadonlyArray<CodexSkillMetadata>): CanonRuntimeCommandDescriptor[];
|
|
54
|
+
export declare function buildCodexRuntimeDescriptor(input: {
|
|
55
|
+
models: Array<{
|
|
56
|
+
value: string;
|
|
57
|
+
label: string;
|
|
58
|
+
}>;
|
|
59
|
+
workspaces: WorkspaceOption[];
|
|
60
|
+
workspaceRoots?: CanonWorkspaceRootMetadata[];
|
|
61
|
+
executionModes: ExecutionEnvironmentMode[];
|
|
62
|
+
permissionModes: Array<{
|
|
63
|
+
value: string;
|
|
64
|
+
label: string;
|
|
65
|
+
}>;
|
|
66
|
+
defaultPermissionMode?: string;
|
|
67
|
+
presentation?: CanonRuntimePresentationPolicy;
|
|
68
|
+
supportsPlanMode: boolean;
|
|
69
|
+
supportsCompact?: boolean;
|
|
70
|
+
supportsRichCards?: boolean;
|
|
71
|
+
skills?: ReadonlyArray<CodexSkillMetadata>;
|
|
72
|
+
}): CanonRuntimeDescriptor;
|
|
54
73
|
export declare function main(): Promise<void>;
|
|
55
74
|
export {};
|
package/dist/host.js
CHANGED
|
@@ -126,7 +126,7 @@ export function buildCodexSkillCommands(skills) {
|
|
|
126
126
|
};
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
-
function buildCodexRuntimeDescriptor(input) {
|
|
129
|
+
export function buildCodexRuntimeDescriptor(input) {
|
|
130
130
|
const commands = [
|
|
131
131
|
{
|
|
132
132
|
id: 'runtime-status',
|
|
@@ -146,6 +146,20 @@ function buildCodexRuntimeDescriptor(input) {
|
|
|
146
146
|
RUNTIME_STOP_ACTION,
|
|
147
147
|
RUNTIME_STOP_AND_DROP_ACTION,
|
|
148
148
|
];
|
|
149
|
+
if (input.supportsCompact) {
|
|
150
|
+
commands.push({
|
|
151
|
+
id: 'codex-compact-context',
|
|
152
|
+
label: 'Compact',
|
|
153
|
+
description: 'Ask Codex to compact the current thread context.',
|
|
154
|
+
primitive: 'context.compact',
|
|
155
|
+
aliases: ['compact'],
|
|
156
|
+
category: 'session',
|
|
157
|
+
placements: ['composer_slash', 'command_palette'],
|
|
158
|
+
availability: ['idle'],
|
|
159
|
+
ownerOnly: true,
|
|
160
|
+
dispatch: { kind: 'primitive', primitive: 'context.compact' },
|
|
161
|
+
});
|
|
162
|
+
}
|
|
149
163
|
const skillCommands = input.skills?.length ? buildCodexSkillCommands(input.skills) : [];
|
|
150
164
|
if (skillCommands.length) {
|
|
151
165
|
commands.push(...skillCommands);
|
|
@@ -1742,6 +1756,7 @@ export async function main() {
|
|
|
1742
1756
|
defaultPermissionMode: codexPermissionEnvelope.defaultPermissionMode,
|
|
1743
1757
|
presentation: runtimePresentation,
|
|
1744
1758
|
supportsPlanMode: useAppServer,
|
|
1759
|
+
supportsCompact: useAppServer,
|
|
1745
1760
|
supportsRichCards: useAppServer,
|
|
1746
1761
|
skills: codexSkills,
|
|
1747
1762
|
}),
|
|
@@ -1838,6 +1853,34 @@ export async function main() {
|
|
|
1838
1853
|
clearStreaming(conversationId);
|
|
1839
1854
|
typingSignals.clear(conversationId).catch(() => { });
|
|
1840
1855
|
}
|
|
1856
|
+
async function handleControlPrimitive(event) {
|
|
1857
|
+
const { conversationId, value } = event;
|
|
1858
|
+
const primitiveId = typeof value.id === 'string' ? value.id : '';
|
|
1859
|
+
if (primitiveId !== 'context.compact') {
|
|
1860
|
+
console.error(`[canon-codex] [${conversationId.slice(0, 8)}] Ignoring unsupported primitive (${primitiveId || 'unknown'})`);
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
const session = sessions.get(conversationId);
|
|
1864
|
+
if (!session || session.closed) {
|
|
1865
|
+
console.error(`[canon-codex] [${conversationId.slice(0, 8)}] Cannot compact context: no live Codex session`);
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
if (!(session.adapter instanceof CodexAppServerAdapter)) {
|
|
1869
|
+
console.error(`[canon-codex] [${conversationId.slice(0, 8)}] Cannot compact context: compact is only available for Codex app-server sessions`);
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
try {
|
|
1873
|
+
await session.adapter.compactThread();
|
|
1874
|
+
console.error(`[canon-codex] [${conversationId.slice(0, 8)}] Compact requested`);
|
|
1875
|
+
writeState(session);
|
|
1876
|
+
}
|
|
1877
|
+
catch (error) {
|
|
1878
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1879
|
+
session.state.lastError = `Could not compact Codex context: ${message}`;
|
|
1880
|
+
console.error(`[canon-codex] [${conversationId.slice(0, 8)}] ${session.state.lastError}`);
|
|
1881
|
+
writeState(session);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1841
1884
|
const controlPoller = createCodexControlPoller({
|
|
1842
1885
|
rtdb,
|
|
1843
1886
|
agentId,
|
|
@@ -1848,6 +1891,7 @@ export async function main() {
|
|
|
1848
1891
|
applySessionControl(conversationId, control);
|
|
1849
1892
|
},
|
|
1850
1893
|
onSignal: handleControlSignal,
|
|
1894
|
+
onPrimitive: handleControlPrimitive,
|
|
1851
1895
|
onError: (error) => {
|
|
1852
1896
|
// The legacy loop ignored transient RTDB failures; keep read/consume
|
|
1853
1897
|
// errors quiet but surface handler failures.
|