@myagentroam/node 0.9.2 → 0.9.4
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/codex-app-server.d.ts +24 -0
- package/dist/codex-app-server.js +100 -5
- package/dist/connector.js +18 -15
- package/dist/control-outbound-scheduler.d.ts +4 -1
- package/dist/control-outbound-scheduler.js +39 -6
- package/dist/database.d.ts +2 -19
- package/dist/database.js +1 -62
- package/dist/event-buffer.d.ts +2 -5
- package/dist/event-buffer.js +3 -12
- package/dist/native-session-history.js +33 -12
- package/dist/runner/claude/managed-run-controller.d.ts +0 -1
- package/dist/runner/claude/managed-run-controller.js +17 -12
- package/dist/runner/codex/conversation-parser.d.ts +1 -1
- package/dist/runner/codex/conversation-parser.js +3 -0
- package/dist/runner/codex/managed-run-controller.d.ts +11 -2
- package/dist/runner/codex/managed-run-controller.js +79 -24
- package/dist/runner/codex-runner.d.ts +3 -0
- package/dist/runner/codex-runner.js +42 -3
- package/dist/runner/opencode/conversation-parser.js +1 -1
- package/dist/runner/opencode/managed-run-controller.d.ts +7 -2
- package/dist/runner/opencode/managed-run-controller.js +72 -14
- package/dist/runner/opencode-runner.d.ts +3 -0
- package/dist/runner/opencode-runner.js +25 -0
- package/dist/runner-profiles.js +10 -6
- package/dist/runtime-state.d.ts +7 -12
- package/dist/runtime-state.js +43 -53
- package/dist/service/attachment-domain-state.d.ts +2 -0
- package/dist/service/attachment-domain-state.js +2 -0
- package/dist/service/conversation-history-service.d.ts +8 -0
- package/dist/service/conversation-history-service.js +181 -9
- package/dist/service/conversation-segment-service.js +17 -10
- package/dist/service/external-session-resume-service.js +9 -0
- package/dist/service/fake-managed-run-service.d.ts +0 -1
- package/dist/service/fake-managed-run-service.js +0 -2
- package/dist/service/native-session-projection-service.js +5 -0
- package/dist/service/native-session-watch-service.d.ts +8 -2
- package/dist/service/native-session-watch-service.js +28 -10
- package/dist/service/node-connection-lifecycle-service.d.ts +0 -2
- package/dist/service/node-connection-lifecycle-service.js +0 -1
- package/dist/service/node-control-channel.js +1 -1
- package/dist/service/node-control-message-service.d.ts +0 -1
- package/dist/service/node-control-message-service.js +9 -6
- package/dist/service/node-request-service.js +2 -1
- package/dist/service/node-workspace-coordinator.d.ts +1 -4
- package/dist/service/node-workspace-coordinator.js +2 -12
- package/dist/service/run-attachment-service.js +30 -6
- package/dist/service/run-event-service.d.ts +1 -0
- package/dist/service/run-event-service.js +80 -0
- package/dist/service/run-workbench-service.d.ts +1 -1
- package/dist/service/run-workbench-service.js +1 -5
- package/dist/service/runner-interaction-service.d.ts +1 -2
- package/dist/service/runner-interaction-service.js +1 -4
- package/dist/service/session-context-service.d.ts +1 -0
- package/dist/service/session-context-service.js +14 -0
- package/dist/service/session-domain-state.d.ts +1 -0
- package/dist/service/session-domain-state.js +1 -0
- package/dist/service/session-lifecycle-service.js +4 -12
- package/dist/service/session-message-service.d.ts +1 -0
- package/dist/service/session-message-service.js +109 -85
- package/dist/service/skill-directory-service.d.ts +3 -1
- package/dist/service/skill-directory-service.js +28 -4
- package/dist/service/skill-node-operation-service.d.ts +1 -1
- package/dist/service/skill-node-operation-service.js +4 -2
- package/dist/service/workbench-event-service.d.ts +1 -13
- package/dist/service/workbench-event-service.js +2 -36
- package/dist/service/workbench-manifest-service.d.ts +0 -1
- package/dist/service/workbench-manifest-service.js +0 -1
- package/dist/service/workspace-change-service.js +1 -1
- package/dist/service/workspace-domain-state.d.ts +1 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +13 -2
- package/dist/service/workspace-queue-workbench-service.js +8 -2
- package/dist/service/workspace-upload-service.d.ts +2 -0
- package/dist/service/workspace-upload-service.js +28 -6
- package/dist/service/workspace-workbench-service.d.ts +0 -3
- package/dist/service/workspace-workbench-service.js +0 -17
- package/dist/util/runner-error.d.ts +6 -0
- package/dist/util/runner-error.js +52 -0
- package/dist/util/runner-native-session-parsers.d.ts +2 -1
- package/dist/util/runner-native-session-parsers.js +63 -15
- package/dist/workspace.js +33 -8
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CodexAppServerClient } from '../codex-app-server.js';
|
|
1
|
+
import { CodexAppServerClient, isCodexRolloutMissingError } from '../codex-app-server.js';
|
|
2
2
|
import { AbstractRunner } from './abstract-runner.js';
|
|
3
3
|
import { declaredRunnerProfiles } from '../runner-profiles.js';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
@@ -11,6 +11,7 @@ import { codexSessionControl } from '../codex-app-server.js';
|
|
|
11
11
|
import { extractId } from '../util/runner-native-session-parsers.js';
|
|
12
12
|
import { nodeLog } from '../operational.js';
|
|
13
13
|
const CODEX_MODEL_CACHE_MS = 10 * 60 * 1_000;
|
|
14
|
+
const CODEX_PROFILE_ENTRY_TTL_MS = 30 * 60 * 1_000;
|
|
14
15
|
const CODEX_MODEL_FAILURE_RETRY_MS = 30 * 1_000;
|
|
15
16
|
const CODEX_MODEL_PAGE_SIZE = 100;
|
|
16
17
|
export class CodexRunner extends AbstractRunner {
|
|
@@ -23,6 +24,7 @@ export class CodexRunner extends AbstractRunner {
|
|
|
23
24
|
environmentFingerprint;
|
|
24
25
|
environmentRuns = new Set();
|
|
25
26
|
profileCache = new Map();
|
|
27
|
+
profileCacheTimers = new Map();
|
|
26
28
|
profileRefreshes = new Map();
|
|
27
29
|
profileClients = new Set();
|
|
28
30
|
profileKeyByEnvironment = new Map();
|
|
@@ -74,7 +76,7 @@ export class CodexRunner extends AbstractRunner {
|
|
|
74
76
|
successful: true,
|
|
75
77
|
retryAt: 0
|
|
76
78
|
};
|
|
77
|
-
this.
|
|
79
|
+
this.cacheProfile(key, cache);
|
|
78
80
|
if (this.selectedProfileKey === key)
|
|
79
81
|
this.latestProfileCache = cache;
|
|
80
82
|
return cache.profile;
|
|
@@ -88,7 +90,7 @@ export class CodexRunner extends AbstractRunner {
|
|
|
88
90
|
cached.retryAt = Date.now() + CODEX_MODEL_FAILURE_RETRY_MS;
|
|
89
91
|
return cached.profile;
|
|
90
92
|
}
|
|
91
|
-
this.
|
|
93
|
+
this.cacheProfile(key, {
|
|
92
94
|
profile: { ...base, models: [] },
|
|
93
95
|
defaultConfiguration: emptyCodexConfiguration(),
|
|
94
96
|
fetchedAt: 0,
|
|
@@ -106,6 +108,25 @@ export class CodexRunner extends AbstractRunner {
|
|
|
106
108
|
this.latestProfileCache = cached;
|
|
107
109
|
return cached.profile;
|
|
108
110
|
}
|
|
111
|
+
cacheProfile(key, cache) {
|
|
112
|
+
const previousTimer = this.profileCacheTimers.get(key);
|
|
113
|
+
if (previousTimer !== undefined)
|
|
114
|
+
clearTimeout(previousTimer);
|
|
115
|
+
this.profileCache.set(key, cache);
|
|
116
|
+
const timer = setTimeout(() => {
|
|
117
|
+
this.profileCacheTimers.delete(key);
|
|
118
|
+
this.profileCache.delete(key);
|
|
119
|
+
for (const [environmentKey, profileKey] of this.profileKeyByEnvironment)
|
|
120
|
+
if (profileKey === key)
|
|
121
|
+
this.profileKeyByEnvironment.delete(environmentKey);
|
|
122
|
+
if (this.selectedProfileKey === key) {
|
|
123
|
+
this.selectedProfileKey = undefined;
|
|
124
|
+
this.latestProfileCache = undefined;
|
|
125
|
+
}
|
|
126
|
+
}, CODEX_PROFILE_ENTRY_TTL_MS);
|
|
127
|
+
timer.unref();
|
|
128
|
+
this.profileCacheTimers.set(key, timer);
|
|
129
|
+
}
|
|
109
130
|
async fetchCodexProfile(base, environment) {
|
|
110
131
|
const client = this.profileClientFactory();
|
|
111
132
|
this.profileClients.add(client);
|
|
@@ -430,6 +451,17 @@ export class CodexRunner extends AbstractRunner {
|
|
|
430
451
|
start() {
|
|
431
452
|
return this.client.start();
|
|
432
453
|
}
|
|
454
|
+
async recoverMissingRollout(runId, error) {
|
|
455
|
+
if (!isCodexRolloutMissingError(error))
|
|
456
|
+
return false;
|
|
457
|
+
if ([...this.environmentRuns].some((activeRunId) => activeRunId !== runId))
|
|
458
|
+
return false;
|
|
459
|
+
if ([...this.execution.runs.keys()].some((activeRunId) => activeRunId !== runId))
|
|
460
|
+
return false;
|
|
461
|
+
nodeLog('runner.codex.rollout.recovering', { runId });
|
|
462
|
+
await this.client.restart();
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
433
465
|
prepareEnvironment(environment, runId) {
|
|
434
466
|
if (Object.keys(environment).length === 0 && this.environmentFingerprint === undefined) {
|
|
435
467
|
this.environmentRuns.add(runId);
|
|
@@ -466,6 +498,13 @@ export class CodexRunner extends AbstractRunner {
|
|
|
466
498
|
this.client.clearEnvironment();
|
|
467
499
|
this.environmentFingerprint = undefined;
|
|
468
500
|
this.environmentRuns.clear();
|
|
501
|
+
for (const timer of this.profileCacheTimers.values())
|
|
502
|
+
clearTimeout(timer);
|
|
503
|
+
this.profileCacheTimers.clear();
|
|
504
|
+
this.profileCache.clear();
|
|
505
|
+
this.profileKeyByEnvironment.clear();
|
|
506
|
+
this.latestProfileCache = undefined;
|
|
507
|
+
this.selectedProfileKey = undefined;
|
|
469
508
|
}
|
|
470
509
|
request(method, params) {
|
|
471
510
|
return this.client.request(method, params);
|
|
@@ -128,7 +128,7 @@ function partItem(session, turnId, raw, planMode, startedAt, completedAt, sequen
|
|
|
128
128
|
}, startedAt, completedAt, sequence);
|
|
129
129
|
}
|
|
130
130
|
export function openCodeQuestions(value) {
|
|
131
|
-
if (!Array.isArray(value) || value.length === 0
|
|
131
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
132
132
|
return [];
|
|
133
133
|
return value.flatMap((value, index) => {
|
|
134
134
|
const question = record(value);
|
|
@@ -17,10 +17,13 @@ interface OpenCodeManagedRunHost {
|
|
|
17
17
|
cwd: string;
|
|
18
18
|
externalSessionId?: string;
|
|
19
19
|
}): void;
|
|
20
|
+
run(runId: string): {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
};
|
|
23
|
+
hasActiveSessionLease(sessionId: string): boolean;
|
|
20
24
|
promote(sessionId: string, nativeSessionId: string): void;
|
|
21
25
|
rememberNative(nativeSessionId: string, sessionId: string): void;
|
|
22
26
|
send(type: string, payload: unknown): void;
|
|
23
|
-
captureSnapshot(runId: string, cwd: string): Promise<void>;
|
|
24
27
|
createApproval(input: {
|
|
25
28
|
readonly runId: string;
|
|
26
29
|
readonly approvalId: string;
|
|
@@ -41,7 +44,7 @@ interface OpenCodeManagedRunHost {
|
|
|
41
44
|
}
|
|
42
45
|
type OpenCodePublicItem = {
|
|
43
46
|
readonly itemId: string;
|
|
44
|
-
readonly kind: 'assistant_message' | 'plan' | 'reasoning_summary' | 'tool_call' | 'user_input_request' | 'context_compaction' | 'unknown';
|
|
47
|
+
readonly kind: 'assistant_message' | 'plan' | 'reasoning_summary' | 'tool_call' | 'user_input_request' | 'context_compaction' | 'error' | 'unknown';
|
|
45
48
|
readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED';
|
|
46
49
|
readonly payload: Record<string, unknown>;
|
|
47
50
|
readonly merge?: boolean;
|
|
@@ -60,6 +63,8 @@ export declare class OpenCodeManagedRunController {
|
|
|
60
63
|
executeCommand(session: NodeAgentSession, command: RunnerCommandDescriptor, context: {
|
|
61
64
|
readonly secretEnvironment: Readonly<Record<string, string>>;
|
|
62
65
|
}): Promise<unknown>;
|
|
66
|
+
private compact;
|
|
67
|
+
private runCompact;
|
|
63
68
|
start(envelope: NodeEnvelope): void;
|
|
64
69
|
cancel(runId: string, intent: 'CANCEL' | 'INTERRUPT'): boolean;
|
|
65
70
|
decideApproval(input: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseSecretEnvironment } from '../../util/secret-environment.js';
|
|
2
|
-
import {
|
|
2
|
+
import { runnerErrorProjection } from '../../util/runner-error.js';
|
|
3
3
|
import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '../codex/conversation-parser.js';
|
|
4
4
|
import { openCodePatchToolPayload, openCodeQuestions } from './conversation-parser.js';
|
|
5
5
|
export class OpenCodeManagedRunController {
|
|
@@ -19,7 +19,7 @@ export class OpenCodeManagedRunController {
|
|
|
19
19
|
}
|
|
20
20
|
async executeCommand(session, command, context) {
|
|
21
21
|
if (command.id === 'compact')
|
|
22
|
-
return this.
|
|
22
|
+
return this.compact(session, context.secretEnvironment);
|
|
23
23
|
if (command.id !== 'plan')
|
|
24
24
|
throw new Error('RUNNER_COMMAND_UNAVAILABLE');
|
|
25
25
|
const current = this.host.commandState(session.id, 'plan');
|
|
@@ -37,6 +37,53 @@ export class OpenCodeManagedRunController {
|
|
|
37
37
|
});
|
|
38
38
|
return { command: command.id, states: this.host.commandStates(session.id) };
|
|
39
39
|
}
|
|
40
|
+
compact(session, environment) {
|
|
41
|
+
if (session.externalSessionId === null ||
|
|
42
|
+
session.model === null ||
|
|
43
|
+
session.nativeControl !== 'MAR_MANAGED' ||
|
|
44
|
+
this.host.hasActiveSessionLease(session.id))
|
|
45
|
+
throw new Error('RUNNER_COMMAND_UNAVAILABLE');
|
|
46
|
+
const runId = crypto.randomUUID();
|
|
47
|
+
const client = this.runner.managedClient(environment);
|
|
48
|
+
this.host.adopt({
|
|
49
|
+
runId,
|
|
50
|
+
sessionId: session.id,
|
|
51
|
+
runner: 'opencode',
|
|
52
|
+
cwd: session.cwd,
|
|
53
|
+
externalSessionId: session.externalSessionId
|
|
54
|
+
});
|
|
55
|
+
this.host.active.add(runId);
|
|
56
|
+
this.runner.execution.set(runId, {
|
|
57
|
+
runId,
|
|
58
|
+
sessionId: session.id,
|
|
59
|
+
nativeSessionId: session.externalSessionId,
|
|
60
|
+
cwd: session.cwd,
|
|
61
|
+
client,
|
|
62
|
+
abort: new AbortController(),
|
|
63
|
+
access: session.access ?? 'default',
|
|
64
|
+
agent: 'build'
|
|
65
|
+
});
|
|
66
|
+
this.host.emit(runId, 'run.started', { command: 'compact' }, 'STARTING');
|
|
67
|
+
void this.runCompact(runId, session.model);
|
|
68
|
+
return {
|
|
69
|
+
command: 'compact',
|
|
70
|
+
run: this.host.run(runId),
|
|
71
|
+
states: this.host.commandStates(session.id)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async runCompact(runId, model) {
|
|
75
|
+
const execution = this.runner.execution.get(runId);
|
|
76
|
+
if (execution === undefined)
|
|
77
|
+
return;
|
|
78
|
+
this.host.emit(runId, 'run.running', { command: 'compact' }, 'RUNNING');
|
|
79
|
+
try {
|
|
80
|
+
await execution.client.summarize(execution.cwd, execution.nativeSessionId, model);
|
|
81
|
+
this.finish(runId, 'SUCCEEDED', 'run.completed', { status: 'SUCCEEDED' });
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
this.finish(runId, 'FAILED', 'run.failed', error, 'OPENCODE_COMPACT_FAILED');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
40
87
|
start(envelope) {
|
|
41
88
|
const payload = envelope.payload;
|
|
42
89
|
if (payload.runner !== 'opencode' ||
|
|
@@ -57,7 +104,14 @@ export class OpenCodeManagedRunController {
|
|
|
57
104
|
attachments = this.host.parseAttachments(payload.attachments);
|
|
58
105
|
}
|
|
59
106
|
catch (error) {
|
|
60
|
-
|
|
107
|
+
const projected = runnerErrorProjection(error, 'RUNNER_INPUT_INVALID');
|
|
108
|
+
this.host.emitItem(payload.runId, {
|
|
109
|
+
itemId: boundedConversationItemId('runner-error', payload.runId),
|
|
110
|
+
kind: 'error',
|
|
111
|
+
status: 'FAILED',
|
|
112
|
+
payload: { ...projected, recoverable: true, retryAfterMs: null }
|
|
113
|
+
});
|
|
114
|
+
this.host.emit(payload.runId, 'run.rejected', projected, 'FAILED');
|
|
61
115
|
return;
|
|
62
116
|
}
|
|
63
117
|
void this.run({
|
|
@@ -181,9 +235,7 @@ export class OpenCodeManagedRunController {
|
|
|
181
235
|
rejectReady(error);
|
|
182
236
|
return;
|
|
183
237
|
}
|
|
184
|
-
this.finish(input.runId, 'FAILED', 'run.failed',
|
|
185
|
-
code: safeErrorCode(error, 'OPENCODE_EVENT_FAILED')
|
|
186
|
-
});
|
|
238
|
+
this.finish(input.runId, 'FAILED', 'run.failed', error, 'OPENCODE_EVENT_FAILED');
|
|
187
239
|
});
|
|
188
240
|
await subscriptionReady;
|
|
189
241
|
this.host.emit(input.runId, 'run.running', {}, 'RUNNING');
|
|
@@ -206,9 +258,7 @@ export class OpenCodeManagedRunController {
|
|
|
206
258
|
this.finish(input.runId, 'SUCCEEDED', 'run.completed', { status: 'SUCCEEDED' });
|
|
207
259
|
}
|
|
208
260
|
catch (error) {
|
|
209
|
-
this.finish(input.runId, 'FAILED', 'run.failed',
|
|
210
|
-
code: safeErrorCode(error, 'OPENCODE_RUN_START_FAILED')
|
|
211
|
-
});
|
|
261
|
+
this.finish(input.runId, 'FAILED', 'run.failed', error, 'OPENCODE_RUN_START_FAILED');
|
|
212
262
|
}
|
|
213
263
|
}
|
|
214
264
|
event(runId, nativeSessionId, value) {
|
|
@@ -231,7 +281,7 @@ export class OpenCodeManagedRunController {
|
|
|
231
281
|
return;
|
|
232
282
|
}
|
|
233
283
|
if (event?.type === 'session.error') {
|
|
234
|
-
this.finish(runId, 'FAILED', 'run.failed',
|
|
284
|
+
this.finish(runId, 'FAILED', 'run.failed', properties?.error ?? properties);
|
|
235
285
|
return;
|
|
236
286
|
}
|
|
237
287
|
if (event?.type === 'message.part.updated') {
|
|
@@ -309,7 +359,7 @@ export class OpenCodeManagedRunController {
|
|
|
309
359
|
if (execution === undefined || requestId === undefined)
|
|
310
360
|
return;
|
|
311
361
|
const questions = openCodeQuestions(rawQuestions);
|
|
312
|
-
if (questions.length === 0 ||
|
|
362
|
+
if (questions.length === 0 || this.questions.has(requestId))
|
|
313
363
|
return;
|
|
314
364
|
const timer = setTimeout(() => {
|
|
315
365
|
const pending = this.questions.get(requestId);
|
|
@@ -340,7 +390,7 @@ export class OpenCodeManagedRunController {
|
|
|
340
390
|
payload: { requestId, questions }
|
|
341
391
|
});
|
|
342
392
|
}
|
|
343
|
-
finish(runId, status, eventType, payload) {
|
|
393
|
+
finish(runId, status, eventType, payload, fallbackCode = 'OPENCODE_RUN_FAILED') {
|
|
344
394
|
const execution = this.runner.execution.get(runId);
|
|
345
395
|
const cwd = execution?.cwd ?? this.startingCwds.get(runId);
|
|
346
396
|
const client = execution?.client ?? this.startingClients.get(runId);
|
|
@@ -363,11 +413,19 @@ export class OpenCodeManagedRunController {
|
|
|
363
413
|
clearTimeout(pending.timer);
|
|
364
414
|
this.questions.delete(id);
|
|
365
415
|
}
|
|
416
|
+
if (status === 'FAILED') {
|
|
417
|
+
const projected = runnerErrorProjection(payload, fallbackCode);
|
|
418
|
+
this.host.emitItem(runId, {
|
|
419
|
+
itemId: boundedConversationItemId('runner-error', runId),
|
|
420
|
+
kind: 'error',
|
|
421
|
+
status: 'FAILED',
|
|
422
|
+
payload: { ...projected, recoverable: true, retryAfterMs: null }
|
|
423
|
+
});
|
|
424
|
+
payload = projected;
|
|
425
|
+
}
|
|
366
426
|
this.host.emit(runId, eventType, payload, status);
|
|
367
427
|
if (client !== undefined)
|
|
368
428
|
this.runner.releaseManagedClient(client);
|
|
369
|
-
if (cwd !== undefined)
|
|
370
|
-
void this.host.captureSnapshot(runId, cwd);
|
|
371
429
|
}
|
|
372
430
|
}
|
|
373
431
|
function openCodeImageInput(input, attachmentPaths) {
|
|
@@ -19,6 +19,7 @@ export declare class OpenCodeRunner extends AbstractRunner<'opencode'> {
|
|
|
19
19
|
readonly discoveryScope: "WORKSPACE_REQUIRED";
|
|
20
20
|
private readonly modelsByWorkspace;
|
|
21
21
|
private readonly contextLimitsByWorkspace;
|
|
22
|
+
private readonly profileTimersByWorkspace;
|
|
22
23
|
readonly execution: Map<string, OpenCodeManagedExecution>;
|
|
23
24
|
readonly managedTurns: Map<string, string>;
|
|
24
25
|
private readonly environmentClients;
|
|
@@ -56,6 +57,8 @@ export declare class OpenCodeRunner extends AbstractRunner<'opencode'> {
|
|
|
56
57
|
maxTokens: number;
|
|
57
58
|
} | undefined>;
|
|
58
59
|
stop(): Promise<void>;
|
|
60
|
+
private scheduleProfileExpiry;
|
|
61
|
+
private clearProfileTimer;
|
|
59
62
|
managedClient(environment: Readonly<Record<string, string>>, isolationKey?: string): OpenCodeServerClient;
|
|
60
63
|
releaseManagedClient(client: OpenCodeServerClient): void;
|
|
61
64
|
}
|
|
@@ -5,6 +5,7 @@ import { AbstractRunner } from './abstract-runner.js';
|
|
|
5
5
|
import { isWithinWorkspace } from './codex/conversation-parser.js';
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
7
7
|
import { openCodeConversationPage } from './opencode/conversation-parser.js';
|
|
8
|
+
const PROFILE_ENTRY_TTL_MS = 30 * 60_000;
|
|
8
9
|
export class OpenCodeRunner extends AbstractRunner {
|
|
9
10
|
client;
|
|
10
11
|
clientFactory;
|
|
@@ -12,6 +13,7 @@ export class OpenCodeRunner extends AbstractRunner {
|
|
|
12
13
|
discoveryScope = 'WORKSPACE_REQUIRED';
|
|
13
14
|
modelsByWorkspace = new Map();
|
|
14
15
|
contextLimitsByWorkspace = new Map();
|
|
16
|
+
profileTimersByWorkspace = new Map();
|
|
15
17
|
execution = new Map();
|
|
16
18
|
managedTurns = new Map();
|
|
17
19
|
environmentClients = new Map();
|
|
@@ -39,11 +41,13 @@ export class OpenCodeRunner extends AbstractRunner {
|
|
|
39
41
|
const models = openCodeProfileModels(catalog);
|
|
40
42
|
this.modelsByWorkspace.set(workspace.path, models);
|
|
41
43
|
this.contextLimitsByWorkspace.set(workspace.path, openCodeContextLimits(catalog));
|
|
44
|
+
this.scheduleProfileExpiry(workspace.path);
|
|
42
45
|
return { ...this.profile(capabilities), models };
|
|
43
46
|
}
|
|
44
47
|
catch {
|
|
45
48
|
this.modelsByWorkspace.delete(workspace.path);
|
|
46
49
|
this.contextLimitsByWorkspace.delete(workspace.path);
|
|
50
|
+
this.clearProfileTimer(workspace.path);
|
|
47
51
|
}
|
|
48
52
|
finally {
|
|
49
53
|
this.releaseManagedClient(client);
|
|
@@ -279,6 +283,11 @@ export class OpenCodeRunner extends AbstractRunner {
|
|
|
279
283
|
execution.abort.abort();
|
|
280
284
|
this.execution.clear();
|
|
281
285
|
this.managedTurns.clear();
|
|
286
|
+
for (const timer of this.profileTimersByWorkspace.values())
|
|
287
|
+
clearTimeout(timer);
|
|
288
|
+
this.profileTimersByWorkspace.clear();
|
|
289
|
+
this.modelsByWorkspace.clear();
|
|
290
|
+
this.contextLimitsByWorkspace.clear();
|
|
282
291
|
const stopping = [
|
|
283
292
|
this.client.stop(),
|
|
284
293
|
...[...this.environmentClients.values()].map(({ client }) => client.stop()),
|
|
@@ -288,6 +297,22 @@ export class OpenCodeRunner extends AbstractRunner {
|
|
|
288
297
|
await Promise.allSettled(stopping);
|
|
289
298
|
this.stoppingClients.clear();
|
|
290
299
|
}
|
|
300
|
+
scheduleProfileExpiry(workspacePath) {
|
|
301
|
+
this.clearProfileTimer(workspacePath);
|
|
302
|
+
const timer = setTimeout(() => {
|
|
303
|
+
this.profileTimersByWorkspace.delete(workspacePath);
|
|
304
|
+
this.modelsByWorkspace.delete(workspacePath);
|
|
305
|
+
this.contextLimitsByWorkspace.delete(workspacePath);
|
|
306
|
+
}, PROFILE_ENTRY_TTL_MS);
|
|
307
|
+
timer.unref();
|
|
308
|
+
this.profileTimersByWorkspace.set(workspacePath, timer);
|
|
309
|
+
}
|
|
310
|
+
clearProfileTimer(workspacePath) {
|
|
311
|
+
const timer = this.profileTimersByWorkspace.get(workspacePath);
|
|
312
|
+
if (timer !== undefined)
|
|
313
|
+
clearTimeout(timer);
|
|
314
|
+
this.profileTimersByWorkspace.delete(workspacePath);
|
|
315
|
+
}
|
|
291
316
|
managedClient(environment, isolationKey) {
|
|
292
317
|
const entries = Object.entries(environment).sort(([left], [right]) => left.localeCompare(right));
|
|
293
318
|
if (entries.length === 0 && isolationKey === undefined)
|
package/dist/runner-profiles.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const COMMON_COMMAND_DESCRIPTIONS = {
|
|
2
|
+
compact: 'Compact the current session context.',
|
|
3
|
+
plan: 'Toggle collaborative Plan Mode.'
|
|
4
|
+
};
|
|
1
5
|
const CLAUDE_MODEL_ENVIRONMENT = {
|
|
2
6
|
opus: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
|
3
7
|
sonnet: 'ANTHROPIC_DEFAULT_SONNET_MODEL',
|
|
@@ -35,7 +39,7 @@ const definitions = {
|
|
|
35
39
|
{
|
|
36
40
|
id: 'compact',
|
|
37
41
|
label: '/compact',
|
|
38
|
-
description:
|
|
42
|
+
description: COMMON_COMMAND_DESCRIPTIONS.compact,
|
|
39
43
|
inputHint: '/compact',
|
|
40
44
|
interaction: 'IMMEDIATE_ACTION'
|
|
41
45
|
},
|
|
@@ -43,7 +47,7 @@ const definitions = {
|
|
|
43
47
|
id: 'plan',
|
|
44
48
|
label: '/plan',
|
|
45
49
|
stateLabel: 'Plan Mode',
|
|
46
|
-
description:
|
|
50
|
+
description: COMMON_COMMAND_DESCRIPTIONS.plan,
|
|
47
51
|
inputHint: '/plan',
|
|
48
52
|
interaction: 'TOGGLE'
|
|
49
53
|
},
|
|
@@ -96,7 +100,7 @@ const definitions = {
|
|
|
96
100
|
id: 'compact',
|
|
97
101
|
runner: 'claude-code',
|
|
98
102
|
label: '/compact',
|
|
99
|
-
description:
|
|
103
|
+
description: COMMON_COMMAND_DESCRIPTIONS.compact,
|
|
100
104
|
inputHint: '/compact',
|
|
101
105
|
source: 'CLAUDE_AGENT_SDK',
|
|
102
106
|
interaction: 'IMMEDIATE_ACTION',
|
|
@@ -108,7 +112,7 @@ const definitions = {
|
|
|
108
112
|
runner: 'claude-code',
|
|
109
113
|
label: '/plan',
|
|
110
114
|
stateLabel: 'Plan Mode',
|
|
111
|
-
description:
|
|
115
|
+
description: COMMON_COMMAND_DESCRIPTIONS.plan,
|
|
112
116
|
inputHint: '/plan',
|
|
113
117
|
source: 'CLAUDE_AGENT_SDK',
|
|
114
118
|
interaction: 'TOGGLE',
|
|
@@ -137,7 +141,7 @@ const definitions = {
|
|
|
137
141
|
id: 'compact',
|
|
138
142
|
runner: 'opencode',
|
|
139
143
|
label: '/compact',
|
|
140
|
-
description:
|
|
144
|
+
description: COMMON_COMMAND_DESCRIPTIONS.compact,
|
|
141
145
|
inputHint: '/compact',
|
|
142
146
|
source: 'OPENCODE_SERVER',
|
|
143
147
|
interaction: 'IMMEDIATE_ACTION',
|
|
@@ -149,7 +153,7 @@ const definitions = {
|
|
|
149
153
|
runner: 'opencode',
|
|
150
154
|
label: '/plan',
|
|
151
155
|
stateLabel: 'Plan Mode',
|
|
152
|
-
description:
|
|
156
|
+
description: COMMON_COMMAND_DESCRIPTIONS.plan,
|
|
153
157
|
inputHint: '/plan',
|
|
154
158
|
source: 'OPENCODE_SERVER',
|
|
155
159
|
interaction: 'TOGGLE',
|
package/dist/runtime-state.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentRunStatus, RunnerName } from '@myagentroam/protocol';
|
|
2
|
-
import type { ConversationItemPage, ConversationPage, NativeSessionControl, NodeAgentRun, NodeAgentSession, NodeApproval, NodeConversationTurn, NodeMessageAttachmentInput, NodeRunEvent, NodeWorkspace
|
|
2
|
+
import type { ConversationItemPage, ConversationPage, NativeSessionControl, NodeAgentRun, NodeAgentSession, NodeApproval, NodeConversationTurn, NodeMessageAttachmentInput, NodeRunEvent, NodeWorkspace } from './database.js';
|
|
3
3
|
/**
|
|
4
4
|
* Deliberately process-local runtime domain. No method in this class writes
|
|
5
5
|
* into Node SQLite: a Node restart loses active runs, approvals, leases and
|
|
@@ -10,22 +10,22 @@ export declare class NodeRuntimeState {
|
|
|
10
10
|
private readonly nodeId;
|
|
11
11
|
private readonly getWorkspace;
|
|
12
12
|
private readonly now;
|
|
13
|
+
private static readonly MAX_COMPLETED_TURNS_PER_SESSION;
|
|
13
14
|
private readonly sessions;
|
|
14
15
|
private readonly runs;
|
|
15
16
|
private readonly messageRuns;
|
|
16
17
|
private readonly events;
|
|
17
18
|
private readonly turns;
|
|
18
19
|
private readonly approvals;
|
|
19
|
-
private readonly workspaceEvents;
|
|
20
20
|
/** A Session owns at most one running turn; Workspace sessions may run concurrently. */
|
|
21
21
|
private readonly leases;
|
|
22
22
|
/** Session FIFO metadata is deliberately process-local with the rest of run state. */
|
|
23
23
|
private readonly queuedRuns;
|
|
24
24
|
private readonly queueVersions;
|
|
25
25
|
private readonly pausedQueues;
|
|
26
|
-
|
|
26
|
+
/** Bounded tombstones reject stale internal start envelopes after terminal cleanup. */
|
|
27
|
+
private readonly terminalRunIds;
|
|
27
28
|
private nextEventId;
|
|
28
|
-
private nextWorkspaceEventId;
|
|
29
29
|
constructor(nodeId: () => string, getWorkspace: (id: string) => NodeWorkspace | undefined, now?: () => number);
|
|
30
30
|
activeWorkspaceLeaseCount(): number;
|
|
31
31
|
activeSessionRun(sessionId: string): NodeAgentRun | undefined;
|
|
@@ -86,9 +86,11 @@ export declare class NodeRuntimeState {
|
|
|
86
86
|
*/
|
|
87
87
|
setRunnerTitleFromNative(id: string, title: string): NodeAgentSession;
|
|
88
88
|
createMessageRun(input: {
|
|
89
|
+
readonly runId?: string;
|
|
89
90
|
readonly sessionId: string;
|
|
90
91
|
readonly clientMessageId: string;
|
|
91
92
|
readonly content: string;
|
|
93
|
+
readonly initiatedByUserId?: number;
|
|
92
94
|
readonly attachments?: readonly NodeMessageAttachmentInput[];
|
|
93
95
|
}): {
|
|
94
96
|
readonly run: NodeAgentRun;
|
|
@@ -138,11 +140,6 @@ export declare class NodeRuntimeState {
|
|
|
138
140
|
readonly outputPreview: string;
|
|
139
141
|
readonly failed?: boolean;
|
|
140
142
|
}): NodeConversationTurn;
|
|
141
|
-
listWorkspaceActivity(input: {
|
|
142
|
-
readonly workspaceId: string;
|
|
143
|
-
readonly cursor?: string;
|
|
144
|
-
readonly limit?: number;
|
|
145
|
-
}): WorkspaceActivityPage;
|
|
146
143
|
createApproval(input: {
|
|
147
144
|
readonly runId: string;
|
|
148
145
|
readonly approvalId: string;
|
|
@@ -156,8 +153,7 @@ export declare class NodeRuntimeState {
|
|
|
156
153
|
expireDueApprovals(): readonly NodeApproval[];
|
|
157
154
|
listNonterminalRuns(): readonly NodeAgentRun[];
|
|
158
155
|
lastRunSequence(id: string): number;
|
|
159
|
-
|
|
160
|
-
getSnapshot(id: string): unknown | undefined;
|
|
156
|
+
removeTerminalRun(runId: string): void;
|
|
161
157
|
hasActiveWorkspaceLease(workspaceId: string): boolean;
|
|
162
158
|
/** Removes a terminal Session's process-local projection after its native history is deleted. */
|
|
163
159
|
removeAgentSession(sessionId: string): void;
|
|
@@ -168,7 +164,6 @@ export declare class NodeRuntimeState {
|
|
|
168
164
|
private requireSession;
|
|
169
165
|
private requireRun;
|
|
170
166
|
private requireApproval;
|
|
171
|
-
private recordWorkspaceActivity;
|
|
172
167
|
private updateTurnForRun;
|
|
173
168
|
private projectEvent;
|
|
174
169
|
}
|