picocode-core 0.9.170 → 0.9.171
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/package.json +1 -1
- package/src/agent.js +1 -1
- package/src/controller.js +8 -7
- package/src/tools/index.js +2 -7
- package/src/tools/web.js +0 -86
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -143,7 +143,7 @@ export async function runTurn({ history, tools, recorder, modelName, effort, aut
|
|
|
143
143
|
// a tool may legitimately run for minutes (test suites, slow fetches)
|
|
144
144
|
// and emits nothing while it does; the watchdog guards the provider
|
|
145
145
|
// stream, so pause it until the tool finishes. tools carry their own
|
|
146
|
-
// timeouts (bash 120s default
|
|
146
|
+
// timeouts (bash 120s default)
|
|
147
147
|
clearTimeout(watchdog)
|
|
148
148
|
recorder.currentCall = event.call
|
|
149
149
|
onStream?.(event)
|
package/src/controller.js
CHANGED
|
@@ -53,7 +53,7 @@ export const SESSION_COLORS = {
|
|
|
53
53
|
gray: '#9ca3af',
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const WORKER_TOOLS = ['read', 'write', 'edit', 'bash', 'glob', 'grep', 'shell_output', 'shell_kill'
|
|
56
|
+
const WORKER_TOOLS = ['read', 'write', 'edit', 'bash', 'glob', 'grep', 'shell_output', 'shell_kill']
|
|
57
57
|
const AGENT_TOOLS = ['agent_plan', 'agent_start', 'agent_list', 'agent_collect', 'agent_cancel']
|
|
58
58
|
const CONTEXT_COLORS = ['#67b7ff', '#c792ea', '#f7c66a', '#f78c6c', '#6be795']
|
|
59
59
|
|
|
@@ -202,7 +202,9 @@ export function createController({ boot }) {
|
|
|
202
202
|
const sessionId = state.session?.id
|
|
203
203
|
if (!sessionId) throw new Error('worker requires an active session')
|
|
204
204
|
const scratchpad = ensureDir(agentScratchDir(boot.root, sessionId, agent.id))
|
|
205
|
-
const
|
|
205
|
+
const mcpTools = boot.mcp.tools()
|
|
206
|
+
const availableNames = [...WORKER_TOOLS, ...mcpTools.map((tool) => tool.name)]
|
|
207
|
+
const requestedTools = agent.tools?.length ? agent.tools.filter((name) => availableNames.includes(name)) : availableNames
|
|
206
208
|
const { tools, recorder } = createToolset({
|
|
207
209
|
cwd: boot.cwd,
|
|
208
210
|
env: { ...boot.env, PICO_SCRATCHPAD: scratchpad },
|
|
@@ -213,10 +215,10 @@ export function createController({ boot }) {
|
|
|
213
215
|
shells: boot.shells,
|
|
214
216
|
sessionId,
|
|
215
217
|
sessionFile: state.session?.file,
|
|
216
|
-
dredge: boot.dredge,
|
|
217
218
|
signal,
|
|
218
219
|
maxToolCalls: 30,
|
|
219
220
|
allowNames: requestedTools,
|
|
221
|
+
mcpTools,
|
|
220
222
|
})
|
|
221
223
|
return runTurn({
|
|
222
224
|
history: [{ role: 'user', content: agent.prompt }],
|
|
@@ -277,6 +279,7 @@ export function createController({ boot }) {
|
|
|
277
279
|
|
|
278
280
|
const runWorker = async ({ history, role, tools: enabled = true, onStream }) => {
|
|
279
281
|
const scratchpad = ensureDir(agentScratchDir(boot.root, sessionId, `deliberation-${id}-${role}`))
|
|
282
|
+
const mcpTools = enabled ? boot.mcp.tools() : []
|
|
280
283
|
const toolset = createToolset({
|
|
281
284
|
cwd: boot.cwd,
|
|
282
285
|
env: { ...boot.env, PICO_SCRATCHPAD: scratchpad },
|
|
@@ -284,10 +287,10 @@ export function createController({ boot }) {
|
|
|
284
287
|
shells: boot.shells,
|
|
285
288
|
sessionId,
|
|
286
289
|
sessionFile: state.session?.file,
|
|
287
|
-
dredge: boot.dredge,
|
|
288
290
|
signal,
|
|
289
291
|
maxToolCalls: 30,
|
|
290
|
-
allowNames: enabled ? WORKER_TOOLS : [],
|
|
292
|
+
allowNames: enabled ? [...WORKER_TOOLS, ...mcpTools.map((tool) => tool.name)] : [],
|
|
293
|
+
mcpTools,
|
|
291
294
|
})
|
|
292
295
|
return runTurn({
|
|
293
296
|
history,
|
|
@@ -622,7 +625,6 @@ export function createController({ boot }) {
|
|
|
622
625
|
deliberations: boot.deliberationModel || (boot.proposerModel && boot.reviewerModel) ? deliberations : null,
|
|
623
626
|
onAgentsCollected: discardCollectedAgentNotes,
|
|
624
627
|
askUser,
|
|
625
|
-
dredge: boot.dredge,
|
|
626
628
|
mcpTools: boot.mcp.tools(),
|
|
627
629
|
userTools: userToolScan.tools,
|
|
628
630
|
signal: controller.signal,
|
|
@@ -1216,7 +1218,6 @@ export function createController({ boot }) {
|
|
|
1216
1218
|
shells: boot.shells,
|
|
1217
1219
|
wakeups: boot.wakeups,
|
|
1218
1220
|
memory: boot.memory,
|
|
1219
|
-
dredge: boot.dredge,
|
|
1220
1221
|
...extra,
|
|
1221
1222
|
})
|
|
1222
1223
|
}
|
package/src/tools/index.js
CHANGED
|
@@ -5,10 +5,9 @@ import { createEdit } from './edit.js'
|
|
|
5
5
|
import { createBash } from './bash.js'
|
|
6
6
|
import { createGlob } from './glob.js'
|
|
7
7
|
import { createGrep } from './grep.js'
|
|
8
|
-
import { createWebTools } from './web.js'
|
|
9
8
|
import { createView } from './view.js'
|
|
10
9
|
|
|
11
|
-
export function createToolset({ cwd, env, tracker, skills, shells, sessionId, sessionFile, wakeups, memory, agents, deliberations, onAgentsCollected, askUser,
|
|
10
|
+
export function createToolset({ cwd, env, tracker, skills, shells, sessionId, sessionFile, wakeups, memory, agents, deliberations, onAgentsCollected, askUser, mcpTools = [], userTools = [], hostTools = [], signal, maxToolCalls, maxAgentStarts, requireAgentPlan = false, allowNames, onToolUpdate, viewer }) {
|
|
12
11
|
const recorder = createRecorder(onToolUpdate)
|
|
13
12
|
let agentStarts = 0
|
|
14
13
|
let plannedAgentStarts = requireAgentPlan ? null : maxAgentStarts
|
|
@@ -25,10 +24,6 @@ export function createToolset({ cwd, env, tracker, skills, shells, sessionId, se
|
|
|
25
24
|
|
|
26
25
|
if (viewer) local.push(createView({ ...deps, viewer }))
|
|
27
26
|
|
|
28
|
-
if (dredge) {
|
|
29
|
-
local.push(...createWebTools({ dredge, recorder, signal }))
|
|
30
|
-
}
|
|
31
|
-
|
|
32
27
|
if (shells) {
|
|
33
28
|
local.push(
|
|
34
29
|
{
|
|
@@ -283,7 +278,7 @@ export function createToolset({ cwd, env, tracker, skills, shells, sessionId, se
|
|
|
283
278
|
})
|
|
284
279
|
}
|
|
285
280
|
|
|
286
|
-
const describedToolNames = new Set(['read', 'write', 'edit', 'bash', 'glob', 'grep', '
|
|
281
|
+
const describedToolNames = new Set(['read', 'write', 'edit', 'bash', 'glob', 'grep', 'schedule_wakeup'])
|
|
287
282
|
const describedTools = new Set(local.filter((tool) => describedToolNames.has(tool.name)).map((tool) => tool.name))
|
|
288
283
|
const byName = new Map()
|
|
289
284
|
for (const tool of [...local, ...hostTools, ...userTools, ...mcpTools]) {
|
package/src/tools/web.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { describeParam } from './recorder.js'
|
|
2
|
-
const DEFAULT_SLICE_CHARS = 24000
|
|
3
|
-
const MAX_SLICE_CHARS = 100000
|
|
4
|
-
|
|
5
|
-
export function resolveDredge(config = {}, env = process.env) {
|
|
6
|
-
const url = env.DREDGE_URL || config.dredge?.url || null
|
|
7
|
-
if (!url) return null
|
|
8
|
-
return {
|
|
9
|
-
url: url.replace(/\/+$/, ''),
|
|
10
|
-
apiKey: env.DREDGE_API_KEY || config.dredge?.apiKey || null,
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const CALL_TIMEOUT_MS = 120000
|
|
15
|
-
|
|
16
|
-
async function call(dredge, path, params, signal) {
|
|
17
|
-
const query = new URLSearchParams(params)
|
|
18
|
-
// bounded above dredge's own 90s queue ceiling so a wedged server becomes
|
|
19
|
-
// a tool error instead of a hung turn
|
|
20
|
-
const signals = [AbortSignal.timeout(CALL_TIMEOUT_MS), ...(signal ? [signal] : [])]
|
|
21
|
-
const response = await fetch(`${dredge.url}${path}?${query}`, {
|
|
22
|
-
signal: AbortSignal.any(signals),
|
|
23
|
-
headers: dredge.apiKey ? { authorization: `Bearer ${dredge.apiKey}` } : {},
|
|
24
|
-
})
|
|
25
|
-
const body = await response.json().catch(() => null)
|
|
26
|
-
if (!body) throw new Error(`dredge returned http ${response.status} with no usable body`)
|
|
27
|
-
return body
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function createWebTools({ dredge, recorder, signal }) {
|
|
31
|
-
return [
|
|
32
|
-
{
|
|
33
|
-
name: 'web_search',
|
|
34
|
-
description:
|
|
35
|
-
'Search the web. Google-style operators work: site:, filetype:pdf, quoted phrases. Returns ranked results; pass a result url to web_fetch to read it.',
|
|
36
|
-
schema: {
|
|
37
|
-
q: { type: 'string', description: 'the search query' },
|
|
38
|
-
description: describeParam,
|
|
39
|
-
},
|
|
40
|
-
execute: async ({ q }) => {
|
|
41
|
-
recorder.extra({ title: q })
|
|
42
|
-
const body = await call(dredge, '/search', { q }, signal)
|
|
43
|
-
if (!body.ok) throw new Error(body.error?.message || 'search failed')
|
|
44
|
-
const results = (body.results || []).map((r) => ({
|
|
45
|
-
title: r.title,
|
|
46
|
-
url: r.url,
|
|
47
|
-
snippet: r.snippet,
|
|
48
|
-
source: r.source,
|
|
49
|
-
}))
|
|
50
|
-
if (results.length === 0) {
|
|
51
|
-
const backends = (body.backends || []).map((b) => `${b.name}: ${b.status}`).join(', ')
|
|
52
|
-
return { results, note: backends ? `no results · backends: ${backends}` : 'no results' }
|
|
53
|
-
}
|
|
54
|
-
return { results }
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: 'web_fetch',
|
|
59
|
-
description:
|
|
60
|
-
'Fetch a url and read it as clean markdown (html, pdf, docx, and textual formats like json). Long documents arrive in slices: the result says which slice you have (e.g. "slice 1 of 12") and next_cursor continues from there. Every slice you fetch permanently occupies conversation context, so only walk cursors for content you actually need, and raise maxChars only when the task genuinely needs a bigger window.',
|
|
61
|
-
schema: {
|
|
62
|
-
description: describeParam,
|
|
63
|
-
url: { type: 'string', description: 'the url to fetch' },
|
|
64
|
-
cursor: { type: 'string', description: 'pagination cursor from a previous web_fetch of the same url', optional: true },
|
|
65
|
-
maxChars: { type: 'number', description: `slice size in characters, default ${DEFAULT_SLICE_CHARS}, max ${MAX_SLICE_CHARS}`, optional: true },
|
|
66
|
-
},
|
|
67
|
-
execute: async ({ url, cursor, maxChars }) => {
|
|
68
|
-
recorder.extra({ title: url.replace(/^https?:\/\//, '').slice(0, 80) })
|
|
69
|
-
const slice = Math.min(MAX_SLICE_CHARS, Math.max(1000, maxChars || DEFAULT_SLICE_CHARS))
|
|
70
|
-
const body = await call(dredge, '/fetch', { url, maxChars: slice, ...(cursor && { cursor }) }, signal)
|
|
71
|
-
if (!body.ok) {
|
|
72
|
-
const { code, message, retryable } = body.error || {}
|
|
73
|
-
throw new Error(`${code || 'fetch failed'}: ${message || url}${retryable ? ' (retryable)' : ''}`)
|
|
74
|
-
}
|
|
75
|
-
const { markdown, metadata, pagination } = body.doc
|
|
76
|
-
return {
|
|
77
|
-
markdown,
|
|
78
|
-
title: metadata?.title || null,
|
|
79
|
-
finalUrl: metadata?.final_url || url,
|
|
80
|
-
...(pagination?.total_chunks > 1 && { slice: `${pagination.chunk_index + 1} of ${pagination.total_chunks}` }),
|
|
81
|
-
...(pagination?.next_cursor && { next_cursor: pagination.next_cursor }),
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
]
|
|
86
|
-
}
|