@myagentroam/node 0.9.0 → 0.9.2
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 +38 -12
- package/dist/native-session-history.js +72 -14
- package/dist/runner/abstract-runner.d.ts +1 -1
- package/dist/runner/abstract-runner.js +2 -2
- package/dist/runner/claude/managed-run-controller.js +17 -7
- package/dist/runner/claude-code-runner.js +3 -4
- package/dist/runner/codex/conversation-parser.d.ts +2 -2
- package/dist/runner/codex/conversation-parser.js +30 -12
- package/dist/runner/codex/managed-run-controller.js +7 -6
- package/dist/runner/codex-runner.d.ts +1 -1
- package/dist/runner/codex-runner.js +10 -8
- package/dist/runner/opencode/conversation-parser.d.ts +11 -7
- package/dist/runner/opencode/conversation-parser.js +15 -15
- package/dist/runner/opencode/managed-run-controller.d.ts +2 -1
- package/dist/runner/opencode/managed-run-controller.js +26 -12
- package/dist/runner-command-engine.js +1 -1
- package/dist/runner-profiles.js +25 -17
- package/dist/runner-usage.js +5 -5
- 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 +155 -0
- package/dist/service/mcp-installation-verifier.js +1 -1
- 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-request-service.js +2 -1
- package/dist/service/run-attachment-service.d.ts +3 -2
- package/dist/service/run-attachment-service.js +21 -11
- package/dist/service/run-event-service.d.ts +1 -0
- package/dist/service/run-event-service.js +8 -2
- package/dist/service/session-catalog-service.js +4 -4
- 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.js +3 -26
- package/dist/service/skill-install-service.js +4 -74
- package/dist/service/skill-node-operation-service.js +2 -1
- 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.js +3 -2
- package/dist/service/workspace-service.js +2 -0
- 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-native-session-parsers.d.ts +2 -3
- package/dist/util/runner-native-session-parsers.js +5 -14
- package/dist/util/safe-error.d.ts +2 -0
- package/dist/util/safe-error.js +5 -0
- package/package.json +2 -2
|
@@ -44,7 +44,7 @@ export declare class CodexRunner extends AbstractRunner<'codex'> {
|
|
|
44
44
|
readExternalActivity(session: NodeAgentSession): Promise<"UNAVAILABLE" | "MANAGED_ACTIVE" | "EXTERNAL_ACTIVE" | "IDLE" | undefined>;
|
|
45
45
|
acceptsTruncatedNativeHistory(): boolean;
|
|
46
46
|
readManagedRunnerTitle(session: NodeAgentSession, nativeSessionId: string): Promise<string | undefined>;
|
|
47
|
-
|
|
47
|
+
nativeImageRoots(session: NodeAgentSession): readonly string[];
|
|
48
48
|
managedRunForNativeTurn(nativeTurnId: string): string | undefined;
|
|
49
49
|
protected profileForValidation(): RunnerProfile;
|
|
50
50
|
defaultConfiguration(_workspace?: NodeWorkspace, environment?: Readonly<Record<string, string>>): RunnerDefaultConfiguration;
|
|
@@ -6,7 +6,7 @@ import { resolve } from 'node:path';
|
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
7
7
|
import { discoverAllNativeSessions } from '../native-session-history.js';
|
|
8
8
|
import { readCodexNativeContextUsage } from '../native-session-history.js';
|
|
9
|
-
import { codexActiveTurnId, codexOfficialConversationPage, codexThreadCwd, codexThreadActivity, deduplicateDirectSessions,
|
|
9
|
+
import { codexActiveTurnId, codexOfficialConversationPage, codexThreadCwd, codexThreadActivity, deduplicateDirectSessions, extractCodexThreads, isWithinWorkspace, latestNativeActivity } from './codex/conversation-parser.js';
|
|
10
10
|
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';
|
|
@@ -248,10 +248,13 @@ export class CodexRunner extends AbstractRunner {
|
|
|
248
248
|
await this.start();
|
|
249
249
|
return extractCodexThreads(await this.listThreads()).find((thread) => thread.id === nativeSessionId)?.title;
|
|
250
250
|
}
|
|
251
|
-
|
|
252
|
-
return
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
nativeImageRoots(session) {
|
|
252
|
+
return [
|
|
253
|
+
session.cwd,
|
|
254
|
+
...(session.externalSessionId === null
|
|
255
|
+
? []
|
|
256
|
+
: [resolve(homedir(), '.codex', 'generated_images', session.externalSessionId)])
|
|
257
|
+
];
|
|
255
258
|
}
|
|
256
259
|
managedRunForNativeTurn(nativeTurnId) {
|
|
257
260
|
return this.execution.managedTurns.get(nativeTurnId)?.runId;
|
|
@@ -313,11 +316,10 @@ export class CodexRunner extends AbstractRunner {
|
|
|
313
316
|
}
|
|
314
317
|
return { activity: 'IDLE', session: context.create(external) };
|
|
315
318
|
}
|
|
316
|
-
catch
|
|
319
|
+
catch {
|
|
317
320
|
return {
|
|
318
321
|
activity: 'UNAVAILABLE',
|
|
319
|
-
failureCode: 'RUNNER_RESUME_FAILED'
|
|
320
|
-
failureDetail: externalResumeFailureDetail(error)
|
|
322
|
+
failureCode: 'RUNNER_RESUME_FAILED'
|
|
321
323
|
};
|
|
322
324
|
}
|
|
323
325
|
}
|
|
@@ -18,10 +18,14 @@ export declare function openCodeQuestions(value: unknown): {
|
|
|
18
18
|
allowOther: boolean;
|
|
19
19
|
multiSelect: boolean;
|
|
20
20
|
}[];
|
|
21
|
-
export declare function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
export declare function openCodePatchToolPayload(): {
|
|
22
|
+
namespace: string;
|
|
23
|
+
toolName: string;
|
|
24
|
+
title: string;
|
|
25
|
+
inputSummary: null;
|
|
26
|
+
outputSummary: string;
|
|
27
|
+
outputSummaryCode: string;
|
|
28
|
+
progressLabel: null;
|
|
29
|
+
errorCode: null;
|
|
30
|
+
truncated: boolean;
|
|
31
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { basename } from 'node:path';
|
|
2
1
|
import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '../codex/conversation-parser.js';
|
|
3
2
|
export function openCodeConversationPage(session, messages, input, managedTurn) {
|
|
4
3
|
const records = messages.flatMap((value) => {
|
|
@@ -114,10 +113,11 @@ function partItem(session, turnId, raw, planMode, startedAt, completedAt, sequen
|
|
|
114
113
|
if (part.type === 'compaction')
|
|
115
114
|
return item(session, turnId, part.id, 'context_compaction', 'COMPLETED', {
|
|
116
115
|
phase: 'COMPLETED',
|
|
117
|
-
summary: '
|
|
116
|
+
summary: 'Context compacted',
|
|
117
|
+
summaryCode: 'CONTEXT_COMPACTED'
|
|
118
118
|
}, startedAt, completedAt, sequence);
|
|
119
119
|
if (part.type === 'patch')
|
|
120
|
-
return item(session, turnId, part.id, '
|
|
120
|
+
return item(session, turnId, part.id, 'tool_call', 'COMPLETED', openCodePatchToolPayload(), startedAt, completedAt, sequence);
|
|
121
121
|
if (part.type === 'step-start' || part.type === 'step-finish')
|
|
122
122
|
return undefined;
|
|
123
123
|
if (part.type === 'text' || part.type === 'reasoning')
|
|
@@ -162,18 +162,18 @@ export function openCodeQuestions(value) {
|
|
|
162
162
|
];
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
-
export function
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
165
|
+
export function openCodePatchToolPayload() {
|
|
166
|
+
return {
|
|
167
|
+
namespace: 'opencode',
|
|
168
|
+
toolName: 'patch',
|
|
169
|
+
title: 'patch',
|
|
170
|
+
inputSummary: null,
|
|
171
|
+
outputSummary: 'OpenCode applied the patch',
|
|
172
|
+
outputSummaryCode: 'OPENCODE_PATCH_APPLIED',
|
|
173
|
+
progressLabel: null,
|
|
174
|
+
errorCode: null,
|
|
175
|
+
truncated: false
|
|
176
|
+
};
|
|
177
177
|
}
|
|
178
178
|
function item(session, turnId, nativeId, kind, status, payload, startedAt, completedAt, sequence) {
|
|
179
179
|
return {
|
|
@@ -7,6 +7,7 @@ interface OpenCodeManagedRunHost {
|
|
|
7
7
|
intercepted(): boolean;
|
|
8
8
|
readonly active: Set<string>;
|
|
9
9
|
parseAttachments(value: unknown): readonly RunnerImageAttachment[];
|
|
10
|
+
persistAttachments(cwd: string, runId: string, attachments: readonly RunnerImageAttachment[]): Promise<readonly string[]>;
|
|
10
11
|
emit(runId: string, eventType: string, payload: unknown, status?: FakeRunnerStatus): void;
|
|
11
12
|
emitItem(runId: string, item: OpenCodePublicItem): void;
|
|
12
13
|
adopt(input: {
|
|
@@ -40,7 +41,7 @@ interface OpenCodeManagedRunHost {
|
|
|
40
41
|
}
|
|
41
42
|
type OpenCodePublicItem = {
|
|
42
43
|
readonly itemId: string;
|
|
43
|
-
readonly kind: 'assistant_message' | 'plan' | 'reasoning_summary' | 'tool_call' | 'user_input_request' | 'context_compaction' | '
|
|
44
|
+
readonly kind: 'assistant_message' | 'plan' | 'reasoning_summary' | 'tool_call' | 'user_input_request' | 'context_compaction' | 'unknown';
|
|
44
45
|
readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED';
|
|
45
46
|
readonly payload: Record<string, unknown>;
|
|
46
47
|
readonly merge?: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseSecretEnvironment } from '../../util/secret-environment.js';
|
|
2
|
+
import { safeErrorCode } from '../../util/safe-error.js';
|
|
2
3
|
import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '../codex/conversation-parser.js';
|
|
3
|
-
import {
|
|
4
|
+
import { openCodePatchToolPayload, openCodeQuestions } from './conversation-parser.js';
|
|
4
5
|
export class OpenCodeManagedRunController {
|
|
5
6
|
runner;
|
|
6
7
|
host;
|
|
@@ -29,10 +30,10 @@ export class OpenCodeManagedRunController {
|
|
|
29
30
|
commandId: 'plan',
|
|
30
31
|
active: true,
|
|
31
32
|
label: 'Plan Mode',
|
|
32
|
-
detail: '
|
|
33
|
+
detail: 'Subsequent messages use the OpenCode Plan Agent for read-only analysis.',
|
|
33
34
|
closable: true,
|
|
34
35
|
closeInput: '/plan',
|
|
35
|
-
continuation: { label: '
|
|
36
|
+
continuation: { label: 'Implement', prompt: 'Implement the plan above.' }
|
|
36
37
|
});
|
|
37
38
|
return { command: command.id, states: this.host.commandStates(session.id) };
|
|
38
39
|
}
|
|
@@ -56,7 +57,7 @@ export class OpenCodeManagedRunController {
|
|
|
56
57
|
attachments = this.host.parseAttachments(payload.attachments);
|
|
57
58
|
}
|
|
58
59
|
catch (error) {
|
|
59
|
-
this.host.emit(payload.runId, 'run.rejected', { code: error
|
|
60
|
+
this.host.emit(payload.runId, 'run.rejected', { code: safeErrorCode(error, 'RUNNER_INPUT_INVALID') }, 'FAILED');
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
62
63
|
void this.run({
|
|
@@ -122,8 +123,8 @@ export class OpenCodeManagedRunController {
|
|
|
122
123
|
return true;
|
|
123
124
|
}
|
|
124
125
|
async run(input) {
|
|
125
|
-
// OpenCode
|
|
126
|
-
//
|
|
126
|
+
// OpenCode dynamic MCP registration belongs to Server process state. Runs that load MCP use an
|
|
127
|
+
// isolated Server so parallel sessions in one workspace do not share MCP processes or context.
|
|
127
128
|
const client = this.runner.managedClient(input.environment, hasMcpConfiguration(input.mcp) ? input.runId : undefined);
|
|
128
129
|
this.startingClients.set(input.runId, client);
|
|
129
130
|
this.startingCwds.set(input.runId, input.cwd);
|
|
@@ -181,17 +182,20 @@ export class OpenCodeManagedRunController {
|
|
|
181
182
|
return;
|
|
182
183
|
}
|
|
183
184
|
this.finish(input.runId, 'FAILED', 'run.failed', {
|
|
184
|
-
code: error
|
|
185
|
+
code: safeErrorCode(error, 'OPENCODE_EVENT_FAILED')
|
|
185
186
|
});
|
|
186
187
|
});
|
|
187
188
|
await subscriptionReady;
|
|
188
189
|
this.host.emit(input.runId, 'run.running', {}, 'RUNNING');
|
|
189
190
|
// The initial SSE snapshot can contain an idle event from before this prompt.
|
|
190
191
|
this.pendingIdle.delete(input.runId);
|
|
192
|
+
const attachmentPaths = input.attachments.length === 0
|
|
193
|
+
? []
|
|
194
|
+
: await this.host.persistAttachments(input.cwd, input.runId, input.attachments);
|
|
191
195
|
await client.prompt({
|
|
192
196
|
directory: input.cwd,
|
|
193
197
|
sessionID: nativeSessionId,
|
|
194
|
-
text: input.input,
|
|
198
|
+
text: openCodeImageInput(input.input, attachmentPaths),
|
|
195
199
|
model: input.model,
|
|
196
200
|
variant: input.effort,
|
|
197
201
|
agent: input.agent,
|
|
@@ -203,7 +207,7 @@ export class OpenCodeManagedRunController {
|
|
|
203
207
|
}
|
|
204
208
|
catch (error) {
|
|
205
209
|
this.finish(input.runId, 'FAILED', 'run.failed', {
|
|
206
|
-
code: error
|
|
210
|
+
code: safeErrorCode(error, 'OPENCODE_RUN_START_FAILED')
|
|
207
211
|
});
|
|
208
212
|
}
|
|
209
213
|
}
|
|
@@ -366,6 +370,12 @@ export class OpenCodeManagedRunController {
|
|
|
366
370
|
void this.host.captureSnapshot(runId, cwd);
|
|
367
371
|
}
|
|
368
372
|
}
|
|
373
|
+
function openCodeImageInput(input, attachmentPaths) {
|
|
374
|
+
if (attachmentPaths.length === 0)
|
|
375
|
+
return input;
|
|
376
|
+
const paths = attachmentPaths.map((path) => `- ${JSON.stringify(path)}`).join('\n');
|
|
377
|
+
return `${input}\n\nIf an inline image in this message is unavailable, use the read tool on the corresponding copy below. Do not read it again when the inline image is already visible:\n${paths}`;
|
|
378
|
+
}
|
|
369
379
|
function hasMcpConfiguration(value) {
|
|
370
380
|
return value !== null && typeof value === 'object' && Object.keys(value).length > 0;
|
|
371
381
|
}
|
|
@@ -425,14 +435,18 @@ function openCodePart(part, planMode = false) {
|
|
|
425
435
|
itemId,
|
|
426
436
|
kind: 'context_compaction',
|
|
427
437
|
status: 'COMPLETED',
|
|
428
|
-
payload: {
|
|
438
|
+
payload: {
|
|
439
|
+
phase: 'COMPLETED',
|
|
440
|
+
summary: 'Context compacted',
|
|
441
|
+
summaryCode: 'CONTEXT_COMPACTED'
|
|
442
|
+
}
|
|
429
443
|
};
|
|
430
444
|
if (part.type === 'patch')
|
|
431
445
|
return {
|
|
432
446
|
itemId,
|
|
433
|
-
kind: '
|
|
447
|
+
kind: 'tool_call',
|
|
434
448
|
status: 'COMPLETED',
|
|
435
|
-
payload:
|
|
449
|
+
payload: openCodePatchToolPayload(),
|
|
436
450
|
merge: true
|
|
437
451
|
};
|
|
438
452
|
if (part.type === 'step-start' || part.type === 'step-finish')
|
|
@@ -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
|
@@ -14,24 +14,28 @@ const definitions = {
|
|
|
14
14
|
runner: 'codex',
|
|
15
15
|
models: [],
|
|
16
16
|
accessOptions: [
|
|
17
|
-
{
|
|
17
|
+
{
|
|
18
|
+
id: 'on-request',
|
|
19
|
+
label: 'On-request',
|
|
20
|
+
description: 'Ask when additional permission is required.'
|
|
21
|
+
},
|
|
18
22
|
{
|
|
19
23
|
id: 'workspace-write',
|
|
20
24
|
label: 'Workspace write',
|
|
21
|
-
description: '
|
|
25
|
+
description: 'Allow writes in the current Workspace.'
|
|
22
26
|
},
|
|
23
27
|
{
|
|
24
28
|
id: 'full-access',
|
|
25
29
|
label: 'Full access',
|
|
26
|
-
description: '
|
|
30
|
+
description: 'Allow full access without individual confirmations.'
|
|
27
31
|
},
|
|
28
|
-
{ id: 'read-only', label: 'Read-only', description: '
|
|
32
|
+
{ id: 'read-only', label: 'Read-only', description: 'Restrict Codex to a read-only sandbox.' }
|
|
29
33
|
],
|
|
30
34
|
commands: [
|
|
31
35
|
{
|
|
32
36
|
id: 'compact',
|
|
33
37
|
label: '/compact',
|
|
34
|
-
description: '
|
|
38
|
+
description: 'Compact the current session context.',
|
|
35
39
|
inputHint: '/compact',
|
|
36
40
|
interaction: 'IMMEDIATE_ACTION'
|
|
37
41
|
},
|
|
@@ -39,14 +43,14 @@ const definitions = {
|
|
|
39
43
|
id: 'plan',
|
|
40
44
|
label: '/plan',
|
|
41
45
|
stateLabel: 'Plan Mode',
|
|
42
|
-
description: '
|
|
46
|
+
description: 'Toggle collaborative Plan Mode.',
|
|
43
47
|
inputHint: '/plan',
|
|
44
48
|
interaction: 'TOGGLE'
|
|
45
49
|
},
|
|
46
50
|
{
|
|
47
51
|
id: 'fast',
|
|
48
52
|
label: '/fast',
|
|
49
|
-
description: '
|
|
53
|
+
description: 'Toggle the fast service tier when supported.',
|
|
50
54
|
inputHint: '/fast',
|
|
51
55
|
interaction: 'TOGGLE'
|
|
52
56
|
}
|
|
@@ -74,21 +78,25 @@ const definitions = {
|
|
|
74
78
|
{ id: 'haiku', label: 'Claude Haiku', supportedEfforts: ['low', 'medium'] }
|
|
75
79
|
],
|
|
76
80
|
accessOptions: [
|
|
77
|
-
{ id: 'default', label: 'Default', description: '
|
|
81
|
+
{ id: 'default', label: 'Default', description: 'Use Claude Code default confirmations.' },
|
|
78
82
|
{
|
|
79
83
|
id: 'accept-edits',
|
|
80
84
|
label: 'Accept edits',
|
|
81
|
-
description: '
|
|
85
|
+
description: 'Automatically accept edits in the current Workspace.'
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'bypass',
|
|
89
|
+
label: 'Bypass permissions',
|
|
90
|
+
description: 'Bypass permission confirmations.'
|
|
82
91
|
},
|
|
83
|
-
{ id: '
|
|
84
|
-
{ id: 'plan', label: 'Plan Mode', description: '以 Claude Code 的计划模式运行,不执行工具。' }
|
|
92
|
+
{ id: 'plan', label: 'Plan Mode', description: 'Run in Plan Mode without executing tools.' }
|
|
85
93
|
],
|
|
86
94
|
commands: [
|
|
87
95
|
{
|
|
88
96
|
id: 'compact',
|
|
89
97
|
runner: 'claude-code',
|
|
90
98
|
label: '/compact',
|
|
91
|
-
description: '
|
|
99
|
+
description: 'Compact context through the Claude Agent SDK.',
|
|
92
100
|
inputHint: '/compact',
|
|
93
101
|
source: 'CLAUDE_AGENT_SDK',
|
|
94
102
|
interaction: 'IMMEDIATE_ACTION',
|
|
@@ -100,7 +108,7 @@ const definitions = {
|
|
|
100
108
|
runner: 'claude-code',
|
|
101
109
|
label: '/plan',
|
|
102
110
|
stateLabel: 'Plan Mode',
|
|
103
|
-
description: '
|
|
111
|
+
description: 'Toggle read-only tagged Plan Mode.',
|
|
104
112
|
inputHint: '/plan',
|
|
105
113
|
source: 'CLAUDE_AGENT_SDK',
|
|
106
114
|
interaction: 'TOGGLE',
|
|
@@ -116,12 +124,12 @@ const definitions = {
|
|
|
116
124
|
{
|
|
117
125
|
id: 'default',
|
|
118
126
|
label: 'Default',
|
|
119
|
-
description: '
|
|
127
|
+
description: 'Use OpenCode and Workspace permission configuration.'
|
|
120
128
|
},
|
|
121
129
|
{
|
|
122
130
|
id: 'auto',
|
|
123
131
|
label: 'Auto approve',
|
|
124
|
-
description: '
|
|
132
|
+
description: 'Automatically allow requested tool permissions.'
|
|
125
133
|
}
|
|
126
134
|
],
|
|
127
135
|
commands: [
|
|
@@ -129,7 +137,7 @@ const definitions = {
|
|
|
129
137
|
id: 'compact',
|
|
130
138
|
runner: 'opencode',
|
|
131
139
|
label: '/compact',
|
|
132
|
-
description: '
|
|
140
|
+
description: 'Compact context through OpenCode.',
|
|
133
141
|
inputHint: '/compact',
|
|
134
142
|
source: 'OPENCODE_SERVER',
|
|
135
143
|
interaction: 'IMMEDIATE_ACTION',
|
|
@@ -141,7 +149,7 @@ const definitions = {
|
|
|
141
149
|
runner: 'opencode',
|
|
142
150
|
label: '/plan',
|
|
143
151
|
stateLabel: 'Plan Mode',
|
|
144
|
-
description: '
|
|
152
|
+
description: 'Toggle the native OpenCode Plan Agent.',
|
|
145
153
|
inputHint: '/plan',
|
|
146
154
|
source: 'OPENCODE_SERVER',
|
|
147
155
|
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
|
}
|
|
@@ -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
|
+
}
|