@canonmsg/codex-plugin 0.18.9 → 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 +36 -1
- package/dist/host.js +64 -8
- 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 } 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;
|
|
@@ -17,6 +17,21 @@ export declare function buildCodexInitialSessionState(input: {
|
|
|
17
17
|
permissionMode?: string;
|
|
18
18
|
effort?: string | null;
|
|
19
19
|
}): HostSessionState;
|
|
20
|
+
export declare function buildCodexLiveSessionConfig(input: {
|
|
21
|
+
model?: string;
|
|
22
|
+
permissionMode?: string;
|
|
23
|
+
effort?: string;
|
|
24
|
+
workspaceId?: string | null;
|
|
25
|
+
executionMode: ExecutionEnvironmentMode;
|
|
26
|
+
executionBranch?: string | null;
|
|
27
|
+
}): {
|
|
28
|
+
executionMode: ExecutionEnvironmentMode;
|
|
29
|
+
executionBranch: string | null;
|
|
30
|
+
workspaceId?: string | undefined;
|
|
31
|
+
effort?: string | undefined;
|
|
32
|
+
permissionMode?: string | undefined;
|
|
33
|
+
model?: string | undefined;
|
|
34
|
+
};
|
|
20
35
|
/** GPT reasoning-effort levels, applied next turn via model_reasoning_effort. */
|
|
21
36
|
export declare const CODEX_EFFORT_OPTIONS: readonly [{
|
|
22
37
|
readonly value: "minimal";
|
|
@@ -34,6 +49,26 @@ export declare const CODEX_EFFORT_OPTIONS: readonly [{
|
|
|
34
49
|
readonly value: "xhigh";
|
|
35
50
|
readonly label: "Extra high";
|
|
36
51
|
}];
|
|
52
|
+
export declare const CODEX_SESSION_CONFIG_FIELDS: readonly ["permissionMode", "effort"];
|
|
37
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;
|
|
38
73
|
export declare function main(): Promise<void>;
|
|
39
74
|
export {};
|
package/dist/host.js
CHANGED
|
@@ -61,6 +61,16 @@ export function buildCodexInitialSessionState(input) {
|
|
|
61
61
|
state: 'idle',
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
export function buildCodexLiveSessionConfig(input) {
|
|
65
|
+
return {
|
|
66
|
+
...(input.model ? { model: input.model } : {}),
|
|
67
|
+
...(input.permissionMode ? { permissionMode: input.permissionMode } : {}),
|
|
68
|
+
...(input.effort ? { effort: input.effort } : {}),
|
|
69
|
+
...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),
|
|
70
|
+
executionMode: input.executionMode,
|
|
71
|
+
executionBranch: input.executionBranch ?? null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
64
74
|
const MAX_SESSIONS = 12;
|
|
65
75
|
const IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
66
76
|
const HEARTBEAT_MS = 30_000;
|
|
@@ -85,6 +95,7 @@ export const CODEX_EFFORT_OPTIONS = [
|
|
|
85
95
|
{ value: 'xhigh', label: 'Extra high' },
|
|
86
96
|
];
|
|
87
97
|
const CODEX_EFFORT_VALUES = new Set(CODEX_EFFORT_OPTIONS.map((option) => option.value));
|
|
98
|
+
export const CODEX_SESSION_CONFIG_FIELDS = ['permissionMode', 'effort'];
|
|
88
99
|
const MAX_CODEX_SKILL_COMMAND_CHOICES = 50;
|
|
89
100
|
export function buildCodexSkillCommands(skills) {
|
|
90
101
|
return skills
|
|
@@ -115,7 +126,7 @@ export function buildCodexSkillCommands(skills) {
|
|
|
115
126
|
};
|
|
116
127
|
});
|
|
117
128
|
}
|
|
118
|
-
function buildCodexRuntimeDescriptor(input) {
|
|
129
|
+
export function buildCodexRuntimeDescriptor(input) {
|
|
119
130
|
const commands = [
|
|
120
131
|
{
|
|
121
132
|
id: 'runtime-status',
|
|
@@ -135,6 +146,20 @@ function buildCodexRuntimeDescriptor(input) {
|
|
|
135
146
|
RUNTIME_STOP_ACTION,
|
|
136
147
|
RUNTIME_STOP_AND_DROP_ACTION,
|
|
137
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
|
+
}
|
|
138
163
|
const skillCommands = input.skills?.length ? buildCodexSkillCommands(input.skills) : [];
|
|
139
164
|
if (skillCommands.length) {
|
|
140
165
|
commands.push(...skillCommands);
|
|
@@ -224,7 +249,7 @@ async function loadSessionConfig(conversationId, agentId) {
|
|
|
224
249
|
return loadHostSessionConfig({
|
|
225
250
|
conversationId,
|
|
226
251
|
agentId,
|
|
227
|
-
extraStringFields:
|
|
252
|
+
extraStringFields: CODEX_SESSION_CONFIG_FIELDS,
|
|
228
253
|
});
|
|
229
254
|
}
|
|
230
255
|
function resolveSessionExecutionMode(config) {
|
|
@@ -1731,6 +1756,7 @@ export async function main() {
|
|
|
1731
1756
|
defaultPermissionMode: codexPermissionEnvelope.defaultPermissionMode,
|
|
1732
1757
|
presentation: runtimePresentation,
|
|
1733
1758
|
supportsPlanMode: useAppServer,
|
|
1759
|
+
supportsCompact: useAppServer,
|
|
1734
1760
|
supportsRichCards: useAppServer,
|
|
1735
1761
|
skills: codexSkills,
|
|
1736
1762
|
}),
|
|
@@ -1827,6 +1853,34 @@ export async function main() {
|
|
|
1827
1853
|
clearStreaming(conversationId);
|
|
1828
1854
|
typingSignals.clear(conversationId).catch(() => { });
|
|
1829
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
|
+
}
|
|
1830
1884
|
const controlPoller = createCodexControlPoller({
|
|
1831
1885
|
rtdb,
|
|
1832
1886
|
agentId,
|
|
@@ -1837,6 +1891,7 @@ export async function main() {
|
|
|
1837
1891
|
applySessionControl(conversationId, control);
|
|
1838
1892
|
},
|
|
1839
1893
|
onSignal: handleControlSignal,
|
|
1894
|
+
onPrimitive: handleControlPrimitive,
|
|
1840
1895
|
onError: (error) => {
|
|
1841
1896
|
// The legacy loop ignored transient RTDB failures; keep read/consume
|
|
1842
1897
|
// errors quiet but surface handler failures.
|
|
@@ -1872,18 +1927,19 @@ export async function main() {
|
|
|
1872
1927
|
runtime: runtimeDescriptor,
|
|
1873
1928
|
workspaceOptions,
|
|
1874
1929
|
defaultCwd: workingDir,
|
|
1875
|
-
extraSessionConfigFields:
|
|
1930
|
+
extraSessionConfigFields: CODEX_SESSION_CONFIG_FIELDS,
|
|
1876
1931
|
liveSessionConfigByConversation: new Map(Array.from(sessions.values()).map((session) => {
|
|
1877
1932
|
const workspaceId = resolveWorkspaceIdForBaseCwd(session.environment.baseCwd);
|
|
1878
1933
|
return [
|
|
1879
1934
|
session.conversationId,
|
|
1880
|
-
{
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1935
|
+
buildCodexLiveSessionConfig({
|
|
1936
|
+
model: session.state.model,
|
|
1937
|
+
permissionMode: session.state.permissionMode,
|
|
1938
|
+
effort: session.state.effort,
|
|
1939
|
+
workspaceId,
|
|
1884
1940
|
executionMode: session.environment.mode,
|
|
1885
1941
|
executionBranch: session.environment.branch ?? null,
|
|
1886
|
-
},
|
|
1942
|
+
}),
|
|
1887
1943
|
];
|
|
1888
1944
|
})),
|
|
1889
1945
|
}).catch((error) => {
|