@pellux/goodvibes-agent 1.1.7 → 1.2.0
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/CHANGELOG.md +170 -0
- package/README.md +46 -30
- package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
- package/dist/package/main.js +132577 -91483
- package/docs/README.md +14 -7
- package/docs/channels-remote-and-api.md +8 -5
- package/docs/connected-host.md +14 -12
- package/docs/getting-started.md +56 -30
- package/docs/knowledge-artifacts-and-multimodal.md +7 -5
- package/docs/project-planning.md +2 -2
- package/docs/providers-and-routing.md +11 -3
- package/docs/tools-and-commands.md +114 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +130 -5
- package/release/release-readiness.json +120 -90
- package/src/agent/assistant-cockpit.ts +247 -0
- package/src/agent/autonomy-schedule-format.ts +96 -0
- package/src/agent/autonomy-schedule.ts +514 -0
- package/src/agent/channel-delivery-receipts.ts +292 -0
- package/src/agent/competitive-feature-inventory.ts +296 -0
- package/src/agent/document-registry-types.ts +106 -0
- package/src/agent/document-registry.ts +734 -0
- package/src/agent/harness-control.ts +2 -2
- package/src/agent/memory-prompt.ts +2 -2
- package/src/agent/operator-actions.ts +50 -6
- package/src/agent/persona-registry.ts +8 -0
- package/src/agent/project-context-files.ts +273 -0
- package/src/agent/prompt-context-receipts.ts +502 -0
- package/src/agent/reminder-schedule-format.ts +16 -2
- package/src/agent/research-run-registry.ts +582 -0
- package/src/agent/research-source-registry.ts +441 -0
- package/src/agent/routine-registry.ts +19 -3
- package/src/agent/routine-schedule-format.ts +27 -2
- package/src/agent/runtime-profile-starters.ts +7 -0
- package/src/agent/runtime-profile.ts +106 -4
- package/src/agent/schedule-edit-format.ts +129 -0
- package/src/agent/schedule-edit.ts +496 -0
- package/src/agent/schedule-next-routes.ts +42 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +447 -0
- package/src/agent/skill-registry-types.ts +102 -0
- package/src/agent/skill-registry.ts +81 -107
- package/src/agent/vibe-confirmation-routes.ts +62 -0
- package/src/agent/vibe-file.ts +285 -0
- package/src/cli/agent-knowledge-command.ts +45 -2
- package/src/cli/help.ts +3 -0
- package/src/cli/profiles-command.ts +25 -11
- package/src/config/agent-settings-policy.ts +1 -18
- package/src/input/agent-workspace-activation.ts +53 -0
- package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
- package/src/input/agent-workspace-artifact-metadata.ts +17 -0
- package/src/input/agent-workspace-basic-command-editors.ts +5 -1
- package/src/input/agent-workspace-categories.ts +153 -155
- package/src/input/agent-workspace-channel-triage.ts +481 -0
- package/src/input/agent-workspace-channels.ts +263 -0
- package/src/input/agent-workspace-command-editor.ts +152 -0
- package/src/input/agent-workspace-context-snapshot.ts +349 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
- package/src/input/agent-workspace-document-editor.ts +502 -0
- package/src/input/agent-workspace-document-ops-editor.ts +523 -0
- package/src/input/agent-workspace-host-category.ts +1 -1
- package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
- package/src/input/agent-workspace-model-compare-editor.ts +376 -0
- package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
- package/src/input/agent-workspace-model-compare-types.ts +82 -0
- package/src/input/agent-workspace-model-compare-utils.ts +35 -0
- package/src/input/agent-workspace-onboarding-categories.ts +141 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
- package/src/input/agent-workspace-operations-command-editors.ts +22 -0
- package/src/input/agent-workspace-research-report-editor.ts +212 -0
- package/src/input/agent-workspace-research-run-editor.ts +144 -0
- package/src/input/agent-workspace-research-source-editor.ts +167 -0
- package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
- package/src/input/agent-workspace-review-packet-utils.ts +265 -0
- package/src/input/agent-workspace-settings.ts +262 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +198 -0
- package/src/input/agent-workspace-setup.ts +34 -1
- package/src/input/agent-workspace-snapshot.ts +162 -147
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +18 -0
- package/src/input/command-registry.ts +9 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
- package/src/input/commands/channels-runtime.ts +102 -114
- package/src/input/commands/delegation-runtime.ts +87 -24
- package/src/input/commands/knowledge-browser-flags.ts +12 -0
- package/src/input/commands/knowledge.ts +28 -14
- package/src/input/commands/operator-actions-runtime.ts +6 -3
- package/src/input/commands/schedule-runtime.ts +71 -14
- package/src/input/commands/session-content.ts +2 -2
- package/src/input/commands/shell-core.ts +2 -0
- package/src/input/commands/vibe-runtime.ts +140 -0
- package/src/input/commands.ts +2 -0
- package/src/input/connected-host-routes.ts +123 -0
- package/src/input/settings-modal-types.ts +14 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +686 -0
- package/src/renderer/agent-workspace.ts +30 -419
- package/src/renderer/settings-modal-helpers.ts +12 -0
- package/src/renderer/settings-modal.ts +12 -0
- package/src/runtime/bootstrap-command-context.ts +11 -1
- package/src/runtime/bootstrap-command-parts.ts +14 -3
- package/src/runtime/bootstrap-core.ts +39 -1
- package/src/runtime/bootstrap-shell.ts +6 -0
- package/src/runtime/bootstrap.ts +113 -30
- package/src/runtime/connected-host-auth.ts +3 -2
- package/src/runtime/execution-ledger.ts +231 -0
- package/src/runtime/services.ts +88 -10
- package/src/runtime/tool-permission-safety.ts +199 -5
- package/src/shell/session-continuity-hints.ts +39 -0
- package/src/tools/agent-artifacts-tool.ts +606 -0
- package/src/tools/agent-audit-tool.ts +155 -0
- package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
- package/src/tools/agent-autonomy-tool.ts +140 -0
- package/src/tools/agent-channel-send-tool.ts +24 -2
- package/src/tools/agent-channels-tool.ts +140 -0
- package/src/tools/agent-computer-tool.ts +168 -0
- package/src/tools/agent-context-policy.ts +137 -7
- package/src/tools/agent-context-tool.ts +143 -0
- package/src/tools/agent-delegation-tool.ts +128 -0
- package/src/tools/agent-device-tool.ts +240 -0
- package/src/tools/agent-documents-tool.ts +684 -0
- package/src/tools/agent-execution-tool.ts +230 -0
- package/src/tools/agent-harness-agent-orchestration.ts +703 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +560 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +794 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
- package/src/tools/agent-harness-browser-control.ts +338 -0
- package/src/tools/agent-harness-channel-metadata.ts +168 -10
- package/src/tools/agent-harness-cli-command-policy.ts +110 -0
- package/src/tools/agent-harness-command-catalog.ts +4 -2
- package/src/tools/agent-harness-command-runner.ts +42 -0
- package/src/tools/agent-harness-connected-host-status.ts +7 -4
- package/src/tools/agent-harness-delegation-posture.ts +234 -19
- package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
- package/src/tools/agent-harness-document-ops-types.ts +72 -0
- package/src/tools/agent-harness-document-ops.ts +671 -0
- package/src/tools/agent-harness-execution-history.ts +489 -0
- package/src/tools/agent-harness-execution-posture.ts +382 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
- package/src/tools/agent-harness-learning-curator-common.ts +102 -0
- package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
- package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
- package/src/tools/agent-harness-learning-curator-types.ts +151 -0
- package/src/tools/agent-harness-learning-curator.ts +417 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
- package/src/tools/agent-harness-media-posture.ts +208 -2
- package/src/tools/agent-harness-memory-posture.ts +556 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +84 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +186 -0
- package/src/tools/agent-harness-model-readiness.ts +406 -0
- package/src/tools/agent-harness-model-routing-types.ts +266 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +137 -190
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +431 -18
- package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
- package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
- package/src/tools/agent-harness-personal-ops-records.ts +732 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +222 -0
- package/src/tools/agent-harness-personal-ops.ts +606 -0
- package/src/tools/agent-harness-project-context.ts +144 -0
- package/src/tools/agent-harness-prompt-context.ts +589 -0
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-release-evidence.ts +9 -7
- package/src/tools/agent-harness-release-readiness.ts +9 -7
- package/src/tools/agent-harness-research-briefing.ts +427 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +295 -0
- package/src/tools/agent-harness-research-workflow.ts +322 -0
- package/src/tools/agent-harness-security-posture.ts +2 -2
- package/src/tools/agent-harness-service-posture.ts +9 -9
- package/src/tools/agent-harness-session-metadata.ts +3 -3
- package/src/tools/agent-harness-setup-connected-host.ts +501 -0
- package/src/tools/agent-harness-setup-describe.ts +557 -0
- package/src/tools/agent-harness-setup-handoffs.ts +502 -0
- package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
- package/src/tools/agent-harness-setup-plan.ts +253 -0
- package/src/tools/agent-harness-setup-posture-types.ts +218 -0
- package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
- package/src/tools/agent-harness-setup-posture.ts +449 -221
- package/src/tools/agent-harness-setup-smoke.ts +508 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +120 -7
- package/src/tools/agent-harness-tool-types.ts +78 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +311 -370
- package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
- package/src/tools/agent-harness-ui-surface-types.ts +46 -0
- package/src/tools/agent-harness-vibe-health.ts +105 -0
- package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
- package/src/tools/agent-harness-workspace-actions.ts +114 -8
- package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
- package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
- package/src/tools/agent-host-tool.ts +159 -0
- package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
- package/src/tools/agent-learning-consolidation-core.ts +327 -0
- package/src/tools/agent-learning-consolidation-tool.ts +758 -0
- package/src/tools/agent-memory-tool.ts +214 -0
- package/src/tools/agent-model-compare-export.ts +315 -0
- package/src/tools/agent-model-compare-handoff.ts +592 -0
- package/src/tools/agent-model-compare-judgment.ts +633 -0
- package/src/tools/agent-model-compare-run.ts +722 -0
- package/src/tools/agent-model-compare-tool.ts +698 -0
- package/src/tools/agent-model-compare-types.ts +191 -0
- package/src/tools/agent-model-compare-utils.ts +93 -0
- package/src/tools/agent-models-tool.ts +208 -0
- package/src/tools/agent-operator-action-tool.ts +1 -1
- package/src/tools/agent-operator-method-tool.ts +643 -0
- package/src/tools/agent-personal-ops-tool.ts +197 -0
- package/src/tools/agent-policy-explanation.ts +415 -0
- package/src/tools/agent-research-report-tool.ts +608 -0
- package/src/tools/agent-research-runs-tool.ts +434 -0
- package/src/tools/agent-research-sources-tool.ts +443 -0
- package/src/tools/agent-research-tool.ts +687 -0
- package/src/tools/agent-review-packet-presets-core.ts +757 -0
- package/src/tools/agent-review-packet-presets-tool.ts +466 -0
- package/src/tools/agent-review-packet-share-tool.ts +305 -0
- package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
- package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
- package/src/tools/agent-route-planner-candidates-work.ts +251 -0
- package/src/tools/agent-route-planner-helpers.ts +667 -0
- package/src/tools/agent-route-planner.ts +185 -0
- package/src/tools/agent-route-tool.ts +105 -0
- package/src/tools/agent-schedule-edit-tool.ts +210 -0
- package/src/tools/agent-schedule-tool.ts +282 -0
- package/src/tools/agent-security-tool.ts +145 -0
- package/src/tools/agent-sessions-tool.ts +122 -0
- package/src/tools/agent-settings-import-tool.ts +104 -0
- package/src/tools/agent-settings-tool.ts +176 -0
- package/src/tools/agent-setup-tool.ts +226 -0
- package/src/tools/agent-support-tool.ts +122 -0
- package/src/tools/agent-terminal-process-tools.ts +167 -0
- package/src/tools/agent-tool-policy-guard-types.ts +77 -0
- package/src/tools/agent-tool-policy-guard.ts +106 -85
- package/src/tools/agent-vibe-tool.ts +297 -0
- package/src/tools/agent-work-plan-tool.ts +265 -6
- package/src/tools/agent-workspace-tool.ts +305 -0
- package/src/tools/artifact-archive.ts +169 -0
- package/src/tools/tool-definition-compaction.ts +36 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
|
+
import {
|
|
3
|
+
AgentResearchSourceRegistry,
|
|
4
|
+
researchSourceReportLine,
|
|
5
|
+
type AgentResearchSourceRecord,
|
|
6
|
+
type AgentResearchSourceStatus,
|
|
7
|
+
} from '../agent/research-source-registry.ts';
|
|
8
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
9
|
+
|
|
10
|
+
interface AgentHarnessResearchQueueArgs {
|
|
11
|
+
readonly sourceId?: unknown;
|
|
12
|
+
readonly target?: unknown;
|
|
13
|
+
readonly query?: unknown;
|
|
14
|
+
readonly includeParameters?: unknown;
|
|
15
|
+
readonly limit?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ResearchQueueItem {
|
|
19
|
+
readonly source: AgentResearchSourceRecord;
|
|
20
|
+
readonly priority: number;
|
|
21
|
+
readonly next: string;
|
|
22
|
+
readonly modelRoute: string;
|
|
23
|
+
readonly inspectRoute: string;
|
|
24
|
+
readonly bundleRoute?: string;
|
|
25
|
+
readonly reviewRoute?: string;
|
|
26
|
+
readonly rejectRoute?: string;
|
|
27
|
+
readonly reportRoute?: string;
|
|
28
|
+
readonly ingestRoute?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ResearchSourceResolution =
|
|
32
|
+
| { readonly status: 'found'; readonly source: Record<string, unknown> }
|
|
33
|
+
| { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
|
|
34
|
+
| { readonly status: 'missing_lookup'; readonly usage: string };
|
|
35
|
+
|
|
36
|
+
function readString(value: unknown): string {
|
|
37
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readLimit(value: unknown, fallback: number): number {
|
|
41
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
42
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
43
|
+
return Math.max(1, Math.min(200, Math.trunc(parsed)));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function routeString(value: string): string {
|
|
47
|
+
return JSON.stringify(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function statusPriority(status: AgentResearchSourceStatus): number {
|
|
51
|
+
if (status === 'candidate') return 86;
|
|
52
|
+
if (status === 'reviewed') return 72;
|
|
53
|
+
if (status === 'used') return 42;
|
|
54
|
+
return 20;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function nextForSource(source: AgentResearchSourceRecord): string {
|
|
58
|
+
if (source.status === 'candidate') return 'Review credibility, score, and notes before citing or ingesting this source.';
|
|
59
|
+
if (source.status === 'reviewed') return 'Use this source in a report, attach it to a document, or explicitly ingest it into Agent Knowledge if it should become durable.';
|
|
60
|
+
if (source.status === 'used') return 'Inspect the saved report or promote the report artifact into Agent Knowledge only after review.';
|
|
61
|
+
return 'Leave rejected unless new evidence changes the source assessment.';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function buildQueueItem(source: AgentResearchSourceRecord): ResearchQueueItem {
|
|
65
|
+
const reviewRoute = source.status === 'candidate' || source.status === 'rejected'
|
|
66
|
+
? `research action:"review_source" id="${source.id}" confirm:true explicitUserRequest="..."`
|
|
67
|
+
: '';
|
|
68
|
+
const rejectRoute = source.status !== 'rejected'
|
|
69
|
+
? `research action:"reject_source" id="${source.id}" confirm:true explicitUserRequest="..."`
|
|
70
|
+
: '';
|
|
71
|
+
const reportRoute = source.status === 'reviewed' || source.status === 'used'
|
|
72
|
+
? 'research action:"report" confirm:true explicitUserRequest:"..."'
|
|
73
|
+
: '';
|
|
74
|
+
const bundleRoute = source.status === 'reviewed' || source.status === 'used'
|
|
75
|
+
? `research action:"bundle" query:${routeString(source.id)} limit:10`
|
|
76
|
+
: '';
|
|
77
|
+
const ingestRoute = source.status === 'reviewed' || source.status === 'used'
|
|
78
|
+
? 'agent_knowledge_ingest sourceKind="url" confirm=true explicitUserRequest="..."'
|
|
79
|
+
: '';
|
|
80
|
+
return {
|
|
81
|
+
source,
|
|
82
|
+
priority: Math.max(statusPriority(source.status), source.score),
|
|
83
|
+
next: nextForSource(source),
|
|
84
|
+
modelRoute: 'research action:"source"',
|
|
85
|
+
inspectRoute: `research action:"source" sourceId="${source.id}"`,
|
|
86
|
+
...(bundleRoute ? { bundleRoute } : {}),
|
|
87
|
+
...(reviewRoute ? { reviewRoute } : {}),
|
|
88
|
+
...(rejectRoute ? { rejectRoute } : {}),
|
|
89
|
+
...(reportRoute ? { reportRoute } : {}),
|
|
90
|
+
...(ingestRoute ? { ingestRoute } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function sourceSearchText(item: ResearchQueueItem): string {
|
|
95
|
+
const source = item.source;
|
|
96
|
+
return [
|
|
97
|
+
source.id,
|
|
98
|
+
source.question,
|
|
99
|
+
source.title,
|
|
100
|
+
source.url ?? '',
|
|
101
|
+
source.publisher ?? '',
|
|
102
|
+
source.summary,
|
|
103
|
+
source.evidence ?? '',
|
|
104
|
+
source.credibility,
|
|
105
|
+
source.status,
|
|
106
|
+
source.note ?? '',
|
|
107
|
+
source.tags.join('\n'),
|
|
108
|
+
item.inspectRoute,
|
|
109
|
+
item.bundleRoute ?? '',
|
|
110
|
+
item.reviewRoute ?? '',
|
|
111
|
+
item.reportRoute ?? '',
|
|
112
|
+
item.ingestRoute ?? '',
|
|
113
|
+
].join('\n').toLowerCase();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function queueItems(context: CommandContext): readonly ResearchQueueItem[] {
|
|
117
|
+
const shellPaths = context.workspace?.shellPaths;
|
|
118
|
+
if (!shellPaths) return [];
|
|
119
|
+
return AgentResearchSourceRegistry.fromShellPaths(shellPaths)
|
|
120
|
+
.list()
|
|
121
|
+
.map(buildQueueItem)
|
|
122
|
+
.sort((left, right) => right.priority - left.priority || right.source.updatedAt.localeCompare(left.source.updatedAt));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function describeSourceItem(item: ResearchQueueItem, includeParameters: boolean, lookup?: Record<string, unknown>): Record<string, unknown> {
|
|
126
|
+
const source = item.source;
|
|
127
|
+
return {
|
|
128
|
+
sourceId: source.id,
|
|
129
|
+
title: source.title,
|
|
130
|
+
question: previewHarnessText(source.question, includeParameters ? 180 : 96),
|
|
131
|
+
status: source.status,
|
|
132
|
+
credibility: source.credibility,
|
|
133
|
+
score: source.score,
|
|
134
|
+
priority: item.priority,
|
|
135
|
+
summary: previewHarnessText(source.summary, includeParameters ? 220 : 96),
|
|
136
|
+
...(source.url ? { url: source.url } : {}),
|
|
137
|
+
...(source.publisher ? { publisher: source.publisher } : {}),
|
|
138
|
+
tags: source.tags,
|
|
139
|
+
next: previewHarnessText(item.next, includeParameters ? 180 : 96),
|
|
140
|
+
modelRoute: item.modelRoute,
|
|
141
|
+
inspectRoute: item.inspectRoute,
|
|
142
|
+
...(item.bundleRoute ? { bundleRoute: item.bundleRoute } : {}),
|
|
143
|
+
...(item.reviewRoute ? { reviewRoute: item.reviewRoute } : {}),
|
|
144
|
+
...(item.rejectRoute ? { rejectRoute: item.rejectRoute } : {}),
|
|
145
|
+
...(item.reportRoute ? { reportRoute: item.reportRoute } : {}),
|
|
146
|
+
...(item.ingestRoute ? { ingestRoute: item.ingestRoute } : {}),
|
|
147
|
+
reportSourceLine: researchSourceReportLine(source),
|
|
148
|
+
...(lookup ? { lookup } : {}),
|
|
149
|
+
...(includeParameters ? {
|
|
150
|
+
evidence: source.evidence ?? null,
|
|
151
|
+
note: source.note ?? null,
|
|
152
|
+
createdAt: source.createdAt,
|
|
153
|
+
updatedAt: source.updatedAt,
|
|
154
|
+
reviewedAt: source.reviewedAt ?? null,
|
|
155
|
+
rejectedAt: source.rejectedAt ?? null,
|
|
156
|
+
usedAt: source.usedAt ?? null,
|
|
157
|
+
policy: 'Research queue rows are local project state only. Report save, Knowledge ingest, external sends, and deletion stay on explicit separate routes.',
|
|
158
|
+
} : {}),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function nextActions(items: readonly ResearchQueueItem[]): readonly string[] {
|
|
163
|
+
return items
|
|
164
|
+
.filter((item) => item.source.status === 'candidate' || item.source.status === 'reviewed')
|
|
165
|
+
.slice(0, 5)
|
|
166
|
+
.map((item) => `${item.source.title}: ${item.next}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function researchQueueCatalogStatus(context: CommandContext): Record<string, unknown> {
|
|
170
|
+
const items = queueItems(context);
|
|
171
|
+
return {
|
|
172
|
+
modes: ['research_queue', 'research_source'],
|
|
173
|
+
sources: items.length,
|
|
174
|
+
candidates: items.filter((item) => item.source.status === 'candidate').length,
|
|
175
|
+
reviewed: items.filter((item) => item.source.status === 'reviewed').length,
|
|
176
|
+
rejected: items.filter((item) => item.source.status === 'rejected').length,
|
|
177
|
+
used: items.filter((item) => item.source.status === 'used').length,
|
|
178
|
+
readOnly: true,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function researchQueueSummary(context: CommandContext, args: AgentHarnessResearchQueueArgs): Record<string, unknown> {
|
|
183
|
+
const includeParameters = args.includeParameters === true;
|
|
184
|
+
const query = readString(args.query).toLowerCase();
|
|
185
|
+
const limit = readLimit(args.limit, 100);
|
|
186
|
+
const items = queueItems(context);
|
|
187
|
+
const filtered = items.filter((item) => !query || sourceSearchText(item).includes(query));
|
|
188
|
+
const bundleItems = filtered.filter((item) => item.source.status === 'reviewed' || item.source.status === 'used');
|
|
189
|
+
return {
|
|
190
|
+
summary: {
|
|
191
|
+
sources: items.length,
|
|
192
|
+
candidates: items.filter((item) => item.source.status === 'candidate').length,
|
|
193
|
+
reviewed: items.filter((item) => item.source.status === 'reviewed').length,
|
|
194
|
+
rejected: items.filter((item) => item.source.status === 'rejected').length,
|
|
195
|
+
used: items.filter((item) => item.source.status === 'used').length,
|
|
196
|
+
},
|
|
197
|
+
sources: filtered.slice(0, limit).map((item) => describeSourceItem(item, includeParameters)),
|
|
198
|
+
bundle: {
|
|
199
|
+
sources: bundleItems.length,
|
|
200
|
+
route: query
|
|
201
|
+
? `research action:"bundle" query:${routeString(query)} limit:${Math.min(limit, 20)}`
|
|
202
|
+
: `research action:"bundle" limit:${Math.min(limit, 20)}`,
|
|
203
|
+
reportRoute: 'research action:"report" requireCitationCoverage:true confirm:true explicitUserRequest:"..."',
|
|
204
|
+
next: 'Use bundle route to assemble reviewed/used sources into citation-ready report input before saving a report artifact.',
|
|
205
|
+
},
|
|
206
|
+
returned: Math.min(filtered.length, limit),
|
|
207
|
+
total: items.length,
|
|
208
|
+
nextActions: nextActions(items),
|
|
209
|
+
policy: 'Research queue is read-only in the harness. Source capture/review writes use confirmed research source actions; report artifacts and Knowledge ingest remain explicit separate steps.',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function describeResearchSource(context: CommandContext, args: AgentHarnessResearchQueueArgs): ResearchSourceResolution {
|
|
214
|
+
const sourceId = readString(args.sourceId);
|
|
215
|
+
const target = readString(args.target);
|
|
216
|
+
const query = readString(args.query);
|
|
217
|
+
const input = sourceId || target || query;
|
|
218
|
+
if (!input) {
|
|
219
|
+
return {
|
|
220
|
+
status: 'missing_lookup',
|
|
221
|
+
usage: 'research_source requires sourceId, target, or query. Use research action:"sources" to inspect source ids.',
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const normalized = input.toLowerCase();
|
|
225
|
+
const items = queueItems(context);
|
|
226
|
+
const exact = items.find((item) => item.source.id === input);
|
|
227
|
+
if (exact) return { status: 'found', source: describeSourceItem(exact, true, { source: sourceId ? 'sourceId' : target ? 'target' : 'query', input, resolvedBy: 'id' }) };
|
|
228
|
+
const insensitive = items.find((item) => item.source.id.toLowerCase() === normalized);
|
|
229
|
+
if (insensitive) return { status: 'found', source: describeSourceItem(insensitive, true, { source: sourceId ? 'sourceId' : target ? 'target' : 'query', input, resolvedBy: 'case-insensitive-id' }) };
|
|
230
|
+
const matches = items.filter((item) => sourceSearchText(item).includes(normalized));
|
|
231
|
+
if (matches.length === 1) return { status: 'found', source: describeSourceItem(matches[0]!, true, { source: sourceId ? 'sourceId' : target ? 'target' : 'query', input, resolvedBy: 'search' }) };
|
|
232
|
+
if (matches.length > 1) {
|
|
233
|
+
return {
|
|
234
|
+
status: 'ambiguous',
|
|
235
|
+
input,
|
|
236
|
+
candidates: matches.slice(0, 8).map((item) => ({
|
|
237
|
+
sourceId: item.source.id,
|
|
238
|
+
title: item.source.title,
|
|
239
|
+
status: item.source.status,
|
|
240
|
+
credibility: item.source.credibility,
|
|
241
|
+
score: item.source.score,
|
|
242
|
+
modelRoute: item.modelRoute,
|
|
243
|
+
})),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
status: 'missing_lookup',
|
|
248
|
+
usage: `Unknown research source ${input}. Use research action:"sources" to inspect source ids.`,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
|
+
import {
|
|
3
|
+
AgentResearchRunRegistry,
|
|
4
|
+
researchRunLogTail,
|
|
5
|
+
researchRunReportLine,
|
|
6
|
+
type AgentResearchRunRecord,
|
|
7
|
+
type AgentResearchRunStatus,
|
|
8
|
+
} from '../agent/research-run-registry.ts';
|
|
9
|
+
import { browserControlPosture } from './agent-harness-browser-control.ts';
|
|
10
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
11
|
+
|
|
12
|
+
interface AgentHarnessResearchRunArgs {
|
|
13
|
+
readonly runId?: unknown;
|
|
14
|
+
readonly target?: unknown;
|
|
15
|
+
readonly query?: unknown;
|
|
16
|
+
readonly includeParameters?: unknown;
|
|
17
|
+
readonly limit?: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface ResearchRunItem {
|
|
21
|
+
readonly run: AgentResearchRunRecord;
|
|
22
|
+
readonly priority: number;
|
|
23
|
+
readonly next: string;
|
|
24
|
+
readonly modelRoute: string;
|
|
25
|
+
readonly inspectRoute: string;
|
|
26
|
+
readonly checkpointRoute?: string;
|
|
27
|
+
readonly pauseRoute?: string;
|
|
28
|
+
readonly resumeRoute?: string;
|
|
29
|
+
readonly cancelRoute?: string;
|
|
30
|
+
readonly completeRoute?: string;
|
|
31
|
+
readonly reportRoute?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ResearchRunResolution =
|
|
35
|
+
| { readonly status: 'found'; readonly run: Record<string, unknown> }
|
|
36
|
+
| { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
|
|
37
|
+
| { readonly status: 'missing_lookup'; readonly usage: string };
|
|
38
|
+
|
|
39
|
+
function readString(value: unknown): string {
|
|
40
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function readLimit(value: unknown, fallback: number): number {
|
|
44
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
45
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
46
|
+
return Math.max(1, Math.min(200, Math.trunc(parsed)));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function statusPriority(status: AgentResearchRunStatus): number {
|
|
50
|
+
if (status === 'running') return 96;
|
|
51
|
+
if (status === 'blocked') return 90;
|
|
52
|
+
if (status === 'paused') return 82;
|
|
53
|
+
if (status === 'planned') return 76;
|
|
54
|
+
if (status === 'failed') return 64;
|
|
55
|
+
if (status === 'cancelled') return 30;
|
|
56
|
+
return 42;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isMutable(status: AgentResearchRunStatus): boolean {
|
|
60
|
+
return status !== 'cancelled' && status !== 'completed' && status !== 'failed';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function nextForRun(run: AgentResearchRunRecord): string {
|
|
64
|
+
if (run.status === 'planned') return 'Start the run or add an initial checkpoint before doing more research.';
|
|
65
|
+
if (run.status === 'running') return 'Checkpoint source ids, progress, and next steps before switching tasks or saving a report.';
|
|
66
|
+
if (run.status === 'paused') return 'Resume only when the user wants this research to continue.';
|
|
67
|
+
if (run.status === 'blocked') return 'Resolve the blocker or cancel with a clear note.';
|
|
68
|
+
if (run.status === 'failed') return 'Inspect the failure note, then create a new run or recover manually.';
|
|
69
|
+
if (run.status === 'completed') return 'Inspect the saved report artifact or explicitly promote reviewed artifacts to Agent Knowledge.';
|
|
70
|
+
return 'Leave cancelled unless the user asks to create a replacement run.';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildRunItem(run: AgentResearchRunRecord): ResearchRunItem {
|
|
74
|
+
const mutable = isMutable(run.status);
|
|
75
|
+
const checkpointRoute = mutable
|
|
76
|
+
? `research action:"checkpoint" id="${run.id}" confirm:true explicitUserRequest="..."`
|
|
77
|
+
: '';
|
|
78
|
+
const pauseRoute = run.status === 'running' || run.status === 'blocked'
|
|
79
|
+
? `research action:"pause" id="${run.id}" confirm:true explicitUserRequest="..."`
|
|
80
|
+
: '';
|
|
81
|
+
const resumeRoute = run.status === 'paused' || run.status === 'planned' || run.status === 'blocked'
|
|
82
|
+
? `research action:"resume" id="${run.id}" confirm:true explicitUserRequest="..."`
|
|
83
|
+
: '';
|
|
84
|
+
const cancelRoute = mutable
|
|
85
|
+
? `research action:"cancel" id="${run.id}" note="..." confirm:true explicitUserRequest="..."`
|
|
86
|
+
: '';
|
|
87
|
+
const completeRoute = mutable
|
|
88
|
+
? `research action:"complete" id="${run.id}" reportArtifactId="..." confirm:true explicitUserRequest="..."`
|
|
89
|
+
: '';
|
|
90
|
+
return {
|
|
91
|
+
run,
|
|
92
|
+
priority: statusPriority(run.status) + Math.min(20, Math.round(run.progress / 5)),
|
|
93
|
+
next: nextForRun(run),
|
|
94
|
+
modelRoute: 'research action:"run"',
|
|
95
|
+
inspectRoute: `research action:"run" runId="${run.id}"`,
|
|
96
|
+
...(checkpointRoute ? { checkpointRoute } : {}),
|
|
97
|
+
...(pauseRoute ? { pauseRoute } : {}),
|
|
98
|
+
...(resumeRoute ? { resumeRoute } : {}),
|
|
99
|
+
...(cancelRoute ? { cancelRoute } : {}),
|
|
100
|
+
...(completeRoute ? { completeRoute } : {}),
|
|
101
|
+
reportRoute: 'research action:"report" confirm:true explicitUserRequest:"..."',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function runSearchText(item: ResearchRunItem): string {
|
|
106
|
+
const run = item.run;
|
|
107
|
+
return [
|
|
108
|
+
run.id,
|
|
109
|
+
run.title,
|
|
110
|
+
run.question,
|
|
111
|
+
run.goal,
|
|
112
|
+
run.status,
|
|
113
|
+
run.phase,
|
|
114
|
+
run.note ?? '',
|
|
115
|
+
run.error ?? '',
|
|
116
|
+
run.reportArtifactId ?? '',
|
|
117
|
+
researchRunLogTail(run, 5).join('\n'),
|
|
118
|
+
run.plan.join('\n'),
|
|
119
|
+
run.nextSteps.join('\n'),
|
|
120
|
+
run.sourceIds.join('\n'),
|
|
121
|
+
item.inspectRoute,
|
|
122
|
+
item.checkpointRoute ?? '',
|
|
123
|
+
item.pauseRoute ?? '',
|
|
124
|
+
item.resumeRoute ?? '',
|
|
125
|
+
item.cancelRoute ?? '',
|
|
126
|
+
item.completeRoute ?? '',
|
|
127
|
+
].join('\n').toLowerCase();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function runItems(context: CommandContext): readonly ResearchRunItem[] {
|
|
131
|
+
const shellPaths = context.workspace?.shellPaths;
|
|
132
|
+
if (!shellPaths) return [];
|
|
133
|
+
return AgentResearchRunRegistry.fromShellPaths(shellPaths)
|
|
134
|
+
.list()
|
|
135
|
+
.map(buildRunItem)
|
|
136
|
+
.sort((left, right) => right.priority - left.priority || right.run.updatedAt.localeCompare(left.run.updatedAt));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function describeRunItem(item: ResearchRunItem, includeParameters: boolean, lookup?: Record<string, unknown>): Record<string, unknown> {
|
|
140
|
+
const run = item.run;
|
|
141
|
+
return {
|
|
142
|
+
runId: run.id,
|
|
143
|
+
title: run.title,
|
|
144
|
+
question: previewHarnessText(run.question, includeParameters ? 180 : 96),
|
|
145
|
+
goal: previewHarnessText(run.goal, includeParameters ? 180 : 96),
|
|
146
|
+
status: run.status,
|
|
147
|
+
phase: run.phase,
|
|
148
|
+
progress: run.progress,
|
|
149
|
+
priority: item.priority,
|
|
150
|
+
sources: run.sourceIds.length,
|
|
151
|
+
checkpoints: run.checkpoints.length,
|
|
152
|
+
logTail: researchRunLogTail(run, includeParameters ? 5 : 3),
|
|
153
|
+
...(run.reportArtifactId ? { reportArtifactId: run.reportArtifactId } : {}),
|
|
154
|
+
next: previewHarnessText(item.next, includeParameters ? 180 : 96),
|
|
155
|
+
modelRoute: item.modelRoute,
|
|
156
|
+
inspectRoute: item.inspectRoute,
|
|
157
|
+
...(item.checkpointRoute ? { checkpointRoute: item.checkpointRoute } : {}),
|
|
158
|
+
...(item.pauseRoute ? { pauseRoute: item.pauseRoute } : {}),
|
|
159
|
+
...(item.resumeRoute ? { resumeRoute: item.resumeRoute } : {}),
|
|
160
|
+
...(item.cancelRoute ? { cancelRoute: item.cancelRoute } : {}),
|
|
161
|
+
...(item.completeRoute ? { completeRoute: item.completeRoute } : {}),
|
|
162
|
+
...(item.reportRoute ? { reportRoute: item.reportRoute } : {}),
|
|
163
|
+
runLine: researchRunReportLine(run),
|
|
164
|
+
...(lookup ? { lookup } : {}),
|
|
165
|
+
...(includeParameters ? {
|
|
166
|
+
plan: run.plan,
|
|
167
|
+
nextSteps: run.nextSteps,
|
|
168
|
+
sourceIds: run.sourceIds,
|
|
169
|
+
note: run.note ?? null,
|
|
170
|
+
error: run.error ?? null,
|
|
171
|
+
createdAt: run.createdAt,
|
|
172
|
+
updatedAt: run.updatedAt,
|
|
173
|
+
startedAt: run.startedAt ?? null,
|
|
174
|
+
pausedAt: run.pausedAt ?? null,
|
|
175
|
+
cancelledAt: run.cancelledAt ?? null,
|
|
176
|
+
completedAt: run.completedAt ?? null,
|
|
177
|
+
failedAt: run.failedAt ?? null,
|
|
178
|
+
checkpoints: run.checkpoints.slice(-10),
|
|
179
|
+
policy: 'Research run rows are local visible state only. Web research, source review, report saves, Knowledge ingest, and external sends stay on explicit separate routes.',
|
|
180
|
+
} : {}),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function researchRunnerPosture(context: CommandContext, includeParameters: boolean): Record<string, unknown> {
|
|
185
|
+
const browser = browserControlPosture(context);
|
|
186
|
+
return {
|
|
187
|
+
browserBackedResearch: {
|
|
188
|
+
status: browser.status,
|
|
189
|
+
configured: browser.configured,
|
|
190
|
+
needsReview: browser.needsReview,
|
|
191
|
+
recommendedRoute: browser.recommendedRoute,
|
|
192
|
+
setupRoute: browser.setupRoute,
|
|
193
|
+
fallbackRoutes: browser.fallbackRoutes,
|
|
194
|
+
workflows: browser.workflows.map((workflow) => ({
|
|
195
|
+
id: workflow.id,
|
|
196
|
+
label: workflow.label,
|
|
197
|
+
status: workflow.status,
|
|
198
|
+
next: previewHarnessText(workflow.next, includeParameters ? 180 : 96),
|
|
199
|
+
inspectRoute: workflow.inspectRoute,
|
|
200
|
+
safety: previewHarnessText(workflow.safety, includeParameters ? 180 : 96),
|
|
201
|
+
})),
|
|
202
|
+
},
|
|
203
|
+
sourceQueueRoute: 'research action:"sources"',
|
|
204
|
+
sourceReviewRoute: 'research action:"review_source" confirm:true explicitUserRequest:"..."',
|
|
205
|
+
reportRoute: 'research action:"report" confirm:true explicitUserRequest:"..."',
|
|
206
|
+
knowledgePromotionRoute: 'agent_knowledge_ingest sourceKind:"artifact" artifactId:"..." confirm:true explicitUserRequest:"..."',
|
|
207
|
+
policy: 'Use browser-backed research only when browser/desktop control is ready or reviewed. Public web research can use web/fetch routes; report saving and Knowledge promotion remain separate confirmed effects.',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function nextActions(items: readonly ResearchRunItem[]): readonly string[] {
|
|
212
|
+
return items
|
|
213
|
+
.filter((item) => item.run.status === 'planned' || item.run.status === 'running' || item.run.status === 'paused' || item.run.status === 'blocked')
|
|
214
|
+
.slice(0, 5)
|
|
215
|
+
.map((item) => `${item.run.title}: ${item.next}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function researchRunsCatalogStatus(context: CommandContext): Record<string, unknown> {
|
|
219
|
+
const items = runItems(context);
|
|
220
|
+
return {
|
|
221
|
+
modes: ['research_runs', 'research_run'],
|
|
222
|
+
runs: items.length,
|
|
223
|
+
planned: items.filter((item) => item.run.status === 'planned').length,
|
|
224
|
+
running: items.filter((item) => item.run.status === 'running').length,
|
|
225
|
+
paused: items.filter((item) => item.run.status === 'paused').length,
|
|
226
|
+
blocked: items.filter((item) => item.run.status === 'blocked').length,
|
|
227
|
+
terminal: items.filter((item) => !isMutable(item.run.status)).length,
|
|
228
|
+
cancellable: items.filter((item) => isMutable(item.run.status)).length,
|
|
229
|
+
readOnly: true,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function researchRunsSummary(context: CommandContext, args: AgentHarnessResearchRunArgs): Record<string, unknown> {
|
|
234
|
+
const includeParameters = args.includeParameters === true;
|
|
235
|
+
const query = readString(args.query).toLowerCase();
|
|
236
|
+
const limit = readLimit(args.limit, 100);
|
|
237
|
+
const items = runItems(context);
|
|
238
|
+
const filtered = items.filter((item) => !query || runSearchText(item).includes(query));
|
|
239
|
+
return {
|
|
240
|
+
summary: {
|
|
241
|
+
runs: items.length,
|
|
242
|
+
planned: items.filter((item) => item.run.status === 'planned').length,
|
|
243
|
+
running: items.filter((item) => item.run.status === 'running').length,
|
|
244
|
+
paused: items.filter((item) => item.run.status === 'paused').length,
|
|
245
|
+
blocked: items.filter((item) => item.run.status === 'blocked').length,
|
|
246
|
+
terminal: items.filter((item) => !isMutable(item.run.status)).length,
|
|
247
|
+
cancellable: items.filter((item) => isMutable(item.run.status)).length,
|
|
248
|
+
},
|
|
249
|
+
runs: filtered.slice(0, limit).map((item) => describeRunItem(item, includeParameters)),
|
|
250
|
+
runnerPosture: researchRunnerPosture(context, includeParameters),
|
|
251
|
+
returned: Math.min(filtered.length, limit),
|
|
252
|
+
total: items.length,
|
|
253
|
+
nextActions: nextActions(items),
|
|
254
|
+
policy: 'Research runs are read-only in the harness. Run-state writes use confirmed research lifecycle actions; sources, reports, Knowledge, and delivery stay on separate explicit routes.',
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function describeResearchRun(context: CommandContext, args: AgentHarnessResearchRunArgs): ResearchRunResolution {
|
|
259
|
+
const runId = readString(args.runId);
|
|
260
|
+
const target = readString(args.target);
|
|
261
|
+
const query = readString(args.query);
|
|
262
|
+
const input = runId || target || query;
|
|
263
|
+
if (!input) {
|
|
264
|
+
return {
|
|
265
|
+
status: 'missing_lookup',
|
|
266
|
+
usage: 'research_run requires runId, target, or query. Use research action:"runs" to inspect run ids.',
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const normalized = input.toLowerCase();
|
|
270
|
+
const items = runItems(context);
|
|
271
|
+
const exact = items.find((item) => item.run.id === input);
|
|
272
|
+
if (exact) return { status: 'found', run: describeRunItem(exact, true, { source: runId ? 'runId' : target ? 'target' : 'query', input, resolvedBy: 'id' }) };
|
|
273
|
+
const insensitive = items.find((item) => item.run.id.toLowerCase() === normalized);
|
|
274
|
+
if (insensitive) return { status: 'found', run: describeRunItem(insensitive, true, { source: runId ? 'runId' : target ? 'target' : 'query', input, resolvedBy: 'case-insensitive-id' }) };
|
|
275
|
+
const matches = items.filter((item) => runSearchText(item).includes(normalized));
|
|
276
|
+
if (matches.length === 1) return { status: 'found', run: describeRunItem(matches[0]!, true, { source: runId ? 'runId' : target ? 'target' : 'query', input, resolvedBy: 'search' }) };
|
|
277
|
+
if (matches.length > 1) {
|
|
278
|
+
return {
|
|
279
|
+
status: 'ambiguous',
|
|
280
|
+
input,
|
|
281
|
+
candidates: matches.slice(0, 8).map((item) => ({
|
|
282
|
+
runId: item.run.id,
|
|
283
|
+
title: item.run.title,
|
|
284
|
+
status: item.run.status,
|
|
285
|
+
phase: item.run.phase,
|
|
286
|
+
progress: item.run.progress,
|
|
287
|
+
modelRoute: item.modelRoute,
|
|
288
|
+
})),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
status: 'missing_lookup',
|
|
293
|
+
usage: `Unknown research run ${input}. Use research action:"runs" to inspect run ids.`,
|
|
294
|
+
};
|
|
295
|
+
}
|