@mjasnikovs/pi-task 0.13.5 → 0.13.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/remote/bridge.js +5 -4
- package/dist/remote/broadcast.d.ts +0 -1
- package/dist/remote/broadcast.js +0 -7
- package/dist/remote/events.js +5 -5
- package/dist/remote/push.d.ts +12 -3
- package/dist/remote/push.js +63 -9
- package/dist/remote/server.js +0 -16
- package/dist/remote/ui-script.d.ts +3 -0
- package/dist/remote/ui-script.js +804 -0
- package/dist/remote/ui-styles.d.ts +1 -0
- package/dist/remote/ui-styles.js +202 -0
- package/dist/remote/ui.js +4 -1000
- package/dist/shared/child-process.d.ts +27 -0
- package/dist/shared/child-process.js +151 -139
- package/dist/task/auto-orchestrator.js +3 -6
- package/dist/task/child-runner.js +1 -1
- package/dist/task/context-usage.d.ts +16 -0
- package/dist/task/context-usage.js +22 -0
- package/dist/task/external-context.d.ts +27 -0
- package/dist/task/external-context.js +93 -0
- package/dist/task/failure-classifier.js +1 -1
- package/dist/task/orchestrator.js +7 -13
- package/dist/task/parsers.d.ts +1 -15
- package/dist/task/parsers.js +17 -84
- package/dist/task/phases.d.ts +5 -7
- package/dist/task/phases.js +40 -84
- package/dist/task/prompts.d.ts +1 -0
- package/dist/task/prompts.js +9 -0
- package/dist/task/spec-validation.d.ts +23 -0
- package/dist/task/spec-validation.js +90 -0
- package/dist/task/widget.d.ts +1 -1
- package/dist/task/widget.js +1 -1
- package/dist/workers/pi-worker-docs.js +69 -58
- package/dist/workers/pi-worker-fetch.js +25 -21
- package/dist/workers/pi-worker-search.js +7 -13
- package/dist/workers/pi-worker.js +8 -14
- package/dist/workers/shared.d.ts +40 -0
- package/dist/workers/shared.js +31 -0
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ import { formatNpmVersionSection } from './npm-version.js';
|
|
|
7
7
|
import { runChild, CHILD_BASE_ARGS } from '../shared/child-process.js';
|
|
8
8
|
import { parseChildOutput, isExcerptInContent } from '../shared/child-output.js';
|
|
9
9
|
import { getPiInvocation } from '../shared/pi-invocation.js';
|
|
10
|
-
import {
|
|
10
|
+
import { formatChildFailure, makeWorkerTool } from './shared.js';
|
|
11
11
|
import { projectDocsRaw, buildProjectPrompt } from './docs-project.js';
|
|
12
12
|
const CHILD_ARGS = [...CHILD_BASE_ARGS, '--no-tools'];
|
|
13
13
|
const RENDER_QUERY_MAX = 100;
|
|
@@ -20,7 +20,7 @@ const Params = Type.Object({
|
|
|
20
20
|
})
|
|
21
21
|
});
|
|
22
22
|
export function registerPiWorkerDocs(pi, internals = {}) {
|
|
23
|
-
pi
|
|
23
|
+
makeWorkerTool(pi, {
|
|
24
24
|
name: 'pi-worker-docs',
|
|
25
25
|
label: 'Pi Worker Docs',
|
|
26
26
|
description: 'Look up an INSTALLED npm package and return a focused, version-pinned '
|
|
@@ -56,8 +56,7 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
56
56
|
+ 'Skip when:\n'
|
|
57
57
|
+ '- You need docs for a specific newer version than what is installed — use pi-worker-fetch on the upstream docs site',
|
|
58
58
|
parameters: Params,
|
|
59
|
-
|
|
60
|
-
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
59
|
+
async run(params, signal, ctx) {
|
|
61
60
|
const spawn = internals.spawn
|
|
62
61
|
?? (globalThis.Bun !== undefined ?
|
|
63
62
|
globalThis.Bun.spawn
|
|
@@ -74,18 +73,24 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
74
73
|
cacheError = err instanceof Error ? err.message : String(err);
|
|
75
74
|
}
|
|
76
75
|
if (!cache) {
|
|
77
|
-
return
|
|
76
|
+
return {
|
|
77
|
+
text: `Project docs unavailable: cache open failed (${cacheError}).`,
|
|
78
|
+
details: {}
|
|
79
|
+
};
|
|
78
80
|
}
|
|
79
81
|
const retrieveChunks = internals.retrieveChunks ?? defaultRetrieveChunks;
|
|
80
82
|
const projectResult = projectDocsRaw(cache, ctx.cwd, params.query, retrieveChunks);
|
|
81
83
|
if (projectResult.kind === 'error') {
|
|
82
|
-
return
|
|
84
|
+
return { text: `Project docs error: ${projectResult.message}`, details: {} };
|
|
83
85
|
}
|
|
84
86
|
if (projectResult.kind === 'no_chunks') {
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
return {
|
|
88
|
+
text: `Project "${projectResult.projectName}" has no .ts/.tsx files indexed.`,
|
|
89
|
+
details: {
|
|
90
|
+
hitCache: projectResult.hitCache,
|
|
91
|
+
indexedFiles: projectResult.filesIngested
|
|
92
|
+
}
|
|
93
|
+
};
|
|
89
94
|
}
|
|
90
95
|
const { projectName, chunks, hitCache, filesIngested, indexingMs } = projectResult;
|
|
91
96
|
const baseDetails = {
|
|
@@ -98,19 +103,16 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
98
103
|
const prompt = buildProjectPrompt(projectName, params.query, concatenated);
|
|
99
104
|
const invocation = getPiInvocation([...CHILD_ARGS, prompt]);
|
|
100
105
|
const child = await runChild(spawn, invocation, ctx.cwd, signal);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
...baseDetails,
|
|
112
|
-
childExitCode: child.exitCode
|
|
113
|
-
});
|
|
106
|
+
const failure = formatChildFailure(child, 'Project docs lookup aborted.');
|
|
107
|
+
if (failure !== null) {
|
|
108
|
+
return {
|
|
109
|
+
text: failure,
|
|
110
|
+
details: {
|
|
111
|
+
...baseDetails,
|
|
112
|
+
...(child.aborted ? { aborted: true } : {}),
|
|
113
|
+
childExitCode: child.exitCode
|
|
114
|
+
}
|
|
115
|
+
};
|
|
114
116
|
}
|
|
115
117
|
const parsed = parseChildOutput(child.stdout);
|
|
116
118
|
const verified = parsed.excerpt ? isExcerptInContent(parsed.excerpt, concatenated) : undefined;
|
|
@@ -121,11 +123,14 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
121
123
|
entryDts: null,
|
|
122
124
|
readme: null
|
|
123
125
|
}, parsed, verified);
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
return {
|
|
127
|
+
text,
|
|
128
|
+
details: {
|
|
129
|
+
...baseDetails,
|
|
130
|
+
childExitCode: 0,
|
|
131
|
+
excerptVerified: verified
|
|
132
|
+
}
|
|
133
|
+
};
|
|
129
134
|
}
|
|
130
135
|
// ── npm package lookup (existing path) ──────────────────────────
|
|
131
136
|
const rawResult = await docsRaw({
|
|
@@ -157,22 +162,28 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
157
162
|
autoInstalled: rawResult.autoInstalled,
|
|
158
163
|
...npmDetails
|
|
159
164
|
};
|
|
160
|
-
return
|
|
165
|
+
return { text: npmHeader + rawResult.message, details };
|
|
161
166
|
}
|
|
162
167
|
if (rawResult.kind === 'not_installed') {
|
|
163
|
-
return
|
|
164
|
-
|
|
168
|
+
return {
|
|
169
|
+
text: npmHeader
|
|
170
|
+
+ `Package "${rawResult.pkg}" is not installed and auto-install failed.`,
|
|
171
|
+
details: { resolveError: 'not_installed', ...npmDetails }
|
|
172
|
+
};
|
|
165
173
|
}
|
|
166
174
|
if (rawResult.kind === 'no_chunks') {
|
|
167
|
-
return
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
return {
|
|
176
|
+
text: npmHeader
|
|
177
|
+
+ `Package ${rawResult.pkg.name}@${rawResult.pkg.version} has no .d.ts files or README. Use pi-worker to read source directly.`,
|
|
178
|
+
details: {
|
|
179
|
+
version: rawResult.pkg.version,
|
|
180
|
+
hitCache: rawResult.hitCache,
|
|
181
|
+
indexedFiles: rawResult.indexedFiles ?? 0,
|
|
182
|
+
cacheError: rawResult.cacheError,
|
|
183
|
+
autoInstalled: rawResult.autoInstalled,
|
|
184
|
+
...npmDetails
|
|
185
|
+
}
|
|
186
|
+
};
|
|
176
187
|
}
|
|
177
188
|
// kind === 'ok'
|
|
178
189
|
const { pkg, chunks, hitCache, indexingMs, cacheError, autoInstalled } = rawResult;
|
|
@@ -189,28 +200,28 @@ export function registerPiWorkerDocs(pi, internals = {}) {
|
|
|
189
200
|
const prompt = buildPrompt(pkg, params.query, concatenated);
|
|
190
201
|
const invocation = getPiInvocation([...CHILD_ARGS, prompt]);
|
|
191
202
|
const child = await runChild(spawn, invocation, ctx.cwd, signal);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
...baseDetails,
|
|
203
|
-
childExitCode: child.exitCode
|
|
204
|
-
});
|
|
203
|
+
const failure = formatChildFailure(child, 'Docs lookup aborted.');
|
|
204
|
+
if (failure !== null) {
|
|
205
|
+
return {
|
|
206
|
+
text: npmHeader + failure,
|
|
207
|
+
details: {
|
|
208
|
+
...baseDetails,
|
|
209
|
+
...(child.aborted ? { aborted: true } : {}),
|
|
210
|
+
childExitCode: child.exitCode
|
|
211
|
+
}
|
|
212
|
+
};
|
|
205
213
|
}
|
|
206
214
|
const parsed = parseChildOutput(child.stdout);
|
|
207
215
|
const verified = parsed.excerpt ? isExcerptInContent(parsed.excerpt, concatenated) : undefined;
|
|
208
216
|
const text = npmHeader + formatResultText(pkg, parsed, verified);
|
|
209
|
-
return
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
217
|
+
return {
|
|
218
|
+
text,
|
|
219
|
+
details: {
|
|
220
|
+
...baseDetails,
|
|
221
|
+
childExitCode: 0,
|
|
222
|
+
excerptVerified: verified
|
|
223
|
+
}
|
|
224
|
+
};
|
|
214
225
|
},
|
|
215
226
|
renderCall(args, theme) {
|
|
216
227
|
const query = args.query.replace(/\s+/g, ' ').trim();
|
|
@@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
2
2
|
import { Text } from '@earendil-works/pi-tui';
|
|
3
3
|
import { FetchAndCleanError } from './html-clean.js';
|
|
4
4
|
import { fetchFocused, formatResultText } from './fetch-core.js';
|
|
5
|
-
import {
|
|
5
|
+
import { formatChildFailure, makeWorkerTool } from './shared.js';
|
|
6
6
|
const RENDER_QUERY_MAX = 100;
|
|
7
7
|
const Params = Type.Object({
|
|
8
8
|
url: Type.String({ description: 'URL to fetch. Must be http or https.' }),
|
|
@@ -11,7 +11,7 @@ const Params = Type.Object({
|
|
|
11
11
|
})
|
|
12
12
|
});
|
|
13
13
|
export function registerPiWorkerFetch(pi, internals = {}) {
|
|
14
|
-
pi
|
|
14
|
+
makeWorkerTool(pi, {
|
|
15
15
|
name: 'pi-worker-fetch',
|
|
16
16
|
label: 'Pi Worker Fetch',
|
|
17
17
|
description: 'Fetch a web page or text resource (HTML, markdown, plain text, JSON, '
|
|
@@ -20,13 +20,12 @@ export function registerPiWorkerFetch(pi, internals = {}) {
|
|
|
20
20
|
+ 'focused answer. Use after `pi-worker-search` (or with a known URL) to '
|
|
21
21
|
+ 'avoid stuffing raw content into the main context.',
|
|
22
22
|
parameters: Params,
|
|
23
|
-
|
|
24
|
-
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
23
|
+
async run(params, signal, ctx) {
|
|
25
24
|
try {
|
|
26
25
|
new URL(params.url);
|
|
27
26
|
}
|
|
28
27
|
catch {
|
|
29
|
-
return
|
|
28
|
+
return { text: `Invalid URL: ${params.url}`, details: {} };
|
|
30
29
|
}
|
|
31
30
|
try {
|
|
32
31
|
const result = await fetchFocused({
|
|
@@ -37,28 +36,33 @@ export function registerPiWorkerFetch(pi, internals = {}) {
|
|
|
37
36
|
fetchAndClean: internals.fetchAndClean,
|
|
38
37
|
spawn: internals.spawn
|
|
39
38
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
});
|
|
39
|
+
const failure = formatChildFailure({
|
|
40
|
+
aborted: result.aborted,
|
|
41
|
+
exitCode: result.childExitCode,
|
|
42
|
+
stderr: result.stderr
|
|
43
|
+
}, 'Fetch aborted.');
|
|
44
|
+
if (failure !== null) {
|
|
45
|
+
return { text: failure, details: { childExitCode: result.childExitCode } };
|
|
48
46
|
}
|
|
49
47
|
const text = formatResultText({ answer: result.answer, excerpt: result.excerpt }, result.excerptVerified) || '(no output)';
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
return {
|
|
49
|
+
text,
|
|
50
|
+
details: {
|
|
51
|
+
childExitCode: 0,
|
|
52
|
+
answer: result.answer,
|
|
53
|
+
excerpt: result.excerpt,
|
|
54
|
+
excerptVerified: result.excerptVerified
|
|
55
|
+
}
|
|
56
|
+
};
|
|
56
57
|
}
|
|
57
58
|
catch (err) {
|
|
58
59
|
if (err instanceof FetchAndCleanError) {
|
|
59
|
-
return
|
|
60
|
+
return { text: err.message, details: {} };
|
|
60
61
|
}
|
|
61
|
-
return
|
|
62
|
+
return {
|
|
63
|
+
text: `Could not fetch ${params.url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
64
|
+
details: {}
|
|
65
|
+
};
|
|
62
66
|
}
|
|
63
67
|
},
|
|
64
68
|
renderCall(args, theme) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
2
|
import { Text } from '@earendil-works/pi-tui';
|
|
3
3
|
import { search } from './search-core.js';
|
|
4
|
-
import {
|
|
4
|
+
import { makeWorkerTool } from './shared.js';
|
|
5
5
|
const Params = Type.Object({
|
|
6
6
|
query: Type.String({ description: 'Search query.' }),
|
|
7
7
|
count: Type.Optional(Type.Integer({
|
|
@@ -11,7 +11,7 @@ const Params = Type.Object({
|
|
|
11
11
|
}))
|
|
12
12
|
});
|
|
13
13
|
export function registerPiWorkerSearch(pi, internals = {}) {
|
|
14
|
-
pi
|
|
14
|
+
makeWorkerTool(pi, {
|
|
15
15
|
name: 'pi-worker-search',
|
|
16
16
|
label: 'Pi Worker Search',
|
|
17
17
|
description: 'Search the live web via Brave Search. CALL THIS BEFORE ANSWERING any '
|
|
@@ -24,8 +24,7 @@ export function registerPiWorkerSearch(pi, internals = {}) {
|
|
|
24
24
|
+ 'call `pi-worker-fetch` on the URL you want to read. '
|
|
25
25
|
+ 'Requires BRAVE_SEARCH_API_KEY env var.',
|
|
26
26
|
parameters: Params,
|
|
27
|
-
|
|
28
|
-
async execute(_toolCallId, params, signal) {
|
|
27
|
+
async run(params, signal) {
|
|
29
28
|
const result = await search({
|
|
30
29
|
query: params.query,
|
|
31
30
|
count: params.count,
|
|
@@ -33,20 +32,15 @@ export function registerPiWorkerSearch(pi, internals = {}) {
|
|
|
33
32
|
getEnv: internals.getEnv,
|
|
34
33
|
braveSearch: internals.braveSearch
|
|
35
34
|
});
|
|
36
|
-
if (result.kind === 'no_key') {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
if (result.kind === 'error') {
|
|
40
|
-
return textResult(result.message, { resultCount: 0 });
|
|
35
|
+
if (result.kind === 'no_key' || result.kind === 'error') {
|
|
36
|
+
return { text: result.message, details: { resultCount: 0 } };
|
|
41
37
|
}
|
|
42
38
|
const { results } = result;
|
|
43
39
|
if (results.length === 0) {
|
|
44
|
-
return
|
|
45
|
-
resultCount: 0
|
|
46
|
-
});
|
|
40
|
+
return { text: `No results for: ${params.query}`, details: { resultCount: 0 } };
|
|
47
41
|
}
|
|
48
42
|
const lines = results.map((r, i) => `${i + 1}. [${r.title}](${r.url}) — ${r.description}`);
|
|
49
|
-
return
|
|
43
|
+
return { text: lines.join('\n'), details: { resultCount: results.length } };
|
|
50
44
|
},
|
|
51
45
|
renderCall(args, theme) {
|
|
52
46
|
let text = theme.fg('toolTitle', theme.bold('pi-worker-search '));
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
import { Text } from '@earendil-works/pi-tui';
|
|
10
10
|
import { Type } from '@sinclair/typebox';
|
|
11
11
|
import { runWorker } from './pi-worker-core.js';
|
|
12
|
-
import {
|
|
12
|
+
import { formatChildFailure, makeWorkerTool } from './shared.js';
|
|
13
13
|
const RENDER_PROMPT_MAX = 120;
|
|
14
14
|
const WorkerParams = Type.Object({
|
|
15
15
|
prompt: Type.String({ description: 'Task for the worker to perform.' })
|
|
16
16
|
});
|
|
17
17
|
export function registerPiWorker(pi) {
|
|
18
|
-
pi
|
|
18
|
+
makeWorkerTool(pi, {
|
|
19
19
|
name: 'pi-worker',
|
|
20
20
|
label: 'Pi Worker',
|
|
21
21
|
description: 'Dispatch an isolated child Pi to investigate and return its CONCLUSION — '
|
|
@@ -37,19 +37,13 @@ export function registerPiWorker(pi) {
|
|
|
37
37
|
+ '- The task needs writes/edits (worker is read-only)\n'
|
|
38
38
|
+ '- The task needs the web — use `pi-worker-search` / `pi-worker-fetch`',
|
|
39
39
|
parameters: WorkerParams,
|
|
40
|
-
|
|
41
|
-
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
40
|
+
async run(params, signal, ctx) {
|
|
42
41
|
const result = await runWorker({ prompt: params.prompt, cwd: ctx.cwd, signal });
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return textResult(`Worker exited ${result.exitCode}.\n${tail}`, {
|
|
49
|
-
exitCode: result.exitCode
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return textResult(result.text || '(no output)', { exitCode: result.exitCode });
|
|
42
|
+
const details = { exitCode: result.exitCode };
|
|
43
|
+
const failure = formatChildFailure(result, 'Worker aborted.');
|
|
44
|
+
if (failure !== null)
|
|
45
|
+
return { text: failure, details };
|
|
46
|
+
return { text: result.text || '(no output)', details };
|
|
53
47
|
},
|
|
54
48
|
renderCall(args, theme) {
|
|
55
49
|
const prompt = args.prompt.replace(/\s+/g, ' ').trim();
|
package/dist/workers/shared.d.ts
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
import type { Static, TSchema } from '@sinclair/typebox';
|
|
1
2
|
import type { AgentToolResult } from '@earendil-works/pi-agent-core';
|
|
3
|
+
import type { ExtensionAPI, ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';
|
|
4
|
+
import type { Text } from '@earendil-works/pi-tui';
|
|
2
5
|
/** Build a plain-text AgentToolResult. */
|
|
3
6
|
export declare function textResult<T>(text: string, details: T): AgentToolResult<T>;
|
|
7
|
+
/**
|
|
8
|
+
* The slice of a child-process result a worker needs to decide failure.
|
|
9
|
+
* `exitCode` is normalised here — `fetch-core` exposes it as `childExitCode`,
|
|
10
|
+
* the others as `exitCode`; callers map to this single name.
|
|
11
|
+
*/
|
|
12
|
+
export interface ChildOutcome {
|
|
13
|
+
aborted: boolean;
|
|
14
|
+
exitCode: number;
|
|
15
|
+
stderr: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The one place worker child-failure is turned into a user-facing message.
|
|
19
|
+
* Returns `null` when the child succeeded (caller proceeds to format output),
|
|
20
|
+
* otherwise the standard abort/exit message. Concentrating this here keeps the
|
|
21
|
+
* stderr-tail rule identical across every worker — it had already drifted
|
|
22
|
+
* (`pi-worker` skipped the `.trim()` the others applied).
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatChildFailure(child: ChildOutcome, abortedMessage: string): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* What a worker tool is, minus the registration ritual: a name/label/schema,
|
|
27
|
+
* a `run` that produces the focused text + structured details, and a `renderCall`
|
|
28
|
+
* for the TUI. `makeWorkerTool` owns `registerTool`, the parallel execution mode,
|
|
29
|
+
* and wrapping the result in `textResult`.
|
|
30
|
+
*/
|
|
31
|
+
export interface WorkerToolSpec<TParams extends TSchema, TDetails> {
|
|
32
|
+
name: string;
|
|
33
|
+
label: string;
|
|
34
|
+
description: string;
|
|
35
|
+
parameters: TParams;
|
|
36
|
+
run(params: Static<TParams>, signal: AbortSignal | undefined, ctx: ExtensionContext): Promise<{
|
|
37
|
+
text: string;
|
|
38
|
+
details: TDetails;
|
|
39
|
+
}>;
|
|
40
|
+
renderCall(args: Static<TParams>, theme: Theme): Text;
|
|
41
|
+
}
|
|
42
|
+
/** Register a worker tool from its spec, supplying the shared registration ritual. */
|
|
43
|
+
export declare function makeWorkerTool<TParams extends TSchema, TDetails>(pi: ExtensionAPI, spec: WorkerToolSpec<TParams, TDetails>): void;
|
package/dist/workers/shared.js
CHANGED
|
@@ -2,3 +2,34 @@
|
|
|
2
2
|
export function textResult(text, details) {
|
|
3
3
|
return { content: [{ type: 'text', text }], details };
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* The one place worker child-failure is turned into a user-facing message.
|
|
7
|
+
* Returns `null` when the child succeeded (caller proceeds to format output),
|
|
8
|
+
* otherwise the standard abort/exit message. Concentrating this here keeps the
|
|
9
|
+
* stderr-tail rule identical across every worker — it had already drifted
|
|
10
|
+
* (`pi-worker` skipped the `.trim()` the others applied).
|
|
11
|
+
*/
|
|
12
|
+
export function formatChildFailure(child, abortedMessage) {
|
|
13
|
+
if (child.aborted)
|
|
14
|
+
return abortedMessage;
|
|
15
|
+
if (child.exitCode !== 0) {
|
|
16
|
+
const tail = child.stderr.trim().slice(-500) || '(no stderr)';
|
|
17
|
+
return `Worker exited ${child.exitCode}.\n${tail}`;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/** Register a worker tool from its spec, supplying the shared registration ritual. */
|
|
22
|
+
export function makeWorkerTool(pi, spec) {
|
|
23
|
+
pi.registerTool({
|
|
24
|
+
name: spec.name,
|
|
25
|
+
label: spec.label,
|
|
26
|
+
description: spec.description,
|
|
27
|
+
parameters: spec.parameters,
|
|
28
|
+
executionMode: 'parallel',
|
|
29
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
30
|
+
const { text, details } = await spec.run(params, signal, ctx);
|
|
31
|
+
return textResult(text, details);
|
|
32
|
+
},
|
|
33
|
+
renderCall: (args, theme) => spec.renderCall(args, theme)
|
|
34
|
+
});
|
|
35
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.7",
|
|
4
4
|
"description": "Deterministic spec-orchestration for local models, with a bundled real-time remote web view and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|