@pellux/goodvibes-agent 1.1.7 → 1.3.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 +329 -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 +138903 -91477
- 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 +58 -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 +116 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +142 -5
- package/release/release-readiness.json +124 -94
- 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 +294 -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-artifact-receipts.ts +366 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +683 -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 +313 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +217 -0
- package/src/input/agent-workspace-setup.ts +61 -1
- package/src/input/agent-workspace-snapshot.ts +184 -149
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +23 -1
- 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/input/setup-wizard-live-receipts.ts +76 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +701 -0
- package/src/renderer/agent-workspace.ts +68 -421
- 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-policy.ts +75 -0
- package/src/tools/agent-harness-agent-orchestration.ts +791 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +742 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +571 -0
- package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +798 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +373 -0
- package/src/tools/agent-harness-browser-control.ts +346 -0
- package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -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-device-live-read-models.ts +366 -0
- 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 +385 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-interactive-runtime-records.ts +421 -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 +269 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +788 -0
- package/src/tools/agent-harness-local-model-smoke.ts +277 -0
- package/src/tools/agent-harness-local-model-url.ts +78 -0
- package/src/tools/agent-harness-media-posture.ts +223 -2
- package/src/tools/agent-harness-memory-external-providers.ts +796 -0
- package/src/tools/agent-harness-memory-posture.ts +672 -0
- package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
- package/src/tools/agent-harness-memory-refinement.ts +340 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +86 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +283 -0
- package/src/tools/agent-harness-model-readiness.ts +432 -0
- package/src/tools/agent-harness-model-routing-types.ts +327 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +165 -193
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +452 -18
- package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
- 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 +270 -0
- package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
- package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
- package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
- package/src/tools/agent-harness-personal-ops-records.ts +684 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +240 -0
- package/src/tools/agent-harness-personal-ops.ts +613 -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-remote-read-models.ts +541 -0
- package/src/tools/agent-harness-research-briefing.ts +446 -0
- package/src/tools/agent-harness-research-live-read-models.ts +500 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +307 -0
- package/src/tools/agent-harness-research-workflow.ts +395 -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 +102 -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 +533 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +142 -7
- package/src/tools/agent-harness-tool-types.ts +83 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +319 -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 +253 -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 +735 -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-runner.ts +367 -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 +515 -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,367 @@
|
|
|
1
|
+
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
3
|
+
import { AgentResearchRunRegistry, type AgentResearchRunRecord } from '../agent/research-run-registry.ts';
|
|
4
|
+
import { AgentResearchSourceRegistry, researchSourceReportLine, type AgentResearchSourceRecord } from '../agent/research-source-registry.ts';
|
|
5
|
+
import type { AgentResearchToolArgs } from './agent-research-tool.ts';
|
|
6
|
+
|
|
7
|
+
type ToolResult = { readonly success: true; readonly output: string } | { readonly success: false; readonly error: string };
|
|
8
|
+
|
|
9
|
+
function error(message: string): { readonly success: false; readonly error: string } {
|
|
10
|
+
return { success: false, error: message };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readString(value: unknown): string {
|
|
14
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readNumber(value: unknown, fallback: number, max: number): number {
|
|
18
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
19
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
20
|
+
return Math.max(1, Math.min(max, Math.trunc(parsed)));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function compactArgs(entries: Record<string, unknown>): Record<string, unknown> {
|
|
24
|
+
return Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== undefined && value !== ''));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function searchArgs(args: AgentResearchToolArgs): Record<string, unknown> {
|
|
28
|
+
const safeSearch = readString(args.safeSearch).toLowerCase() === 'strict' ? 'strict' : 'moderate';
|
|
29
|
+
return compactArgs({
|
|
30
|
+
query: args.query ?? args.target,
|
|
31
|
+
providerId: args.providerId,
|
|
32
|
+
maxResults: readNumber(args.maxResults, readNumber(args.limit, 5, 10), 10),
|
|
33
|
+
verbosity: 'evidence',
|
|
34
|
+
region: args.region,
|
|
35
|
+
safeSearch,
|
|
36
|
+
timeRange: args.timeRange,
|
|
37
|
+
includeEvidence: true,
|
|
38
|
+
evidenceTopN: readNumber(args.evidenceTopN, 3, 3),
|
|
39
|
+
evidenceExtract: args.evidenceExtract ?? 'readable',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function previewText(value: unknown, limit: number): string {
|
|
44
|
+
const text = typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : '';
|
|
45
|
+
if (text.length <= limit) return text;
|
|
46
|
+
return `${text.slice(0, Math.max(0, limit - 3)).trimEnd()}...`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function quote(value: string): string {
|
|
50
|
+
return JSON.stringify(value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function fallbackTitle(question: string): string {
|
|
54
|
+
const cleaned = question.trim().replace(/\s+/g, ' ');
|
|
55
|
+
if (!cleaned) return 'Deep research run';
|
|
56
|
+
return cleaned.length <= 72 ? cleaned : `${cleaned.slice(0, 71).trimEnd()}...`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readRecord(value: unknown): Record<string, unknown> | null {
|
|
60
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function readRecordArray(value: unknown): readonly Record<string, unknown>[] {
|
|
64
|
+
return Array.isArray(value) ? value.map(readRecord).filter((entry): entry is Record<string, unknown> => Boolean(entry)) : [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function hostname(value: string): string {
|
|
68
|
+
try {
|
|
69
|
+
return new URL(value).hostname.replace(/^www\./i, '');
|
|
70
|
+
} catch {
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function sanitizeUrlForRoute(value: string): string {
|
|
76
|
+
try {
|
|
77
|
+
const url = new URL(value);
|
|
78
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
79
|
+
if (/token|secret|password|authorization|credential|api[-_]?key/i.test(key)) url.searchParams.set(key, '<redacted>');
|
|
80
|
+
}
|
|
81
|
+
return url.toString();
|
|
82
|
+
} catch {
|
|
83
|
+
return value.replace(/([?&\s](?:token|secret|password|authorization|credential|api[-_]?key)=)[^\s&]+/gi, '$1<redacted>');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function candidateFromSearchResult(question: string, result: Record<string, unknown>, index: number): Record<string, unknown> {
|
|
88
|
+
const rawUrl = readString(result.url);
|
|
89
|
+
const url = sanitizeUrlForRoute(rawUrl);
|
|
90
|
+
const title = previewText(result.title, 120) || hostname(rawUrl) || `Search result ${index + 1}`;
|
|
91
|
+
const publisher = previewText(result.domain, 80) || hostname(rawUrl);
|
|
92
|
+
const evidenceRecords = readRecordArray(result.evidence);
|
|
93
|
+
const evidenceText = previewText(
|
|
94
|
+
evidenceRecords.map((entry) => readString(entry.content)).filter(Boolean).join('\n\n') || result.snippet,
|
|
95
|
+
420,
|
|
96
|
+
);
|
|
97
|
+
const summary = previewText(result.snippet, 260) || previewText(evidenceText, 260) || `Public web result for ${question}.`;
|
|
98
|
+
const captureArgs = compactArgs({
|
|
99
|
+
action: 'add_source',
|
|
100
|
+
question,
|
|
101
|
+
title,
|
|
102
|
+
url,
|
|
103
|
+
publisher,
|
|
104
|
+
summary,
|
|
105
|
+
evidence: evidenceText,
|
|
106
|
+
credibility: 'unreviewed',
|
|
107
|
+
tags: ['research', 'web-search'],
|
|
108
|
+
confirm: true,
|
|
109
|
+
explicitUserRequest: '...',
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
rank: typeof result.rank === 'number' ? result.rank : index + 1,
|
|
113
|
+
title,
|
|
114
|
+
url,
|
|
115
|
+
...(publisher ? { publisher } : {}),
|
|
116
|
+
summary,
|
|
117
|
+
...(evidenceText ? { evidencePreview: evidenceText } : {}),
|
|
118
|
+
captureArgs,
|
|
119
|
+
captureRoute: [
|
|
120
|
+
'research action:"add_source"',
|
|
121
|
+
`question:${quote(question)}`,
|
|
122
|
+
`title:${quote(title)}`,
|
|
123
|
+
...(url ? [`url:${quote(url)}`] : []),
|
|
124
|
+
...(publisher ? [`publisher:${quote(publisher)}`] : []),
|
|
125
|
+
`summary:${quote(summary)}`,
|
|
126
|
+
...(evidenceText ? [`evidence:${quote(evidenceText)}`] : []),
|
|
127
|
+
'credibility:"unreviewed"',
|
|
128
|
+
'tags:["research","web-search"]',
|
|
129
|
+
'confirm:true',
|
|
130
|
+
'explicitUserRequest:"..."',
|
|
131
|
+
].join(' '),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function parseSearchPayload(outputValue: unknown): Record<string, unknown> | null {
|
|
136
|
+
if (typeof outputValue !== 'string') return readRecord(outputValue);
|
|
137
|
+
try {
|
|
138
|
+
return readRecord(JSON.parse(outputValue));
|
|
139
|
+
} catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function resolveSearchRun(args: AgentResearchToolArgs, shellPaths: CommandContext['workspace']['shellPaths'] | undefined): AgentResearchRunRecord | null {
|
|
145
|
+
if (!shellPaths) return null;
|
|
146
|
+
const lookup = readString(args.runId) || readString(args.id);
|
|
147
|
+
if (!lookup) return null;
|
|
148
|
+
return AgentResearchRunRegistry.fromShellPaths(shellPaths).get(lookup);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function runPublicSearch(
|
|
152
|
+
webSearchTool: Tool | undefined,
|
|
153
|
+
args: AgentResearchToolArgs,
|
|
154
|
+
shellPaths: CommandContext['workspace']['shellPaths'] | undefined,
|
|
155
|
+
): Promise<ToolResult> {
|
|
156
|
+
const run = resolveSearchRun(args, shellPaths);
|
|
157
|
+
const query = readString(args.query) || readString(args.question) || run?.question || readString(args.target);
|
|
158
|
+
if ((readString(args.runId) || readString(args.id)) && !run && !readString(args.query) && !readString(args.question)) {
|
|
159
|
+
return error(`Unknown research run ${readString(args.runId) || readString(args.id)}. Use research action:"runs" to inspect run ids.`);
|
|
160
|
+
}
|
|
161
|
+
if (!query) return error('research action:"search" requires query or target.');
|
|
162
|
+
if (!webSearchTool) {
|
|
163
|
+
return error('Bounded public web search is unavailable because web_search is not registered. Use research action:"briefing" for the offline next-action queue or action:"plan" for the route plan.');
|
|
164
|
+
}
|
|
165
|
+
const webArgs = searchArgs({ ...args, query });
|
|
166
|
+
const webResult = await webSearchTool.execute(webArgs);
|
|
167
|
+
if (!webResult.success) return { success: false, error: readString(webResult.error) || 'web_search failed.' };
|
|
168
|
+
const payload = parseSearchPayload(webResult.output);
|
|
169
|
+
const results = readRecordArray(payload?.results);
|
|
170
|
+
const sourceCandidates = results
|
|
171
|
+
.filter((result) => readString(result.url))
|
|
172
|
+
.map((result, index) => candidateFromSearchResult(query, result, index));
|
|
173
|
+
return {
|
|
174
|
+
success: true,
|
|
175
|
+
output: JSON.stringify({
|
|
176
|
+
status: sourceCandidates.length > 0 ? 'source-candidates-ready' : 'no-source-candidates',
|
|
177
|
+
query,
|
|
178
|
+
providerId: readString(payload?.providerId),
|
|
179
|
+
providerLabel: readString(payload?.providerLabel),
|
|
180
|
+
resultCount: results.length,
|
|
181
|
+
sourceCandidateCount: sourceCandidates.length,
|
|
182
|
+
sourceCandidates,
|
|
183
|
+
nextRoutes: {
|
|
184
|
+
...(run ? {
|
|
185
|
+
run: `research action:"run" runId:${quote(run.id)}`,
|
|
186
|
+
briefing: `research action:"briefing" target:${quote(run.id)}`,
|
|
187
|
+
startRun: `research action:"start_run" id:${quote(run.id)} confirm:true explicitUserRequest:"..."`,
|
|
188
|
+
checkpointAfterCapture: `research action:"checkpoint" id:${quote(run.id)} phase:"reading" progress:${Math.max(run.progress, 25)} note:"Captured candidate sources for review." sourceIds:["..."] confirm:true explicitUserRequest:"..."`,
|
|
189
|
+
} : {
|
|
190
|
+
createRun: `research action:"create_run" question:${quote(query)} plan:["Search bounded public web sources","Capture candidate sources","Review credibility","Save sourced report"] confirm:true explicitUserRequest:"..."`,
|
|
191
|
+
}),
|
|
192
|
+
sourceQueue: `research action:"sources" query:${quote(query)}`,
|
|
193
|
+
reviewedBundle: `research action:"bundle" query:${quote(query)} includeReportLines:true`,
|
|
194
|
+
saveReport: `research action:"report" question:${quote(query)} sources:[...] visualReport:true requireCitationCoverage:true confirm:true explicitUserRequest:"..."`,
|
|
195
|
+
},
|
|
196
|
+
...(run ? { run: { id: run.id, title: run.title, status: run.status, phase: run.phase, progress: run.progress } } : {}),
|
|
197
|
+
searchArgs: webArgs,
|
|
198
|
+
policy: 'This route performs bounded read-only public web search only. It does not create or start a run, save sources, checkpoint progress, write a report, ingest Knowledge, or send messages. Use each returned route only after explicit user confirmation.',
|
|
199
|
+
}, null, 2),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function requireConfirmedRunner(args: AgentResearchToolArgs): string {
|
|
204
|
+
const explicitUserRequest = readString(args.explicitUserRequest);
|
|
205
|
+
if (!explicitUserRequest) throw new Error('research action:"runner" requires explicitUserRequest before it can create or checkpoint a visible research run.');
|
|
206
|
+
if (args.confirm !== true) throw new Error('research action:"runner" requires confirm:true before it can create or checkpoint a visible research run.');
|
|
207
|
+
return explicitUserRequest;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function researchSourceRoutes(source: AgentResearchSourceRecord): Record<string, unknown> {
|
|
211
|
+
return {
|
|
212
|
+
sourceId: source.id,
|
|
213
|
+
title: source.title,
|
|
214
|
+
status: source.status,
|
|
215
|
+
credibility: source.credibility,
|
|
216
|
+
score: source.score,
|
|
217
|
+
inspectRoute: `research action:"source" sourceId:${quote(source.id)}`,
|
|
218
|
+
reviewRoute: `research action:"review_source" id:${quote(source.id)} credibility:"high|medium|mixed|low" score:80 note:"..." confirm:true explicitUserRequest:"..."`,
|
|
219
|
+
reportLine: researchSourceReportLine(source),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function sourceFromCandidate(
|
|
224
|
+
registry: AgentResearchSourceRegistry,
|
|
225
|
+
question: string,
|
|
226
|
+
candidate: Record<string, unknown>,
|
|
227
|
+
): { readonly source: AgentResearchSourceRecord; readonly created: boolean } | null {
|
|
228
|
+
const title = readString(candidate.title);
|
|
229
|
+
const summary = readString(candidate.summary);
|
|
230
|
+
const url = readString(candidate.url);
|
|
231
|
+
if (!title || !summary) return null;
|
|
232
|
+
const publisher = readString(candidate.publisher);
|
|
233
|
+
const evidence = readString(candidate.evidencePreview);
|
|
234
|
+
try {
|
|
235
|
+
return {
|
|
236
|
+
created: true,
|
|
237
|
+
source: registry.create({
|
|
238
|
+
question,
|
|
239
|
+
title,
|
|
240
|
+
...(url ? { url } : {}),
|
|
241
|
+
...(publisher ? { publisher } : {}),
|
|
242
|
+
summary,
|
|
243
|
+
...(evidence ? { evidence } : {}),
|
|
244
|
+
credibility: 'unreviewed',
|
|
245
|
+
tags: ['research', 'web-search', 'runner'],
|
|
246
|
+
note: 'Captured by confirmed GoodVibes research runner.',
|
|
247
|
+
provenance: 'agent-research-runner',
|
|
248
|
+
}),
|
|
249
|
+
};
|
|
250
|
+
} catch (err) {
|
|
251
|
+
const existing = registry.get(url || title);
|
|
252
|
+
if (existing) return { created: false, source: existing };
|
|
253
|
+
throw err;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export async function runConfirmedResearchRunner(
|
|
258
|
+
webSearchTool: Tool | undefined,
|
|
259
|
+
args: AgentResearchToolArgs,
|
|
260
|
+
shellPaths: CommandContext['workspace']['shellPaths'] | undefined,
|
|
261
|
+
): Promise<ToolResult> {
|
|
262
|
+
try {
|
|
263
|
+
const explicitUserRequest = requireConfirmedRunner(args);
|
|
264
|
+
if (!shellPaths) return error('Confirmed research runner is unavailable because this runtime did not provide shell paths.');
|
|
265
|
+
if (!webSearchTool) return error('Confirmed research runner requires the web_search tool for bounded source collection. Use research action:"plan" for offline routing.');
|
|
266
|
+
const runRegistry = AgentResearchRunRegistry.fromShellPaths(shellPaths);
|
|
267
|
+
const sourceRegistry = AgentResearchSourceRegistry.fromShellPaths(shellPaths);
|
|
268
|
+
const lookup = readString(args.runId) || readString(args.id);
|
|
269
|
+
const existingRun = lookup ? runRegistry.get(lookup) : null;
|
|
270
|
+
if (lookup && !existingRun) return error(`Unknown research run ${lookup}. Use research action:"runs" to inspect run ids.`);
|
|
271
|
+
const question = readString(args.query) || readString(args.question) || readString(args.target) || existingRun?.question || explicitUserRequest;
|
|
272
|
+
if (!question) return error('Confirmed research runner requires query, question, target, or an existing run with a question.');
|
|
273
|
+
let run = existingRun ?? runRegistry.create({
|
|
274
|
+
title: readString(args.title) || fallbackTitle(question),
|
|
275
|
+
question,
|
|
276
|
+
goal: readString(args.goal) || `Collect reviewed source candidates for: ${question}`,
|
|
277
|
+
plan: [
|
|
278
|
+
'Run bounded public web source collection.',
|
|
279
|
+
'Save candidate sources into the local research source queue.',
|
|
280
|
+
'Checkpoint the visible research run with source ids and next review steps.',
|
|
281
|
+
'Save a citation-covered report only after source review.',
|
|
282
|
+
],
|
|
283
|
+
nextSteps: ['Run bounded source collection.', 'Review candidate sources.', 'Save a sourced report artifact.'],
|
|
284
|
+
note: `Confirmed runner authorized by user request: ${previewText(explicitUserRequest, 160)}`,
|
|
285
|
+
provenance: 'agent-research-runner',
|
|
286
|
+
});
|
|
287
|
+
if (run.status === 'planned') {
|
|
288
|
+
run = runRegistry.start(run.id, 'Confirmed research runner started bounded source collection.');
|
|
289
|
+
} else if (run.status === 'paused' || run.status === 'blocked') {
|
|
290
|
+
run = runRegistry.resume(run.id, 'Confirmed research runner resumed bounded source collection.');
|
|
291
|
+
} else if (run.status === 'completed' || run.status === 'failed' || run.status === 'cancelled') {
|
|
292
|
+
return error(`Cannot run confirmed research runner for ${run.status} research run ${run.id}. Create a follow-up run instead.`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const webResult = await webSearchTool.execute(searchArgs({ ...args, query: run.question }));
|
|
296
|
+
if (!webResult.success) {
|
|
297
|
+
run = runRegistry.checkpoint(run.id, {
|
|
298
|
+
status: 'blocked',
|
|
299
|
+
phase: 'searching',
|
|
300
|
+
progress: Math.max(run.progress, 10),
|
|
301
|
+
note: `Confirmed research runner blocked during source collection: ${readString(webResult.error) || 'web_search failed.'}`,
|
|
302
|
+
nextSteps: ['Inspect runner readiness.', 'Retry bounded source collection after search is available.'],
|
|
303
|
+
});
|
|
304
|
+
return {
|
|
305
|
+
success: false,
|
|
306
|
+
error: `Confirmed research runner blocked for ${run.id}: ${readString(webResult.error) || 'web_search failed.'}`,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const payload = parseSearchPayload(webResult.output);
|
|
311
|
+
const results = readRecordArray(payload?.results);
|
|
312
|
+
const candidates = results
|
|
313
|
+
.filter((result) => readString(result.url))
|
|
314
|
+
.map((result, index) => candidateFromSearchResult(run.question, result, index));
|
|
315
|
+
const saved = candidates
|
|
316
|
+
.map((candidate) => sourceFromCandidate(sourceRegistry, run.question, candidate))
|
|
317
|
+
.filter((entry): entry is { readonly source: AgentResearchSourceRecord; readonly created: boolean } => entry !== null);
|
|
318
|
+
const sourceIds = saved.map((entry) => entry.source.id);
|
|
319
|
+
const createdCount = saved.filter((entry) => entry.created).length;
|
|
320
|
+
const duplicateCount = saved.length - createdCount;
|
|
321
|
+
run = runRegistry.checkpoint(run.id, {
|
|
322
|
+
status: 'running',
|
|
323
|
+
phase: 'reading',
|
|
324
|
+
progress: Math.max(run.progress, sourceIds.length > 0 ? 35 : 20),
|
|
325
|
+
note: `Confirmed research runner captured ${createdCount} new source candidate(s)${duplicateCount > 0 ? ` and reused ${duplicateCount} existing source(s)` : ''}.`,
|
|
326
|
+
nextSteps: sourceIds.length > 0
|
|
327
|
+
? ['Review candidate source credibility.', 'Save a citation-covered report artifact after source review.']
|
|
328
|
+
: ['Try a more specific query or provider.', 'Capture sources manually if public search found none.'],
|
|
329
|
+
sourceIds,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
success: true,
|
|
334
|
+
output: JSON.stringify({
|
|
335
|
+
status: sourceIds.length > 0 ? 'source-collection-checkpointed' : 'no-source-candidates-checkpointed',
|
|
336
|
+
run: {
|
|
337
|
+
id: run.id,
|
|
338
|
+
title: run.title,
|
|
339
|
+
status: run.status,
|
|
340
|
+
phase: run.phase,
|
|
341
|
+
progress: run.progress,
|
|
342
|
+
sourceIds: run.sourceIds,
|
|
343
|
+
inspectRoute: `research action:"run" runId:${quote(run.id)}`,
|
|
344
|
+
checkpointRoute: `research action:"checkpoint" id:${quote(run.id)} phase:"reading" progress:${Math.max(run.progress, 35)} note:"..." sourceIds:["..."] confirm:true explicitUserRequest:"..."`,
|
|
345
|
+
cancelRoute: `research action:"cancel" id:${quote(run.id)} note:"..." confirm:true explicitUserRequest:"..."`,
|
|
346
|
+
},
|
|
347
|
+
query: run.question,
|
|
348
|
+
providerId: readString(payload?.providerId),
|
|
349
|
+
resultCount: results.length,
|
|
350
|
+
sourceCandidateCount: candidates.length,
|
|
351
|
+
savedSourceCount: createdCount,
|
|
352
|
+
reusedSourceCount: duplicateCount,
|
|
353
|
+
sources: saved.map((entry) => researchSourceRoutes(entry.source)),
|
|
354
|
+
nextRoutes: {
|
|
355
|
+
run: `research action:"run" runId:${quote(run.id)}`,
|
|
356
|
+
sources: `research action:"sources" query:${quote(run.question)} includeReportLines:true`,
|
|
357
|
+
reviewSource: 'research action:"review_source" id:"..." credibility:"high|medium|mixed|low" score:80 note:"..." confirm:true explicitUserRequest:"..."',
|
|
358
|
+
bundle: `research action:"bundle" query:${quote(run.question)} includeReportLines:true`,
|
|
359
|
+
saveReport: `research action:"report" question:${quote(run.question)} sources:[...] visualReport:true requireCitationCoverage:true confirm:true explicitUserRequest:"..."`,
|
|
360
|
+
},
|
|
361
|
+
policy: 'Confirmed research runner only creates/updates local visible research run state and local source queue records. It does not save a report, ingest Knowledge, send messages, or control a browser/PWA surface.',
|
|
362
|
+
}, null, 2),
|
|
363
|
+
};
|
|
364
|
+
} catch (err) {
|
|
365
|
+
return error(err instanceof Error ? err.message : String(err));
|
|
366
|
+
}
|
|
367
|
+
}
|