Previously the data tool caught all errors and returned them as normal
tool results with error info in the JSON content. This meant pi-agent-core
never saw an exception and always set isError=false in the run-log, even
for rate limit errors (errCode 9001) and other API failures.
Now errors propagate to pi-agent-core which sets isError=true and formats
the error message for the LLM automatically.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UC4 test times out in CI (5s default) because generateSummary's API
provider layer takes longer to fail on slow CI runners. Increase to 15s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The setTimeout in runSubagentTask was never cleared when childAgent.run()
completed before the timeout. The dangling timer would later reject an
unobserved promise, causing an unhandled promise rejection crash in Node.js
v15+. Capture the timer and clear it in a .finally() block.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete sessions-spawn.ts, sessions-list.ts and their tests. Update CLI
to remove waitForSubagents polling workaround (delegate is synchronous).
Update UI, desktop IPC, SWE-bench, and system prompt tests to use the
new delegate tool name.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the async sessions_spawn/sessions_list sub-agent system with a
single synchronous `delegate` tool. The new tool runs tasks in parallel
via Promise.all with per-task timeout, returning combined results directly
in the tool response. This eliminates the need for registry, announce queue,
persistence, and Hub involvement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pre-emptive truncation, tool result pruning, and summary fallback
only checked for Anthropic-style `role: "user"` messages with
`type: "tool_result"` blocks. The actual runtime uses pi-agent-core
format with `role: "toolResult"`, `toolCallId`, and `toolName` on the
message itself. This caused truncation and pruning to silently skip
all tool results in real agent runs.
Add handlers for the pi-agent-core format in all four affected modules:
- session-manager.ts: check both "user" and "toolResult" roles
- tool-result-truncation.ts: new handler for toolResult format
- tool-result-pruning.ts: new processToolResultMessage() + updated loops
- summary-fallback.ts: include "toolResult" in artifact ref extraction
Verified via agent-driven E2E tests (5 test sessions, 6 artifacts).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add real user messages for bootstrap protection in pruning tests
- Fix artifact directory path assertions (baseDir vs sessions/baseDir)
- Add cross-phase tests (Phase 1 truncation → Phase 2 pruning)
- Remove conditional assertion guards that could silently skip checks
- All 30 E2E integration tests now pass with mandatory assertions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The extractArtifactRef regex only matched "Full result saved to" (from
pre-emptive truncation) but not "Full result available at" (from soft
trim). This caused hard clear to lose artifact references when preceded
by soft trim in the same pruning pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SectionReport now includes truncated/originalChars fields for budget-controlled
sections. formatPromptReport shows estimated token count and truncation details.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workspace.md content is capped at 20k chars and skills prompt at 12k chars.
Oversized content is intelligently truncated (head 70% + marker + tail 20%)
with newline-boundary snapping. Inspired by OpenClaw's bootstrap budget system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Soft trim and hard clear now detect and preserve artifact references
in their markers. Summary instructions include guidance to note artifact
paths. Plain-text fallback extracts and lists all artifact references
in a "Saved Artifacts" section.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Oversized tool results (>30% of context window) are now saved as artifacts
before being truncated in the session. The LLM sees a truncated version with
head+tail preservation and a marker pointing to the full artifact file,
which it can re-read on demand. This prevents information loss during
context window management.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add instructions for the agent to understand [Replying to: "..."] annotations
and to send brief acknowledgments before tool calls when messages come from
messaging channels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove compactMessagesWithSummary (~100 lines, never called; only
the Chunked variant was used)
- Remove compactMessagesByCount, findSafeCompactionPoint, and all
count-mode references (~90 lines)
- Narrow CompactionResult.reason to "tokens" | "summary" | "pruning"
- Narrow compactionMode to "tokens" | "summary" (was "count" | ...)
- Simplify session-manager: remove maxMessages/keepLast params,
enable tool result pruning by default
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-flight compaction runs in-memory only (not persisted), so tool
result pruning in this path was wasted work — results were thrown away
after the LLM call. Post-turn compaction still handles pruning and
persists the results. Only Phase 2 (emergency message drop) remains
as a safety net in pre-flight.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- estimateSystemPromptTokens now uses estimateTokens() (chars/4) instead
of chars/2, eliminating the 2x overestimate that caused pre-flight
compaction to fire on every LLM call at small context windows
- ESTIMATION_SAFETY_MARGIN reduced from 1.5 to 1.2, increasing usable
context from ~53% to ~73% before compaction triggers
At 200k context, effective usable tokens before compaction improved from
~86k to ~120k message tokens (39% increase).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
resolveContextWindowInfo now uses config > model > default priority so
explicit --context-window flag overrides model defaults. Also adds
--context-window CLI option to the run command.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track the last assistant message saved by the message_end event handler
and skip saving it again in the abort handler. This prevents the
duplicate assistant entries in session.jsonl that caused the
"tool_call_id is not found" bug.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a session is aborted mid-tool-execution, the assistant message can
be persisted twice (once by message_end, once by the abort handler).
The repair logic failed to handle this: it generated a synthetic tool
result for the first copy but deduplicated the result for the second,
leaving an orphaned tool call that caused "tool_call_id is not found"
errors on all subsequent API calls.
Detect and remove duplicate assistant messages whose tool call IDs
have all already been paired with results from an earlier copy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SKILL.md: python → python3 (macOS has no `python` binary)
- skills/index.ts: inject skill directory path so agent can resolve
relative paths like scripts/recalc.py to absolute paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>