picocode-core 0.9.177 → 0.9.178

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.177",
3
+ "version": "0.9.178",
4
4
  "description": "The agent runtime behind pico: sessions, tools, subagents, MCP, memory, and model access",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/controller.js CHANGED
@@ -11,7 +11,7 @@ import { createAgentManager } from './agents.js'
11
11
  import { runDeliberation, validateDeliberation } from './deliberation.js'
12
12
  import { deliberationsFromEvents } from './deliberation-history.js'
13
13
  import { compactionPrompt, formatCompactSummary, summarySections, compactionKeepFrom } from './compaction.js'
14
- import { completedToolCalls, TOOL_TRIM_VERSION } from './tool-trimming.js'
14
+ import { completedToolCalls, retrieveToolResult, TOOL_TRIM_VERSION } from './tool-trimming.js'
15
15
  import { createToolset } from './tools/index.js'
16
16
  import { defaultTitle } from './tools/recorder.js'
17
17
  import { scanUserTools } from './user-tools.js'
@@ -603,6 +603,7 @@ export function createController({ boot }) {
603
603
  const context = await createAgentContext(boot, { userTools: userToolScan.tools })
604
604
  const { tools, recorder } = createToolset({
605
605
  ...context.tools,
606
+ toolResult: (id) => retrieveToolResult(state.events, id),
606
607
  sessionId: state.session?.id,
607
608
  sessionFile: state.session?.file,
608
609
  wakeups: boot.wakeups,
@@ -1217,6 +1218,7 @@ export function createController({ boot }) {
1217
1218
  return createToolset({
1218
1219
  cwd: boot.cwd,
1219
1220
  env: boot.env,
1221
+ toolResult: (id) => retrieveToolResult(state.events, id),
1220
1222
  hostTools: boot.hostTools ?? [],
1221
1223
  tracker: boot.tracker,
1222
1224
  skills: boot.skills,
package/src/derive.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { continuationMessage } from './compaction.js'
2
2
  import { applySteering } from './steer.js'
3
- import { annotateToolContext, applyToolTrims } from './tool-trimming.js'
3
+ import { annotateToolContext, applyToolTrims, toolResultArchive } from './tool-trimming.js'
4
4
 
5
5
  const DROPPING_MODES = ['both', 'chat', 'summary']
6
6
 
@@ -304,7 +304,7 @@ export function deriveState(events) {
304
304
  }
305
305
 
306
306
  const effectiveHistory = elideStaleToolResults(state.providerHistory)
307
- state.providerHistory = applyToolTrims(effectiveHistory, state.trimmedToolIds, state.toolTrimVersions, state.toolItems)
307
+ state.providerHistory = applyToolTrims(effectiveHistory, state.trimmedToolIds, state.toolTrimVersions, state.toolItems, toolResultArchive(events).references)
308
308
  annotateToolContext(state, state.providerHistory, state.trimmedToolIds)
309
309
  return state
310
310
  }
@@ -92,7 +92,28 @@ export function completedToolCalls(history) {
92
92
  return new Map([...callsIn(history)].filter(([, entry]) => entry.result))
93
93
  }
94
94
 
95
- export function applyToolTrims(history, trimmedIds, versions = new Map(), toolItems = new Map()) {
95
+ export function toolResultArchive(events) {
96
+ const history = events.filter((event) => event.type === 'message').map((event) => event.data.message)
97
+ const references = new Map()
98
+ for (const message of history) {
99
+ for (const call of message.tool_calls || []) {
100
+ if (!references.has(call.id)) references.set(call.id, `t${references.size + 1}`)
101
+ }
102
+ }
103
+ const results = new Map()
104
+ for (const [callId, entry] of completedToolCalls(history)) {
105
+ results.set(references.get(callId), { callId, name: entry.call.function.name, arguments: entry.call.function.arguments, result: entry.result.content })
106
+ }
107
+ return { references, results }
108
+ }
109
+
110
+ export function retrieveToolResult(events, id) {
111
+ const result = toolResultArchive(events).results.get(id)
112
+ if (!result) throw new Error(`no saved tool result with id ${id}`)
113
+ return structuredClone(result)
114
+ }
115
+
116
+ export function applyToolTrims(history, trimmedIds, versions = new Map(), toolItems = new Map(), references = new Map()) {
96
117
  if (!trimmedIds.size) return history
97
118
  const completed = completedToolCalls(history)
98
119
  const callMessages = new Map()
@@ -112,8 +133,9 @@ export function applyToolTrims(history, trimmedIds, versions = new Map(), toolIt
112
133
  try { args = JSON.parse(call.function.arguments) } catch { args = {} }
113
134
  const description = item?.description || args?.description || call.function.name
114
135
  call.function.arguments = JSON.stringify({ description })
115
- const outcome = item?.status === 'error' ? 'error' : item?.status || 'completed'
116
- resultMessages.set(entry.resultIndex, { ...entry.result, content: `[${outcome}; tool arguments and result compacted, originals retained in session log]` })
136
+ const error = item?.status === 'error' ? `error: ${item.error || 'tool failed'}\n` : ''
137
+ const reference = references.get(id)
138
+ resultMessages.set(entry.resultIndex, { ...entry.result, content: `${error}[compacted; retrieve with tool_result(${JSON.stringify({ id: reference })})]` })
117
139
  } else {
118
140
  call.function.arguments = trimArguments(call.function.arguments)
119
141
  resultMessages.set(entry.resultIndex, { ...entry.result, content: trimResult(entry.result.content) })
@@ -7,7 +7,7 @@ import { createGlob } from './glob.js'
7
7
  import { createGrep } from './grep.js'
8
8
  import { createView } from './view.js'
9
9
 
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 }) {
10
+ export function createToolset({ toolResult, cwd, env, tracker, skills, shells, sessionId, sessionFile, wakeups, memory, agents, deliberations, onAgentsCollected, askUser, mcpTools = [], userTools = [], hostTools = [], signal, maxToolCalls, maxAgentStarts, requireAgentPlan = false, allowNames, onToolUpdate, viewer }) {
11
11
  const recorder = createRecorder(onToolUpdate)
12
12
  let agentStarts = 0
13
13
  let plannedAgentStarts = requireAgentPlan ? null : maxAgentStarts
@@ -22,6 +22,16 @@ export function createToolset({ cwd, env, tracker, skills, shells, sessionId, se
22
22
  createGrep(deps),
23
23
  ]
24
24
 
25
+ if (toolResult) local.push({
26
+ name: 'tool_result',
27
+ description: 'Retrieve the original arguments and result of a compacted tool call using its retrieval ID. This reads saved data without rerunning the tool or restoring other calls.',
28
+ schema: {
29
+ description: describeParam,
30
+ id: { type: 'string', description: 'retrieval ID shown in the compacted result, such as t42' },
31
+ },
32
+ execute: ({ id }) => toolResult(id),
33
+ })
34
+
25
35
  if (viewer) local.push(createView({ ...deps, viewer }))
26
36
 
27
37
  if (shells) {