picocode-core 0.9.176 → 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 +1 -1
- package/src/controller.js +4 -2
- package/src/derive.js +8 -3
- package/src/tool-trimming.js +37 -6
- package/src/tools/index.js +11 -1
package/package.json
CHANGED
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,
|
|
@@ -835,7 +836,7 @@ export function createController({ boot }) {
|
|
|
835
836
|
const unavailable = ids.filter((id) => !completed.has(id))
|
|
836
837
|
if (unavailable.length) return flash(`error: tool calls are not completed in current context: ${unavailable.join(', ')}`)
|
|
837
838
|
const eligible = type === 'tool_trim'
|
|
838
|
-
? ids.filter((id) => state.derived.
|
|
839
|
+
? ids.filter((id) => !state.derived.trimmedToolIds.has(id))
|
|
839
840
|
: ids.filter((id) => state.derived.toolItems.get(id)?.contextTrimmed)
|
|
840
841
|
if (!eligible.length) return false
|
|
841
842
|
persist(makeEvent(type, { callIds: eligible, version: TOOL_TRIM_VERSION }))
|
|
@@ -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
|
|
|
@@ -180,6 +180,7 @@ export function deriveState(events) {
|
|
|
180
180
|
toolItems: new Map(),
|
|
181
181
|
latestCompactIndex,
|
|
182
182
|
trimmedToolIds: new Set(),
|
|
183
|
+
toolTrimVersions: new Map(),
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
for (const event of effectiveEvents) {
|
|
@@ -259,7 +260,10 @@ export function deriveState(events) {
|
|
|
259
260
|
break
|
|
260
261
|
}
|
|
261
262
|
case 'tool_trim':
|
|
262
|
-
for (const callId of event.data.callIds || [])
|
|
263
|
+
for (const callId of event.data.callIds || []) {
|
|
264
|
+
state.trimmedToolIds.add(callId)
|
|
265
|
+
state.toolTrimVersions.set(callId, event.data.version?.algorithm || 'tool-trim-v1')
|
|
266
|
+
}
|
|
263
267
|
state.lastPromptTokens = 0
|
|
264
268
|
break
|
|
265
269
|
case 'tool_restore':
|
|
@@ -272,6 +276,7 @@ export function deriveState(events) {
|
|
|
272
276
|
state.historyEventIds = []
|
|
273
277
|
state.toolItems = new Map()
|
|
274
278
|
state.trimmedToolIds = new Set()
|
|
279
|
+
state.toolTrimVersions = new Map()
|
|
275
280
|
state.lastPromptTokens = 0
|
|
276
281
|
break
|
|
277
282
|
case 'context_file':
|
|
@@ -299,7 +304,7 @@ export function deriveState(events) {
|
|
|
299
304
|
}
|
|
300
305
|
|
|
301
306
|
const effectiveHistory = elideStaleToolResults(state.providerHistory)
|
|
302
|
-
state.providerHistory = applyToolTrims(effectiveHistory, state.trimmedToolIds)
|
|
307
|
+
state.providerHistory = applyToolTrims(effectiveHistory, state.trimmedToolIds, state.toolTrimVersions, state.toolItems, toolResultArchive(events).references)
|
|
303
308
|
annotateToolContext(state, state.providerHistory, state.trimmedToolIds)
|
|
304
309
|
return state
|
|
305
310
|
}
|
package/src/tool-trimming.js
CHANGED
|
@@ -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
|
|
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()
|
|
@@ -106,8 +127,19 @@ export function applyToolTrims(history, trimmedIds) {
|
|
|
106
127
|
callMessages.set(entry.callIndex, callMessage)
|
|
107
128
|
}
|
|
108
129
|
const call = callMessage.tool_calls.find((candidate) => candidate.id === id)
|
|
109
|
-
|
|
110
|
-
|
|
130
|
+
if (versions.get(id) === 'tool-compact-v2') {
|
|
131
|
+
const item = toolItems.get(id)
|
|
132
|
+
let args
|
|
133
|
+
try { args = JSON.parse(call.function.arguments) } catch { args = {} }
|
|
134
|
+
const description = item?.description || args?.description || call.function.name
|
|
135
|
+
call.function.arguments = JSON.stringify({ description })
|
|
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 })})]` })
|
|
139
|
+
} else {
|
|
140
|
+
call.function.arguments = trimArguments(call.function.arguments)
|
|
141
|
+
resultMessages.set(entry.resultIndex, { ...entry.result, content: trimResult(entry.result.content) })
|
|
142
|
+
}
|
|
111
143
|
}
|
|
112
144
|
return history.map((message, index) => callMessages.get(index) || resultMessages.get(index) || message)
|
|
113
145
|
}
|
|
@@ -129,13 +161,12 @@ export function annotateToolContext(state, effectiveHistory, trimmedIds) {
|
|
|
129
161
|
item.contextAvailable = !!entry
|
|
130
162
|
item.contextTrimmed = !!entry && trimmedIds.has(item.callId)
|
|
131
163
|
item.contextTokens = entry ? entryTokens(entry.call.function.arguments, entry.result.content) : 0
|
|
132
|
-
item.contextCanTrim = !!entry && !item.contextTrimmed
|
|
133
|
-
entryTokens(trimArguments(entry.call.function.arguments), trimResult(entry.result.content)) < item.contextTokens
|
|
164
|
+
item.contextCanTrim = !!entry && !item.contextTrimmed
|
|
134
165
|
}
|
|
135
166
|
}
|
|
136
167
|
|
|
137
168
|
export const TOOL_TRIM_VERSION = {
|
|
138
|
-
algorithm:
|
|
169
|
+
algorithm: 'tool-compact-v2',
|
|
139
170
|
argumentChars: ARGUMENT_CHARS,
|
|
140
171
|
resultChars: RESULT_CHARS,
|
|
141
172
|
stringChars: STRING_CHARS,
|
package/src/tools/index.js
CHANGED
|
@@ -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) {
|