picocode-core 0.9.173 → 0.9.174

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picocode-core",
3
- "version": "0.9.173",
3
+ "version": "0.9.174",
4
4
  "description": "The agent runtime behind pico: sessions, tools, subagents, MCP, memory, and model access",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,39 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { createContextTracker } from './context.js'
3
+ import { buildSystemPrompt } from './system-prompt.js'
4
+ import { memoryIndex } from './memory.js'
5
+
6
+ export async function createAgentContext(boot, { userTools = [], isolated = false, instructions = '' } = {}) {
7
+ const files = [...boot.startupContext.files]
8
+ if (isolated) {
9
+ const known = new Set(files.map((file) => file.path))
10
+ for (const path of boot.tracker.loaded) {
11
+ if (known.has(path)) continue
12
+ const content = await readFile(path, 'utf8').catch(() => null)
13
+ if (content !== null) files.push({ path, content })
14
+ }
15
+ }
16
+ const tracker = isolated
17
+ ? createContextTracker({ stopDir: boot.startupContext.stopDir, loaded: new Set(files.map((file) => file.path)) })
18
+ : boot.tracker
19
+ const system = buildSystemPrompt({
20
+ cwd: boot.cwd,
21
+ contextFiles: files,
22
+ skills: boot.skills.list(),
23
+ memoryIndexText: memoryIndex(await boot.memory.list().catch(() => []), boot.root),
24
+ })
25
+ return {
26
+ system: instructions ? `${system}\n\n${instructions}` : system,
27
+ tools: {
28
+ cwd: boot.cwd,
29
+ env: boot.env,
30
+ tracker,
31
+ skills: boot.skills,
32
+ memory: boot.memory,
33
+ shells: boot.shells,
34
+ hostTools: (boot.hostTools ?? []).filter((tool) => !isolated || !tool.name.startsWith('browser_')),
35
+ userTools,
36
+ mcpTools: boot.mcp.tools(),
37
+ },
38
+ }
39
+ }
package/src/controller.js CHANGED
@@ -3,7 +3,7 @@ import { writeFile } from 'node:fs/promises'
3
3
  import { join } from 'node:path'
4
4
  import { makeEvent } from './events.js'
5
5
  import { createSession, createEphemeralSession, forkSession, openSession, loadSession, listSessions, deleteSession, appendSessionEvent, onSessionWriteError } from './session.js'
6
- import { createContextTracker } from './context.js'
6
+ import { createAgentContext } from './agent-context.js'
7
7
  import { deriveState, userEntries, rewindStats } from './derive.js'
8
8
  import { appendPrompt } from './history.js'
9
9
  import { runTurn, summarizeText, compactHistory, compactProgress } from './agent.js'
@@ -53,7 +53,6 @@ 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']
57
56
  const AGENT_TOOLS = ['agent_plan', 'agent_start', 'agent_list', 'agent_collect', 'agent_cancel']
58
57
  const CONTEXT_COLORS = ['#67b7ff', '#c792ea', '#f7c66a', '#f78c6c', '#6be795']
59
58
 
@@ -202,23 +201,16 @@ export function createController({ boot }) {
202
201
  const sessionId = state.session?.id
203
202
  if (!sessionId) throw new Error('worker requires an active session')
204
203
  const scratchpad = ensureDir(agentScratchDir(boot.root, sessionId, agent.id))
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
204
+ const scan = await refreshProjectIndexes()
205
+ const context = await createAgentContext(boot, { userTools: scan.tools, isolated: true, instructions: workerSystemPrompt(scratchpad) })
208
206
  const { tools, recorder } = createToolset({
209
- cwd: boot.cwd,
207
+ ...context.tools,
210
208
  env: { ...boot.env, PICO_SCRATCHPAD: scratchpad },
211
- // a private tracker seeded from the main one: a worker may read an
212
- // AGENTS.md the main agent has not seen, and consuming it from the
213
- // shared set would mean the main agent never receives it
214
- tracker: createContextTracker({ stopDir: boot.startupContext.stopDir, loaded: new Set(boot.tracker.loaded) }),
215
- shells: boot.shells,
216
209
  sessionId,
217
210
  sessionFile: state.session?.file,
218
211
  signal,
219
212
  maxToolCalls: 30,
220
- allowNames: requestedTools,
221
- mcpTools,
213
+ allowNames: agent.tools?.length ? agent.tools : undefined,
222
214
  })
223
215
  return runTurn({
224
216
  history: [{ role: 'user', content: agent.prompt }],
@@ -227,7 +219,7 @@ export function createController({ boot }) {
227
219
  modelName: worker.name,
228
220
  effort: worker.effort ? 'low' : null,
229
221
  auth,
230
- system: workerSystemPrompt(scratchpad),
222
+ system: context.system,
231
223
  signal,
232
224
  onStream,
233
225
  })
@@ -279,18 +271,16 @@ export function createController({ boot }) {
279
271
 
280
272
  const runWorker = async ({ history, role, tools: enabled = true, onStream }) => {
281
273
  const scratchpad = ensureDir(agentScratchDir(boot.root, sessionId, `deliberation-${id}-${role}`))
282
- const mcpTools = enabled ? boot.mcp.tools() : []
274
+ const scan = await refreshProjectIndexes()
275
+ const context = await createAgentContext(boot, { userTools: scan.tools, isolated: true, instructions: participantSystemPrompt(scratchpad) })
283
276
  const toolset = createToolset({
284
- cwd: boot.cwd,
277
+ ...context.tools,
285
278
  env: { ...boot.env, PICO_SCRATCHPAD: scratchpad },
286
- tracker: createContextTracker({ stopDir: boot.startupContext.stopDir, loaded: new Set(boot.tracker.loaded) }),
287
- shells: boot.shells,
288
279
  sessionId,
289
280
  sessionFile: state.session?.file,
290
281
  signal,
291
282
  maxToolCalls: 30,
292
- allowNames: enabled ? [...WORKER_TOOLS, ...mcpTools.map((tool) => tool.name)] : [],
293
- mcpTools,
283
+ allowNames: enabled ? undefined : [],
294
284
  })
295
285
  return runTurn({
296
286
  history,
@@ -299,7 +289,7 @@ export function createController({ boot }) {
299
289
  modelName: roleWorkers[role].name,
300
290
  effort: roleWorkers[role].effort ? 'low' : null,
301
291
  auth: roleAuths[role],
302
- system: participantSystemPrompt(scratchpad),
292
+ system: context.system,
303
293
  signal,
304
294
  onStream,
305
295
  })
@@ -609,24 +599,16 @@ export function createController({ boot }) {
609
599
  const { tracker } = boot
610
600
  const loadedBefore = new Set(tracker.loaded)
611
601
  const userToolScan = await refreshProjectIndexes()
612
- const freshSkills = boot.skills
602
+ const context = await createAgentContext(boot, { userTools: userToolScan.tools })
613
603
  const { tools, recorder } = createToolset({
614
- cwd: boot.cwd,
615
- env: boot.env,
616
- hostTools: boot.hostTools ?? [],
617
- tracker,
618
- skills: freshSkills,
619
- shells: boot.shells,
604
+ ...context.tools,
620
605
  sessionId: state.session?.id,
621
606
  sessionFile: state.session?.file,
622
607
  wakeups: boot.wakeups,
623
- memory: boot.memory,
624
608
  agents: boot.researchModel ? agents : null,
625
609
  deliberations: boot.deliberationModel || (boot.proposerModel && boot.reviewerModel) ? deliberations : null,
626
610
  onAgentsCollected: discardCollectedAgentNotes,
627
611
  askUser,
628
- mcpTools: boot.mcp.tools(),
629
- userTools: userToolScan.tools,
630
612
  signal: controller.signal,
631
613
  maxAgentStarts: researchAgentLimit ? 100 : undefined,
632
614
  requireAgentPlan: !!researchAgentLimit,
@@ -645,12 +627,7 @@ export function createController({ boot }) {
645
627
  modelName: state.model.name,
646
628
  effort: effortApplies() ? state.effort ?? 'auto' : null,
647
629
  auth,
648
- system: buildSystemPrompt({
649
- cwd: boot.cwd,
650
- contextFiles: boot.startupContext.files,
651
- skills: freshSkills.list(),
652
- memoryIndexText: memoryIndex(await boot.memory.list().catch(() => []), boot.root),
653
- }),
630
+ system: context.system,
654
631
  signal: controller.signal,
655
632
  onStream: streamHandler(recorder, controller),
656
633
  })