picocode-core 0.9.175 → 0.9.177

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.175",
3
+ "version": "0.9.177",
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
@@ -834,7 +834,11 @@ export function createController({ boot }) {
834
834
  const completed = completedToolCalls(state.derived.providerHistory)
835
835
  const unavailable = ids.filter((id) => !completed.has(id))
836
836
  if (unavailable.length) return flash(`error: tool calls are not completed in current context: ${unavailable.join(', ')}`)
837
- persist(makeEvent(type, { callIds: ids, version: TOOL_TRIM_VERSION }))
837
+ const eligible = type === 'tool_trim'
838
+ ? ids.filter((id) => !state.derived.trimmedToolIds.has(id))
839
+ : ids.filter((id) => state.derived.toolItems.get(id)?.contextTrimmed)
840
+ if (!eligible.length) return false
841
+ persist(makeEvent(type, { callIds: eligible, version: TOOL_TRIM_VERSION }))
838
842
  ensureSession()
839
843
  reDerive()
840
844
  return true
package/src/derive.js CHANGED
@@ -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 || []) state.trimmedToolIds.add(callId)
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)
303
308
  annotateToolContext(state, state.providerHistory, state.trimmedToolIds)
304
309
  return state
305
310
  }
@@ -92,7 +92,7 @@ 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) {
95
+ export function applyToolTrims(history, trimmedIds, versions = new Map(), toolItems = new Map()) {
96
96
  if (!trimmedIds.size) return history
97
97
  const completed = completedToolCalls(history)
98
98
  const callMessages = new Map()
@@ -106,8 +106,18 @@ export function applyToolTrims(history, trimmedIds) {
106
106
  callMessages.set(entry.callIndex, callMessage)
107
107
  }
108
108
  const call = callMessage.tool_calls.find((candidate) => candidate.id === id)
109
- call.function.arguments = trimArguments(call.function.arguments)
110
- resultMessages.set(entry.resultIndex, { ...entry.result, content: trimResult(entry.result.content) })
109
+ if (versions.get(id) === 'tool-compact-v2') {
110
+ const item = toolItems.get(id)
111
+ let args
112
+ try { args = JSON.parse(call.function.arguments) } catch { args = {} }
113
+ const description = item?.description || args?.description || call.function.name
114
+ 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]` })
117
+ } else {
118
+ call.function.arguments = trimArguments(call.function.arguments)
119
+ resultMessages.set(entry.resultIndex, { ...entry.result, content: trimResult(entry.result.content) })
120
+ }
111
121
  }
112
122
  return history.map((message, index) => callMessages.get(index) || resultMessages.get(index) || message)
113
123
  }
@@ -118,20 +128,23 @@ function resultText(content) {
118
128
  return JSON.stringify(content ?? '')
119
129
  }
120
130
 
131
+ function entryTokens(args, result) {
132
+ return Math.ceil((String(args ?? '').length + resultText(result).length) / 4)
133
+ }
134
+
121
135
  export function annotateToolContext(state, effectiveHistory, trimmedIds) {
122
136
  const completed = completedToolCalls(effectiveHistory)
123
137
  for (const item of state.toolItems.values()) {
124
138
  const entry = completed.get(item.callId)
125
139
  item.contextAvailable = !!entry
126
140
  item.contextTrimmed = !!entry && trimmedIds.has(item.callId)
127
- item.contextTokens = entry
128
- ? Math.ceil((String(entry.call.function.arguments ?? '').length + resultText(entry.result.content).length) / 4)
129
- : 0
141
+ item.contextTokens = entry ? entryTokens(entry.call.function.arguments, entry.result.content) : 0
142
+ item.contextCanTrim = !!entry && !item.contextTrimmed
130
143
  }
131
144
  }
132
145
 
133
146
  export const TOOL_TRIM_VERSION = {
134
- algorithm: ALGORITHM,
147
+ algorithm: 'tool-compact-v2',
135
148
  argumentChars: ARGUMENT_CHARS,
136
149
  resultChars: RESULT_CHARS,
137
150
  stringChars: STRING_CHARS,