openhorse 0.2.21 → 0.2.22
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/cli.js +25 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +189 -49
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/parser.d.ts.map +1 -1
- package/dist/commands/parser.js +8 -3
- package/dist/commands/parser.js.map +1 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/core/cost-tracker.d.ts +45 -5
- package/dist/core/cost-tracker.d.ts.map +1 -1
- package/dist/core/cost-tracker.js +78 -13
- package/dist/core/cost-tracker.js.map +1 -1
- package/dist/framework/index.d.ts +1 -1
- package/dist/framework/index.d.ts.map +1 -1
- package/dist/framework/index.js.map +1 -1
- package/dist/framework/query.d.ts +25 -0
- package/dist/framework/query.d.ts.map +1 -1
- package/dist/framework/query.js +196 -49
- package/dist/framework/query.js.map +1 -1
- package/dist/framework/store.d.ts +6 -1
- package/dist/framework/store.d.ts.map +1 -1
- package/dist/framework/store.js +10 -1
- package/dist/framework/store.js.map +1 -1
- package/dist/harness/ledger.d.ts.map +1 -1
- package/dist/harness/ledger.js +6 -2
- package/dist/harness/ledger.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/ink-ui/components/StatusLine.d.ts.map +1 -1
- package/dist/ink-ui/components/StatusLine.js +0 -2
- package/dist/ink-ui/components/StatusLine.js.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.js +12 -5
- package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
- package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-controller.js +11 -1
- package/dist/runtime/agent-runtime-controller.js.map +1 -1
- package/dist/runtime/chat-controller.d.ts.map +1 -1
- package/dist/runtime/chat-controller.js +229 -86
- package/dist/runtime/chat-controller.js.map +1 -1
- package/dist/runtime/rich-text/ansi-parser.d.ts +1 -1
- package/dist/runtime/rich-text/ansi-parser.d.ts.map +1 -1
- package/dist/runtime/rich-text/ansi-parser.js +93 -55
- package/dist/runtime/rich-text/ansi-parser.js.map +1 -1
- package/dist/runtime/rich-text/layout.d.ts +2 -11
- package/dist/runtime/rich-text/layout.d.ts.map +1 -1
- package/dist/runtime/rich-text/layout.js +280 -245
- package/dist/runtime/rich-text/layout.js.map +1 -1
- package/dist/runtime/rich-text/markdown-parser.js +31 -24
- package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
- package/dist/runtime/rich-text/types.d.ts +1 -1
- package/dist/runtime/rich-text/types.d.ts.map +1 -1
- package/dist/runtime/subagents/production.d.ts.map +1 -1
- package/dist/runtime/subagents/production.js +28 -3
- package/dist/runtime/subagents/production.js.map +1 -1
- package/dist/runtime/subagents/result-parser.d.ts.map +1 -1
- package/dist/runtime/subagents/result-parser.js +54 -40
- package/dist/runtime/subagents/result-parser.js.map +1 -1
- package/dist/runtime/subagents/types.d.ts +2 -0
- package/dist/runtime/subagents/types.d.ts.map +1 -1
- package/dist/runtime/subagents/types.js +5 -1
- package/dist/runtime/subagents/types.js.map +1 -1
- package/dist/runtime/ui-events.d.ts +13 -0
- package/dist/runtime/ui-events.d.ts.map +1 -1
- package/dist/runtime/ui-events.js.map +1 -1
- package/dist/runtime/ui-view-model.d.ts +9 -0
- package/dist/runtime/ui-view-model.d.ts.map +1 -1
- package/dist/runtime/ui-view-model.js +59 -37
- package/dist/runtime/ui-view-model.js.map +1 -1
- package/dist/services/compact/auto-compact.d.ts +15 -2
- package/dist/services/compact/auto-compact.d.ts.map +1 -1
- package/dist/services/compact/auto-compact.js +56 -24
- package/dist/services/compact/auto-compact.js.map +1 -1
- package/dist/services/compact/compact.d.ts +2 -0
- package/dist/services/compact/compact.d.ts.map +1 -1
- package/dist/services/compact/compact.js +22 -5
- package/dist/services/compact/compact.js.map +1 -1
- package/dist/services/compact/coordinator.d.ts +26 -0
- package/dist/services/compact/coordinator.d.ts.map +1 -0
- package/dist/services/compact/coordinator.js +44 -0
- package/dist/services/compact/coordinator.js.map +1 -0
- package/dist/services/compact/index.d.ts +1 -0
- package/dist/services/compact/index.d.ts.map +1 -1
- package/dist/services/compact/index.js +3 -1
- package/dist/services/compact/index.js.map +1 -1
- package/dist/services/compact/summary-generator.d.ts +6 -2
- package/dist/services/compact/summary-generator.d.ts.map +1 -1
- package/dist/services/compact/summary-generator.js +73 -31
- package/dist/services/compact/summary-generator.js.map +1 -1
- package/dist/services/config-dir.d.ts +11 -1
- package/dist/services/config-dir.d.ts.map +1 -1
- package/dist/services/config-dir.js +19 -2
- package/dist/services/config-dir.js.map +1 -1
- package/dist/services/config.d.ts +4 -2
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +40 -0
- package/dist/services/config.js.map +1 -1
- package/dist/services/doctor.d.ts +2 -0
- package/dist/services/doctor.d.ts.map +1 -1
- package/dist/services/doctor.js +8 -1
- package/dist/services/doctor.js.map +1 -1
- package/dist/services/global-config.d.ts +10 -0
- package/dist/services/global-config.d.ts.map +1 -1
- package/dist/services/global-config.js.map +1 -1
- package/dist/services/llm.d.ts +21 -4
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +66 -8
- package/dist/services/llm.js.map +1 -1
- package/dist/services/model-context.d.ts +36 -0
- package/dist/services/model-context.d.ts.map +1 -1
- package/dist/services/model-context.js +238 -32
- package/dist/services/model-context.js.map +1 -1
- package/dist/services/redaction.js +1 -1
- package/dist/services/redaction.js.map +1 -1
- package/dist/services/session-storage.d.ts +39 -1
- package/dist/services/session-storage.d.ts.map +1 -1
- package/dist/services/session-storage.js +121 -27
- package/dist/services/session-storage.js.map +1 -1
- package/dist/services/usage-state.d.ts +55 -5
- package/dist/services/usage-state.d.ts.map +1 -1
- package/dist/services/usage-state.js +185 -59
- package/dist/services/usage-state.js.map +1 -1
- package/dist/services/verification-profile.d.ts.map +1 -1
- package/dist/services/verification-profile.js +3 -2
- package/dist/services/verification-profile.js.map +1 -1
- package/dist/services/workspace-diff.d.ts.map +1 -1
- package/dist/services/workspace-diff.js +34 -3
- package/dist/services/workspace-diff.js.map +1 -1
- package/dist/services/yaml-config.js +1 -1
- package/dist/skills/runtime.d.ts +9 -5
- package/dist/skills/runtime.d.ts.map +1 -1
- package/dist/skills/runtime.js +157 -12
- package/dist/skills/runtime.js.map +1 -1
- package/dist/terminal-ui/launch.d.ts +2 -0
- package/dist/terminal-ui/launch.d.ts.map +1 -1
- package/dist/terminal-ui/launch.js +65 -21
- package/dist/terminal-ui/launch.js.map +1 -1
- package/dist/terminal-ui/raw-editor.d.ts +9 -0
- package/dist/terminal-ui/raw-editor.d.ts.map +1 -1
- package/dist/terminal-ui/raw-editor.js +207 -30
- package/dist/terminal-ui/raw-editor.js.map +1 -1
- package/dist/tools/bash_security.d.ts.map +1 -1
- package/dist/tools/bash_security.js +14 -5
- package/dist/tools/bash_security.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +48 -20
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/plan.d.ts.map +1 -1
- package/dist/tools/plan.js +7 -0
- package/dist/tools/plan.js.map +1 -1
- package/dist/tools/web.d.ts +10 -0
- package/dist/tools/web.d.ts.map +1 -1
- package/dist/tools/web.js +81 -1
- package/dist/tools/web.js.map +1 -1
- package/dist/tui-core/input-parser.d.ts +1 -1
- package/dist/tui-core/input-parser.d.ts.map +1 -1
- package/dist/tui-core/input-parser.js +20 -1
- package/dist/tui-core/input-parser.js.map +1 -1
- package/dist/tui-core/style.d.ts +16 -0
- package/dist/tui-core/style.d.ts.map +1 -1
- package/dist/tui-core/style.js +22 -1
- package/dist/tui-core/style.js.map +1 -1
- package/dist/tui-ui/inline-surface.d.ts +62 -11
- package/dist/tui-ui/inline-surface.d.ts.map +1 -1
- package/dist/tui-ui/inline-surface.js +343 -92
- package/dist/tui-ui/inline-surface.js.map +1 -1
- package/dist/tui-ui/launch.d.ts +1 -0
- package/dist/tui-ui/launch.d.ts.map +1 -1
- package/dist/tui-ui/launch.js +185 -41
- package/dist/tui-ui/launch.js.map +1 -1
- package/dist/tui-ui/layout.d.ts +51 -2
- package/dist/tui-ui/layout.d.ts.map +1 -1
- package/dist/tui-ui/layout.js +226 -76
- package/dist/tui-ui/layout.js.map +1 -1
- package/dist/tui-ui/runner.d.ts +69 -8
- package/dist/tui-ui/runner.d.ts.map +1 -1
- package/dist/tui-ui/runner.js +304 -41
- package/dist/tui-ui/runner.js.map +1 -1
- package/dist/tui-ui/state.d.ts +5 -4
- package/dist/tui-ui/state.d.ts.map +1 -1
- package/dist/tui-ui/state.js +65 -19
- package/dist/tui-ui/state.js.map +1 -1
- package/dist/tui-ui/theme.d.ts +13 -0
- package/dist/tui-ui/theme.d.ts.map +1 -0
- package/dist/tui-ui/theme.js +20 -0
- package/dist/tui-ui/theme.js.map +1 -0
- package/dist/tui-ui/transcript-cache.d.ts +5 -3
- package/dist/tui-ui/transcript-cache.d.ts.map +1 -1
- package/dist/tui-ui/transcript-cache.js +16 -9
- package/dist/tui-ui/transcript-cache.js.map +1 -1
- package/dist/tui-ui/transcript-layout.d.ts +21 -0
- package/dist/tui-ui/transcript-layout.d.ts.map +1 -0
- package/dist/tui-ui/transcript-layout.js +398 -0
- package/dist/tui-ui/transcript-layout.js.map +1 -0
- package/dist/ui/status-bar.d.ts +1 -1
- package/dist/ui/status-bar.d.ts.map +1 -1
- package/dist/ui/status-bar.js +2 -15
- package/dist/ui/status-bar.js.map +1 -1
- package/dist/ui-v2/components/shell.d.ts.map +1 -1
- package/dist/ui-v2/components/shell.js +0 -8
- package/dist/ui-v2/components/shell.js.map +1 -1
- package/package.json +1 -1
|
@@ -121,7 +121,18 @@ function compactMiddle(text, maxLength) {
|
|
|
121
121
|
return `${compact.slice(0, headLength)}...${compact.slice(-tailLength)}`;
|
|
122
122
|
}
|
|
123
123
|
function compactToolArgs(args, maxLength = 160) {
|
|
124
|
-
for (const key of [
|
|
124
|
+
for (const key of [
|
|
125
|
+
'path',
|
|
126
|
+
'file_path',
|
|
127
|
+
'file',
|
|
128
|
+
'cwd',
|
|
129
|
+
'command',
|
|
130
|
+
'pattern',
|
|
131
|
+
'query',
|
|
132
|
+
'url',
|
|
133
|
+
'target',
|
|
134
|
+
'sessionId',
|
|
135
|
+
]) {
|
|
125
136
|
const value = args[key];
|
|
126
137
|
if (typeof value === 'string') {
|
|
127
138
|
return compactMiddle(value, maxLength);
|
|
@@ -148,16 +159,14 @@ function buildTraceArgsDetails(projectPath, name, args) {
|
|
|
148
159
|
const argsSummary = compactToolArgs(args);
|
|
149
160
|
const fullArgs = (0, session_storage_1.redactTraceText)(fullToolArgsForTrace(name, args)).trim();
|
|
150
161
|
const argsBytes = byteLength(fullArgs);
|
|
151
|
-
if (!projectPath
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
162
|
+
if (!projectPath ||
|
|
163
|
+
!fullArgs ||
|
|
164
|
+
fullArgs === (0, session_storage_1.redactTraceText)(argsSummary) ||
|
|
165
|
+
argsBytes <= TRACE_ARGS_ARTIFACT_THRESHOLD_BYTES) {
|
|
155
166
|
return { argsSummary };
|
|
156
167
|
}
|
|
157
168
|
const artifact = (0, tool_artifacts_1.storeArtifact)(projectPath, `${name}-args`, fullArgs, argsBytes);
|
|
158
|
-
return artifact
|
|
159
|
-
? { argsSummary, argsArtifactId: artifact.id, argsBytes }
|
|
160
|
-
: { argsSummary };
|
|
169
|
+
return artifact ? { argsSummary, argsArtifactId: artifact.id, argsBytes } : { argsSummary };
|
|
161
170
|
}
|
|
162
171
|
function parseToolCallArgsForRuntime(toolCall) {
|
|
163
172
|
try {
|
|
@@ -211,7 +220,9 @@ function createPreToolCheckpoint(events, sessionId, turnId, checkpointId, cwd, t
|
|
|
211
220
|
checkpointFiles: checkpoint?.files.map(file => file.path) ?? [],
|
|
212
221
|
workspaceFiles: relativeTargets,
|
|
213
222
|
note: checkpoint
|
|
214
|
-
?
|
|
223
|
+
? risky
|
|
224
|
+
? 'risky_multi_file_checkpoint'
|
|
225
|
+
: 'pre_edit_checkpoint'
|
|
215
226
|
: 'pre_edit_checkpoint_skipped',
|
|
216
227
|
});
|
|
217
228
|
return { created: true, targetCount: targets.length, risky };
|
|
@@ -239,7 +250,9 @@ function formatWorkspaceFileForTrace(file) {
|
|
|
239
250
|
const metadata = [
|
|
240
251
|
typeof file.sizeBytes === 'number' ? `${file.sizeBytes}B` : '',
|
|
241
252
|
typeof file.mtimeMs === 'number' ? `mtime=${file.mtimeMs}` : '',
|
|
242
|
-
]
|
|
253
|
+
]
|
|
254
|
+
.filter(Boolean)
|
|
255
|
+
.join(' ');
|
|
243
256
|
return `${file.status} ${file.path}${metadata ? ` (${metadata})` : ''}`;
|
|
244
257
|
}
|
|
245
258
|
function appendWorkspaceSnapshotTrace(events, sessionId, turnId, phase, snapshot) {
|
|
@@ -275,19 +288,13 @@ function appendWorkspaceDeltaTrace(events, sessionId, turnId, before, after) {
|
|
|
275
288
|
return delta;
|
|
276
289
|
}
|
|
277
290
|
function workspaceDeltaHasTurnChanges(delta) {
|
|
278
|
-
return delta.newFilesByTurn.length > 0
|
|
279
|
-
|
|
280
|
-
|
|
291
|
+
return (delta.newFilesByTurn.length > 0 ||
|
|
292
|
+
delta.changedByTurn.length > 0 ||
|
|
293
|
+
delta.resolvedByTurn.length > 0);
|
|
281
294
|
}
|
|
282
295
|
function formatFailureRecoveryNotice(turnId, delta, checkpointIds) {
|
|
283
|
-
const files = compactPathList([
|
|
284
|
-
|
|
285
|
-
...delta.changedByTurn,
|
|
286
|
-
...delta.resolvedByTurn,
|
|
287
|
-
], 8);
|
|
288
|
-
const fileText = files.length > 0
|
|
289
|
-
? files.join(', ')
|
|
290
|
-
: 'workspace changes recorded';
|
|
296
|
+
const files = compactPathList([...delta.newFilesByTurn, ...delta.changedByTurn, ...delta.resolvedByTurn], 8);
|
|
297
|
+
const fileText = files.length > 0 ? files.join(', ') : 'workspace changes recorded';
|
|
291
298
|
const checkpointText = checkpointIds.length > 0
|
|
292
299
|
? ` Checkpoints: ${checkpointIds.join(', ')}. Preview rollback with /checkpoint restore <id>; restore each listed checkpoint if multiple.`
|
|
293
300
|
: '';
|
|
@@ -348,15 +355,17 @@ function withVerificationLoopStats(stats, summary) {
|
|
|
348
355
|
verificationPassedCommands: compactVerificationCommands(summary.passedCommands),
|
|
349
356
|
verificationFailedCommands: compactVerificationCommands(summary.failedCommands),
|
|
350
357
|
verificationMissingCommands: compactVerificationCommands(summary.missingCommands),
|
|
351
|
-
verificationSkippedReason: summary.skippedReason
|
|
358
|
+
verificationSkippedReason: summary.skippedReason
|
|
359
|
+
? (0, session_storage_1.redactTraceText)(summary.skippedReason)
|
|
360
|
+
: undefined,
|
|
352
361
|
};
|
|
353
362
|
}
|
|
354
363
|
function shouldRecordVerificationLoopStats(profile, summary) {
|
|
355
|
-
return profile.changedFiles.length > 0
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
364
|
+
return (profile.changedFiles.length > 0 ||
|
|
365
|
+
summary.commandsRun.length > 0 ||
|
|
366
|
+
summary.passedCommands.length > 0 ||
|
|
367
|
+
summary.failedCommands.length > 0 ||
|
|
368
|
+
summary.missingCommands.length > 0);
|
|
360
369
|
}
|
|
361
370
|
function appendPostWorkspaceTrace(events, sessionId, turnId, cwd, before, verificationResults = []) {
|
|
362
371
|
const postWorkspace = (0, workspace_state_1.captureWorkspaceSnapshot)(cwd);
|
|
@@ -451,11 +460,43 @@ function toolStartContent(event) {
|
|
|
451
460
|
function toolFinishContent(event) {
|
|
452
461
|
return (0, ui_view_model_1.formatToolActivityTranscript)((0, ui_view_model_1.toolActivityFromFinished)(event, compactToolArgs(event.args, TOOL_TRANSCRIPT_ARG_BUDGET)));
|
|
453
462
|
}
|
|
463
|
+
function structuredToolStartActivity(event, seq) {
|
|
464
|
+
const command = event.name === 'exec_command' && typeof event.args.command === 'string'
|
|
465
|
+
? event.args.command
|
|
466
|
+
: undefined;
|
|
467
|
+
return {
|
|
468
|
+
state: 'running',
|
|
469
|
+
name: event.name,
|
|
470
|
+
detail: command ? '' : compactToolArgs(event.args, TOOL_TRANSCRIPT_ARG_BUDGET),
|
|
471
|
+
command,
|
|
472
|
+
body: '',
|
|
473
|
+
seq,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function structuredToolFinishActivity(event, seq) {
|
|
477
|
+
const modelVisible = (0, tool_serializer_1.parseToolResultEnvelope)(event.modelVisibleResult);
|
|
478
|
+
const command = event.name === 'exec_command' && typeof event.args.command === 'string'
|
|
479
|
+
? event.args.command
|
|
480
|
+
: undefined;
|
|
481
|
+
return {
|
|
482
|
+
state: event.success ? 'success' : 'error',
|
|
483
|
+
name: event.name,
|
|
484
|
+
detail: command ? '' : compactToolArgs(event.args, TOOL_TRANSCRIPT_ARG_BUDGET),
|
|
485
|
+
command,
|
|
486
|
+
duration: `${event.duration}ms`,
|
|
487
|
+
summary: event.summary?.split(/\r?\n/u, 1)[0],
|
|
488
|
+
outputBytes: event.outputBytes,
|
|
489
|
+
body: modelVisible.output,
|
|
490
|
+
error: event.error,
|
|
491
|
+
seq,
|
|
492
|
+
artifactHint: event.artifactRef ? `/artifacts show ${event.artifactRef.id} --full` : undefined,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
454
495
|
function isSyntheticCompactContext(content) {
|
|
455
|
-
return content.startsWith('[OpenHorse Context State v2]')
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
496
|
+
return (content.startsWith('[OpenHorse Context State v2]') ||
|
|
497
|
+
content.startsWith('[Context Summary]') ||
|
|
498
|
+
content.startsWith('I will continue from this OpenHorse Context State') ||
|
|
499
|
+
content.startsWith('I understand the context. I will continue the conversation with this background information.'));
|
|
459
500
|
}
|
|
460
501
|
function sessionToolCallSummaries(message) {
|
|
461
502
|
return (message.tool_calls ?? []).map(call => {
|
|
@@ -506,13 +547,12 @@ function sessionToolResultSummary(message, toolCallsById) {
|
|
|
506
547
|
const args = parseToolCallArgs(call.function.arguments);
|
|
507
548
|
const detail = compactToolArgs(args);
|
|
508
549
|
const parsed = parseSessionToolResult(message.content);
|
|
509
|
-
const firstLine = parsed.summary ||
|
|
550
|
+
const firstLine = parsed.summary ||
|
|
551
|
+
`${parsed.success ? '✓' : '✗'} ${call.function.name}${detail ? ` ${detail}` : ''}`;
|
|
510
552
|
return parsed.error ? `${firstLine}\nError: ${parsed.error}` : firstLine;
|
|
511
553
|
}
|
|
512
554
|
function sessionMessagesToTranscriptEntries(sessionId) {
|
|
513
|
-
const
|
|
514
|
-
const displayStartTime = session?.transcriptDisplayStartTime;
|
|
515
|
-
const messages = (0, session_storage_1.readSessionMessages)(sessionId).filter(message => typeof displayStartTime !== 'number' || (message.timestamp ?? 0) >= displayStartTime);
|
|
555
|
+
const messages = (0, session_storage_1.loadSessionTranscriptMessages)(sessionId);
|
|
516
556
|
const entries = [];
|
|
517
557
|
const toolCallsById = new Map();
|
|
518
558
|
const completedToolCallIds = new Set();
|
|
@@ -538,7 +578,11 @@ function sessionMessagesToTranscriptEntries(sessionId) {
|
|
|
538
578
|
}
|
|
539
579
|
for (const summary of sessionToolCallSummaries(message)) {
|
|
540
580
|
if (!completedToolCallIds.has(summary.id)) {
|
|
541
|
-
entries.push({
|
|
581
|
+
entries.push({
|
|
582
|
+
id: `${idBase}-tool-call-${entries.length}`,
|
|
583
|
+
role: 'tool',
|
|
584
|
+
content: summary.content,
|
|
585
|
+
});
|
|
542
586
|
}
|
|
543
587
|
}
|
|
544
588
|
return;
|
|
@@ -548,7 +592,10 @@ function sessionMessagesToTranscriptEntries(sessionId) {
|
|
|
548
592
|
entries.push({
|
|
549
593
|
id: `${idBase}-tool`,
|
|
550
594
|
role: 'tool',
|
|
551
|
-
content: summary ??
|
|
595
|
+
content: summary ??
|
|
596
|
+
(message.toolCallId
|
|
597
|
+
? `Tool result ${message.toolCallId}\n${message.content}`
|
|
598
|
+
: message.content),
|
|
552
599
|
});
|
|
553
600
|
return;
|
|
554
601
|
}
|
|
@@ -633,19 +680,27 @@ function parseLocalFastPath(input) {
|
|
|
633
680
|
}
|
|
634
681
|
const readMatch = /^(?:read|读取)\s+(.+)$/i.exec(text);
|
|
635
682
|
const readTarget = readMatch?.[1]?.trim();
|
|
636
|
-
const looksLikePath = Boolean(readTarget)
|
|
637
|
-
|
|
638
|
-
|
|
683
|
+
const looksLikePath = Boolean(readTarget) &&
|
|
684
|
+
!/\s/.test(readTarget) &&
|
|
685
|
+
(/[/\\.]/.test(readTarget) || readTarget.startsWith('~'));
|
|
639
686
|
if (readTarget && looksLikePath) {
|
|
640
687
|
return { tool: 'read_file', args: { path: readTarget }, label: `read ${readTarget}` };
|
|
641
688
|
}
|
|
642
689
|
const grepMatch = /^(?:grep|搜索)\s+(.+)$/i.exec(text);
|
|
643
690
|
if (grepMatch?.[1]?.trim()) {
|
|
644
|
-
return {
|
|
691
|
+
return {
|
|
692
|
+
tool: 'grep',
|
|
693
|
+
args: { pattern: grepMatch[1].trim() },
|
|
694
|
+
label: `grep ${grepMatch[1].trim()}`,
|
|
695
|
+
};
|
|
645
696
|
}
|
|
646
697
|
const runTestMatch = /^(?:run\s+test|运行测试)\s*[::]\s*(.+)$/i.exec(text);
|
|
647
698
|
if (runTestMatch?.[1]?.trim()) {
|
|
648
|
-
return {
|
|
699
|
+
return {
|
|
700
|
+
tool: 'exec_command',
|
|
701
|
+
args: { command: runTestMatch[1].trim() },
|
|
702
|
+
label: `run test: ${runTestMatch[1].trim()}`,
|
|
703
|
+
};
|
|
649
704
|
}
|
|
650
705
|
return null;
|
|
651
706
|
}
|
|
@@ -693,12 +748,7 @@ function createToolEventPresenter(events) {
|
|
|
693
748
|
role: 'tool',
|
|
694
749
|
title: 'tool',
|
|
695
750
|
content: toolStartContent(event),
|
|
696
|
-
toolActivity:
|
|
697
|
-
state: 'running',
|
|
698
|
-
name: event.name,
|
|
699
|
-
detail: '',
|
|
700
|
-
seq,
|
|
701
|
-
},
|
|
751
|
+
toolActivity: structuredToolStartActivity(event, seq),
|
|
702
752
|
});
|
|
703
753
|
runningToolEntries.set(event.callId, {
|
|
704
754
|
entryId,
|
|
@@ -721,15 +771,7 @@ function createToolEventPresenter(events) {
|
|
|
721
771
|
const content = toolFinishContent(event);
|
|
722
772
|
const stored = runningToolEntries.get(event.callId);
|
|
723
773
|
const seq = stored?.sequence ?? ++toolSequenceCounter;
|
|
724
|
-
const
|
|
725
|
-
const toolActivity = {
|
|
726
|
-
state,
|
|
727
|
-
name: event.name,
|
|
728
|
-
detail: '',
|
|
729
|
-
duration: `${event.duration}ms`,
|
|
730
|
-
error: event.error,
|
|
731
|
-
seq,
|
|
732
|
-
};
|
|
774
|
+
const toolActivity = structuredToolFinishActivity(event, seq);
|
|
733
775
|
if (stored) {
|
|
734
776
|
events.finalize(stored.entryId, {
|
|
735
777
|
role: event.success ? 'tool' : 'error',
|
|
@@ -773,6 +815,7 @@ function createToolEventPresenter(events) {
|
|
|
773
815
|
state: 'skipped',
|
|
774
816
|
name: entry.name,
|
|
775
817
|
detail: '',
|
|
818
|
+
body: '',
|
|
776
819
|
error: reason,
|
|
777
820
|
seq: entry.sequence,
|
|
778
821
|
},
|
|
@@ -800,7 +843,7 @@ async function captureConsoleOutput(fn) {
|
|
|
800
843
|
const originalError = console.error;
|
|
801
844
|
const originalWarn = console.warn;
|
|
802
845
|
const capture = (...args) => {
|
|
803
|
-
lines.push(stripAnsi(args.map(arg => typeof arg === 'string' ? arg : JSON.stringify(arg)).join(' ')));
|
|
846
|
+
lines.push(stripAnsi(args.map(arg => (typeof arg === 'string' ? arg : JSON.stringify(arg))).join(' ')));
|
|
804
847
|
};
|
|
805
848
|
console.log = capture;
|
|
806
849
|
console.error = capture;
|
|
@@ -850,7 +893,7 @@ class AgentChatController {
|
|
|
850
893
|
}
|
|
851
894
|
const command = (0, commands_1.findCommand)(parsed.name);
|
|
852
895
|
if (!command) {
|
|
853
|
-
if ((0, skills_1.hasMatchingSkill)(text)) {
|
|
896
|
+
if ((0, skills_1.hasMatchingSkill)(text, this.runtime.cwd)) {
|
|
854
897
|
await this.runChat(text, options);
|
|
855
898
|
return;
|
|
856
899
|
}
|
|
@@ -902,7 +945,9 @@ class AgentChatController {
|
|
|
902
945
|
}
|
|
903
946
|
}
|
|
904
947
|
async runLocalFastPath(input, action, options = {}) {
|
|
905
|
-
const activeSession = this.runtime.getSession() ??
|
|
948
|
+
const activeSession = this.runtime.getSession() ??
|
|
949
|
+
this.runtime.ensureSession() ??
|
|
950
|
+
(0, session_storage_1.loadSessionMeta)(this.runtime.getSession()?.id ?? '');
|
|
906
951
|
const sessionId = activeSession?.id;
|
|
907
952
|
const turnId = traceTurnId(options.turnId);
|
|
908
953
|
const localCallId = `local-${turnId}`;
|
|
@@ -981,23 +1026,25 @@ class AgentChatController {
|
|
|
981
1026
|
modelVisibleToolBytes: 0,
|
|
982
1027
|
summarizedBytes: outputBytes,
|
|
983
1028
|
});
|
|
1029
|
+
const localToolResultEvent = {
|
|
1030
|
+
type: 'tool_result',
|
|
1031
|
+
name: action.tool,
|
|
1032
|
+
args: action.args,
|
|
1033
|
+
callId: localCallId,
|
|
1034
|
+
result,
|
|
1035
|
+
modelVisibleResult: result,
|
|
1036
|
+
duration,
|
|
1037
|
+
success: envelope.success,
|
|
1038
|
+
error: envelope.error,
|
|
1039
|
+
summary: envelope.summary,
|
|
1040
|
+
outputBytes,
|
|
1041
|
+
artifactRef: formattedLocalResult.artifactRef,
|
|
1042
|
+
};
|
|
984
1043
|
this.events.append({
|
|
985
1044
|
role: envelope.success ? 'tool' : 'error',
|
|
986
1045
|
title: 'local',
|
|
987
|
-
content: toolFinishContent(
|
|
988
|
-
|
|
989
|
-
name: action.tool,
|
|
990
|
-
args: action.args,
|
|
991
|
-
callId: localCallId,
|
|
992
|
-
result,
|
|
993
|
-
modelVisibleResult: result,
|
|
994
|
-
duration,
|
|
995
|
-
success: envelope.success,
|
|
996
|
-
error: envelope.error,
|
|
997
|
-
summary: envelope.summary,
|
|
998
|
-
outputBytes,
|
|
999
|
-
artifactRef: formattedLocalResult.artifactRef,
|
|
1000
|
-
}),
|
|
1046
|
+
content: toolFinishContent(localToolResultEvent),
|
|
1047
|
+
toolActivity: structuredToolFinishActivity(localToolResultEvent, 1),
|
|
1001
1048
|
});
|
|
1002
1049
|
this.runtime.store.addMessage({ role: 'assistant', content: assistantContent });
|
|
1003
1050
|
this.setLoopStats(stats);
|
|
@@ -1083,6 +1130,7 @@ class AgentChatController {
|
|
|
1083
1130
|
config: this.runtime.config,
|
|
1084
1131
|
store: this.runtime.store,
|
|
1085
1132
|
llm: this.runtime.llm,
|
|
1133
|
+
compactCoordinator: this.runtime.compactCoordinator,
|
|
1086
1134
|
runtime: this.runtime.runtime,
|
|
1087
1135
|
sessionId: this.runtime.getSession()?.id,
|
|
1088
1136
|
turnId,
|
|
@@ -1147,7 +1195,11 @@ class AgentChatController {
|
|
|
1147
1195
|
content: `▸ subtask ${event.role} started: ${event.objective.slice(0, 120)}`,
|
|
1148
1196
|
});
|
|
1149
1197
|
}
|
|
1150
|
-
else if (event.state === 'completed' ||
|
|
1198
|
+
else if (event.state === 'completed' ||
|
|
1199
|
+
event.state === 'failed' ||
|
|
1200
|
+
event.state === 'cancelled' ||
|
|
1201
|
+
event.state === 'timed_out' ||
|
|
1202
|
+
event.state === 'rejected') {
|
|
1151
1203
|
const summary = event.summary ? ` — ${event.summary.slice(0, 200)}` : '';
|
|
1152
1204
|
this.events.append({
|
|
1153
1205
|
role: 'system',
|
|
@@ -1181,7 +1233,11 @@ class AgentChatController {
|
|
|
1181
1233
|
}
|
|
1182
1234
|
async runChat(input, options = {}) {
|
|
1183
1235
|
if (!input) {
|
|
1184
|
-
this.events.append({
|
|
1236
|
+
this.events.append({
|
|
1237
|
+
role: 'error',
|
|
1238
|
+
content: 'Usage: /chat <message>',
|
|
1239
|
+
errorLayer: 'runtime',
|
|
1240
|
+
});
|
|
1185
1241
|
return;
|
|
1186
1242
|
}
|
|
1187
1243
|
if (!this.runtime.llm || !(0, config_1.isConfigured)(this.runtime.config)) {
|
|
@@ -1194,7 +1250,9 @@ class AgentChatController {
|
|
|
1194
1250
|
}
|
|
1195
1251
|
const abortSignal = options.abortSignal;
|
|
1196
1252
|
const turnId = traceTurnId(options.turnId);
|
|
1197
|
-
const activeSession = this.runtime.getSession() ??
|
|
1253
|
+
const activeSession = this.runtime.getSession() ??
|
|
1254
|
+
this.runtime.ensureSession() ??
|
|
1255
|
+
(0, session_storage_1.loadSessionMeta)(this.runtime.getSession()?.id ?? '');
|
|
1198
1256
|
const sessionId = activeSession?.id;
|
|
1199
1257
|
const preWorkspace = (0, workspace_state_1.captureWorkspaceSnapshot)(this.runtime.cwd);
|
|
1200
1258
|
const runtimeTools = (0, tools_1.getRuntimeTools)();
|
|
@@ -1237,7 +1295,9 @@ class AgentChatController {
|
|
|
1237
1295
|
const intent = harness.updateContractFromUserInput(input);
|
|
1238
1296
|
harness.recordAppliedSkills(skillResolution.skills);
|
|
1239
1297
|
// Reconcile diagnostic: when harness state is present but objective may be incomplete
|
|
1240
|
-
if (snapshot.harnessState &&
|
|
1298
|
+
if (snapshot.harnessState &&
|
|
1299
|
+
!snapshot.harnessState.rootObjective &&
|
|
1300
|
+
!snapshot.harnessState.contract?.objective) {
|
|
1241
1301
|
this.events.setStatus('Resume diagnostic: harness state restored but objective may be incomplete. Run /harness explain to review.');
|
|
1242
1302
|
}
|
|
1243
1303
|
const subagentConfig = this.runtime.config.subagents;
|
|
@@ -1245,7 +1305,10 @@ class AgentChatController {
|
|
|
1245
1305
|
// turns, but respects an active skill scope: when a skill restricts the
|
|
1246
1306
|
// tool set, subtask is not appended (the skill owns the scope).
|
|
1247
1307
|
const projectPath = activeSession?.projectPath;
|
|
1248
|
-
const subagentBundle = subagentConfig &&
|
|
1308
|
+
const subagentBundle = subagentConfig &&
|
|
1309
|
+
subagentConfig.mode !== 'off' &&
|
|
1310
|
+
this.runtime.llm &&
|
|
1311
|
+
!skillResolution.toolScopeActive
|
|
1249
1312
|
? (0, subagents_1.createSubagentBundleForTurn)({
|
|
1250
1313
|
config: subagentConfig,
|
|
1251
1314
|
cwd: this.runtime.cwd,
|
|
@@ -1253,7 +1316,7 @@ class AgentChatController {
|
|
|
1253
1316
|
modelLabel: this.runtime.llm.getModel(),
|
|
1254
1317
|
rootObjectiveSummary: harness.toJSON()?.rootObjective ?? input,
|
|
1255
1318
|
abortSignal,
|
|
1256
|
-
onSubtaskEvent:
|
|
1319
|
+
onSubtaskEvent: event => {
|
|
1257
1320
|
this.handleSubtaskEvent(event, sessionId, turnId);
|
|
1258
1321
|
},
|
|
1259
1322
|
onSubtaskResult: (result, _batchId) => {
|
|
@@ -1310,6 +1373,7 @@ class AgentChatController {
|
|
|
1310
1373
|
let finalModel = '';
|
|
1311
1374
|
let pendingCompleteTrace = null;
|
|
1312
1375
|
let pendingCompleteStats;
|
|
1376
|
+
let pendingCompact;
|
|
1313
1377
|
const verificationResults = [];
|
|
1314
1378
|
const sessionMessagesToRecord = [];
|
|
1315
1379
|
const assistantStream = createAssistantStreamPresenter(this.events, abortSignal);
|
|
@@ -1384,6 +1448,10 @@ class AgentChatController {
|
|
|
1384
1448
|
harness,
|
|
1385
1449
|
input,
|
|
1386
1450
|
loopBudget,
|
|
1451
|
+
onContextUsage: usage => {
|
|
1452
|
+
this.runtime.store.setContextUsage(usage);
|
|
1453
|
+
},
|
|
1454
|
+
compactCoordinator: this.runtime.compactCoordinator,
|
|
1387
1455
|
})) {
|
|
1388
1456
|
switch (event.type) {
|
|
1389
1457
|
case 'request_start':
|
|
@@ -1434,9 +1502,7 @@ class AgentChatController {
|
|
|
1434
1502
|
this.events.append({ role: 'status', content: suggestion });
|
|
1435
1503
|
}
|
|
1436
1504
|
}
|
|
1437
|
-
const checkpointId = checkpointSequence === 0
|
|
1438
|
-
? turnId
|
|
1439
|
-
: `${turnId}-checkpoint-${checkpointSequence + 1}`;
|
|
1505
|
+
const checkpointId = checkpointSequence === 0 ? turnId : `${turnId}-checkpoint-${checkpointSequence + 1}`;
|
|
1440
1506
|
const checkpointResult = createPreToolCheckpoint(this.events, sessionId, turnId, checkpointId, this.runtime.cwd, event.toolCalls);
|
|
1441
1507
|
if (checkpointResult.created) {
|
|
1442
1508
|
checkpointIds.push(checkpointId);
|
|
@@ -1446,6 +1512,7 @@ class AgentChatController {
|
|
|
1446
1512
|
this.events.append({
|
|
1447
1513
|
role: 'status',
|
|
1448
1514
|
title: 'checkpoint',
|
|
1515
|
+
statusTone: 'warning',
|
|
1449
1516
|
content: `Risky edit: ${checkpointResult.targetCount} files in one turn. Checkpoint ${checkpointId} created for rollback (/checkpoints restore ${checkpointId}).`,
|
|
1450
1517
|
});
|
|
1451
1518
|
}
|
|
@@ -1453,6 +1520,7 @@ class AgentChatController {
|
|
|
1453
1520
|
this.events.append({
|
|
1454
1521
|
role: 'status',
|
|
1455
1522
|
title: 'checkpoint',
|
|
1523
|
+
statusTone: 'warning',
|
|
1456
1524
|
content: `Risky edit: ${checkpointResult.targetCount} files in one turn, but checkpoint creation failed. Restore any pre-existing checkpoint manually or revert via git.`,
|
|
1457
1525
|
});
|
|
1458
1526
|
}
|
|
@@ -1606,6 +1674,7 @@ class AgentChatController {
|
|
|
1606
1674
|
finalContent = event.content;
|
|
1607
1675
|
finalUsage = event.usage;
|
|
1608
1676
|
finalModel = event.model;
|
|
1677
|
+
pendingCompact = event.compact;
|
|
1609
1678
|
if (event.stats) {
|
|
1610
1679
|
pendingCompleteStats = event.stats;
|
|
1611
1680
|
recordProviderTraceEvents(this.events, sessionId, turnId, event.stats);
|
|
@@ -1662,6 +1731,7 @@ class AgentChatController {
|
|
|
1662
1731
|
this.events.append({
|
|
1663
1732
|
role: 'status',
|
|
1664
1733
|
title: 'recovery',
|
|
1734
|
+
statusTone: 'warning',
|
|
1665
1735
|
content: recoveryNotice,
|
|
1666
1736
|
});
|
|
1667
1737
|
}
|
|
@@ -1694,6 +1764,7 @@ class AgentChatController {
|
|
|
1694
1764
|
this.events.append({
|
|
1695
1765
|
role: 'status',
|
|
1696
1766
|
title: 'verification',
|
|
1767
|
+
statusTone: 'warning',
|
|
1697
1768
|
content: notice,
|
|
1698
1769
|
});
|
|
1699
1770
|
finalContent = finalContent ? `${finalContent}\n\n${notice}` : notice;
|
|
@@ -1738,7 +1809,12 @@ class AgentChatController {
|
|
|
1738
1809
|
lines.push(`Next: ${stats.continuationHint}`);
|
|
1739
1810
|
}
|
|
1740
1811
|
const notice = lines.join('\n');
|
|
1741
|
-
this.events.append({
|
|
1812
|
+
this.events.append({
|
|
1813
|
+
role: 'status',
|
|
1814
|
+
title: 'budget',
|
|
1815
|
+
statusTone: 'warning',
|
|
1816
|
+
content: notice,
|
|
1817
|
+
});
|
|
1742
1818
|
finalContent = finalContent ? `${finalContent}\n\n${notice}` : notice;
|
|
1743
1819
|
appendAssistantNotice(sessionMessagesToRecord, notice);
|
|
1744
1820
|
}
|
|
@@ -1751,6 +1827,65 @@ class AgentChatController {
|
|
|
1751
1827
|
if (sessionId && sessionMessagesToRecord.length > 0) {
|
|
1752
1828
|
(0, session_storage_1.appendSessionMessages)(sessionId, sessionMessagesToRecord);
|
|
1753
1829
|
}
|
|
1830
|
+
if (pendingCompact) {
|
|
1831
|
+
try {
|
|
1832
|
+
let committedCheckpointId;
|
|
1833
|
+
if (sessionId) {
|
|
1834
|
+
const sourceMessageCount = (0, session_storage_1.readSessionMessages)(sessionId).length;
|
|
1835
|
+
const checkpoint = (0, session_storage_1.commitSessionCompactCheckpoint)({
|
|
1836
|
+
sessionId,
|
|
1837
|
+
mode: pendingCompact.mode,
|
|
1838
|
+
modelId: finalModel || this.runtime.llm.getModel(),
|
|
1839
|
+
sourceMessageCount,
|
|
1840
|
+
transcriptStartMessageIndex: Math.max(0, sourceMessageCount - 20),
|
|
1841
|
+
modelHistory: pendingCompact.modelHistory,
|
|
1842
|
+
summary: pendingCompact.summary,
|
|
1843
|
+
beforeUsage: pendingCompact.before,
|
|
1844
|
+
afterUsage: pendingCompact.after,
|
|
1845
|
+
});
|
|
1846
|
+
committedCheckpointId = checkpoint.checkpointId;
|
|
1847
|
+
this.runtime.store.setState({ conversationHistory: checkpoint.modelHistory });
|
|
1848
|
+
}
|
|
1849
|
+
else {
|
|
1850
|
+
this.runtime.store.setState({
|
|
1851
|
+
conversationHistory: pendingCompact.modelHistory.filter(message => message.role !== 'system'),
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
this.runtime.store.setContextUsage(pendingCompact.after);
|
|
1855
|
+
if (sessionId) {
|
|
1856
|
+
recordTraceEvent(this.events, sessionId, {
|
|
1857
|
+
turnId,
|
|
1858
|
+
type: 'compact_completed',
|
|
1859
|
+
checkpointId: committedCheckpointId,
|
|
1860
|
+
model: finalModel || this.runtime.llm.getModel(),
|
|
1861
|
+
note: pendingCompact.mode,
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
this.events.append({
|
|
1865
|
+
role: 'status',
|
|
1866
|
+
title: 'auto-compact',
|
|
1867
|
+
statusTone: 'neutral',
|
|
1868
|
+
content: `Context reached ${pendingCompact.before.percent}% of the safe input budget. Agent core committed a ${pendingCompact.mode} compact checkpoint; current context is ${pendingCompact.after.percent}%.`,
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
catch (error) {
|
|
1872
|
+
if (sessionId) {
|
|
1873
|
+
recordTraceEvent(this.events, sessionId, {
|
|
1874
|
+
turnId,
|
|
1875
|
+
type: 'compact_failed',
|
|
1876
|
+
model: finalModel || this.runtime.llm.getModel(),
|
|
1877
|
+
error: compactTraceError(error),
|
|
1878
|
+
note: pendingCompact.mode,
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
this.events.append({
|
|
1882
|
+
role: 'error',
|
|
1883
|
+
title: 'compact-failed',
|
|
1884
|
+
content: `Compact checkpoint failed; the previous model context remains active. ${error instanceof Error ? error.message : String(error)}`,
|
|
1885
|
+
errorLayer: 'runtime',
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1754
1889
|
if (finalUsage) {
|
|
1755
1890
|
// Fold subagent token usage into /cost accounting.
|
|
1756
1891
|
if (subagentBundle) {
|
|
@@ -1803,6 +1938,7 @@ class AgentChatController {
|
|
|
1803
1938
|
this.events.append({
|
|
1804
1939
|
role: 'status',
|
|
1805
1940
|
title: 'recovery',
|
|
1941
|
+
statusTone: 'warning',
|
|
1806
1942
|
content: recoveryNotice,
|
|
1807
1943
|
});
|
|
1808
1944
|
}
|
|
@@ -1811,7 +1947,11 @@ class AgentChatController {
|
|
|
1811
1947
|
return;
|
|
1812
1948
|
}
|
|
1813
1949
|
assistantStream.discardSegment();
|
|
1814
|
-
this.events.append({
|
|
1950
|
+
this.events.append({
|
|
1951
|
+
role: 'error',
|
|
1952
|
+
content: formatChatError(error),
|
|
1953
|
+
errorLayer: errorLayerForChatError(error),
|
|
1954
|
+
});
|
|
1815
1955
|
this.events.setStatus('Turn failed. Ready for the next input.');
|
|
1816
1956
|
const failedStats = error instanceof framework_1.QueryLoopError
|
|
1817
1957
|
? error.stats
|
|
@@ -1837,6 +1977,7 @@ class AgentChatController {
|
|
|
1837
1977
|
this.events.append({
|
|
1838
1978
|
role: 'status',
|
|
1839
1979
|
title: 'recovery',
|
|
1980
|
+
statusTone: 'warning',
|
|
1840
1981
|
content: recoveryNotice,
|
|
1841
1982
|
});
|
|
1842
1983
|
}
|
|
@@ -1879,7 +2020,9 @@ exports.InkChatController = AgentChatController;
|
|
|
1879
2020
|
function loadSessionIntoRuntime(runtime, sessionId) {
|
|
1880
2021
|
const history = (0, session_storage_1.loadSessionHistory)(sessionId);
|
|
1881
2022
|
runtime.store.setState({ conversationHistory: history });
|
|
1882
|
-
runtime.store.setState({
|
|
2023
|
+
runtime.store.setState({
|
|
2024
|
+
harnessState: (0, session_storage_1.loadSessionHarnessState)(sessionId) ?? (0, session_storage_1.loadSessionMeta)(sessionId)?.harnessState,
|
|
2025
|
+
});
|
|
1883
2026
|
return `Restored ${history.length} messages`;
|
|
1884
2027
|
}
|
|
1885
2028
|
function closeSession(runtime) {
|