@myagentroam/node 0.9.0 → 0.9.3
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/connector.d.ts +2 -0
- package/dist/connector.js +50 -25
- package/dist/control-outbound-scheduler.d.ts +4 -1
- package/dist/control-outbound-scheduler.js +39 -6
- package/dist/database.d.ts +0 -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 +105 -26
- package/dist/runner/abstract-runner.d.ts +1 -1
- package/dist/runner/abstract-runner.js +2 -2
- package/dist/runner/claude/managed-run-controller.d.ts +0 -1
- package/dist/runner/claude/managed-run-controller.js +32 -17
- package/dist/runner/claude-code-runner.js +3 -4
- package/dist/runner/codex/conversation-parser.d.ts +3 -3
- package/dist/runner/codex/conversation-parser.js +33 -12
- package/dist/runner/codex/managed-run-controller.d.ts +2 -2
- package/dist/runner/codex/managed-run-controller.js +26 -10
- package/dist/runner/codex-runner.d.ts +3 -1
- package/dist/runner/codex-runner.js +40 -10
- package/dist/runner/opencode/conversation-parser.d.ts +11 -7
- package/dist/runner/opencode/conversation-parser.js +16 -16
- package/dist/runner/opencode/managed-run-controller.d.ts +8 -2
- package/dist/runner/opencode/managed-run-controller.js +94 -22
- package/dist/runner/opencode-runner.d.ts +3 -0
- package/dist/runner/opencode-runner.js +25 -0
- package/dist/runner-command-engine.js +1 -1
- package/dist/runner-profiles.js +29 -17
- package/dist/runner-usage.js +5 -5
- package/dist/runtime-state.d.ts +5 -12
- package/dist/runtime-state.js +32 -46
- 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.js +55 -24
- package/dist/service/conversation-segment-service.d.ts +20 -0
- package/dist/service/conversation-segment-service.js +156 -0
- 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/mcp-installation-verifier.js +1 -1
- package/dist/service/native-session-projection-service.js +5 -0
- package/dist/service/native-session-watch-service.d.ts +1 -0
- package/dist/service/native-session-watch-service.js +21 -4
- 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.d.ts +3 -2
- package/dist/service/run-attachment-service.js +51 -17
- package/dist/service/run-event-service.d.ts +2 -0
- package/dist/service/run-event-service.js +77 -2
- 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-catalog-service.js +4 -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-message-service.js +5 -10
- package/dist/service/session-presentation-service.d.ts +1 -0
- package/dist/service/session-presentation-service.js +8 -1
- package/dist/service/session-query-service.d.ts +4 -0
- package/dist/service/session-query-service.js +6 -1
- package/dist/service/skill-directory-service.d.ts +3 -1
- package/dist/service/skill-directory-service.js +31 -30
- package/dist/service/skill-install-service.js +4 -74
- package/dist/service/skill-node-operation-service.d.ts +1 -1
- package/dist/service/skill-node-operation-service.js +6 -3
- 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-domain-state.d.ts +1 -0
- package/dist/service/workspace-git-exclude-service.d.ts +4 -0
- package/dist/service/workspace-git-exclude-service.js +119 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +1 -0
- package/dist/service/workspace-queue-workbench-service.js +4 -2
- package/dist/service/workspace-service.js +2 -0
- 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/supervisor.js +2 -1
- package/dist/terminal.js +1 -1
- package/dist/util/node-operation-parsers.js +2 -2
- 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 -3
- package/dist/util/runner-native-session-parsers.js +48 -20
- package/dist/util/safe-error.d.ts +2 -0
- package/dist/util/safe-error.js +5 -0
- package/package.json +2 -2
|
@@ -8,7 +8,7 @@ const CLAUDE_PLAN_TAG_CLOSE = '</plan_mode>';
|
|
|
8
8
|
*/
|
|
9
9
|
export function withClaudePlanTag(input) {
|
|
10
10
|
return `${CLAUDE_PLAN_TAG_OPEN}
|
|
11
|
-
|
|
11
|
+
You are in Plan Mode. Perform only read-only analysis and planning. Do not create, modify, or delete files, and do not run commands with side effects. Wrap the complete final plan in <proposed_plan> and </proposed_plan> tags without repeating the plan outside those tags.
|
|
12
12
|
${CLAUDE_PLAN_TAG_CLOSE}
|
|
13
13
|
|
|
14
14
|
${input}`;
|
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',
|
|
@@ -14,24 +18,28 @@ const definitions = {
|
|
|
14
18
|
runner: 'codex',
|
|
15
19
|
models: [],
|
|
16
20
|
accessOptions: [
|
|
17
|
-
{
|
|
21
|
+
{
|
|
22
|
+
id: 'on-request',
|
|
23
|
+
label: 'On-request',
|
|
24
|
+
description: 'Ask when additional permission is required.'
|
|
25
|
+
},
|
|
18
26
|
{
|
|
19
27
|
id: 'workspace-write',
|
|
20
28
|
label: 'Workspace write',
|
|
21
|
-
description: '
|
|
29
|
+
description: 'Allow writes in the current Workspace.'
|
|
22
30
|
},
|
|
23
31
|
{
|
|
24
32
|
id: 'full-access',
|
|
25
33
|
label: 'Full access',
|
|
26
|
-
description: '
|
|
34
|
+
description: 'Allow full access without individual confirmations.'
|
|
27
35
|
},
|
|
28
|
-
{ id: 'read-only', label: 'Read-only', description: '
|
|
36
|
+
{ id: 'read-only', label: 'Read-only', description: 'Restrict Codex to a read-only sandbox.' }
|
|
29
37
|
],
|
|
30
38
|
commands: [
|
|
31
39
|
{
|
|
32
40
|
id: 'compact',
|
|
33
41
|
label: '/compact',
|
|
34
|
-
description:
|
|
42
|
+
description: COMMON_COMMAND_DESCRIPTIONS.compact,
|
|
35
43
|
inputHint: '/compact',
|
|
36
44
|
interaction: 'IMMEDIATE_ACTION'
|
|
37
45
|
},
|
|
@@ -39,14 +47,14 @@ const definitions = {
|
|
|
39
47
|
id: 'plan',
|
|
40
48
|
label: '/plan',
|
|
41
49
|
stateLabel: 'Plan Mode',
|
|
42
|
-
description:
|
|
50
|
+
description: COMMON_COMMAND_DESCRIPTIONS.plan,
|
|
43
51
|
inputHint: '/plan',
|
|
44
52
|
interaction: 'TOGGLE'
|
|
45
53
|
},
|
|
46
54
|
{
|
|
47
55
|
id: 'fast',
|
|
48
56
|
label: '/fast',
|
|
49
|
-
description: '
|
|
57
|
+
description: 'Toggle the fast service tier when supported.',
|
|
50
58
|
inputHint: '/fast',
|
|
51
59
|
interaction: 'TOGGLE'
|
|
52
60
|
}
|
|
@@ -74,21 +82,25 @@ const definitions = {
|
|
|
74
82
|
{ id: 'haiku', label: 'Claude Haiku', supportedEfforts: ['low', 'medium'] }
|
|
75
83
|
],
|
|
76
84
|
accessOptions: [
|
|
77
|
-
{ id: 'default', label: 'Default', description: '
|
|
85
|
+
{ id: 'default', label: 'Default', description: 'Use Claude Code default confirmations.' },
|
|
78
86
|
{
|
|
79
87
|
id: 'accept-edits',
|
|
80
88
|
label: 'Accept edits',
|
|
81
|
-
description: '
|
|
89
|
+
description: 'Automatically accept edits in the current Workspace.'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'bypass',
|
|
93
|
+
label: 'Bypass permissions',
|
|
94
|
+
description: 'Bypass permission confirmations.'
|
|
82
95
|
},
|
|
83
|
-
{ id: '
|
|
84
|
-
{ id: 'plan', label: 'Plan Mode', description: '以 Claude Code 的计划模式运行,不执行工具。' }
|
|
96
|
+
{ id: 'plan', label: 'Plan Mode', description: 'Run in Plan Mode without executing tools.' }
|
|
85
97
|
],
|
|
86
98
|
commands: [
|
|
87
99
|
{
|
|
88
100
|
id: 'compact',
|
|
89
101
|
runner: 'claude-code',
|
|
90
102
|
label: '/compact',
|
|
91
|
-
description:
|
|
103
|
+
description: COMMON_COMMAND_DESCRIPTIONS.compact,
|
|
92
104
|
inputHint: '/compact',
|
|
93
105
|
source: 'CLAUDE_AGENT_SDK',
|
|
94
106
|
interaction: 'IMMEDIATE_ACTION',
|
|
@@ -100,7 +112,7 @@ const definitions = {
|
|
|
100
112
|
runner: 'claude-code',
|
|
101
113
|
label: '/plan',
|
|
102
114
|
stateLabel: 'Plan Mode',
|
|
103
|
-
description:
|
|
115
|
+
description: COMMON_COMMAND_DESCRIPTIONS.plan,
|
|
104
116
|
inputHint: '/plan',
|
|
105
117
|
source: 'CLAUDE_AGENT_SDK',
|
|
106
118
|
interaction: 'TOGGLE',
|
|
@@ -116,12 +128,12 @@ const definitions = {
|
|
|
116
128
|
{
|
|
117
129
|
id: 'default',
|
|
118
130
|
label: 'Default',
|
|
119
|
-
description: '
|
|
131
|
+
description: 'Use OpenCode and Workspace permission configuration.'
|
|
120
132
|
},
|
|
121
133
|
{
|
|
122
134
|
id: 'auto',
|
|
123
135
|
label: 'Auto approve',
|
|
124
|
-
description: '
|
|
136
|
+
description: 'Automatically allow requested tool permissions.'
|
|
125
137
|
}
|
|
126
138
|
],
|
|
127
139
|
commands: [
|
|
@@ -129,7 +141,7 @@ const definitions = {
|
|
|
129
141
|
id: 'compact',
|
|
130
142
|
runner: 'opencode',
|
|
131
143
|
label: '/compact',
|
|
132
|
-
description:
|
|
144
|
+
description: COMMON_COMMAND_DESCRIPTIONS.compact,
|
|
133
145
|
inputHint: '/compact',
|
|
134
146
|
source: 'OPENCODE_SERVER',
|
|
135
147
|
interaction: 'IMMEDIATE_ACTION',
|
|
@@ -141,7 +153,7 @@ const definitions = {
|
|
|
141
153
|
runner: 'opencode',
|
|
142
154
|
label: '/plan',
|
|
143
155
|
stateLabel: 'Plan Mode',
|
|
144
|
-
description:
|
|
156
|
+
description: COMMON_COMMAND_DESCRIPTIONS.plan,
|
|
145
157
|
inputHint: '/plan',
|
|
146
158
|
source: 'OPENCODE_SERVER',
|
|
147
159
|
interaction: 'TOGGLE',
|
package/dist/runner-usage.js
CHANGED
|
@@ -70,9 +70,9 @@ export class RunnerUsageReader {
|
|
|
70
70
|
'Content-Type': 'application/json'
|
|
71
71
|
});
|
|
72
72
|
const windows = [
|
|
73
|
-
usageWindow(value, 'five_hour', '5
|
|
74
|
-
usageWindow(value, 'seven_day', '7
|
|
75
|
-
usageWindow(value, 'seven_day_sonnet', '7
|
|
73
|
+
usageWindow(value, 'five_hour', '5-hour limit'),
|
|
74
|
+
usageWindow(value, 'seven_day', '7-day limit'),
|
|
75
|
+
usageWindow(value, 'seven_day_sonnet', '7-day Sonnet limit')
|
|
76
76
|
].filter((window) => window !== undefined);
|
|
77
77
|
if (windows.length === 0)
|
|
78
78
|
throw new Error('USAGE_RESPONSE_INVALID');
|
|
@@ -158,9 +158,9 @@ function codexUsageWindow(value, key) {
|
|
|
158
158
|
const window = record(record(value)?.rate_limit)?.[key];
|
|
159
159
|
const duration = number(record(window)?.limit_window_seconds);
|
|
160
160
|
const label = duration !== undefined && approximately(duration, 5 * 60 * 60)
|
|
161
|
-
? '5
|
|
161
|
+
? '5-hour limit'
|
|
162
162
|
: duration !== undefined && approximately(duration, 7 * 24 * 60 * 60)
|
|
163
|
-
? '7
|
|
163
|
+
? '7-day limit'
|
|
164
164
|
: undefined;
|
|
165
165
|
return label === undefined ? undefined : usageWindow(value, key, label);
|
|
166
166
|
}
|
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;
|
|
@@ -138,11 +138,6 @@ export declare class NodeRuntimeState {
|
|
|
138
138
|
readonly outputPreview: string;
|
|
139
139
|
readonly failed?: boolean;
|
|
140
140
|
}): NodeConversationTurn;
|
|
141
|
-
listWorkspaceActivity(input: {
|
|
142
|
-
readonly workspaceId: string;
|
|
143
|
-
readonly cursor?: string;
|
|
144
|
-
readonly limit?: number;
|
|
145
|
-
}): WorkspaceActivityPage;
|
|
146
141
|
createApproval(input: {
|
|
147
142
|
readonly runId: string;
|
|
148
143
|
readonly approvalId: string;
|
|
@@ -156,8 +151,7 @@ export declare class NodeRuntimeState {
|
|
|
156
151
|
expireDueApprovals(): readonly NodeApproval[];
|
|
157
152
|
listNonterminalRuns(): readonly NodeAgentRun[];
|
|
158
153
|
lastRunSequence(id: string): number;
|
|
159
|
-
|
|
160
|
-
getSnapshot(id: string): unknown | undefined;
|
|
154
|
+
removeTerminalRun(runId: string): void;
|
|
161
155
|
hasActiveWorkspaceLease(workspaceId: string): boolean;
|
|
162
156
|
/** Removes a terminal Session's process-local projection after its native history is deleted. */
|
|
163
157
|
removeAgentSession(sessionId: string): void;
|
|
@@ -168,7 +162,6 @@ export declare class NodeRuntimeState {
|
|
|
168
162
|
private requireSession;
|
|
169
163
|
private requireRun;
|
|
170
164
|
private requireApproval;
|
|
171
|
-
private recordWorkspaceActivity;
|
|
172
165
|
private updateTurnForRun;
|
|
173
166
|
private projectEvent;
|
|
174
167
|
}
|
package/dist/runtime-state.js
CHANGED
|
@@ -9,22 +9,22 @@ export class NodeRuntimeState {
|
|
|
9
9
|
nodeId;
|
|
10
10
|
getWorkspace;
|
|
11
11
|
now;
|
|
12
|
+
static MAX_COMPLETED_TURNS_PER_SESSION = 10;
|
|
12
13
|
sessions = new Map();
|
|
13
14
|
runs = new Map();
|
|
14
15
|
messageRuns = new Map();
|
|
15
16
|
events = new Map();
|
|
16
17
|
turns = new Map();
|
|
17
18
|
approvals = new Map();
|
|
18
|
-
workspaceEvents = new Map();
|
|
19
19
|
/** A Session owns at most one running turn; Workspace sessions may run concurrently. */
|
|
20
20
|
leases = new Map();
|
|
21
21
|
/** Session FIFO metadata is deliberately process-local with the rest of run state. */
|
|
22
22
|
queuedRuns = new Map();
|
|
23
23
|
queueVersions = new Map();
|
|
24
24
|
pausedQueues = new Set();
|
|
25
|
-
|
|
25
|
+
/** Bounded tombstones reject stale internal start envelopes after terminal cleanup. */
|
|
26
|
+
terminalRunIds = new Set();
|
|
26
27
|
nextEventId = 1;
|
|
27
|
-
nextWorkspaceEventId = 1;
|
|
28
28
|
constructor(nodeId, getWorkspace, now = Date.now) {
|
|
29
29
|
this.nodeId = nodeId;
|
|
30
30
|
this.getWorkspace = getWorkspace;
|
|
@@ -73,6 +73,8 @@ export class NodeRuntimeState {
|
|
|
73
73
|
}
|
|
74
74
|
/** Internal envelope compatibility for a Run already accepted in this process. */
|
|
75
75
|
adoptRun(input) {
|
|
76
|
+
if (this.terminalRunIds.has(input.runId))
|
|
77
|
+
throw new Error('RUN_TERMINAL');
|
|
76
78
|
let session = this.sessions.get(input.sessionId);
|
|
77
79
|
if (session === undefined) {
|
|
78
80
|
const now = this.now();
|
|
@@ -316,11 +318,6 @@ export class NodeRuntimeState {
|
|
|
316
318
|
this.queuedRuns.set(session.id, [...(this.queuedRuns.get(session.id) ?? []), run.id]);
|
|
317
319
|
this.bumpQueueVersion(session.id);
|
|
318
320
|
this.turns.set(session.id, [...(this.turns.get(session.id) ?? []), fixedTurn]);
|
|
319
|
-
this.recordWorkspaceActivity(run.workspaceId, 'run.created', {
|
|
320
|
-
runId: run.id,
|
|
321
|
-
sessionId: session.id,
|
|
322
|
-
runner: run.runner
|
|
323
|
-
});
|
|
324
321
|
this.replaceSession(session.id, { lastActivityAt: now });
|
|
325
322
|
return { run, created: true };
|
|
326
323
|
}
|
|
@@ -402,7 +399,6 @@ export class NodeRuntimeState {
|
|
|
402
399
|
this.bumpQueueVersion(run.sessionId);
|
|
403
400
|
this.runs.delete(runId);
|
|
404
401
|
this.events.delete(runId);
|
|
405
|
-
this.snapshots.delete(runId);
|
|
406
402
|
this.turns.set(run.sessionId, (this.turns.get(run.sessionId) ?? []).filter((turn) => turn.runId !== runId));
|
|
407
403
|
for (const [key, candidate] of this.messageRuns)
|
|
408
404
|
if (candidate === runId)
|
|
@@ -468,12 +464,6 @@ export class NodeRuntimeState {
|
|
|
468
464
|
if (input.status !== undefined)
|
|
469
465
|
this.transitionRun(input.runId, input.status);
|
|
470
466
|
this.projectEvent(value);
|
|
471
|
-
const run = this.requireRun(input.runId);
|
|
472
|
-
this.recordWorkspaceActivity(run.workspaceId, 'run.updated', {
|
|
473
|
-
runId: run.id,
|
|
474
|
-
eventType: input.eventType,
|
|
475
|
-
status: input.status ?? null
|
|
476
|
-
});
|
|
477
467
|
return value;
|
|
478
468
|
}
|
|
479
469
|
listRunEvents(id, after = 0) {
|
|
@@ -559,16 +549,6 @@ export class NodeRuntimeState {
|
|
|
559
549
|
this.replaceSession(session.id, { lastActivityAt: now });
|
|
560
550
|
return completedTurn;
|
|
561
551
|
}
|
|
562
|
-
listWorkspaceActivity(input) {
|
|
563
|
-
const all = this.workspaceEvents.get(input.workspaceId) ?? [];
|
|
564
|
-
const start = decodeCursor(input.cursor, input.workspaceId);
|
|
565
|
-
const limit = Math.min(Math.max(input.limit ?? 30, 1), 500);
|
|
566
|
-
const events = all.slice(start, start + limit);
|
|
567
|
-
return {
|
|
568
|
-
events,
|
|
569
|
-
nextCursor: start + limit < all.length ? encodeCursor(input.workspaceId, start + limit) : null
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
552
|
createApproval(input) {
|
|
573
553
|
this.requireRun(input.runId);
|
|
574
554
|
if (this.approvals.has(input.approvalId))
|
|
@@ -631,11 +611,30 @@ export class NodeRuntimeState {
|
|
|
631
611
|
lastRunSequence(id) {
|
|
632
612
|
return this.events.get(id)?.at(-1)?.sequence ?? 0;
|
|
633
613
|
}
|
|
634
|
-
|
|
635
|
-
this.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
614
|
+
removeTerminalRun(runId) {
|
|
615
|
+
const run = this.requireRun(runId);
|
|
616
|
+
if (!terminal(run.status))
|
|
617
|
+
throw new Error('RUN_ACTIVE');
|
|
618
|
+
this.terminalRunIds.add(runId);
|
|
619
|
+
if (this.terminalRunIds.size > 1_024)
|
|
620
|
+
this.terminalRunIds.delete(this.terminalRunIds.values().next().value);
|
|
621
|
+
const queue = this.queuedRuns.get(run.sessionId) ?? [];
|
|
622
|
+
if (queue.includes(runId)) {
|
|
623
|
+
this.queuedRuns.set(run.sessionId, queue.filter((candidate) => candidate !== runId));
|
|
624
|
+
this.bumpQueueVersion(run.sessionId);
|
|
625
|
+
}
|
|
626
|
+
this.runs.delete(runId);
|
|
627
|
+
this.events.delete(runId);
|
|
628
|
+
const turns = this.turns.get(run.sessionId) ?? [];
|
|
629
|
+
const completed = turns.filter((turn) => terminalTurn(turn.status));
|
|
630
|
+
const retainedCompleted = new Set(completed.slice(-NodeRuntimeState.MAX_COMPLETED_TURNS_PER_SESSION).map((turn) => turn.id));
|
|
631
|
+
this.turns.set(run.sessionId, turns.filter((turn) => !terminalTurn(turn.status) || retainedCompleted.has(turn.id)));
|
|
632
|
+
for (const [key, candidate] of this.messageRuns)
|
|
633
|
+
if (candidate === runId)
|
|
634
|
+
this.messageRuns.delete(key);
|
|
635
|
+
for (const [approvalId, approval] of this.approvals)
|
|
636
|
+
if (approval.runId === runId)
|
|
637
|
+
this.approvals.delete(approvalId);
|
|
639
638
|
}
|
|
640
639
|
hasActiveWorkspaceLease(workspaceId) {
|
|
641
640
|
return [...this.leases.values()]
|
|
@@ -658,7 +657,6 @@ export class NodeRuntimeState {
|
|
|
658
657
|
for (const runId of runIds) {
|
|
659
658
|
this.runs.delete(runId);
|
|
660
659
|
this.events.delete(runId);
|
|
661
|
-
this.snapshots.delete(runId);
|
|
662
660
|
}
|
|
663
661
|
for (const [key, runId] of this.messageRuns)
|
|
664
662
|
if (runIds.has(runId))
|
|
@@ -681,7 +679,6 @@ export class NodeRuntimeState {
|
|
|
681
679
|
for (const runId of runIds) {
|
|
682
680
|
this.runs.delete(runId);
|
|
683
681
|
this.events.delete(runId);
|
|
684
|
-
this.snapshots.delete(runId);
|
|
685
682
|
}
|
|
686
683
|
for (const [key, runId] of this.messageRuns)
|
|
687
684
|
if (runIds.has(runId))
|
|
@@ -689,7 +686,6 @@ export class NodeRuntimeState {
|
|
|
689
686
|
for (const [approvalId, approval] of this.approvals)
|
|
690
687
|
if (runIds.has(approval.runId))
|
|
691
688
|
this.approvals.delete(approvalId);
|
|
692
|
-
this.workspaceEvents.delete(workspaceId);
|
|
693
689
|
for (const sessionId of sessionIds) {
|
|
694
690
|
this.queuedRuns.delete(sessionId);
|
|
695
691
|
this.queueVersions.delete(sessionId);
|
|
@@ -730,19 +726,6 @@ export class NodeRuntimeState {
|
|
|
730
726
|
throw new Error('APPROVAL_NOT_FOUND');
|
|
731
727
|
return value;
|
|
732
728
|
}
|
|
733
|
-
recordWorkspaceActivity(workspaceId, eventType, payload) {
|
|
734
|
-
const event = {
|
|
735
|
-
id: this.nextWorkspaceEventId++,
|
|
736
|
-
workspaceId,
|
|
737
|
-
eventType,
|
|
738
|
-
payload,
|
|
739
|
-
createdAt: this.now()
|
|
740
|
-
};
|
|
741
|
-
this.workspaceEvents.set(workspaceId, [
|
|
742
|
-
...(this.workspaceEvents.get(workspaceId) ?? []),
|
|
743
|
-
event
|
|
744
|
-
]);
|
|
745
|
-
}
|
|
746
729
|
updateTurnForRun(runId, update) {
|
|
747
730
|
const run = this.requireRun(runId);
|
|
748
731
|
const current = this.turns.get(run.sessionId) ?? [];
|
|
@@ -840,6 +823,9 @@ export class NodeRuntimeState {
|
|
|
840
823
|
function terminal(status) {
|
|
841
824
|
return ['SUCCEEDED', 'FAILED', 'CANCELLED', 'INTERRUPTED', 'LOST'].includes(status);
|
|
842
825
|
}
|
|
826
|
+
function terminalTurn(status) {
|
|
827
|
+
return ['SUCCEEDED', 'FAILED', 'CANCELLED', 'INTERRUPTED'].includes(status);
|
|
828
|
+
}
|
|
843
829
|
function transitionAllowed(from, to) {
|
|
844
830
|
return !terminal(from) || from === to;
|
|
845
831
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare class AttachmentDomainState<TCachedRunImages, TNativeImageSource> {
|
|
2
2
|
readonly runDirectories: Map<string, string>;
|
|
3
|
+
readonly runFileDirectories: Map<string, string>;
|
|
3
4
|
readonly runImages: Map<string, TCachedRunImages>;
|
|
4
5
|
readonly nativeHistoryImages: Map<string, TNativeImageSource[]>;
|
|
6
|
+
readonly nativeHistoryImageTimers: Map<string, NodeJS.Timeout>;
|
|
5
7
|
}
|
|
@@ -16,35 +16,66 @@ export class ConversationHistoryService {
|
|
|
16
16
|
async read(session, input) {
|
|
17
17
|
const snapshotSequence = this.options.snapshotSequence();
|
|
18
18
|
const readAt = Date.now();
|
|
19
|
-
|
|
19
|
+
let official = await this.readOfficial(session, input);
|
|
20
20
|
if (official !== undefined) {
|
|
21
|
+
const limit = Math.min(Math.max(input.limit ?? 30, 1), 500);
|
|
22
|
+
const runtimeTurns = this.options.runtime.getAgentSession(session.id) === undefined
|
|
23
|
+
? []
|
|
24
|
+
: this.options.runtime.listConversationTurns({ sessionId: session.id, limit: 500 }).turns;
|
|
25
|
+
const initialOfficialRunIds = new Set(official.turns.flatMap((turn) => (turn.runId === null ? [] : [turn.runId])));
|
|
26
|
+
const absentLocalTurns = runtimeTurns.filter((turn) => turn.runId === null || !initialOfficialRunIds.has(turn.runId));
|
|
27
|
+
const officialFloor = Math.min(...official.turns.map((turn) => Math.max(turn.startedAt ?? 0, turn.completedAt ?? 0)));
|
|
28
|
+
const missingLocalTurns = official.turns.length === 0
|
|
29
|
+
? absentLocalTurns.slice(-limit)
|
|
30
|
+
: officialFloor > 0
|
|
31
|
+
? absentLocalTurns.filter((turn) => Math.max(turn.startedAt ?? 0, turn.completedAt ?? 0) >= officialFloor)
|
|
32
|
+
: absentLocalTurns.slice(-1);
|
|
33
|
+
if (input.cursor === undefined &&
|
|
34
|
+
missingLocalTurns.length > 0 &&
|
|
35
|
+
official.turns.length + missingLocalTurns.length > limit) {
|
|
36
|
+
const reserved = Math.min(missingLocalTurns.length, Math.max(0, limit - 1));
|
|
37
|
+
const narrowed = await this.readOfficial(session, { ...input, limit: limit - reserved });
|
|
38
|
+
if (narrowed !== undefined)
|
|
39
|
+
official = narrowed;
|
|
40
|
+
}
|
|
21
41
|
const officialTurns = await this.attachNativeImages(session, official.turns);
|
|
22
42
|
const officialRunIds = new Set(officialTurns.flatMap((turn) => (turn.runId === null ? [] : [turn.runId])));
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const pendingItemsByRunId = new Map();
|
|
44
|
+
for (const turn of runtimeTurns) {
|
|
45
|
+
if (turn.runId === null || !officialRunIds.has(turn.runId))
|
|
46
|
+
continue;
|
|
47
|
+
const pendingItems = turn.items.filter((item) => item.kind === 'user_input_request' && item.status === 'PENDING');
|
|
48
|
+
if (pendingItems.length > 0)
|
|
49
|
+
pendingItemsByRunId.set(turn.runId, pendingItems);
|
|
50
|
+
}
|
|
51
|
+
const availableLocalSlots = Math.max(0, limit - officialTurns.length);
|
|
52
|
+
const localCandidates = (input.cursor === undefined ? missingLocalTurns : []).sort((left, right) => (left.startedAt ?? 0) - (right.startedAt ?? 0));
|
|
53
|
+
const localTurns = availableLocalSlots === 0 ? [] : localCandidates.slice(-availableLocalSlots);
|
|
54
|
+
const localRequestIds = new Set([
|
|
55
|
+
...localTurns.flatMap((turn) => turn.items.flatMap((item) => {
|
|
56
|
+
const requestId = item.kind === 'user_input_request' && isPlainRecord(item.payload)
|
|
57
|
+
? item.payload.requestId
|
|
58
|
+
: undefined;
|
|
59
|
+
return typeof requestId === 'string' ? [requestId] : [];
|
|
60
|
+
})),
|
|
61
|
+
...[...pendingItemsByRunId.values()].flatMap((items) => items.flatMap((item) => {
|
|
62
|
+
const requestId = isPlainRecord(item.payload) ? item.payload.requestId : undefined;
|
|
63
|
+
return typeof requestId === 'string' ? [requestId] : [];
|
|
64
|
+
}))
|
|
65
|
+
]);
|
|
39
66
|
const turns = [
|
|
40
67
|
...officialTurns
|
|
41
|
-
.map((turn) =>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
68
|
+
.map((turn) => {
|
|
69
|
+
const pendingItems = turn.runId === null ? [] : (pendingItemsByRunId.get(turn.runId) ?? []);
|
|
70
|
+
const items = [
|
|
71
|
+
...turn.items.filter((item) => item.kind !== 'user_input_request' ||
|
|
72
|
+
!isPlainRecord(item.payload) ||
|
|
73
|
+
typeof item.payload.requestId !== 'string' ||
|
|
74
|
+
!localRequestIds.has(item.payload.requestId)),
|
|
75
|
+
...pendingItems
|
|
76
|
+
];
|
|
77
|
+
return { ...turn, items };
|
|
78
|
+
})
|
|
48
79
|
.filter((turn) => turn.items.length > 0),
|
|
49
80
|
...localTurns
|
|
50
81
|
].sort((left, right) => (left.startedAt ?? 0) - (right.startedAt ?? 0));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ConversationSegment, ConversationSegmentPage } from '@myagentroam/protocol';
|
|
2
|
+
import type { NodeAgentSession, NodeConversationTurn } from '../database.js';
|
|
3
|
+
import type { ConversationHistoryPage } from '../util/runner-native-session-parsers.js';
|
|
4
|
+
export declare function conversationSegments(turn: NodeConversationTurn): ConversationSegment[];
|
|
5
|
+
export declare function conversationSegmentIdentityForItem(turn: NodeConversationTurn, itemId: string, itemKind?: string): {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly index: number;
|
|
8
|
+
};
|
|
9
|
+
export declare class ConversationSegmentService {
|
|
10
|
+
private readonly readTurns;
|
|
11
|
+
constructor(readTurns: (session: NodeAgentSession, input: {
|
|
12
|
+
readonly cursor?: string;
|
|
13
|
+
readonly limit?: number;
|
|
14
|
+
}) => Promise<ConversationHistoryPage>);
|
|
15
|
+
projectInitial(session: NodeAgentSession, page: ConversationHistoryPage, limit: number): ConversationSegmentPage;
|
|
16
|
+
read(session: NodeAgentSession, input: {
|
|
17
|
+
readonly cursor?: string;
|
|
18
|
+
readonly limit?: number;
|
|
19
|
+
}): Promise<ConversationSegmentPage>;
|
|
20
|
+
}
|