@lincoln504/pi-research 0.1.13 → 1.0.1
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/LICENSE +1 -1
- package/README.md +55 -138
- package/dist/cli.mjs +23375 -0
- package/dist/prompts/research-knowledge-relevance-triage.md +35 -0
- package/dist/prompts/research-knowledge-search-extractor.md +41 -0
- package/dist/prompts/research-tool-usage.md +92 -0
- package/dist/prompts/researcher.md +89 -0
- package/dist/prompts/system-coordinator.md +75 -0
- package/dist/prompts/system-lead-evaluator.md +118 -0
- package/dist/thread-worker.mjs +2611 -0
- package/dist/webgpu-probe.mjs +80 -0
- package/docs/AGENT-SKILL.md +130 -0
- package/docs/ARCHITECTURE.md +306 -80
- package/docs/CONFIGURATION.md +249 -0
- package/docs/KNOWLEDGE-STORE.md +211 -0
- package/docs/PI-EXTENSION.md +91 -0
- package/docs/SDK.md +122 -0
- package/docs/THIRD-PARTY-NOTICES.md +66 -0
- package/package.json +102 -36
- package/scripts/build.cjs +140 -0
- package/scripts/cleanup.cjs +149 -0
- package/scripts/prepare.cjs +28 -0
- package/scripts/setup.cjs +134 -0
- package/skills/pi-research/README.md +90 -0
- package/skills/pi-research/SKILL.md +102 -0
- package/skills/pi-research/references/configuration.md +77 -0
- package/skills/pi-research/scripts/run.mjs +237 -0
- package/src/cleanup/research-cleanup.ts +140 -0
- package/src/cli.ts +1195 -0
- package/src/config.ts +1032 -155
- package/src/constants.ts +115 -84
- package/src/core/health-check-service.ts +265 -0
- package/src/core/interfaces/health-check-interfaces.ts +50 -0
- package/src/core/interfaces/knowledge-interfaces.ts +190 -0
- package/src/core/interfaces/observer-interfaces.ts +67 -0
- package/src/core/interfaces/orchestration-interfaces.ts +86 -0
- package/src/core/interfaces/planning-interfaces.ts +100 -0
- package/src/core/interfaces/process-interfaces.ts +37 -0
- package/src/core/interfaces/research-plan-types.ts +52 -0
- package/src/core/interfaces/scheduler-interfaces.ts +91 -0
- package/src/core/interfaces/service-names.ts +39 -0
- package/src/core/interfaces/state-manager-interfaces.ts +29 -0
- package/src/core/interfaces/steering-interfaces.ts +31 -0
- package/src/core/llm/agentic-repair.ts +169 -0
- package/src/core/llm/inject-date.ts +52 -0
- package/src/core/llm/llm-timeout.ts +64 -0
- package/src/core/llm/llm-utils.ts +86 -0
- package/src/core/llm/model-registry-factory.ts +287 -0
- package/src/core/llm/pi-ai-completion.ts +29 -0
- package/src/core/llm/prompts.ts +50 -0
- package/src/core/llm/research-model-resolver.ts +91 -0
- package/src/core/planning-constants.ts +13 -0
- package/src/core/planning-service.ts +649 -0
- package/src/core/planning-utils.ts +299 -0
- package/src/core/scheduler-factory.ts +48 -0
- package/src/core/scheduler-service.ts +123 -0
- package/src/core/service-initialization.ts +194 -0
- package/src/core/service-interfaces.ts +48 -0
- package/src/core/service-registry.ts +659 -0
- package/src/healthcheck/index.ts +271 -265
- package/src/healthcheck/registry.ts +130 -0
- package/src/index.ts +639 -50
- package/src/infrastructure/browser/browser-cleanup.ts +309 -0
- package/src/infrastructure/browser/browser-client.ts +199 -0
- package/src/infrastructure/browser/browser-error-utils.ts +160 -0
- package/src/infrastructure/browser/browser-lifecycle.ts +120 -0
- package/src/infrastructure/browser/browser-server.ts +174 -0
- package/src/infrastructure/browser/browser-task-scheduler.ts +461 -0
- package/src/infrastructure/browser/cleanup-utils.ts +155 -0
- package/src/infrastructure/browser/client-agent.ts +31 -0
- package/src/infrastructure/browser/config.ts +288 -0
- package/src/infrastructure/browser/ensure-browser.ts +205 -0
- package/src/infrastructure/browser/index.ts +37 -0
- package/src/infrastructure/browser/priority-task-queue.ts +226 -0
- package/src/infrastructure/browser/scheduler-factory.ts +354 -0
- package/src/infrastructure/browser/task-execution-service.ts +209 -0
- package/src/infrastructure/browser/thread-worker-browser.ts +282 -0
- package/src/infrastructure/browser/thread-worker-lifecycle.ts +323 -0
- package/src/infrastructure/browser/thread-worker-messaging.ts +662 -0
- package/src/infrastructure/browser/thread-worker-types.ts +25 -0
- package/src/infrastructure/browser/thread-worker.mjs +2611 -0
- package/src/infrastructure/browser/thread-worker.ts +168 -0
- package/src/infrastructure/browser/worker-pool-manager.ts +449 -0
- package/src/infrastructure/embedding/embedding-client.ts +205 -0
- package/src/infrastructure/embedding/embedding-factory.ts +324 -0
- package/src/infrastructure/embedding/embedding-server.ts +535 -0
- package/src/infrastructure/file-lock-service.ts +592 -0
- package/src/infrastructure/gpu-resource-service.ts +191 -0
- package/src/infrastructure/knowledge-store-service.ts +475 -0
- package/src/infrastructure/metrics-service.ts +129 -0
- package/src/infrastructure/process-lifecycle-service.ts +253 -0
- package/src/infrastructure/scheduler-factory-service.ts +58 -0
- package/src/infrastructure/service-initialization.ts +292 -0
- package/src/infrastructure/state/state-backup-manager.ts +290 -0
- package/src/infrastructure/state/state-browser-api.ts +62 -0
- package/src/infrastructure/state/state-browser-manager.ts +70 -0
- package/src/infrastructure/state/state-manager-service.ts +264 -0
- package/src/infrastructure/state/state-manager.ts +547 -0
- package/src/infrastructure/state/state-metrics.ts +92 -0
- package/src/infrastructure/state/state-migration.ts +103 -0
- package/src/infrastructure/state/state-path-configuration.ts +119 -0
- package/src/infrastructure/state/state-session-api.ts +94 -0
- package/src/infrastructure/state/state-session-manager.ts +127 -0
- package/src/infrastructure/state/state-validator.ts +93 -0
- package/src/infrastructure/types/state-types.ts +85 -0
- package/src/knowledge/chunker.ts +157 -0
- package/src/knowledge/embedder-init.ts +413 -0
- package/src/knowledge/embedder-utils.ts +296 -0
- package/src/knowledge/embedder.ts +592 -0
- package/src/knowledge/index.ts +126 -0
- package/src/knowledge/lancedb-loader.ts +35 -0
- package/src/knowledge/migration.ts +17 -0
- package/src/knowledge/model-config.ts +132 -0
- package/src/knowledge/onnx-env.ts +48 -0
- package/src/knowledge/store-operations.ts +291 -0
- package/src/knowledge/store-schema.ts +79 -0
- package/src/knowledge/store.ts +1251 -0
- package/src/knowledge/transformers-loader.ts +31 -0
- package/src/knowledge/webgpu-probe.mjs +80 -0
- package/src/knowledge/webgpu-viability.ts +255 -0
- package/src/knowledge/writer-queue.ts +252 -0
- package/src/logger.ts +316 -122
- package/src/observers/research-observer-impl.ts +459 -0
- package/src/orchestration/deep-research-orchestrator.ts +524 -773
- package/src/orchestration/deep-research-types.ts +47 -35
- package/src/orchestration/headless-observer.ts +114 -0
- package/src/orchestration/orchestration-types.ts +33 -0
- package/src/orchestration/quick-research-orchestrator.ts +463 -0
- package/src/orchestration/research-orchestration-service.ts +549 -0
- package/src/orchestration/research-session-service.ts +178 -0
- package/src/orchestration/research-synthesis-service.ts +348 -0
- package/src/orchestration/researcher-executor.ts +394 -0
- package/src/orchestration/researcher.ts +115 -42
- package/src/orchestration/service-initialization.ts +109 -0
- package/src/orchestration/session-context.ts +7 -3
- package/src/orchestration/session-state.ts +672 -0
- package/src/prompts/research-knowledge-relevance-triage.md +35 -0
- package/src/prompts/research-knowledge-search-extractor.md +41 -0
- package/src/prompts/research-tool-usage.md +63 -16
- package/src/prompts/researcher.md +59 -136
- package/src/prompts/system-coordinator.md +64 -13
- package/src/prompts/system-lead-evaluator.md +82 -189
- package/src/research-config.ts +872 -0
- package/src/sdk.ts +847 -0
- package/src/security/cisa-kev.ts +72 -9
- package/src/security/cvss.ts +92 -0
- package/src/security/ecosystem.ts +45 -0
- package/src/security/github-advisories.ts +168 -428
- package/src/security/github-advisory-types.ts +282 -0
- package/src/security/index.ts +63 -177
- package/src/security/nvd-client.ts +550 -0
- package/src/security/nvd-types.ts +179 -0
- package/src/security/osv-client.ts +246 -0
- package/src/security/osv-types.ts +285 -0
- package/src/security/types.ts +67 -53
- package/src/skill-install/skill-installer.ts +519 -0
- package/src/stackexchange/index.ts +81 -27
- package/src/stackexchange/output/compact.ts +7 -6
- package/src/stackexchange/output/table.ts +11 -7
- package/src/stackexchange/queries.ts +0 -10
- package/src/stackexchange/rest-client.ts +141 -66
- package/src/stackexchange/types.ts +0 -17
- package/src/tool.ts +15 -423
- package/src/tools/grep.ts +32 -310
- package/src/tools/health-tool-definition.ts +101 -0
- package/src/tools/index.ts +38 -9
- package/src/tools/research-knowledge-search.ts +974 -0
- package/src/tools/research-knowledge-types.ts +77 -0
- package/src/tools/research-tool-definition.ts +494 -0
- package/src/tools/scrape.ts +286 -388
- package/src/tools/search.ts +98 -153
- package/src/tools/security.ts +107 -80
- package/src/tools/stackexchange.ts +58 -35
- package/src/tools/youtube-transcript.ts +163 -0
- package/src/tui/knowledge-search-panel.ts +86 -0
- package/src/tui/pulse.ts +86 -0
- package/src/tui/research-health.ts +124 -0
- package/src/tui/research-panel-color-utils.ts +340 -0
- package/src/tui/research-panel-format.ts +54 -0
- package/src/tui/research-panel-state.ts +404 -0
- package/src/tui/research-panel-wave.ts +280 -0
- package/src/tui/research-panel.ts +339 -435
- package/src/tui/research-tui-manager.ts +233 -0
- package/src/tui/tui-controller.ts +137 -0
- package/src/types/extension-context.ts +18 -49
- package/src/types/index.ts +61 -0
- package/src/types/llm.ts +68 -29
- package/src/types/research-panel-types.ts +61 -0
- package/src/utils/circuit-breaker.ts +146 -0
- package/src/utils/citation-utils.ts +97 -0
- package/src/utils/disk-space-checker.ts +55 -0
- package/src/utils/error-tracker.ts +265 -0
- package/src/utils/host-config.ts +45 -0
- package/src/utils/input-validation.ts +8 -10
- package/src/utils/json-utils.ts +150 -16
- package/src/utils/llm-usage.ts +54 -0
- package/src/utils/log-rotation.ts +125 -0
- package/src/utils/log-utils.ts +159 -0
- package/src/utils/make-resource-loader.ts +3 -1
- package/src/utils/metrics-summary.ts +459 -0
- package/src/utils/metrics.ts +302 -0
- package/src/utils/research-export.ts +28 -12
- package/src/utils/safe-unref.ts +31 -0
- package/src/utils/shared-links.ts +195 -90
- package/src/utils/shutdown-manager.ts +65 -0
- package/src/utils/stdio-capture.ts +407 -0
- package/src/utils/text-utils.ts +258 -11
- package/src/utils/tool-usage-tracker.ts +83 -16
- package/src/utils/url-utils.ts +255 -0
- package/src/utils/user-agent.ts +28 -0
- package/src/web-research/browser-search.ts +179 -0
- package/src/web-research/retry-utils.ts +173 -77
- package/src/web-research/scraper-types.ts +72 -0
- package/src/web-research/scraper-utils.ts +434 -0
- package/src/web-research/search.ts +78 -218
- package/src/web-research/types.ts +9 -24
- package/src/web-research/utils.ts +2 -143
- package/src/web-research/web-scraper.ts +477 -0
- package/src/youtube/index.ts +154 -0
- package/src/youtube/potoken.ts +259 -0
- package/src/youtube/transcript-client.ts +390 -0
- package/src/youtube/video-id.ts +118 -0
- package/config/searxng/default-settings.yml +0 -189
- package/config/searxng/limiter.toml +0 -34
- package/config/tooling/eslint.config.js +0 -73
- package/config/tooling/vitest.config.integration.ts +0 -17
- package/config/tooling/vitest.config.ts +0 -40
- package/config/tooling/vitest.config.unit.ts +0 -12
- package/docs/assets/README-banner.jpg +0 -0
- package/scripts/setup.js +0 -212
- package/src/infrastructure/searxng-lifecycle.ts +0 -644
- package/src/infrastructure/searxng-manager.ts +0 -1183
- package/src/infrastructure/state-manager.ts +0 -918
- package/src/orchestration/deep-research-reducer.ts +0 -129
- package/src/orchestration/id-utils.ts +0 -63
- package/src/security/nvd.ts +0 -532
- package/src/security/osv.ts +0 -487
- package/src/stackexchange/cache.ts +0 -111
- package/src/stackexchange/output/index.ts +0 -7
- package/src/stackexchange/output/json.ts +0 -21
- package/src/tui/searxng-status.ts +0 -80
- package/src/utils/inject-date.ts +0 -29
- package/src/utils/research-error.ts +0 -205
- package/src/utils/searxng-config.ts +0 -94
- package/src/utils/session-state.ts +0 -295
- package/src/web-research/dependencies.ts +0 -20
- package/src/web-research/scrapers.ts +0 -935
- package/tsconfig.json +0 -40
package/src/tools/grep.ts
CHANGED
|
@@ -1,335 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Grep Tool
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Thin wrapper around the SDK's built-in grep tool that adds
|
|
5
|
+
* ToolUsageTracker budget enforcement before delegating execution.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import type { ToolDefinition
|
|
10
|
-
import { Type } from '@sinclair/typebox';
|
|
8
|
+
import { createGrepToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
9
|
+
import { Value } from 'typebox/value';
|
|
10
|
+
import type { ToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
11
11
|
import type { ToolUsageTracker } from '../utils/tool-usage-tracker.ts';
|
|
12
|
-
|
|
13
|
-
const DEFAULT_MAX_BYTES = 100 * 1024; // 100KB
|
|
14
|
-
const DEFAULT_MAX_LINES = 200;
|
|
15
|
-
const STREAM_MAX_BYTES = 10 * 1024 * 1024; // 10MB max in stream (prevent RangeError)
|
|
16
|
-
|
|
17
|
-
interface RgGrepParams {
|
|
18
|
-
pattern: string;
|
|
19
|
-
path?: string;
|
|
20
|
-
flags?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function truncateHead(content: string, maxBytes: number, maxLines: number): string {
|
|
24
|
-
const lines = content.split('\n');
|
|
25
|
-
|
|
26
|
-
if (lines.length <= maxLines && Buffer.byteLength(content, 'utf-8') <= maxBytes) {
|
|
27
|
-
return content;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const truncatedLines = lines.slice(0, maxLines);
|
|
31
|
-
let result = truncatedLines.join('\n');
|
|
32
|
-
|
|
33
|
-
if (Buffer.byteLength(result, 'utf-8') > maxBytes) {
|
|
34
|
-
let byteCount = 0;
|
|
35
|
-
const charArray: string[] = [];
|
|
36
|
-
|
|
37
|
-
for (const char of result) {
|
|
38
|
-
byteCount += Buffer.byteLength(char, 'utf-8');
|
|
39
|
-
if (byteCount > maxBytes) break;
|
|
40
|
-
charArray.push(char);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
result = charArray.join('');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return result;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function execCommand(
|
|
50
|
-
command: string,
|
|
51
|
-
args: string[],
|
|
52
|
-
): Promise<{ stdout: string; stderr: string; exitCode: number | null; wasTruncated: boolean }> {
|
|
53
|
-
return new Promise((resolve, reject) => {
|
|
54
|
-
const child = spawn(command, args);
|
|
55
|
-
let stdout = '';
|
|
56
|
-
let stderr = '';
|
|
57
|
-
let wasTruncated = false;
|
|
58
|
-
|
|
59
|
-
child.stdout?.on('data', (data) => {
|
|
60
|
-
// Check if adding this chunk would exceed stream limit
|
|
61
|
-
const chunk = data.toString();
|
|
62
|
-
if (stdout.length + chunk.length > STREAM_MAX_BYTES) {
|
|
63
|
-
// Stop collecting data to prevent RangeError
|
|
64
|
-
wasTruncated = true;
|
|
65
|
-
child.kill();
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
stdout += chunk;
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
child.stderr?.on('data', (data) => {
|
|
72
|
-
stderr += data.toString();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
child.on('close', (code) => {
|
|
76
|
-
resolve({ stdout, stderr, exitCode: code, wasTruncated });
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
child.on('error', (error) => {
|
|
80
|
-
reject(error);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function resolveWorkspacePath(input: string): string {
|
|
86
|
-
const root = process.cwd();
|
|
87
|
-
const resolved = nodePath.resolve(root, input);
|
|
88
|
-
if (resolved !== root && !resolved.startsWith(root + nodePath.sep)) {
|
|
89
|
-
throw new Error(`Path outside workspace: ${input}`);
|
|
90
|
-
}
|
|
91
|
-
return resolved;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function sanitizeInput(input: string): string[] {
|
|
95
|
-
// Simple sanitization: split on whitespace, preserve quoted strings
|
|
96
|
-
const result: string[] = [];
|
|
97
|
-
let current = '';
|
|
98
|
-
let inQuotes = false;
|
|
99
|
-
|
|
100
|
-
for (const char of input) {
|
|
101
|
-
if (char === '"' || char === "'") {
|
|
102
|
-
inQuotes = !inQuotes;
|
|
103
|
-
} else if (char === ' ' && !inQuotes) {
|
|
104
|
-
if (current) {
|
|
105
|
-
result.push(current);
|
|
106
|
-
current = '';
|
|
107
|
-
}
|
|
108
|
-
} else {
|
|
109
|
-
current += char;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (current) {
|
|
114
|
-
result.push(current);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function normalizeSearchOutput(output: string): string {
|
|
121
|
-
return process.platform === 'win32' ? output.replace(/\\/g, '/') : output;
|
|
122
|
-
}
|
|
12
|
+
import { MAX_GREP_CALLS } from '../constants.ts';
|
|
123
13
|
|
|
124
14
|
export function createGrepTool(options: {
|
|
125
15
|
tracker: ToolUsageTracker;
|
|
16
|
+
cwd?: string;
|
|
126
17
|
}): ToolDefinition {
|
|
18
|
+
const cwd = options.cwd ?? process.cwd();
|
|
19
|
+
const sdkGrep = createGrepToolDefinition(cwd);
|
|
20
|
+
const { execute: sdkExecute } = sdkGrep;
|
|
21
|
+
|
|
127
22
|
return {
|
|
128
|
-
|
|
23
|
+
...sdkGrep,
|
|
129
24
|
label: 'Code Search',
|
|
130
|
-
description: 'Search codebase using ripgrep (rg) or grep fallback. Fast recursive text search.',
|
|
131
|
-
promptSnippet: 'Search codebase using ripgrep/grep',
|
|
132
25
|
promptGuidelines: [
|
|
133
|
-
'
|
|
134
|
-
'Pattern supports regex.
|
|
135
|
-
'
|
|
136
|
-
|
|
26
|
+
'Available for fast recursive text search in codebases.',
|
|
27
|
+
'Pattern supports regex. Use glob to scope to file types (e.g., "**/*.ts").',
|
|
28
|
+
'Options: ignoreCase, literal (disable regex), context (lines around match), limit (max matches).',
|
|
29
|
+
`Local code search — it does NOT consume your web-gathering budget (limit: ${MAX_GREP_CALLS} calls).`,
|
|
137
30
|
],
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
_toolCallId: string,
|
|
145
|
-
params: unknown,
|
|
146
|
-
_signal: unknown,
|
|
147
|
-
_onUpdate: unknown,
|
|
148
|
-
_ctx: ExtensionContext,
|
|
149
|
-
): Promise<AgentToolResult<unknown>> {
|
|
150
|
-
// Record call in tracker - returns false if limit reached
|
|
151
|
-
const allowed = options.tracker.recordCall('grep');
|
|
152
|
-
if (!allowed) {
|
|
153
|
-
// THROW to prevent researcher from calling again
|
|
154
|
-
throw new Error(options.tracker.getLimitMessage('grep'));
|
|
31
|
+
execute: async (toolCallId, params, signal, onUpdate, ctx) => {
|
|
32
|
+
if (!Value.Check(sdkGrep.parameters, params)) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: 'Invalid parameters for grep tool.' }],
|
|
35
|
+
details: { error: 'invalid_parameters' },
|
|
36
|
+
};
|
|
155
37
|
}
|
|
156
38
|
|
|
157
|
-
|
|
158
|
-
const { pattern } = record;
|
|
159
|
-
const path = resolveWorkspacePath(record.path ?? '.');
|
|
160
|
-
const flags = record.flags ?? '';
|
|
161
|
-
|
|
162
|
-
if (!pattern) {
|
|
39
|
+
if (!options.tracker.recordCall('grep')) {
|
|
163
40
|
return {
|
|
164
|
-
content: [{ type: 'text', text: '
|
|
165
|
-
details: {},
|
|
41
|
+
content: [{ type: 'text', text: options.tracker.getLimitMessage('grep') }],
|
|
42
|
+
details: { blocked: true, reason: 'limit_reached' },
|
|
166
43
|
};
|
|
167
44
|
}
|
|
168
45
|
|
|
169
|
-
// Sanitize inputs to prevent shell injection
|
|
170
|
-
const flagParts = flags ? sanitizeInput(flags) : [];
|
|
171
|
-
|
|
172
|
-
// Try rg first
|
|
173
46
|
try {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const truncated = truncateHead(normalizeSearchOutput(stdout), DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES);
|
|
178
|
-
|
|
179
|
-
let markdown = '# Search Results (rg)\n\n';
|
|
180
|
-
markdown += `**Pattern:** \`${pattern}\`\n`;
|
|
181
|
-
markdown += `**Path:** \`${path}\`\n`;
|
|
182
|
-
if (flags) markdown += `**Flags:** \`${flags}\`\n`;
|
|
183
|
-
markdown += `**Exit Code:** ${exitCode}\n\n`;
|
|
184
|
-
|
|
185
|
-
if (wasTruncated) {
|
|
186
|
-
markdown += '⚠️ **Output was truncated to prevent memory overflow (>10MB)**\n\n';
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (truncated) {
|
|
190
|
-
markdown += '```\n' + truncated + '\n```';
|
|
191
|
-
} else {
|
|
192
|
-
markdown += 'No matches found.';
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (stderr) {
|
|
196
|
-
markdown += '\n\n**Stderr:**\n```\n' + stderr + '\n```';
|
|
197
|
-
}
|
|
198
|
-
|
|
47
|
+
return await sdkExecute(toolCallId, params as any, signal, onUpdate, ctx);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
199
50
|
return {
|
|
200
|
-
content: [{ type: 'text', text:
|
|
201
|
-
details: {
|
|
202
|
-
command: 'rg',
|
|
203
|
-
args: rgArgs,
|
|
204
|
-
exitCode,
|
|
205
|
-
wasTruncated,
|
|
206
|
-
},
|
|
51
|
+
content: [{ type: 'text', text: `Error: ${msg}` }],
|
|
52
|
+
details: { error: 'execution_error', message: msg },
|
|
207
53
|
};
|
|
208
|
-
} catch (rgError) {
|
|
209
|
-
// rg not found, try grep
|
|
210
|
-
try {
|
|
211
|
-
const grepArgs = ['-rn', ...flagParts, pattern, path];
|
|
212
|
-
const { stdout, stderr, exitCode, wasTruncated } = await execCommand('grep', grepArgs);
|
|
213
|
-
|
|
214
|
-
const truncated = truncateHead(normalizeSearchOutput(stdout), DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES);
|
|
215
|
-
|
|
216
|
-
let markdown = '# Search Results (grep)\n\n';
|
|
217
|
-
markdown += `**Pattern:** \`${pattern}\`\n`;
|
|
218
|
-
markdown += `**Path:** \`${path}\`\n`;
|
|
219
|
-
if (flags) markdown += `**Flags:** \`${flags}\`\n`;
|
|
220
|
-
markdown += `**Exit Code:** ${exitCode}\n\n`;
|
|
221
|
-
markdown += '*Note: Using grep fallback (rg not available)*\n\n';
|
|
222
|
-
|
|
223
|
-
if (wasTruncated) {
|
|
224
|
-
markdown += '⚠️ **Output was truncated to prevent memory overflow (>10MB)**\n\n';
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (truncated) {
|
|
228
|
-
markdown += '```\n' + truncated + '\n```';
|
|
229
|
-
} else {
|
|
230
|
-
markdown += 'No matches found.';
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (stderr) {
|
|
234
|
-
markdown += '\n\n**Stderr:**\n```\n' + stderr + '\n```';
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return {
|
|
238
|
-
content: [{ type: 'text', text: markdown }],
|
|
239
|
-
details: {
|
|
240
|
-
command: 'grep',
|
|
241
|
-
args: grepArgs,
|
|
242
|
-
exitCode,
|
|
243
|
-
wasTruncated,
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
} catch (grepError) {
|
|
247
|
-
return {
|
|
248
|
-
content: [
|
|
249
|
-
{
|
|
250
|
-
type: 'text',
|
|
251
|
-
text: `Error: Neither rg nor grep is available.\n\nrg error: ${rgError}\ngrep error: ${grepError}`,
|
|
252
|
-
},
|
|
253
|
-
],
|
|
254
|
-
details: {},
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
54
|
}
|
|
258
55
|
},
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Standalone function to execute rg/grep search
|
|
264
|
-
*/
|
|
265
|
-
export async function grep(pattern: string, path: string = '.', flags: string = ''): Promise<string> {
|
|
266
|
-
if (!pattern) {
|
|
267
|
-
throw new Error('Pattern is required');
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const resolvedPath = resolveWorkspacePath(path);
|
|
271
|
-
const flagParts = flags ? sanitizeInput(flags) : [];
|
|
272
|
-
|
|
273
|
-
// Try rg first
|
|
274
|
-
try {
|
|
275
|
-
const rgArgs = ['--no-heading', '-n', ...flagParts, pattern, resolvedPath];
|
|
276
|
-
const { stdout, stderr, exitCode, wasTruncated } = await execCommand('rg', rgArgs);
|
|
277
|
-
|
|
278
|
-
let markdown = '# Search Results (rg)\n\n';
|
|
279
|
-
markdown += `**Pattern:** \`${pattern}\`\n`;
|
|
280
|
-
markdown += `**Path:** \`${resolvedPath}\`\n`;
|
|
281
|
-
if (flags) markdown += `**Flags:** \`${flags}\`\n`;
|
|
282
|
-
markdown += `**Exit Code:** ${exitCode}\n\n`;
|
|
283
|
-
|
|
284
|
-
const truncated = truncateHead(normalizeSearchOutput(stdout), DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES);
|
|
285
|
-
|
|
286
|
-
if (wasTruncated) {
|
|
287
|
-
markdown += '⚠️ **Output was truncated to prevent memory overflow (>10MB)**\n\n';
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (truncated) {
|
|
291
|
-
markdown += '```\n' + truncated + '\n```';
|
|
292
|
-
} else {
|
|
293
|
-
markdown += 'No matches found.';
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (stderr) {
|
|
297
|
-
markdown += '\n\n**Stderr:**\n```\n' + stderr + '\n```';
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return markdown;
|
|
301
|
-
} catch (rgError) {
|
|
302
|
-
// rg not found, try grep
|
|
303
|
-
try {
|
|
304
|
-
const grepArgs = ['-rn', ...flagParts, pattern, resolvedPath];
|
|
305
|
-
const { stdout, stderr, exitCode, wasTruncated } = await execCommand('grep', grepArgs);
|
|
306
|
-
|
|
307
|
-
let markdown = '# Search Results (grep)\n\n';
|
|
308
|
-
markdown += `**Pattern:** \`${pattern}\`\n`;
|
|
309
|
-
markdown += `**Path:** \`${resolvedPath}\`\n`;
|
|
310
|
-
if (flags) markdown += `**Flags:** \`${flags}\`\n`;
|
|
311
|
-
markdown += `**Exit Code:** ${exitCode}\n\n`;
|
|
312
|
-
markdown += '*Note: Using grep fallback (rg not available)*\n\n';
|
|
313
|
-
|
|
314
|
-
const truncated = truncateHead(normalizeSearchOutput(stdout), DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES);
|
|
315
|
-
|
|
316
|
-
if (wasTruncated) {
|
|
317
|
-
markdown += '⚠️ **Output was truncated to prevent memory overflow (>10MB)**\n\n';
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (truncated) {
|
|
321
|
-
markdown += '```\n' + truncated + '\n```';
|
|
322
|
-
} else {
|
|
323
|
-
markdown += 'No matches found.';
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (stderr) {
|
|
327
|
-
markdown += '\n\n**Stderr:**\n```\n' + stderr + '\n```';
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
return markdown;
|
|
331
|
-
} catch (grepError) {
|
|
332
|
-
return `Error: Neither rg nor grep is available.\n\nrg error: ${rgError}\ngrep error: ${grepError}`;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
56
|
+
} as ToolDefinition;
|
|
335
57
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Tool Definition
|
|
3
|
+
*
|
|
4
|
+
* Provides health check functionality for the research system:
|
|
5
|
+
* - Check system health status across all components (browser pool, knowledge store, GPU lock)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
ToolDefinition,
|
|
10
|
+
AgentToolResult,
|
|
11
|
+
ExtensionContext,
|
|
12
|
+
} from '@earendil-works/pi-coding-agent';
|
|
13
|
+
import { Type, type Static } from 'typebox';
|
|
14
|
+
import { healthRegistry } from '../healthcheck/index.ts';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create the health check tool definition
|
|
18
|
+
*/
|
|
19
|
+
export function createHealthTool(): ToolDefinition {
|
|
20
|
+
const parameters = Type.Object({
|
|
21
|
+
verbose: Type.Optional(Type.Boolean({
|
|
22
|
+
description: 'Show detailed diagnostic information.',
|
|
23
|
+
default: true,
|
|
24
|
+
})),
|
|
25
|
+
probe: Type.Optional(Type.Boolean({
|
|
26
|
+
description: 'Force liveness checks (browser/GPU models).',
|
|
27
|
+
default: false,
|
|
28
|
+
})),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
type HealthParams = Static<typeof parameters>;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
name: 'health',
|
|
35
|
+
label: 'Health Check',
|
|
36
|
+
description: 'Verify system status (browser pool, knowledge store, GPU lock).',
|
|
37
|
+
promptSnippet: 'Run system health checks',
|
|
38
|
+
parameters,
|
|
39
|
+
renderShell: 'self',
|
|
40
|
+
executionMode: 'parallel',
|
|
41
|
+
async execute(
|
|
42
|
+
_toolCallId: string,
|
|
43
|
+
params: unknown,
|
|
44
|
+
_signal: AbortSignal | undefined,
|
|
45
|
+
_onUpdate: unknown,
|
|
46
|
+
_ctx: ExtensionContext,
|
|
47
|
+
): Promise<AgentToolResult<unknown>> {
|
|
48
|
+
const { verbose = true, probe = false } = params as HealthParams;
|
|
49
|
+
|
|
50
|
+
const outputLines: string[] = [];
|
|
51
|
+
|
|
52
|
+
// Run health checks
|
|
53
|
+
try {
|
|
54
|
+
const systemHealth = await healthRegistry.runAll({ force: probe });
|
|
55
|
+
|
|
56
|
+
outputLines.push('## System Health Status');
|
|
57
|
+
outputLines.push('');
|
|
58
|
+
|
|
59
|
+
const statusIcon = systemHealth.status === 'healthy' ? '[OK]' :
|
|
60
|
+
systemHealth.status === 'degraded' ? '[WARN]' : '[ERROR]';
|
|
61
|
+
const statusText = systemHealth.status === 'healthy' ? 'All systems operational' :
|
|
62
|
+
systemHealth.status === 'degraded' ? 'System degraded (non-critical issues)' :
|
|
63
|
+
'System unhealthy (critical failures)';
|
|
64
|
+
|
|
65
|
+
outputLines.push(`**${statusIcon} ${statusText}**`);
|
|
66
|
+
outputLines.push('');
|
|
67
|
+
|
|
68
|
+
for (const component of systemHealth.components) {
|
|
69
|
+
const icon = component.healthy ? '[OK]' : '[FAIL]';
|
|
70
|
+
const criticalMark = healthRegistry.isCritical(component.component) ? ' [CRITICAL]' : '';
|
|
71
|
+
outputLines.push(`${icon} **${component.component}**${criticalMark}`);
|
|
72
|
+
|
|
73
|
+
if (component.error) {
|
|
74
|
+
outputLines.push(` - Error: ${component.error}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (verbose && component.diagnostic) {
|
|
78
|
+
const diagnostics = Object.entries(component.diagnostic)
|
|
79
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
80
|
+
.join(', ');
|
|
81
|
+
if (diagnostics) {
|
|
82
|
+
outputLines.push(` - Diagnostic: ${diagnostics}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (verbose) {
|
|
87
|
+
outputLines.push(` - Duration: ${component.durationMs.toFixed(1)}ms`);
|
|
88
|
+
}
|
|
89
|
+
outputLines.push('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
outputLines.push(`Checked at: ${new Date(systemHealth.timestamp).toLocaleString()}`);
|
|
93
|
+
|
|
94
|
+
return { content: [{ type: 'text', text: outputLines.join('\n') }], details: { health: systemHealth } };
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
97
|
+
return { content: [{ type: 'text', text: `**Health check failed**\n\n${message}` }], details: { error: message } };
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
package/src/tools/index.ts
CHANGED
|
@@ -1,39 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool Factory
|
|
3
3
|
*
|
|
4
|
-
* Creates all research tools with properly configured
|
|
4
|
+
* Creates all research tools with properly configured browser manager.
|
|
5
5
|
* These tools are used by both direct tool calls and researcher agents.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: `research_knowledge_search` is NOT included here. It is a top-level tool
|
|
8
|
+
* registered via pi.registerTool() in src/index.ts. Researcher sub-agents
|
|
9
|
+
* already receive knowledge store data via the store_section prompt injection.
|
|
6
10
|
*/
|
|
7
11
|
|
|
8
|
-
import type { ToolDefinition, ExtensionContext } from '@
|
|
12
|
+
import type { ToolDefinition, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
9
13
|
import type { ToolUsageTracker } from '../utils/tool-usage-tracker.ts';
|
|
10
14
|
import type { SystemResearchState } from '../orchestration/deep-research-types.ts';
|
|
15
|
+
import { createReadToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
11
16
|
import { createSearchTool } from './search.ts';
|
|
12
17
|
import { createScrapeTool } from './scrape.ts';
|
|
13
18
|
import { createSecuritySearchTool } from './security.ts';
|
|
14
19
|
import { createStackexchangeTool } from './stackexchange.ts';
|
|
15
20
|
import { createGrepTool } from './grep.ts';
|
|
21
|
+
import { createYoutubeTranscriptTool } from './youtube-transcript.ts';
|
|
22
|
+
import type { Config } from '../config.ts';
|
|
16
23
|
|
|
17
24
|
interface CreateToolsOptions {
|
|
18
|
-
|
|
25
|
+
cwd: string;
|
|
19
26
|
ctx: ExtensionContext;
|
|
20
27
|
tracker: ToolUsageTracker;
|
|
21
28
|
getGlobalState?: () => SystemResearchState;
|
|
22
29
|
updateGlobalLinks?: (links: string[]) => void;
|
|
23
|
-
/**
|
|
30
|
+
/** Optional researcher ID for per-researcher scrape tracking. */
|
|
31
|
+
researcherId?: string;
|
|
32
|
+
/** Callback invoked during search with cumulative link count found so far */
|
|
33
|
+
onSearchProgress?: (links: number) => void;
|
|
34
|
+
/** Fires for each individual URL as it completes (success or failure). Used for per-URL TUI flash. */
|
|
35
|
+
onUrlScrapeResult?: (url: string, success: boolean) => void;
|
|
36
|
+
/** Returns total tokens used so far in this researcher's session (for context gating). */
|
|
24
37
|
getTokensUsed?: () => number;
|
|
25
|
-
/**
|
|
38
|
+
/** Context window size in tokens. */
|
|
26
39
|
contextWindowSize?: number;
|
|
40
|
+
config?: Config;
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
/**
|
|
30
|
-
* Create all research tools
|
|
44
|
+
* Create all research tools for researcher sub-agents.
|
|
31
45
|
*/
|
|
32
46
|
export function createResearchTools(options: CreateToolsOptions): ToolDefinition[] {
|
|
33
47
|
// Create a fresh fallback state per tool instance to avoid state leakage between research runs
|
|
34
|
-
// This is only used when getGlobalState is not provided (e.g., quick mode with single researcher)
|
|
35
48
|
const createFallbackState = (): SystemResearchState => ({
|
|
36
49
|
version: 1,
|
|
50
|
+
researchId: 'fallback',
|
|
37
51
|
rootQuery: '',
|
|
38
52
|
complexity: 1,
|
|
39
53
|
currentRound: 1,
|
|
@@ -55,15 +69,29 @@ export function createResearchTools(options: CreateToolsOptions): ToolDefinition
|
|
|
55
69
|
};
|
|
56
70
|
|
|
57
71
|
return [
|
|
58
|
-
|
|
72
|
+
createReadToolDefinition(options.cwd) as ToolDefinition,
|
|
73
|
+
createSearchTool({
|
|
74
|
+
...resolvedOptions,
|
|
75
|
+
onProgress: options.onSearchProgress,
|
|
76
|
+
}),
|
|
59
77
|
createScrapeTool({
|
|
60
78
|
...resolvedOptions,
|
|
79
|
+
onUrlScrapeResult: options.onUrlScrapeResult,
|
|
61
80
|
getTokensUsed: options.getTokensUsed,
|
|
62
81
|
contextWindowSize: options.contextWindowSize,
|
|
63
82
|
}),
|
|
64
83
|
createSecuritySearchTool(resolvedOptions),
|
|
65
84
|
createStackexchangeTool(resolvedOptions),
|
|
66
|
-
createGrepTool(resolvedOptions),
|
|
85
|
+
createGrepTool({ tracker: resolvedOptions.tracker, cwd: resolvedOptions.cwd }),
|
|
86
|
+
createYoutubeTranscriptTool({
|
|
87
|
+
ctx: resolvedOptions.ctx,
|
|
88
|
+
tracker: resolvedOptions.tracker,
|
|
89
|
+
onUrlScrapeResult: options.onUrlScrapeResult,
|
|
90
|
+
getGlobalState: resolvedOptions.getGlobalState,
|
|
91
|
+
updateGlobalLinks: resolvedOptions.updateGlobalLinks,
|
|
92
|
+
researcherId: resolvedOptions.researcherId,
|
|
93
|
+
config: resolvedOptions.config,
|
|
94
|
+
}),
|
|
67
95
|
];
|
|
68
96
|
}
|
|
69
97
|
|
|
@@ -75,3 +103,4 @@ export { createScrapeTool } from './scrape.ts';
|
|
|
75
103
|
export { createSecuritySearchTool } from './security.ts';
|
|
76
104
|
export { createStackexchangeTool } from './stackexchange.ts';
|
|
77
105
|
export { createGrepTool } from './grep.ts';
|
|
106
|
+
export { createYoutubeTranscriptTool } from './youtube-transcript.ts';
|