Commit Graph
327 Commits
Author SHA1 Message Date
can1357 c375ff5a92 fix(coding-agent): resolved agent session /exit Ctrl+C hang in dispose
- Short-circuited `agent_end` when `#checkCompaction` deferred handoff, skipping rewind/todo passes and `agent.continue()` race.
- Aborted retry/compaction paths in `AgentSession.dispose()` before draining post-prompt tasks so `/exit` and Ctrl+C no longer hang.
- Added handoff-deadlock regression tests in `agent-session-handoff.test.ts` to prevent reordering races.
2026-05-26 22:48:13 +02:00
can1357 796c437dc1 feat: overhauled stream timeout and eval session management
- Replaced external watchdog timers with per-request SDK timeouts for first-event budget across OpenAI, Anthropic, and Azure providers.
- Keyed Python shared kernels by (sessionId, cwd) to prevent cross-directory state bleed.
- Deduplicated concurrent cold-start session acquisition for JS and Python executors.
- Moved `isOpenAIResponsesProgressEvent` to shared module and scoped display output routing per run for interleaved async cells.
2026-05-26 16:49:11 +02:00
can1357 5364a9bfd0 refactor(tool-discovery): simplified tool discovery API by removing MCP-specific shims
- Removed deprecated MCP-specific type aliases and functions from tool-discovery module, consolidating to unified generic tool discovery API.
- Migrated session and SDK code to use generic filterBySource() and collectDiscoverableTools() instead of MCP-specific variants.
- Removed deprecated interface members including hasQueuedMessages(), FocusPane, AcpBuiltinCommandRuntime, and legacy settings methods.
- Updated test suites to use renamed generic discovery methods and removed back-compat test coverage for legacy MCP shapes.
2026-05-26 15:27:05 +02:00
can1357 bb4c9cae1e feat(coding-agent): added configurable IRC timeout with AbortSignal cancellation
- Added configurable IRC message timeout setting with 120-second default to prevent indefinite hangs.
- Implemented timeout enforcement for IRC send operations using AbortSignal-based cancellation.
- Modified Python tool bridge to route concurrent evaluations using per-run identifiers alongside session IDs.
- Enhanced test coverage for IRC timeout behavior, tool validation, and ephemeral cache key separation.
2026-05-26 14:56:49 +02:00
can1357 8a5b3e9552 feat(eval): added shared executor inheritance for subagents with concurrent async cells
- Removed per-session run queues from JS and Python backends, allowing async cells on the same session id to interleave.
- Introduced `getEvalSessionId` on ToolSession so subagents spawned via `task` inherit the parent's executor id and share JS VM and Python kernel state.
- Switched JS runtime state from module-level fields to AsyncLocalStorage so concurrent runs route output and tool calls to their own context.
- Changed Python runner to an asyncio event loop with per-request tasks and ContextVar-based run id tracking for concurrent execution.
- Added mtime-based module cache eviction to preserve singleton state across re-imports of unchanged local files.
2026-05-26 14:37:56 +02:00
can1357 7fd7397790 fix: resolved Bun HTTP/2 retry matching and thinking-only turn filtering
- Expanded transient error matching for Bun HTTP2StreamReset, RefusedStream, and EnhanceYourCalm.
- Dropped thinking-only/error/aborted turns without text/toolCall, reset aborted tool-call map, and stored timestamps.
- Updated TUI render planning to track scrollback high-water and suppress suffix-scroll artifacts in non-multiplexer sessions.
- Added regression tests and changelog notes for Bun HTTP/2 retry handling, thinking-only filtering, and scrollback regressions.
2026-05-26 08:55:57 +02:00
Can BölükandGitHub d201442a16 Merge pull request #1372 from can1357/farm/e4c67c73/fix-subagent-session-start-busy
fix(agent): prevent subagent session_start busy race
2026-05-25 21:59:38 +03:00
roboomp 1217091557 fix(agent): prevented subagent session_start busy race
Queued extension-delivered user messages when deliverAs is set and waited for session_start extension message sends before prompting subagents.

Fixes #1343
2026-05-25 18:48:06 +00:00
can1357 80186e341c feat(agent): threaded intentTracing option through append-only context
- Exported `normalizeTools` so `AppendOnlyContext` uses the same tool normalization as the agent loop.
- Added `BuildOptions.intentTracing` to `build()`/`reset()`/`takeSnapshot()` so intent injection is consistent and included in the prefix fingerprint.
- Improved `#computeDigest` to cover tool_calls, tool_call_id, name, and id fields to catch in-place mutations.
- Fixed `#unsubscribeAppendOnly` leak and added no-op guard in `#syncAppendOnlyContext`.
2026-05-25 14:06:44 +02:00
can1357 3801b4ee32 fix(coding-agent): added configurable retry delay cap and surfaced rate-limit failure state
- Added `retry.maxDelayMs` to the settings schema and interfaces, with a default cap for provider backoff delays.
- Updated session auto-retry logic to fail fast when a requested wait exceeds the cap without fallback, emitting terminal auto-retry failure state.
- Propagated retry state and failure data into task progress and rendering so children show retry/wait details and reminder prompts stop after terminal errors.
2026-05-25 12:37:32 +02:00
Can BölükandGitHub 98603c669b Merge branch 'main' into farm/7f8acce1/loop-mode-can-auto-submit-again-before-t 2026-05-25 12:58:57 +03:00
Brit c93126ee3f fix: re-evaluate append-only mode on setting changes (not just model switch) 2026-05-24 22:48:12 +02:00
Brit e71d2ff49e fix: detect content rewrites in syncMessages, reset append-only cache on model switch 2026-05-24 22:39:20 +02:00
Brit 648bbdc163 fix(agent): passed AbortSignal to transformContext and re-evaluated append-only on model switch 2026-05-24 22:28:38 +02:00
roboomp 5573270e5e fix(loop-mode): block auto-submit while post-prompt background work is pending
When session.prompt() returns, idle-flush tasks for async-job result
deliveries are scheduled via #schedulePostPromptTask (1ms delay) and
added to #postPromptTasks immediately.  The 800ms loop timer could fire
in that window before isStreaming became true, causing the loop to
submit the next prompt while the delivery turn was still pending.  The
delivery then hit AgentBusyError and the job result was silently dropped.

Add AgentSession.hasPostPromptWork (= #postPromptTasks.size > 0) and
include it in #isLoopAutoSubmitBlocked() alongside isStreaming and
isCompacting.  Add a regression test that verifies the loop defers when
hasPostPromptWork is true and fires once it becomes false.

Fixes #1294
2026-05-22 13:41:17 +00:00
can1357andCan Bölük 796f963da9 feat(coding-agent): added coding-agent follow-up queue with onBeforeYield
- Added optional `onBeforeYield` configuration and `setOnBeforeYield` in Agent, executed before follow-up checks.
- Added `YieldQueue` to `AgentSession`, with setup/teardown and streaming/idle flush via `setOnBeforeYield`.
- Replaced immediate async-result follow-up dispatch with queued batch entries, including stale-state suppression.
- Added MCP follow-up queueing in SDK, deduplicating updates by `serverName` and `uri`.
- Added changelog entries for `onBeforeYield`, async-result batching, MCP dedupe, and `display.shimmer` modes.
- Added yield queue unit tests for streaming emission, debounced idle batches, stale filtering, and error isolation.
2026-05-22 13:08:51 +09:00
roboomp 1b6ef3b5dc fix(coding-agent): respected google retry hints
Parsed provider retry hint text before falling back to quota cooldowns so Google per-minute token limits use the server-provided delay.

Fixes #1253
2026-05-21 09:38:43 +00:00
can1357 3d96fd0d9e fix(coding-agent): fixed compaction to prefer active session model over role default
- Added the active session model to compaction candidate selection before role-based candidates.
- Updated compaction routing so role-based models are only considered after the current chat model.
- Added a regression test proving an Anthropic session prefers its active model over `modelRoles.default` on OpenAI.
2026-05-21 16:37:44 +09:00
can1357andCan Bölük fd42c8da26 fix(coding-agent): stop mutating todo state via timer-based autoclear
#scheduleTodoAutoClear / #runTodoAutoClear used to splice completed and
abandoned tasks out of #todoPhases on a 60s (later 30min) timer. The
mutation made earlier completions vanish from phase counts ("5 tasks"
dropped to 4) and contradicted the model's own claim of progress.

The autoclear path is removed entirely. Canonical #todoPhases is only
mutated by explicit todo_write calls. formatSummary's denominator
(`current.tasks.length`) now stays stable across tool calls, so phase
counts include completed tasks until the model explicitly removes them.

Leaves the `tasks.todoClearDelay` setting in place (inert) to avoid
changing the schema in this patch.
2026-05-21 15:22:46 +09:00
can1357andCan Bölük d30dc78409 fix(coding-agent): clean up ephemeral irc reply turn
Three coordinated tweaks in runEphemeralTurn and the supporting
#buildEphemeralSnapshot so IRC reply text stops leaking tool-call
markup, duplicating verbatim, and breaking DeepSeek-class encoders:

- Drop the recipient's tools array entirely instead of relying on
  toolChoice:"none" (not every backend enforces it). The model now has
  no tool surface to emit so leaked function_call / DSML markup stops.
- Preserve thinking content blocks when snapshotting the in-flight
  streaming assistant message so the openai-completions encoder can
  re-emit reasoning_content for DeepSeek-routed recipients (10 reports
  of HTTP 400 "'reasoning_content' in thinking mode must be passed
  back").
- Collapse consecutive duplicate sentences in replyText and cap reply
  length so a looping recipient does not spam the IRC channel with the
  same line repeated N times.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 965bd095a5 fix(coding-agent): keep completed todo tasks visible for the full turn
The 60s autoclear was mutating canonical #todoPhases via setTimeout, so
earlier completions vanished from the model's view of phase progress.
Default delay bumped well above any plausible turn duration and a
dedup helper added so the canonical list remains intact until the next
explicit prompt boundary.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 3e567b1852 fix(coding-agent): stop dropping rewind checkpoint on every aborted message
The unconditional clear of #checkpointState on stopReason==="aborted"
fired on user interrupts, TTSR rule injection, streaming-edit guards,
plan-compact, and auto-compaction, silently dropping the user's
checkpoint with no signal to the model. Downstream #applyRewind already
tolerates message-count drift via its safeCount clamp, so the clear is
safe to remove. Accounts for 100% of rewind tool grievances.
2026-05-19 19:24:16 +09:00
Can Bölük 899983859e Merge remote-tracking branch 'origin/main' 2026-05-19 18:18:34 +09:00
can1357 94803877bd fix(coding-agent): fixed Anthropic fast-mode detection and scoped fast-mode icon
- Expanded `isAnthropicFastModeUnsupportedError` to treat 429 `rate_limit_error` responses mentioning fast mode as unsupported alongside 400 `invalid_request_error` speed-rejection cases.
- Added tests for unsupported-fast-mode detection covering 400, 429, and unrelated error payloads.
- Added `AgentSession.isFastModeActive()` with provider-scoped resolution and switched status-line rendering to use it for the fast-mode icon.
2026-05-19 18:18:26 +09:00
Can BölükandGitHub d80b9ca084 Merge branch 'main' into fix/acp-bash-permission-shape 2026-05-19 18:13:40 +09:00
can1357 7e93d9b79c feat(ai,coding-agent): add scoped service tiers (claude-only, openai-only)
Two new `ServiceTier` values let users target priority/fast mode at one
provider family without paying premium costs on the other when switching
models mid-session:

- `"openai-only"` → resolves to `"priority"` on `openai` and
  `openai-codex`; `undefined` everywhere else.
- `"claude-only"` → resolves to `"priority"` on direct `anthropic`;
  `undefined` on Bedrock/Vertex Claude and elsewhere.

Implementation centers on a new `resolveServiceTier(serviceTier, provider)`
helper exported from `@oh-my-pi/pi-ai`. The three OpenAI providers and the
Anthropic provider all route through it, replacing the previous
`shouldSendServiceTier` type-guard pattern (which couldn't survive scoped
values — the input variable's literal type stops matching the wire type
once scopes are introduced). `shouldSendServiceTier` is kept as a plain
boolean for external callers but no longer narrows the input.

`getPriorityPremiumRequests` is reworked: it now counts Anthropic +
`"priority"` (fast mode) as one premium request — the original PR
introduced the realization but didn't update billing — and continues to
ignore providers that silently drop the field on the wire.

User-facing:
- `serviceTier` setting enum gains `"openai-only"` and `"claude-only"`
  with clear UI descriptions.
- `/fast on` still sets the unscoped `"priority"`, but `/fast status`
  and `isFastModeEnabled()` now report `on` for any priority-granting
  tier (including scoped values). `/fast off` clears to `undefined`
  regardless of scope.
- The Anthropic auto-fallback listener and re-arm clearing both cover
  `"priority"` and `"claude-only"` (the two values that grant priority
  on Anthropic). `"openai-only"` doesn't trigger the anthropic
  fallback even if the user is on an Anthropic model — by design.

Tests cover all four resolver branches (unscoped passthrough, openai-only
match/miss, claude-only match/miss), Anthropic provider's wire `speed`
field under each scope, and updated premium accounting.
2026-05-19 18:06:00 +09:00
can1357 250e55283e refactor(ai,coding-agent): unify fast mode under serviceTier
Replaces the parallel `speed` knob with the existing `serviceTier`
concept. The anthropic-messages provider now realizes
`serviceTier: "priority"` by setting `speed: "fast"` on the wire and
appending the `fast-mode-2026-02-01` beta header; other providers
continue to pass `service_tier` through natively or ignore it.

User-facing impact:
- `/fast` no longer dispatches on model.api. It just toggles
  `serviceTier: "priority"`. Anthropic-specific translation lives
  entirely in the provider.
- Anthropic auto-fallback marker is now the generic `"priority"`
  identifier in `AssistantMessage.disabledFeatures` instead of
  `"anthropic.fast_mode"`.
- New `clearAnthropicFastModeFallback(providerSessionState)` export is
  invoked from `AgentSession.setServiceTier` when transitioning into
  `"priority"`, so re-running `/fast on` after the provider
  auto-disabled fast mode actually re-arms the next request instead of
  silently no-oping.

Provider-side cleanups:
- Tightened cast site (`ParamsWithSpeed` alias) for the typed
  `speed: "fast"` injection.
- Widened the rejection matcher (`\bspeed\b` + `not support`) so
  phrasing drift ("is not supported" vs "does not support", quoted vs
  backticked) doesn't break the fallback.

Dropped from the PR:
- `Agent.speed` / `AgentOptions.speed` / `SimpleStreamOptions.speed`
  fields.
- `SpeedChangeEntry` and `appendSpeedChange` from the session entry
  schema; service-tier change entries already cover this.
- `AgentSession.setSpeed` / `.speed` and the previousSpeed
  capture/restore in `switchSession` — collapsed back into
  `setServiceTier` + previousServiceTier, which now covers the rollback
  too.
2026-05-19 17:55:44 +09:00
jiwangyihao 0820982b6a fix(acp): include execute metadata in bash permissions 2026-05-19 16:41:05 +08:00
Lucas Szwarcberg d0efcea5ad feat(ai,coding-agent): added Anthropic fast mode with auto-fallback
Wires `speed: "fast"` and the `fast-mode-2026-02-01` beta into the
Anthropic provider, plumbs a matching `speed` option through
`SimpleStreamOptions` and the Agent, and teaches `/fast` to dispatch
on the active model's API (Anthropic -> speed=fast, OpenAI -> existing
serviceTier=priority path). Server is the authority on which models
support fast mode.

When the server rejects an unsupported model, the provider mirrors the
strict-tools fallback: drops the field, retries the same turn
transparently, persists the disable via `providerSessionState`, and
surfaces the action through the new `AssistantMessage.disabledFeatures`
marker so the session can sync the toggle off and warn the user.
2026-05-18 11:48:40 -07:00
can1357 bfae4d46c3 fix(coding-agent): tracked acp tool args by session for replay
- Tracked ACP tool-call inputs per session and replayed them via `toolArgsById`/`getToolArgs` plumbing.
- Merged ACP tool execution end content from start and result events so command output replay preserves original args.
- Scoped ACP async-job draining by session `ownerId` and `agentId` with in-flight tracking and permission-gated deferred turns.
- Refactored compaction telemetry and async tests with per-test telemetry setup and asynchronous teardown resets.
2026-05-17 13:15:07 +02:00
Can BölükandGitHub 34ce96e42f Merge pull request #1138 from jiwangyihao/acp-autonomous-continuation
fix(coding-agent): keep ACP async continuations owned
2026-05-17 13:12:15 +02:00
Can BölükandGitHub b39c8c8460 Merge pull request #1134 from jiwangyihao/fix/acp-zed-permission-gate
fix(coding-agent): repair ACP permission flow for file edits
2026-05-17 13:12:07 +02:00
jiwangyihao 05e1e702dd fix(coding-agent): keep ACP async continuations owned 2026-05-17 15:30:09 +08:00
can1357 8f204539b8 fix(coding-agent): deferred agent_end emission until prompt unwinds
- Held wire-level agent_end until #promptInFlightCount drops to 0, preventing AgentBusyError when subscribers fire the next prompt synchronously from agent_end.
- Added #pendingAgentEndEmit field and #flushPendingAgentEnd(), called from #endInFlight and #resetInFlight.
- Added regression test covering re-entrant prompt() from agent_end listener.
2026-05-17 08:53:41 +02:00
jiwangyihao cb7d30a437 Merge remote-tracking branch 'origin/main' into fix/acp-zed-permission-gate 2026-05-17 11:44:41 +08:00
can1357 2155b8e020 perf: replaced WeakMap caches with symbol-keyed properties
- Migrated per-object caches (chat/tool starts, model fingerprints, validation contexts, provider indexes, render IDs) from WeakMap to Symbol-keyed properties on the objects themselves.
- Rewrote SSE debug tee as a single-pass inline parser, eliminating the body.tee() + readSseEvents re-parse pipeline.
- Refactored MockModel from a factory function + external WeakMap state into a self-contained class.
- Added FIFO memoization caches for heuristic candidate expansion and namespace suffix lookups.
2026-05-17 03:47:45 +02:00
jiwangyihao ef2d536b96 fix(coding-agent): 修复 ACP 文件编辑权限请求 2026-05-17 09:40:50 +08:00
can1357 484fca9c01 feat: added auth-gateway usage cache with single-flight 15s ttl fallback
- Added AbortSignal propagation and timeout-race handling for broker health, usage, refresh, and snapshot calls.
- Added single-flight usage-report caching with 15s TTL, per-caller abort races, and null-on-fail fallback.
- Expanded provider schemas and parse/build logic for cache metadata, headers, stop controls, and image/file content.
- Hardened auth flows by rejecting refresh sentinels and using timing-safe bearer-token comparisons.
2026-05-17 01:10:25 +02:00
can1357 7ea9e16408 feat(coding-agent): changed TTSR non-interrupt tool matches to fold into toolResult
- Non-interrupting tool-source TTSR matches now prepend a system-reminder to the matched tool's `toolResult` content instead of queuing a loop-wide deferred follow-up turn.
- Text/thinking source matches retain the previous deferred-injection behavior.
- Added deduplication so one rule attaches to exactly one sibling tool call per batch.
- Stale per-tool injections are cleared on abort/error before tools produce results.
2026-05-16 20:15:53 +02:00
can1357 32453aaff0 feat(agent): added AgentTelemetry across compaction and branch-summary
- Added optional AgentTelemetry to summary, handoff, branch-summary, and compact option types.
- Replaced one-shot `completeSimple` usage with `instrumentedCompleteSimple` across compaction, summary, and branch-summary calls and passed `oneshotKind`.
- Added `PiGenAIAttr.OneshotKind`, `InstrumentedChatSpanOptions`, and response-header forwarding in telemetry span lifecycle.
- Added `resolveTelemetry` propagation in coding-agent session and inspect-image paths to pass request-scoped telemetry.
- Added compaction telemetry test harness and span assertions for success, no-telemetry, and error cases.
2026-05-16 18:03:07 +02:00
Gerben Meijer 694f5e9a54 Refresh SSH hosts without restart 2026-05-16 00:20:00 +02:00
can1357 8b1364d4c2 feat(coding-agent): implemented one-shot generateHandoff in coding-agent
- Replaced event-driven handoff with one-shot `generateHandoff(...)` via `completeSimple`.
- Added cancellable `/handoff` command handling with a loader and Escape-to-abort flow.
- Removed legacy `compaction/handoff.ts` exports and added `generateHandoff(messages, model, apiKey, options)`.
- Fixed pre-cancelled handoff behavior to return `Handoff cancelled` and propagate abort signals.
- Updated handoff tests/mocks to assert `generateHandoff` invocation details and `AgentSession.handoff()` options.
2026-05-15 18:49:53 +02:00
can1357 e1aaf78874 refactor(compaction): moved compaction APIs to @oh-my-pi/pi-agent-core
- Relocated compaction, branch-summarization, pruning, and utils from coding-agent to packages/agent/src/compaction.
- Moved OpenAI remote compaction helpers from packages/ai to the new compaction module.
- Added handoff.ts with extractHandoffDocument, createHandoffContext, and renderHandoffPrompt helpers.
- Exposed new entries.ts with standalone SessionEntry types so coding-agent no longer owns them.
2026-05-15 18:31:12 +02:00
can1357 933058a241 feat(goals): added per-session goal mode with token budget tracking
- Added GoalRuntime with wall-clock and token accounting, budget steering, and lifecycle operations (create, pause, resume, drop, complete).
- Exposed goal tool as a hidden agent tool, activated only when goal mode is enabled.
- Integrated goal continuation loop in InteractiveMode with auto-submit between turns.
- Added status line segment and theme icons for goal mode state.
2026-05-14 06:40:41 +02:00
can1357 ef5cbef51f feat(coding-agent): added resolve-based plan approval flow in coding-agent
- Removed ExitPlanModeTool and deleted exit-plan-mode docs/tests, dropping the old approval contract outputs.
- Replaced plan-mode approval flow from exit_plan_mode to resolve across session, SDK, controllers, and discovery.
- Added standing resolve handler accessors and updated resolve routing for queued or standing approval handlers.
- Added PlanApprovalDetails and enforced normalized, validated approval titles with readable plan-file requirements.
- Extended resolve schema and invocation signatures with optional extra metadata and reason trimming behavior updates.
- Updated plan and resolve prompts and changelog guidance to require resolve action, reason, and extra.title for apply/discard.
2026-05-14 05:33:30 +02:00
Can BölükandGitHub 8f1d98fa38 Merge branch 'main' into fix/skill-chip-and-silent-abort 2026-05-14 04:51:41 +02:00
Can BölükandGitHub 3ad9255b18 Merge branch 'main' into dmarsh/acp-thinking-level-push 2026-05-14 04:43:55 +02:00
Can BölükandGitHub 38255a4e6e Merge pull request #1062 from enieuwy/fix/copy-handoff-context
Fix /copy fallback for handoff context
2026-05-14 04:42:53 +02:00
can1357 f1f6516056 refactor: reorganized exports and removed obsolete helper branches
- Removed export leakage by demoting many helper and const symbols to module-local scope.
- Renamed underscore-prefixed internals and cache fields, then updated related references and `satisfies never` checks.
- Deleted obsolete logic branches and helpers, including harmony-stream interruption flow and unused benchmark runtime helpers.
- Updated Biome config and manifests by broadening lint coverage and removing an unused `@napi-rs/cli` dev dependency.
- Adjusted tests and utilities to use renamed test helpers and remove redundant private test-only helpers/locals.
2026-05-14 04:36:19 +02:00
enieuwy fa1d83e527 Fix copy fallback for handoff context 2026-05-14 09:41:06 +08:00