remote-codex 0.11.19 → 0.11.21
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/apps/relay-server/dist/index.js +48 -1
- package/apps/supervisor-api/dist/index.js +27999 -4
- package/apps/supervisor-web/dist/assets/index-BfspE5mQ.js +5 -0
- package/apps/supervisor-web/dist/assets/index-BmBS1Wzk.css +1 -0
- package/apps/supervisor-web/dist/assets/thread-ui-CDgAOcDh.js +3631 -0
- package/apps/supervisor-web/dist/index.html +3 -3
- package/package.json +1 -39
- package/packages/agent-runtime/src/types.ts +3 -1
- package/packages/claude/src/runtimeAdapter.test.ts +31 -1
- package/packages/claude/src/runtimeAdapter.ts +104 -24
- package/packages/codex/src/appServerManager.test.ts +2 -1
- package/packages/codex/src/historyItems.test.ts +26 -0
- package/packages/codex/src/historyItems.ts +17 -0
- package/packages/codex/src/runtimeAdapter.ts +1 -1
- package/packages/db/src/repositories.ts +0 -123
- package/packages/db/src/schema.ts +1 -334
- package/packages/opencode/src/runtimeAdapter.test.ts +13 -1
- package/packages/opencode/src/runtimeAdapter.ts +1 -2
- package/packages/shared/src/index.ts +4 -1
- package/apps/supervisor-api/dist/chunk-IZBNFCMP.js +0 -29346
- package/apps/supervisor-api/dist/worker-index.d.ts +0 -2
- package/apps/supervisor-api/dist/worker-index.js +0 -197
- package/apps/supervisor-web/dist/assets/index-CUnlRID-.js +0 -6
- package/apps/supervisor-web/dist/assets/index-D3I41SIH.css +0 -1
- package/apps/supervisor-web/dist/assets/thread-ui-TBhog-RK.js +0 -3614
- package/packages/db/migrations/0018_control_plane.sql +0 -129
- package/packages/db/migrations/0019_control_plane_projects.sql +0 -19
- package/packages/db/migrations/0020_control_workspace_status.sql +0 -1
- package/packages/db/migrations/0021_control_sandbox_lifecycle_fields.sql +0 -3
- package/packages/db/migrations/0022_control_sandbox_resource_profile.sql +0 -1
- package/packages/db/migrations/0023_control_usage_import_state.sql +0 -18
- package/packages/db/migrations/0024_control_auth.sql +0 -23
- package/packages/db/migrations/0025_control_harness_credentials.sql +0 -29
- package/packages/db/migrations/0026_control_harness_usage_events.sql +0 -27
- package/packages/db/migrations/0027_harness_job_watches.sql +0 -24
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Remote Codex Supervisor</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-BfspE5mQ.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="/assets/react-vendor-CgLzZcV4.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/ui-vendor-CeKGesq3.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/graph-vendor-DVPtkh3h.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/terminal-vendor-B365Go3Z.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/markdown-vendor-BQJfKm05.js">
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/thread-ui-
|
|
13
|
+
<link rel="modulepreload" crossorigin href="/assets/thread-ui-CDgAOcDh.js">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/graph-vendor-C5ap-Sga.css">
|
|
15
15
|
<link rel="stylesheet" crossorigin href="/assets/terminal-vendor-Beg8tuEN.css">
|
|
16
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BmBS1Wzk.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body class="bg-stone-950">
|
|
19
19
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remote-codex",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.21",
|
|
4
4
|
"description": "Local web supervisor for Codex workspaces and threads.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -40,44 +40,8 @@
|
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"dev": "concurrently -k -n api,web -c blue,green \"pnpm --filter @remote-codex/supervisor-api dev\" \"pnpm --filter @remote-codex/supervisor-web dev\"",
|
|
43
|
-
"dev:control-plane": "pnpm --filter @remote-codex/control-plane-api dev",
|
|
44
43
|
"dev:stop": "node scripts/stop-dev-servers.mjs",
|
|
45
44
|
"dev:reset": "pnpm dev:stop && pnpm dev",
|
|
46
|
-
"smoke:local-route-token": "tsx scripts/local-route-token-smoke.ts",
|
|
47
|
-
"smoke:local-worker-checkpoint": "tsx scripts/local-worker-checkpoint-smoke.ts",
|
|
48
|
-
"smoke:production-auth": "tsx scripts/local-production-auth-smoke.ts",
|
|
49
|
-
"smoke:harness-admin-contract": "tsx scripts/harness-admin-contract-smoke.ts",
|
|
50
|
-
"smoke:harness-k8s-secret": "tsx scripts/harness-k8s-secret-smoke.ts",
|
|
51
|
-
"smoke:provider-gateway": "tsx scripts/provider-gateway-smoke.ts",
|
|
52
|
-
"smoke:staging-phase-one": "tsx scripts/staging-phase-one-smoke.ts",
|
|
53
|
-
"collect:harness-integration-evidence": "tsx scripts/collect-harness-integration-evidence.ts",
|
|
54
|
-
"collect:aws-staging-preflight-evidence": "tsx scripts/collect-aws-staging-preflight-evidence.ts",
|
|
55
|
-
"collect:phase-zero-six-evidence": "tsx scripts/run-phase-zero-six-staging-evidence.ts",
|
|
56
|
-
"verify:aws-staging-preflight-evidence": "tsx scripts/verify-aws-staging-preflight-evidence.ts",
|
|
57
|
-
"verify:staging-phase-one-evidence": "tsx scripts/verify-staging-phase-one-evidence.ts",
|
|
58
|
-
"verify:phase-zero-six-env-ready": "tsx scripts/verify-phase-zero-six-env-ready.ts",
|
|
59
|
-
"verify:phase-zero-six-evidence": "tsx scripts/verify-phase-zero-six-evidence.ts",
|
|
60
|
-
"verify:harness-integration-evidence": "tsx scripts/verify-harness-integration-evidence.ts",
|
|
61
|
-
"verify:harness-evidence-review": "tsx scripts/verify-harness-evidence-review.ts",
|
|
62
|
-
"verify:harness-evidence-env": "tsx scripts/verify-harness-evidence-env.ts",
|
|
63
|
-
"verify:phase-zero-six-artifacts-safe": "tsx scripts/verify-phase-zero-six-artifacts-safe.ts",
|
|
64
|
-
"verify:github-staging-evidence-env": "tsx scripts/verify-github-staging-evidence-env.ts",
|
|
65
|
-
"phase-zero-six:env": "pnpm verify:phase-zero-six-env-ready",
|
|
66
|
-
"phase-zero-six:env:aws": "pnpm verify:phase-zero-six-env-ready -- --skip-staging-smoke",
|
|
67
|
-
"phase-zero-six:env:report": "pnpm verify:phase-zero-six-env-ready -- --format text --no-fail",
|
|
68
|
-
"phase-zero-six:env:aws:report": "pnpm verify:phase-zero-six-env-ready -- --skip-staging-smoke --format text --no-fail",
|
|
69
|
-
"phase-zero-six:template": "pnpm verify:phase-zero-six-env-ready -- --write-env-template ./.temp/phase-zero-six-evidence/phase-zero-six.env.sh",
|
|
70
|
-
"phase-zero-six:template:aws": "pnpm verify:phase-zero-six-env-ready -- --skip-staging-smoke --write-env-template ./.temp/phase-zero-six-evidence/aws-preflight.env.sh",
|
|
71
|
-
"phase-zero-six:collect": "pnpm collect:phase-zero-six-evidence -- --output-dir ./.temp/phase-zero-six-evidence/latest",
|
|
72
|
-
"phase-zero-six:collect:aws": "pnpm collect:phase-zero-six-evidence -- --output-dir ./.temp/phase-zero-six-evidence/latest-aws --skip-staging-smoke",
|
|
73
|
-
"phase-zero-six:apply": "pnpm collect:phase-zero-six-evidence -- --from-output-dir ./.temp/phase-zero-six-evidence/latest --output-dir ./.temp/phase-zero-six-evidence/latest-apply --apply-ready",
|
|
74
|
-
"phase-zero-six:apply:aws": "pnpm collect:phase-zero-six-evidence -- --from-output-dir ./.temp/phase-zero-six-evidence/latest-aws --output-dir ./.temp/phase-zero-six-evidence/latest-aws-apply --apply-ready --skip-staging-smoke",
|
|
75
|
-
"phase-zero-six:audit": "pnpm verify:phase-zero-six-evidence",
|
|
76
|
-
"phase-zero-six:audit:report": "pnpm verify:phase-zero-six-evidence -- --format text",
|
|
77
|
-
"phase-zero-six:github-env": "pnpm verify:github-staging-evidence-env",
|
|
78
|
-
"phase-zero-six:github-env:report": "pnpm verify:github-staging-evidence-env -- --format text --no-fail",
|
|
79
|
-
"phase-zero-six:github-env:template": "tsx scripts/configure-github-staging-evidence-env.ts --write-template ./.temp/phase-zero-six-evidence/github-staging.env.sh",
|
|
80
|
-
"phase-zero-six:github-env:configure": "tsx scripts/configure-github-staging-evidence-env.ts",
|
|
81
45
|
"service:start": "node scripts/service-manager.mjs start",
|
|
82
46
|
"service:stop": "node scripts/service-manager.mjs stop",
|
|
83
47
|
"service:status": "node scripts/service-manager.mjs status",
|
|
@@ -85,11 +49,9 @@
|
|
|
85
49
|
"prepack": "pnpm build:package",
|
|
86
50
|
"build": "pnpm -r --if-present build",
|
|
87
51
|
"build:package": "pnpm --filter @remote-codex/supervisor-api build && pnpm --filter @remote-codex/relay-server build && pnpm --filter @remote-codex/supervisor-web build",
|
|
88
|
-
"build:worker-image": "docker build -f Dockerfile.worker -t remote-codex-worker:local .",
|
|
89
52
|
"lint": "pnpm -r --if-present lint",
|
|
90
53
|
"typecheck": "pnpm -r --if-present typecheck",
|
|
91
54
|
"test": "NODE_ENV=test pnpm -r --if-present test",
|
|
92
|
-
"test:phase-zero-six-evidence": "vitest run scripts/phase-zero-six-evidence.test.ts",
|
|
93
55
|
"test:e2e": "playwright test",
|
|
94
56
|
"db:migrate": "pnpm --filter @remote-codex/db db:migrate",
|
|
95
57
|
"impeccable": "impeccable",
|
|
@@ -250,6 +250,31 @@ describe('ClaudeRuntimeAdapter', () => {
|
|
|
250
250
|
expect(sdkOptions[0]).not.toHaveProperty('tools');
|
|
251
251
|
});
|
|
252
252
|
|
|
253
|
+
it('updates slash toolbox items from Claude SDK system init commands', async () => {
|
|
254
|
+
const adapter = makeAdapter(() => [
|
|
255
|
+
{
|
|
256
|
+
...systemInit(),
|
|
257
|
+
slash_commands: ['compact', 'usage', 'code-review'],
|
|
258
|
+
},
|
|
259
|
+
result(),
|
|
260
|
+
]);
|
|
261
|
+
|
|
262
|
+
await adapter.startSession({
|
|
263
|
+
cwd: '/tmp/workspace',
|
|
264
|
+
model: 'sonnet',
|
|
265
|
+
approvalMode: 'guarded',
|
|
266
|
+
sandboxMode: 'workspace-write',
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
expect(adapter.managementSchema.toolboxItems).toEqual([
|
|
270
|
+
expect.objectContaining({ action: 'mcp', command: '/mcp', panel: 'mcp' }),
|
|
271
|
+
expect.objectContaining({ action: 'prompt', command: '/code-review' }),
|
|
272
|
+
expect.objectContaining({ action: 'prompt', command: '/compact' }),
|
|
273
|
+
expect.objectContaining({ action: 'prompt', command: '/usage' }),
|
|
274
|
+
expect.objectContaining({ action: 'unsupported', command: '/btw' }),
|
|
275
|
+
]);
|
|
276
|
+
});
|
|
277
|
+
|
|
253
278
|
it('maps thread sandbox modes to Claude permission and sandbox settings', async () => {
|
|
254
279
|
const turnOptions: Record<string, unknown>[] = [];
|
|
255
280
|
const adapter = makeAdapter((_prompt, options) => {
|
|
@@ -550,7 +575,7 @@ describe('ClaudeRuntimeAdapter', () => {
|
|
|
550
575
|
await expect(adapter.listLoadedSessions()).resolves.toEqual(['claude-session-1']);
|
|
551
576
|
});
|
|
552
577
|
|
|
553
|
-
it('exposes
|
|
578
|
+
it('exposes Claude Code model aliases and enables the 1M context beta', async () => {
|
|
554
579
|
const sdkOptions: Record<string, unknown>[] = [];
|
|
555
580
|
const adapter = new ClaudeRuntimeAdapter({
|
|
556
581
|
home: '/tmp/claude-home',
|
|
@@ -575,6 +600,11 @@ describe('ClaudeRuntimeAdapter', () => {
|
|
|
575
600
|
model: 'sonnet[1m]',
|
|
576
601
|
displayName: 'Claude Sonnet 1M',
|
|
577
602
|
}),
|
|
603
|
+
expect.objectContaining({
|
|
604
|
+
model: 'fable',
|
|
605
|
+
displayName: 'Claude Fable',
|
|
606
|
+
defaultReasoningEffort: 'medium',
|
|
607
|
+
}),
|
|
578
608
|
]),
|
|
579
609
|
);
|
|
580
610
|
|
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
AgentRuntime,
|
|
21
21
|
AgentRuntimeEvent,
|
|
22
22
|
AgentRuntimeManagementSchema,
|
|
23
|
+
AgentRuntimeToolboxItemSchema,
|
|
23
24
|
AgentRuntimeStatus,
|
|
24
25
|
AgentSessionDetail,
|
|
25
26
|
AgentSessionSummary,
|
|
@@ -103,6 +104,7 @@ interface SDKMessage {
|
|
|
103
104
|
session_id?: string;
|
|
104
105
|
cwd?: string;
|
|
105
106
|
model?: string;
|
|
107
|
+
slash_commands?: unknown;
|
|
106
108
|
uuid?: string;
|
|
107
109
|
message?: unknown;
|
|
108
110
|
event?: unknown;
|
|
@@ -387,7 +389,7 @@ export const claudeCapabilities: AgentProviderCapabilities = {
|
|
|
387
389
|
controls: {
|
|
388
390
|
planMode: true,
|
|
389
391
|
permissionRequests: false,
|
|
390
|
-
sandboxMode:
|
|
392
|
+
sandboxMode: false,
|
|
391
393
|
performanceMode: false,
|
|
392
394
|
goals: false,
|
|
393
395
|
},
|
|
@@ -407,6 +409,78 @@ export const claudeCapabilities: AgentProviderCapabilities = {
|
|
|
407
409
|
},
|
|
408
410
|
};
|
|
409
411
|
|
|
412
|
+
function normalizeClaudeSlashCommands(value: unknown) {
|
|
413
|
+
if (!Array.isArray(value)) {
|
|
414
|
+
return [];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const commands = new Set<string>();
|
|
418
|
+
for (const entry of value) {
|
|
419
|
+
if (typeof entry !== 'string') {
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
const command = entry.trim().replace(/^\/+/, '');
|
|
423
|
+
if (command) {
|
|
424
|
+
commands.add(command);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return [...commands].sort((left, right) => left.localeCompare(right));
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function claudeSlashLabel(command: string) {
|
|
431
|
+
switch (command) {
|
|
432
|
+
case 'compact':
|
|
433
|
+
return '/compact';
|
|
434
|
+
case 'clear':
|
|
435
|
+
return '/clear';
|
|
436
|
+
case 'context':
|
|
437
|
+
return '/context';
|
|
438
|
+
case 'usage':
|
|
439
|
+
return '/usage';
|
|
440
|
+
default:
|
|
441
|
+
return `/${command}`;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function buildClaudeToolboxItems(
|
|
446
|
+
slashCommands: string[],
|
|
447
|
+
): AgentRuntimeToolboxItemSchema[] {
|
|
448
|
+
const discovered = new Set(slashCommands);
|
|
449
|
+
const items: AgentRuntimeToolboxItemSchema[] = [
|
|
450
|
+
{
|
|
451
|
+
action: 'mcp',
|
|
452
|
+
command: '/mcp',
|
|
453
|
+
label: 'MCP',
|
|
454
|
+
description: 'Open MCP status for this Claude Code session.',
|
|
455
|
+
panel: 'mcp',
|
|
456
|
+
},
|
|
457
|
+
];
|
|
458
|
+
|
|
459
|
+
for (const command of slashCommands) {
|
|
460
|
+
if (command === 'mcp') {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
items.push({
|
|
464
|
+
action: 'prompt',
|
|
465
|
+
command: `/${command}`,
|
|
466
|
+
label: claudeSlashLabel(command),
|
|
467
|
+
description: 'Claude Code slash command discovered from the SDK session.',
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (!discovered.has('btw')) {
|
|
472
|
+
items.push({
|
|
473
|
+
action: 'unsupported',
|
|
474
|
+
command: '/btw',
|
|
475
|
+
label: '/btw',
|
|
476
|
+
description:
|
|
477
|
+
'Not listed by the current Claude Agent SDK session; it may require the interactive Claude TTY or a different Claude Code version.',
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return items;
|
|
482
|
+
}
|
|
483
|
+
|
|
410
484
|
const DEFAULT_CLAUDE_MODELS: AgentModel[] = [
|
|
411
485
|
{
|
|
412
486
|
id: 'sonnet',
|
|
@@ -438,6 +512,21 @@ const DEFAULT_CLAUDE_MODELS: AgentModel[] = [
|
|
|
438
512
|
],
|
|
439
513
|
defaultReasoningEffort: 'medium',
|
|
440
514
|
},
|
|
515
|
+
{
|
|
516
|
+
id: 'fable',
|
|
517
|
+
model: 'fable',
|
|
518
|
+
displayName: 'Claude Fable',
|
|
519
|
+
description: 'Claude Code Fable model alias.',
|
|
520
|
+
isDefault: false,
|
|
521
|
+
hidden: false,
|
|
522
|
+
supportedReasoningEfforts: [
|
|
523
|
+
{ reasoningEffort: 'low', description: 'Low effort' },
|
|
524
|
+
{ reasoningEffort: 'medium', description: 'Medium effort' },
|
|
525
|
+
{ reasoningEffort: 'high', description: 'High effort' },
|
|
526
|
+
{ reasoningEffort: 'xhigh', description: 'Extra high effort' },
|
|
527
|
+
],
|
|
528
|
+
defaultReasoningEffort: 'medium',
|
|
529
|
+
},
|
|
441
530
|
{
|
|
442
531
|
id: 'opus',
|
|
443
532
|
model: 'opus',
|
|
@@ -515,6 +604,7 @@ function withClaudeCodeModelAliases(models: AgentModel[]) {
|
|
|
515
604
|
const output = [...models];
|
|
516
605
|
const defaultSonnet = DEFAULT_CLAUDE_MODELS[0]!;
|
|
517
606
|
const oneMillionSonnet = DEFAULT_CLAUDE_MODELS[1]!;
|
|
607
|
+
const fable = DEFAULT_CLAUDE_MODELS[2]!;
|
|
518
608
|
const hasSonnetAlias = output.some((model) => model.model === 'sonnet');
|
|
519
609
|
if (!hasSonnetAlias) {
|
|
520
610
|
output.unshift(defaultSonnet);
|
|
@@ -522,6 +612,9 @@ function withClaudeCodeModelAliases(models: AgentModel[]) {
|
|
|
522
612
|
if (!output.some((model) => model.model === 'sonnet[1m]')) {
|
|
523
613
|
output.splice(1, 0, oneMillionSonnet);
|
|
524
614
|
}
|
|
615
|
+
if (!output.some((model) => model.model === 'fable')) {
|
|
616
|
+
output.splice(2, 0, fable);
|
|
617
|
+
}
|
|
525
618
|
return output.map((model, index) => ({
|
|
526
619
|
...model,
|
|
527
620
|
isDefault: index === 0,
|
|
@@ -959,8 +1052,6 @@ function queryOptionsForRuntime(
|
|
|
959
1052
|
},
|
|
960
1053
|
env: {
|
|
961
1054
|
...process.env,
|
|
962
|
-
CLAUDE_CONFIG_DIR: input.home,
|
|
963
|
-
CLAUDE_HOME: input.home,
|
|
964
1055
|
CLAUDE_AGENT_SDK_CLIENT_APP: input.clientApp,
|
|
965
1056
|
},
|
|
966
1057
|
};
|
|
@@ -1022,9 +1113,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1022
1113
|
};
|
|
1023
1114
|
readonly managementSchema: AgentRuntimeManagementSchema = {
|
|
1024
1115
|
hostConfigFiles: [],
|
|
1025
|
-
toolboxItems: [
|
|
1026
|
-
{ action: 'mcp', command: '/mcp', label: 'MCP', panel: 'mcp' },
|
|
1027
|
-
],
|
|
1116
|
+
toolboxItems: buildClaudeToolboxItems([]),
|
|
1028
1117
|
hookCommandTemplates: [],
|
|
1029
1118
|
providerConfigFormat: 'none',
|
|
1030
1119
|
mcpConfigFormat: 'none',
|
|
@@ -1069,6 +1158,12 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1069
1158
|
return { ...this.status };
|
|
1070
1159
|
}
|
|
1071
1160
|
|
|
1161
|
+
private updateToolboxItemsFromSystemInit(message: SDKMessage) {
|
|
1162
|
+
this.managementSchema.toolboxItems = buildClaudeToolboxItems(
|
|
1163
|
+
normalizeClaudeSlashCommands(message.slash_commands),
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1072
1167
|
async start() {
|
|
1073
1168
|
await fs.mkdir(this.options.home, { recursive: true });
|
|
1074
1169
|
if (!this.options.query && !this.options.sdk) {
|
|
@@ -1222,6 +1317,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1222
1317
|
for await (const message of query) {
|
|
1223
1318
|
rawMessages.push(message);
|
|
1224
1319
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
1320
|
+
this.updateToolboxItemsFromSystemInit(message);
|
|
1225
1321
|
const sessionId = message.session_id;
|
|
1226
1322
|
if (sessionId) {
|
|
1227
1323
|
providerSessionId = sessionId;
|
|
@@ -1558,6 +1654,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
1558
1654
|
this.captureUsage(state, message);
|
|
1559
1655
|
|
|
1560
1656
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
1657
|
+
this.updateToolboxItemsFromSystemInit(message);
|
|
1561
1658
|
if (message.session_id) {
|
|
1562
1659
|
this.sessionCwds.set(message.session_id, message.cwd ?? '');
|
|
1563
1660
|
this.sessionModels.set(message.session_id, message.model ?? null);
|
|
@@ -2084,24 +2181,7 @@ export class ClaudeRuntimeAdapter extends EventEmitter implements AgentRuntime {
|
|
|
2084
2181
|
}
|
|
2085
2182
|
|
|
2086
2183
|
private async withClaudeConfigEnv<T>(callback: () => Promise<T>): Promise<T> {
|
|
2087
|
-
|
|
2088
|
-
const previousClaudeHome = process.env.CLAUDE_HOME;
|
|
2089
|
-
process.env.CLAUDE_CONFIG_DIR = this.options.home;
|
|
2090
|
-
process.env.CLAUDE_HOME = this.options.home;
|
|
2091
|
-
try {
|
|
2092
|
-
return await callback();
|
|
2093
|
-
} finally {
|
|
2094
|
-
if (previousConfigDir === undefined) {
|
|
2095
|
-
delete process.env.CLAUDE_CONFIG_DIR;
|
|
2096
|
-
} else {
|
|
2097
|
-
process.env.CLAUDE_CONFIG_DIR = previousConfigDir;
|
|
2098
|
-
}
|
|
2099
|
-
if (previousClaudeHome === undefined) {
|
|
2100
|
-
delete process.env.CLAUDE_HOME;
|
|
2101
|
-
} else {
|
|
2102
|
-
process.env.CLAUDE_HOME = previousClaudeHome;
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2184
|
+
return callback();
|
|
2105
2185
|
}
|
|
2106
2186
|
|
|
2107
2187
|
private markFailed(error: unknown) {
|
|
@@ -5,6 +5,7 @@ import { PassThrough, Writable } from 'node:stream';
|
|
|
5
5
|
import { describe, expect, it } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { CodexAppServerManager } from './appServerManager';
|
|
8
|
+
import type { CodexUserInput } from './types';
|
|
8
9
|
|
|
9
10
|
async function waitForCondition(
|
|
10
11
|
condition: () => boolean,
|
|
@@ -198,7 +199,7 @@ describe('CodexAppServerManager', () => {
|
|
|
198
199
|
});
|
|
199
200
|
|
|
200
201
|
it('forwards structured image input when starting a turn', async () => {
|
|
201
|
-
const expectedInput = [
|
|
202
|
+
const expectedInput: CodexUserInput[] = [
|
|
202
203
|
{ type: 'text', text: 'Inspect this ', text_elements: [] },
|
|
203
204
|
{ type: 'localImage', path: '/tmp/workspace/photo.png' },
|
|
204
205
|
{ type: 'text', text: ' and summarize.', text_elements: [] },
|
|
@@ -117,6 +117,32 @@ describe('codex history item persistence policy', () => {
|
|
|
117
117
|
]);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
it('maps local image content with a path back to a photo token', () => {
|
|
121
|
+
const turn = codexTurnToAgentTurn({
|
|
122
|
+
id: 'turn-1',
|
|
123
|
+
status: 'completed',
|
|
124
|
+
error: null,
|
|
125
|
+
items: [
|
|
126
|
+
{
|
|
127
|
+
id: 'user-1',
|
|
128
|
+
type: 'userMessage',
|
|
129
|
+
content: [
|
|
130
|
+
{ type: 'text', text: 'Inspect this' },
|
|
131
|
+
{
|
|
132
|
+
type: 'localImage',
|
|
133
|
+
path: '/tmp/workspace/.temp/threads/thread-1/photo.png',
|
|
134
|
+
} as any,
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(turn.items[0]).toMatchObject({
|
|
141
|
+
kind: 'userMessage',
|
|
142
|
+
text: 'Inspect this\n[PHOTO /tmp/workspace/.temp/threads/thread-1/photo.png]',
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
120
146
|
it('keeps MCP tool result text extractable for plugin artifacts', () => {
|
|
121
147
|
const artifactText = [
|
|
122
148
|
'Created a 3D molecule artifact for Methane.',
|
|
@@ -178,6 +178,23 @@ function textFromContentEntries(
|
|
|
178
178
|
return entry.text;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
const assetEntry = entry as {
|
|
182
|
+
path?: unknown;
|
|
183
|
+
imagePath?: unknown;
|
|
184
|
+
filePath?: unknown;
|
|
185
|
+
};
|
|
186
|
+
const assetPath =
|
|
187
|
+
typeof assetEntry.path === 'string'
|
|
188
|
+
? assetEntry.path
|
|
189
|
+
: typeof assetEntry.imagePath === 'string'
|
|
190
|
+
? assetEntry.imagePath
|
|
191
|
+
: typeof assetEntry.filePath === 'string'
|
|
192
|
+
? assetEntry.filePath
|
|
193
|
+
: null;
|
|
194
|
+
if (entry.type === 'localImage' && assetPath) {
|
|
195
|
+
return `[PHOTO ${assetPath}]`;
|
|
196
|
+
}
|
|
197
|
+
|
|
181
198
|
return `[${entry.type}]`;
|
|
182
199
|
})
|
|
183
200
|
.join('\n')
|
|
@@ -5,8 +5,6 @@ import { and, desc, eq, inArray } from 'drizzle-orm';
|
|
|
5
5
|
import { DatabaseClient } from './client';
|
|
6
6
|
import { getDefaultHostRecord } from './client';
|
|
7
7
|
import {
|
|
8
|
-
harnessJobWatches,
|
|
9
|
-
harnessNotifyRegistrations,
|
|
10
8
|
notifications,
|
|
11
9
|
shellSessions,
|
|
12
10
|
threadActivityNotes,
|
|
@@ -946,124 +944,3 @@ export function deleteNotificationsByThreadId(db: DatabaseClient, threadId: stri
|
|
|
946
944
|
export function deleteWorkspaceRecord(db: DatabaseClient, id: string) {
|
|
947
945
|
db.delete(workspaces).where(eq(workspaces.id, id)).run();
|
|
948
946
|
}
|
|
949
|
-
|
|
950
|
-
export type HarnessJobWatchStatus = 'pending' | 'delivered' | 'failed';
|
|
951
|
-
|
|
952
|
-
export interface UpsertHarnessNotifyRegistrationInput {
|
|
953
|
-
agentId: string;
|
|
954
|
-
hookToken: string;
|
|
955
|
-
secret: string;
|
|
956
|
-
callbackUrl: string;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
export function getHarnessNotifyRegistration(db: DatabaseClient) {
|
|
960
|
-
return db
|
|
961
|
-
.select()
|
|
962
|
-
.from(harnessNotifyRegistrations)
|
|
963
|
-
.where(eq(harnessNotifyRegistrations.id, 'default'))
|
|
964
|
-
.get();
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
export function upsertHarnessNotifyRegistration(
|
|
968
|
-
db: DatabaseClient,
|
|
969
|
-
input: UpsertHarnessNotifyRegistrationInput,
|
|
970
|
-
) {
|
|
971
|
-
const now = new Date().toISOString();
|
|
972
|
-
const existing = getHarnessNotifyRegistration(db);
|
|
973
|
-
if (existing) {
|
|
974
|
-
db.update(harnessNotifyRegistrations)
|
|
975
|
-
.set({
|
|
976
|
-
agentId: input.agentId,
|
|
977
|
-
hookToken: input.hookToken,
|
|
978
|
-
secret: input.secret,
|
|
979
|
-
callbackUrl: input.callbackUrl,
|
|
980
|
-
updatedAt: now,
|
|
981
|
-
})
|
|
982
|
-
.where(eq(harnessNotifyRegistrations.id, 'default'))
|
|
983
|
-
.run();
|
|
984
|
-
return getHarnessNotifyRegistration(db)!;
|
|
985
|
-
}
|
|
986
|
-
const record = {
|
|
987
|
-
id: 'default',
|
|
988
|
-
agentId: input.agentId,
|
|
989
|
-
hookToken: input.hookToken,
|
|
990
|
-
secret: input.secret,
|
|
991
|
-
callbackUrl: input.callbackUrl,
|
|
992
|
-
registeredAt: now,
|
|
993
|
-
updatedAt: now,
|
|
994
|
-
};
|
|
995
|
-
db.insert(harnessNotifyRegistrations).values(record).run();
|
|
996
|
-
return record;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
export interface CreateHarnessJobWatchInput {
|
|
1000
|
-
jobId: string;
|
|
1001
|
-
threadId: string;
|
|
1002
|
-
title?: string | null;
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
export function getHarnessJobWatchByJobId(db: DatabaseClient, jobId: string) {
|
|
1006
|
-
return db
|
|
1007
|
-
.select()
|
|
1008
|
-
.from(harnessJobWatches)
|
|
1009
|
-
.where(eq(harnessJobWatches.jobId, jobId))
|
|
1010
|
-
.get();
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
export function listHarnessJobWatches(db: DatabaseClient) {
|
|
1014
|
-
return db.select().from(harnessJobWatches).orderBy(desc(harnessJobWatches.createdAt)).all();
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
export function listPendingHarnessJobWatches(db: DatabaseClient) {
|
|
1018
|
-
return db
|
|
1019
|
-
.select()
|
|
1020
|
-
.from(harnessJobWatches)
|
|
1021
|
-
.where(eq(harnessJobWatches.status, 'pending'))
|
|
1022
|
-
.all();
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
export function upsertHarnessJobWatch(db: DatabaseClient, input: CreateHarnessJobWatchInput) {
|
|
1026
|
-
const now = new Date().toISOString();
|
|
1027
|
-
const existing = getHarnessJobWatchByJobId(db, input.jobId);
|
|
1028
|
-
if (existing) {
|
|
1029
|
-
db.update(harnessJobWatches)
|
|
1030
|
-
.set({
|
|
1031
|
-
threadId: input.threadId,
|
|
1032
|
-
title: input.title ?? existing.title,
|
|
1033
|
-
updatedAt: now,
|
|
1034
|
-
})
|
|
1035
|
-
.where(eq(harnessJobWatches.id, existing.id))
|
|
1036
|
-
.run();
|
|
1037
|
-
return getHarnessJobWatchByJobId(db, input.jobId)!;
|
|
1038
|
-
}
|
|
1039
|
-
const record = {
|
|
1040
|
-
id: randomUUID(),
|
|
1041
|
-
jobId: input.jobId,
|
|
1042
|
-
threadId: input.threadId,
|
|
1043
|
-
title: input.title ?? null,
|
|
1044
|
-
status: 'pending',
|
|
1045
|
-
lastJobStatus: null,
|
|
1046
|
-
lastError: null,
|
|
1047
|
-
createdAt: now,
|
|
1048
|
-
updatedAt: now,
|
|
1049
|
-
deliveredAt: null,
|
|
1050
|
-
};
|
|
1051
|
-
db.insert(harnessJobWatches).values(record).run();
|
|
1052
|
-
return record;
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
export function updateHarnessJobWatch(
|
|
1056
|
-
db: DatabaseClient,
|
|
1057
|
-
id: string,
|
|
1058
|
-
input: {
|
|
1059
|
-
status?: HarnessJobWatchStatus;
|
|
1060
|
-
lastJobStatus?: string | null;
|
|
1061
|
-
lastError?: string | null;
|
|
1062
|
-
deliveredAt?: string | null;
|
|
1063
|
-
},
|
|
1064
|
-
) {
|
|
1065
|
-
db.update(harnessJobWatches)
|
|
1066
|
-
.set({ ...input, updatedAt: new Date().toISOString() })
|
|
1067
|
-
.where(eq(harnessJobWatches.id, id))
|
|
1068
|
-
.run();
|
|
1069
|
-
}
|