Commit Graph

131 Commits

Author SHA1 Message Date
roboomp 7463803c95 fix(extensions): populated runtime mode in context
Expose the Pi-compatible tui, rpc, json, or print host mode to every extension context and cover mode transitions in the runner regression suite.

Fixes #8419
2026-08-13 08:51:05 +00:00
roboomp 4981eba1c2 fix(task): refreshed agent definitions without restart
Published per-cwd discovery snapshots to existing task tools and refreshed them from TUI, ACP, and Agent Control Center reload paths.

Added regressions for existing and future task tools across TUI and ACP reloads.

Fixes #7940
2026-08-07 23:38:25 +02:00
can1357 0060ebacb1 Merge PR #7783: fix(acp): resolve session/load across legacy session directories (@roboomp) 2026-08-07 13:39:53 +02:00
roboomp 07bb0ac51f fix(acp): resolve session/load across legacy session directories
session/load and session/resume resolved a session only within the
directory re-derived from cwd (SessionManager.list(cwd)), so sessions
stored under the legacy/hashed project-directory scheme (17.2.5+,
reverted in #7656) were unreachable and threw "ACP session not found"
despite existing on disk.

#findStoredSession now falls back to a global by-id scan (listAll,
already used by the fork path) when the cwd-scoped lookup misses. The
session id is globally unique and #openStoredSession reopens the file
with the request cwd, so no directory-scheme knowledge is needed.

Fixes #7779
2026-08-06 02:08:49 +00:00
can1357 677b6f10f5 Merge PR #7735: fix(coding-agent): return ToolInfo[] from getAllTools extension API (@roboomp) 2026-08-05 22:15:46 +02:00
roboomp 83496b8211 fix(coding-agent): returned ToolInfo[] from getAllTools extension API
The ExtensionAPI getAllTools() wired to session.getAllToolNames(),
returning bare tool-name strings. Upstream @earendil-works/pi-coding-agent
promises ToolInfo[] with sourceInfo, so extensions loaded through the
legacy-pi shim (e.g. gentle-pi) crashed on t.sourceInfo.source at every
session start.

Added SourceInfo/ToolInfo types plus SessionTools.getAllToolInfos(), which
returns { name, description, parameters, sourceInfo } and classifies each
tool as builtin/mcp/sdk/extension. Rewired every getAllTools action site
(interactive, acp, print/rpc, subagent executor) and the example extension.

Fixes #7732
2026-08-05 15:42:06 +00:00
can1357 e9888367d1 refactor: migrated packages to internal utility modules and removed external dependencies
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
2026-08-05 13:39:09 +02:00
Brent db97103c32 fix(coding-agent): complete usage-aware fallback integration 2026-08-03 16:34:35 +00:00
Márton Danóczy 38f63b792a fix(acp): preserved whitespace-only editor prefill
editor's prefill is the actual document being edited, not a placeholder
like input's — the interactive (hook-editor.ts) and RPC implementations
set it verbatim on any truthy value. Trimming before the presence check
silently dropped whitespace/blank-line prefill content from the ACP
elicitation schema, so a client-side form opened empty and accepting it
could not reproduce the extension's supplied indentation.

Now only a genuinely empty string omits `default`; any other prefill,
including whitespace-only, passes through unchanged.
2026-07-30 22:53:54 +02:00
Márton Danóczy 490bdd3c4b docs(acp): fixed stale editor-stub note in createAcpExtensionUiContext JSDoc
The factory-level doc comment still listed editor among the non-elicitation
surface that 'remains stubbed', contradicting the elicitation bridge added
in ec3144860. Reflows the sentence without changing its meaning otherwise.
2026-07-30 22:53:54 +02:00
Márton Danóczy f62e528042 acp: wire ctx.ui.editor through elicitFromAcpClient
createAcpExtensionUiContext stubbed editor as a hardcoded no-op
(async () => undefined), so free-text elicitation requests from
/review's custom-instructions branch and the ask tool's custom-input
path never reached the client and silently resolved to undefined.

Wire editor through the existing elicitFromAcpClient bridge used by
select/confirm/input, using a {type: "string"} schema with default
set to the prefill text when non-blank.

Verified against a real stdio JSON-RPC transport via acp-probe: the
elicitation/create request now fires with the expected schema and
round-trips the accepted value back to the prompt without hanging.

Adds matching unit test coverage in acp-agent.test.ts mirroring the
existing select/confirm/input bridge tests (prefill->default mapping,
whitespace-prefill omits default, decline/cancel->undefined, no-form
fallback).
2026-07-30 22:53:54 +02:00
can1357 70e6d2c7dc Merge PR #6680: feat(coding-agent): add opt-in max ceiling for auto thinking (@everton-dgn) 2026-07-30 01:48:51 +02:00
Márton Danóczy 0ca0739eeb fix(acp): sync model config option on internal model changes
Zed (and any other ACP client) never learned about a model switch that
happened from inside the agent loop — prewalk hand-offs, retry-fallback,
model cycling — because #pushConfigOptionUpdate was only ever wired to
the client-initiated setSessionConfigOption/setSessionMode RPCs and to
the thinking_level_changed lifetime event. The model itself did switch
correctly (subsequent requests used the new model), but the client's
model picker/status bar kept showing the session's starting model.

#handleLifetimeEvent now also reacts to the model_changed event added
in the previous commit and re-pushes config_option_update. Extend the
existing thinking-only subscription dedupe in setSessionConfigOption to
cover the model config id too, so a client-initiated model change still
produces exactly one notification once the lifetime subscription is
installed.

Regression tests mirror the existing thinking-level coverage:
- 'pushes config_option_update when the model changes internally'
- 'emits a single config_option_update per setSessionConfigOption(model) call'

Verified: bun test test/acp-agent.test.ts (57/57), plus
agent-session-prewalk.test.ts, agent-session-retry-fallback.test.ts,
retry-fallback.test.ts, model-resolver.test.ts, and the other acp-*.test.ts
files all still pass; tsgo --noEmit and biome check clean.

(cherry picked from commit f5c5081088e8cbac2650a9de89049731de1b2777)
2026-07-29 23:08:25 +02:00
roboomp 0c04e86efd fix(acp): kept hub job-wait results visible
Only a peer-scoped wait (from, no ids) is internal messaging; bare and ids waits settle on background-job delivery whose snapshot is the job result.

Fixes #6872
2026-07-28 07:34:49 +00:00
roboomp b38472b111 fix(acp): hid internal hub messages
Prevented internal Hub send, inbox, list, and non-process wait calls from crossing ACP, including xd:// routing and replayed sessions.
Preserved Hub process-control calls.

Fixes #6872
2026-07-28 07:26:52 +00:00
Éverton Toffanetto fbd3ebffc6 feat(coding-agent): add opt-in max ceiling for auto thinking
`max` became a first-class effort tier in d435385a, but the `auto`
classifier prompt still offers only `low|medium|high|xhigh`. On a model
that exposes the tier, `auto` can therefore never reach it — only the
`ultrathink` keyword can, because it bypasses the classifier entirely.

`providers.autoThinkingMaxEffort` (`xhigh` | `max`, default `xhigh`) lifts
that ceiling. Opting in adds `max` to the classifier vocabulary, gated on
the target model actually supporting the tier, and scopes the tie-break
exception to that prompt variant so the default renders byte-for-byte as
before. A classification above the configured ceiling is clamped before
the model clamp, so a hallucinated `max` cannot cross a ceiling the user
did not opt into. The on-device 3-bucket classifier stays capped at
`xhigh`, and the provisional/fallback level still never provisions `max`.

Also corrects the two `Auto-detect per prompt (low-xhigh)` labels and the
stale `xhigh auto ceiling` comment, which the new setting makes wrong.
2026-07-26 03:16:56 -03:00
roboomp 28068f53d3 fix(plan-mode): promoted reviewed plan path into state before refine
handlePlanApproval and the ACP rejection path selected a resolved draft that could differ from PlanModeState.planFilePath but never updated the state, so a refine turn was rebuilt by #buildPlanModeMessage() from the stale path. Both paths now promote the reviewed path into plan-mode state.

Fixes #6569
2026-07-25 01:51:52 +00:00
can1357 366bd6203e Merge PR #6392: feat(coding-agent): add usage-aware model fallback (@eggpeat) 2026-07-24 02:25:35 +02:00
can1357 0689092866 Merge PR #6445: feat(extensions): expose session service tiers (@atyrode) 2026-07-24 02:24:29 +02:00
can1357 9d2456415e fix(acp): propagated initial MCP refresh failure, drained stale chain 2026-07-24 02:24:16 +02:00
Brent 0bfb0bd1e3 feat(coding-agent): add usage-aware model fallback 2026-07-24 02:23:51 +02:00
Alex TYRODE e0928070c2 feat(extensions): expose session service tiers 2026-07-23 21:49:20 +00:00
Baris Demirdelen d4f97d39f0 Fix race condition in the race condition fix 2026-07-23 22:10:15 +02:00
Baris Demirdelen bddbbfd5cf fix(acp): pick up MCP tools that connect after the startup race 2026-07-23 22:10:15 +02:00
can1357 154d4ace9f Merge PR #4448: feat(todo): add blocked status with block/unblock ops (@mattwilkinsonn)
# Conflicts:
#	packages/coding-agent/src/modes/interactive-mode.ts
#	packages/coding-agent/src/prompts/tools/todo.md
2026-07-23 17:32:43 +02:00
can1357 fd54f897f4 merged PR #5419: fix(acp): await teardown on stdio disconnect
# Conflicts:
#	packages/coding-agent/src/modes/acp/acp-mode.ts
2026-07-16 03:50:06 +02:00
can1357 93cc1fed1c merged PR #5417: fix(openai): render native response images
# Conflicts:
#	packages/coding-agent/src/modes/components/chat-transcript-builder.ts
#	packages/coding-agent/test/agent-session-skill-keywords.test.ts
2026-07-16 03:48:21 +02:00
can1357 3601692c8d merged PR #5515: fix(skills): reload runtime skill state 2026-07-16 03:31:59 +02:00
can1357 9afedb591e feat(coding-agent): added opt-in task prewalk and tightened --tools and xdev behavior
- Added a `task.prewalk` option (default `false`), removed default task `prewalk` flags, and updated prewalk resolution so bunded generic task execution only prewalks when explicitly enabled.
- Enforced strict `--tools` validation in CLI parsing, making unknown tool names fail fast with `CliUsageError` instead of being silently filtered.
- Migrated legacy discovery settings (`tools.discoveryMode`, `tools.essentialOverride`, MCP discovery keys) into updated `tools.xdev` handling with preserved explicit override behavior.
- Hardened xdev/ACP execution flow by capping `docsAll` payloads with overflow listing and remapping `xd://` dispatches/approval gating for correct execute/read behavior and reduced duplicate prompts.
2026-07-15 18:39:36 +02:00
can1357 5ff277349c refactor(coding-agent): consolidated tool surface onto xd:// devices and hub
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
2026-07-15 15:16:29 +02:00
roboomp 19674b8dfa fix(skills): reloaded runtime skill state
- Rediscovered enabled skills across TUI, ACP, and RPC plugin reloads.
- Rebuilt skill commands, system prompts, tool snapshots, and skill URL resolution.
- Hot-refreshed managed skills after manage_skill create, update, or delete.

Fixes #4996
2026-07-14 20:01:45 +00:00
roboomp 953859d956 fix(acp): awaited teardown on stdio disconnect
Registered ACP session disposal with postmortem and replaced the hard EOF exit with the awaited graceful shutdown path.

Classified stdio-write EPIPE separately from worker IPC EPIPE so ACP peer loss exits successfully after cleanup.

Fixes #4788
2026-07-14 16:20:48 +00:00
roboomp b6b947bdbe fix(openai): rendered native response images
- Normalized completed image_generation_call results into assistant image blocks.
- Persisted image bytes through the session blob store and rendered them in live, replay, ACP, proxy, telemetry, and HTML paths.
- Added response normalization, persistence, and TUI rendering regressions.

Fixes #4768
2026-07-14 16:15:53 +00:00
can1357 59ecd2a4d8 refactor(coding-agent/modes): added ACP type guards for elicitation narrowing
- Added `isAcceptedElicitation` in the ACP agent to narrow accepted elicitations before accessing response content.
- Added `isFormElicitation` in ACP tests and used it to narrow form-mode requests before assertions.
2026-07-13 18:53:19 +02:00
can1357 54af1c03fd fix(coding-agent): ensured provider errors are surfaced to ACP clients
- Added a fallback to emit error messages during `agent_end` if no error was previously streamed during the turn.
- Added tracking to prevent duplicate error messages when a provider error is successfully delivered during streaming.
- Added a stderr hint for interactive users launching the ACP server directly from a terminal.
2026-07-11 05:47:55 +02:00
can1357 7c560c7151 fix(acp): flushed final assistant text lost to agent_end race
The assistant message_end fan-out is fire-and-forget in the session layer
and can be parked on extension delivery while agent_end is flushed through
#endInFlight, so agent_end can overtake it. #finishPrompt then unsubscribes
the prompt turn and the mapAssistantMessageEnd fallback never runs: an ACP
client that only received agent_thought_chunk updates (thinking streamed,
text arrived only on the trailing message) stays stuck on the thinking
block with no visible answer. On agent_end, emit the last assistant
message's text before resolving the prompt when live-message progress shows
no text was ever delivered, and defer the live-state reset past that flush
so a late message_end cannot resurrect fresh progress and double-emit.

Fixes #4902
2026-07-09 18:36:39 +02:00
can1357 c944870566 fix(coding-agent): implemented pi's ui.addAutocompleteProvider API
Extensions calling ctx.ui.addAutocompleteProvider (e.g. @ff-labs/pi-fff)
crashed at load with 'TypeError: ... is not a function' because omp's
ExtensionAPI.ui omitted pi's autocomplete-provider API; the throw also
aborted the rest of a try/catch-guarded session_start init.

ExtensionUIContext now declares addAutocompleteProvider(factory).
Interactive mode stacks each factory on the built-in editor provider in
registration order, re-applies the stack on every slash-command refresh,
and skips throwing/malformed factories; RPC, ACP, and headless contexts
accept the factory as a no-op, matching upstream pi's RPC behavior.

Fixes #4919
2026-07-09 18:27:23 +02:00
can1357 e429166673 fix(coding-agent): queued extension sendUserMessage as steer while streaming
Extension sendUserMessage() without deliverAs fell through to prompt(),
which throws AgentBusyError during an active stream; the message was
dropped and surfaced as 'Extension sendUserMessage failed'. Route the
omitted-deliverAs path through prompt() with streamingBehavior 'steer'
so streaming queues a steer with normal prompt-flow side effects
(keyword notices, advisor auto-resume reset) and idle still starts a
turn.

ACP skill-command prompts now pass streamingBehavior 'steer'; the RPC
skill fast-path honors the prompt command's streamingBehavior field
(default steer) like the plain-prompt path already did. Documented the
extension-facing delivery semantics.

Synthesized from PR #4942 (prompt-flow steer routing, docs, tests) and
PR #4922 (RPC streamingBehavior threading, steer regression test);
dropped PR #4942's unrelated workflow-notice.md ellipsis churn.

Fixes #4923

Co-authored-by: roboomp <omp@can.ac>
Co-authored-by: metaphorics <metaphorics@users.noreply.github.com>
2026-07-09 18:27:22 +02:00
roboomp a52ed682c7 fix(ai): separated codex orchestration usage
- Added a Usage.orchestration sidecar for provider-side service tokens so Responses/Codex totals and costs stay accurate without inflating visible prompt input/cache buckets.
- Updated Codex/WebSocket usage, session/status aggregates, and usage reporting to preserve orchestration-aware totals.
- Added regressions for OpenAI Responses accounting, Codex WebSocket terminal usage, cost calculation, and session aggregation.

Fixes #4469
2026-07-03 16:44:12 +00:00
Matt Wilkinson 792645e707 feat(todo): add blocked status with block/unblock ops
A `blocked` status (plus `block`/`unblock` ops and an optional blocker
note) for tasks that are open but waiting on something the agent can't act
on — a user decision, another agent, or an external action. Blocked tasks
stay in the tracker but are excluded from the stop-time incomplete-todo
reminder (via the existing pending/in_progress allowlist) and from
auto-promotion. Syncs the mode-layer TodoStatus, the ACP status map/guard,
the markdown markers, and the renderers.

Refs can1357/oh-my-pi#3581
2026-07-03 09:21:51 -04:00
can1357 63b812320d Merge PR #3903: fix(coding-agent): identify user-invoked skills and expose skill directory (@metaphorics)
# Conflicts:
#	packages/coding-agent/src/extensibility/skills.ts
#	packages/coding-agent/src/modes/acp/acp-agent.ts
#	packages/coding-agent/src/modes/rpc/rpc-mode.ts
#	packages/coding-agent/src/modes/skill-command.ts
2026-07-01 22:16:53 +02:00
roboomp 095392d144 fix(tui,coding-agent): preserved draft when accepting mid-prompt /skill: autocomplete
The mid-prompt slash skill autocomplete added in #3654 replaced the
entire editor draft with /skill:<name> on accept so the dispatcher
(which only matched leading /skill:) would still fire. That wiped
every keystroke the user had typed before reaching for the skill.

Insert the /skill:<name> token at the cursor in the TUI editor —
replacing only the partial /sk slash token, leaving prose before and
after intact — and extend the skill-command parser so a /skill:<name>
token surrounded by whitespace is recognized as an invocation too,
with the surrounding prose threaded through to the skill as args.

The parser change is shared across all three dispatch sites
(interactive TUI, ACP, RPC) via a new parseSkillInvocation helper
in extensibility/skills, so the three Map<string,string> /
session.skills lookups stay aligned on the same parse.

Fixes #3913
2026-06-30 16:12:53 +00:00
metaphorics fa64097992 fix(coding-agent): identify user-invoked skills and expose skill directory
User-invoked skills (typed /skill:, steered, follow-up, interrupted/
resumed via compaction, ACP, RPC) only appended a bare "Skill: <path>"
line, so the model neither learned the user had invoked that specific
skill nor where the skill directory was. Relative paths in skill bodies
(scripts/, templates/) could not be resolved.

Route all user-invoked paths through a self-identifying, baseDir-aware
prompt template; keep hidden autoload skills on the minimal non-user
format. Interactive skillCommands now carries the loaded Skill object
instead of a bare path so baseDir flows through without reconstruction.
The invocation kind defaults to "user" to keep buildSkillPromptMessage
source-compatible.

Op: correct
Restores: spec:user-invoked-skill-prompt-self-identifies-and-exposes-skill-directory
2026-06-30 23:11:05 +09:00
can1357 c3f7e849e5 refactor: centralized AI error handling into a dedicated module
- Migrated 288 lines of scattered error classification logic from `utils/error-id.ts` into a cohesive `packages/ai/src/error/` module with 13 specialized submodules covering flags, classes, OAuth, providers, rate-limiting, and finalization.
- Replaced 100+ generic `Error` throws across 60+ provider and registry files with semantic `AIError.*` classes (e.g., `AIError.MissingApiKeyError`, `AIError.OAuthError`, `AIError.ProviderResponseError`), improving error diagnostics and retry logic.
- Consolidated error utility imports from `pi-utils` and scattered classification functions into a single `AIError` namespace, reducing coupling and simplifying error handling across all packages.
2026-06-27 10:44:13 +02:00
roboomp 9d5b1f245d fix(acp): resolved generated image blob refs
Resolved live ACP generate_image payloads through the blob store before emitting image content while keeping rawOutput compact.

Added regression coverage for content[] image blocks and details.images entries without duplicating blob refs as fallback text.

Fixes #3623
2026-06-27 03:46:05 +00:00
can1357 ae1650d689 refactor: renamed search and find tools to grep and glob
- Renamed the `find` and `search` tools to `glob` and `grep` respectively across the codebase to improve command clarity.
- Implemented full-stack support for the renamed tools, including CLI arguments, system prompts, SDK exports, and tool registration.
- Added automated migration logic in `settings` to transform legacy `find` and `search` configuration keys to their new equivalents.
- Updated the `collab-web` renderer registry to ensure backwards compatibility with legacy tool outputs.
2026-06-27 00:57:55 +02:00
can1357 060f4004e7 feat(coding-agent): refactored eval tool to single-step execution
- Transitioned the eval tool from batch multi-cell execution to a single-step input structure with flat parameters.
- Updated core agent logic, UI components, and documentation to support state persistence across incremental eval calls.
- Restricted bash tool capabilities by requiring explicit use of `read` or `find` instead of `ls` or `find`.
- Added support for Ruby and Julia language runtimes to the eval tool and associated web renderers.
2026-06-23 00:59:58 +02:00
roboomp 9a8e625a44 fix(acp): listed local speech models
Added the ACP mobile speech.models.list method so voice settings can fetch static local STT, TTS, and voice catalog options without invoking setup/download paths.

Fixes #3011
2026-06-19 01:19:08 +00:00
can1357 b1c0243bab fix(coding-agent): fixed advisor auto-resume suppression for user interruptions
- Passed USER_INTERRUPT_LABEL through abort paths in collab, ACP, RPC, runtime, and SDK flows.
- Added userInitiated to synthetic continue inputs and session prompt calls.
- Suppressed advisor auto-resume during user aborts and preserved queued concerns.
- Cleared suppression on user prompts and reclaimed parked advisor cards on abort settle.
2026-06-15 20:51:56 +02:00
can1357 e8ef706abf fix: filtered out whitespace-only assistant and thinking blocks from output
- Canonicalized assistant and thinking messages by trimming and collapsing dot text.
- Skipped rendering assistant and thinking blocks when canonicalized content was empty.
- Filtered ACP thinking notifications and session outputs to ignore placeholder content.
- Added canonicalizeMessage tests for undefined, blank, whitespace, and dot-only inputs.
2026-06-15 12:40:00 +02:00