Commit Graph
6360 Commits
Author SHA1 Message Date
roboompandcan1357 7d3476216a fix(ai): dropped nanogpt :tools route on deepseek
The :tools model suffix engages NanoGPT's server-side tool-call parser,
which 502s with code malformed_tool_call on complex DeepSeek payloads
(observed reliably on todo_write). The default route forwards
delta.content (including DSML envelope leaks) which our StreamMarkupHealing
already heals into a structured tool call.

The DSML allowlist still covers nanogpt and the parallel-index fix
remains; only the :tools suffix is removed.

Fixes #1488
2026-05-29 13:45:40 +02:00
can1357 1fe843de2e fix(agent): handled skipped tool calls for non-toolUse assistant turns
- Updated the agent loop to execute tool calls only when the assistant stop reason was `toolUse`.
- Added skipped placeholder `tool_result` messages for leftover `toolCall` blocks when a turn ended without `toolUse`.
- Promoted OpenAI/Ollama `stop` tool-call turns to `toolUse` and stripped thinking signatures on abandoned tool-use turns during message transforms.
2026-05-29 13:31:37 +02:00
can1357 c5e74952bf feat(ai): added antml changelog note and removed antml healing logic
- Added an Unreleased `Removed` changelog note for antml:function_calls and antml:thinking parsing.
- Removed antml from stream-markup healing pattern selection and event dispatch flow.
- Deleted ANTML parser state, regex constants, and antml leak-check logic from stream-markup-healing.
- Removed ANTML healing tests for function-call/thinking patterns and OpenAI-completions output mapping.
2026-05-29 12:55:28 +02:00
can1357 729836f226 fix(tui): added a historyRebuild render intent to clear
- Added a `historyRebuild` render intent to clear viewport and scrollback and emit a full repaint when geometry change invalidated terminal history.
- Updated render planning so width and height changes now rebuild native history immediately, while non-size content-only shrink updates only repaint the viewport to avoid yanking users in existing scrollback.
2026-05-29 12:42:43 +02:00
roboompandcan1357 7b1bcfd13d fix(ai): preserved indexed parallel tool-call deltas
Tracked OpenAI-compatible streaming tool calls by provider index so parallel NanoGPT read calls keep their argument deltas attached to the matching tool-call block instead of falling through to the most recently opened call.

Added a NanoGPT DeepSeek regression covering two parallel read calls whose argument chunks arrive by index after the start chunk.

Fixes #1488
2026-05-29 12:31:22 +02:00
roboompandcan1357 5f58979d1d fix(ai): healed nanogpt deepseek dsml tool-call leaks
NanoGPT-hosted DeepSeek models (e.g. `nanogpt/deepseek/deepseek-v4-pro`
with reasoning enabled) emit `<|DSML|tool_calls>` envelopes inside
`delta.content` rather than the structured `tool_calls` array. The
healing pass that turns those leaks into real tool calls only engaged
when `modelMayLeakDsmlToolCalls` saw a known DeepSeek-hosting provider
in its allowlist; NanoGPT was missing, so the markup fell through as
visible text and the turn failed with malformed tool-call data.

Add `nanogpt` to the allowlist so the existing dsml grammar parses
the envelope into a structured tool call, mirroring `deepseek`,
`ollama`, `openrouter`, etc. Covered by a new repro test that
streams the reporter's verbatim DSML leak through the NanoGPT model.

Fixes #1488
2026-05-29 12:24:54 +02:00
can1357 6a68b12f4b Merge remote-tracking branch 'origin/farm/951a0583/extension-package-discovery' 2026-05-29 12:21:50 +02:00
can1357 bb1cb72fea Merge remote-tracking branch 'origin/farm/48457ba2/fix-zai-glm-plan-stream-stall' 2026-05-29 12:21:24 +02:00
can1357 f852d8763f Merge remote-tracking branch 'H4vC/main' 2026-05-29 12:21:11 +02:00
can1357 ea9a33a04a feat(hashline): implemented InMemorySnapshotStore snapshot tag merging
- Coalesced overlapping and abutting same-path reads in InMemorySnapshotStore into one existing tag.
- Folded disjoint but consistent reads into a single SparseSnapshot tag when their shared lines matched.
- Minted a new InMemorySnapshotStore tag when shared lines disagreed, treating the view as a changed file.
2026-05-29 12:20:16 +02:00
roboomp 4d108c1951 fix(plugins): enumerate linked plugins for sub-discovery
PluginManager.link symlinks the package into <plugins>/node_modules
and records it in omp-plugins.lock.json, but never writes to
<plugins>/package.json#dependencies. getEnabledPlugins iterated only
the dependency map, so the documented `omp install ./local-extension`
workflow (delegated to plugin link) succeeded but its sibling skills/,
hooks/, tools/, etc. stayed invisible after install.

Iterate the union of package.json#dependencies and
omp-plugins.lock.json#plugins so symlinked-only packages surface
alongside npm/marketplace installs. Lockfile entries whose
node_modules tree has since been deleted (stale link) are skipped
silently. Linked-only setups with no <plugins>/package.json at all
now work too.

Per-PR review feedback: https://github.com/can1357/oh-my-pi/pull/1498
2026-05-29 06:34:10 +00:00
roboomp bdce9cf068 feat(discovery): scan installed plugin packages for sub-discovery
Marketplace and `omp plugin link` installs write to
`<plugins>/node_modules/` rather than to `extensions:` in settings,
so the original PR still missed their sibling skills/, hooks/,
tools/, commands/, rules/, prompts/, .mcp.json sub-trees. Wire
listOmpExtensionRoots to enumerate getEnabledPlugins(cwd, { home })
in addition to CLI-injected and settings-driven roots.

Adds an optional { home } parameter to getEnabledPlugins so the
discovery loader can pass through LoadContext.home for tempdir-rooted
tests. The getPluginsNodeModules/getPluginsPackageJson/
getPluginsLockfile helpers gain the same optional home overload so
they mirror getPluginsDir.

Per-PR review feedback: https://github.com/can1357/oh-my-pi/pull/1498
2026-05-29 06:28:33 +00:00
roboomp db525316ab fix(discovery): wire extension package sub-dirs into discovery + add top-level install command
Bug 1: capability loaders in src/discovery/builtin.ts only walked
.omp/ and ~/.omp/agent/, so extension packages registered via
extensions: in settings or --extension on the CLI shipped their
skills/, hooks/pre|post/, tools/, commands/, rules/, prompts/, and
.mcp.json silently — the docs at omp.sh/docs/extension-authoring
advertise the opposite. Add a new omp-plugins discovery provider that
scans every configured extension package directory for those
sub-trees, plus a small omp-extension-roots helper that resolves the
union of settings-driven and CLI-injected roots. main.ts injects CLI
extension paths via injectOmpExtensionCliRoots before any capability
load.

Bug 2: install was never registered as a top-level subcommand, so
`omp install ./my-extension` was rewritten to `launch install
./my-extension` and forwarded to the LLM as an initial prompt. Add a
top-level install command that routes local paths to plugin link and
remote specs to plugin install. Extract the command table into
src/cli-commands.ts so tests can introspect registered subcommands
without triggering cli.ts's top-level await.

Fixes #1496
2026-05-29 06:16:32 +00:00
roboomp 7a1b164a9c fix(ai): used zhipu coding plan endpoint
Updated zhipu-coding-plan discovery and credential validation to use the dedicated Coding Plan API base URL instead of the general BigModel endpoint.

Added regression coverage for the default discovery URL.

Fixes #1494
2026-05-29 06:06:58 +00:00
roboomp b7f466aa3b docs(ai): moved glm changelog entry to unreleased 2026-05-29 05:57:25 +00:00
roboomp 8b19a9c292 fix(ai): widened glm coding-plan stream watchdog
Raised the default OpenAI-compatible stream idle floor for slow GLM-5.x coding-plan endpoints and taught the OpenAI timeout helper to honor provider fallbacks.

Added regression coverage for OpenAI timeout fallback precedence and GLM coding-plan fallback selection.

Fixes #1494
2026-05-29 05:54:22 +00:00
can1357 e707b90652 chore: bump version to 15.5.11 2026-05-29 07:19:54 +02:00
can1357 4b96071dc7 feat(ai): added Anthropic per-model mid-conversation system-role map
- Added AnthropicCompat.supportsMidConversationSystem and AnthropicMessageParam system-role support for per-model control.
- Added supportsMidConversationSystemMessages(modelId) to return false on unknown models and true only for opus >=4.8.
- Updated convertAnthropicMessages/buildParams to map eligible developer turns to system role and keep unsupported turns as user.
- Added tests and fixtures for mid-conversation handling and documented `claude-opus-4-8` Bedrock metadata in changelog.
2026-05-29 07:19:11 +02:00
can1357 f874837d9c feat(coding-agent): added ultrathink keyword detection and prompt notice injection
- Added a new ultrathink mode module with standalone, case-insensitive detection, rainbow editor highlighting, and a hidden notice payload.
- Updated `CustomEditor` and the shared TUI `Editor` to support optional zero-width text decoration and apply the `ultrathink` styling during input rendering.
- Extended `AgentSession` prompt handling to append the hidden ultrathink notice after user turns in both streaming and non-streaming message flows, excluding synthetic messages.
2026-05-29 07:12:43 +02:00
can1357 625c8b1992 test(ai): updated tests for model metadata and auth token fallback
- Mocked the Vertex stream E2E test to override the home directory and clear GOOGLE_APPLICATION_CREDENTIALS so token resolution uses metadata credentials instead of local ADC files.
- Updated wafer and model-registry test expectations to match current model metadata values (Qwen3.7 Max and claude-opus-4-8).
2026-05-29 06:56:29 +02:00
can1357 037bf15b53 feat(hashline): distinguished mismatch diagnostics for drifted vs unrecognized hashes
- Added a `hashRecognized` field to `MismatchDetails` and `MismatchError`, defaulting it to `true` for compatibility.
- Updated stale mismatch rejection messaging to distinguish drifted hashes from session-absent hashes with explicit guidance.
- Propagated `hashRecognized: snapshot !== null` in `Patcher` and added tests for both mismatch branches.
2026-05-29 06:42:47 +02:00
can1357 ab5029d188 feat(ai): added Opus4.8 metadata and mapped xhigh effort tiers
- Added Opus 4.8 metadata and expanded provider entries, including Bedrock and other model variants.
- Updated `models.json` with additional Claude, Grok, Gemini, and Qwen entries carrying reasoning or image support.
- Adjusted Anthropic effort mapping for Opus 4.7+ to a five-tier scale and cached `requireSupportedEffort` results.
- Adjusted xhigh handling so legacy models now map to max and Opus 4.7+ map to low/med/high/xhigh/max.
- Updated thinking and alignment tests to expect revised xhigh/max mappings for opus47 and legacy models.
2026-05-29 06:42:47 +02:00
roboompandcan1357 e33a39d766 style: bun run fix 2026-05-29 06:42:47 +02:00
roboompandcan1357 82f5db2fbc fix(coding-agent): clamped memory phase1/phase2 reasoning effort to the model's supported range
The memory pipeline hardcoded `Effort.Low` (stage1) and `Effort.Medium` (phase2
consolidation) when calling `completeSimple`. On models whose supported efforts
exclude those levels (e.g. `deepseek/deepseek-v4-pro` → [high, xhigh]),
`completeSimple → mapOptionsForApi → resolveOpenAiReasoningEffort →
requireSupportedEffort` threw "Thinking effort low is not supported by
<provider>/<model>" and every stage1 job was recorded as failed, blocking phase2
and producing no memory artifacts.

Route both call sites through `clampThinkingLevelForModel(model, requested)` —
the same helper already used by compaction (#1182). For `[high, xhigh]` both
`low` and `medium` lift to `high`; non-reasoning models continue to receive
`undefined`, preserving prior behaviour.

Fixes #1480
2026-05-29 06:42:47 +02:00
roboompandcan1357 437b6524cd fix(cli): restored package resolver for non-compiled pi root remaps
Limited bunfs package-root overrides to compiled-binary mode so non-compiled installs (monorepo, source-link, node_modules) keep resolving legacy pi roots through Bun's package resolver instead of a hardcoded source-tree path.

Refs #1474
2026-05-29 06:42:47 +02:00
roboompandcan1357 349fb51ddb fix(cli): preserved legacy peer fallback for subpaths
Retried original legacy specifiers after canonical peer fallback fails so direct plugin imports with only legacy-scoped peer dependencies continue to load.
2026-05-29 06:42:46 +02:00
roboompandcan1357 564b6d0f22 fix(cli): routed legacy pi-coding-agent imports through a sibling shim
Listing the coding-agent's own ./src/index.ts as a bun --compile extra entrypoint silently breaks the CLI binary startup. Added a dedicated legacy-pi-coding-agent-shim.ts that re-exports the canonical barrel, registered the shim instead of the package index, and updated the compat resolver to point pi-coding-agent at the shim path.
2026-05-29 06:42:46 +02:00
roboompandcan1357 92a2fd5b8f docs(changelog): moved legacy pi fix to unreleased
Moved the legacy pi compat entry out of the released 15.5.8 notes and into the Unreleased section.
2026-05-29 06:42:46 +02:00
roboompandcan1357 82008e4f38 fix(cli): restored legacy pi package root remaps
Added bundled root overrides for legacy pi package imports in compiled binaries and corrected fallback resolution to use canonical @oh-my-pi specifiers.

Fixes #1474
2026-05-29 06:42:46 +02:00
can1357 11da79a6bf fix(read): fixed column truncation mutating snapshot with display content
- Column truncation is now applied to a cloned array so `collectedLines` retains on-disk content for snapshot recording.
- Snapshots bound to hashline TAGs now hold the original file text, preventing hash-mismatch failures on subsequent edits to files with long lines.
- Added regression tests covering full-file, range, multi-range reads and a live edit-after-read scenario.
2026-05-29 06:42:46 +02:00
can1357 31f3fbda61 feat(write): added snapshot header to write tool output in hashline mode
- Prepended `¶path#TAG` hashline header to plain file, ACP-bridge, and conflict resolution write results.
- Bulk conflict resolutions emit a trailing `Snapshots:` block with one header per written file.
- Suppressed when hashline display mode is disabled or for archive/SQLite/internal-URL targets.
- Added tests covering header presence, patcher usability, and disabled-mode suppression.
2026-05-29 06:42:46 +02:00
can1357 cacf996f90 feat(session): added sql session storage with queue-backed async writes
- Added `SqlSessionStorage` with SQL row persistence, optional schema bootstrap, and async queue-backed writes.
- Added adapter inference with postgres/mysql/sqlite query generation and in-memory `#mirror` with monotonic mtime sync.
- Added `SqlSessionStorage` export in package entry and Unreleased changelog notes for SQL session persistence.
- Added SQLite/session-manager tests covering helper creation, write/read/list/opening, and delete/rename error paths.
2026-05-29 06:42:46 +02:00
can1357 47bd4fd766 feat(session): added RedisSessionStorage with redis-backed session persistence
- Added RedisSessionStorage with Redis-backed session JSONL persistence and storage options.
- Added create/refresh/list/read behavior with in-memory mirror, SCAN hydration, and monotonic mtime tracking.
- Added package exports for SessionStorage backends and a Redis session SDK example with usage guidance.
- Added in-memory fake Redis tests covering persistence restore, session listing, rename, and error-injection paths.
2026-05-29 06:42:45 +02:00
roboomp e2ddf1a0d1 fix(ai): generalize reasoning_content replay to all opencode models
@yofriadi flagged that DeepSeek V4, GLM-5.x, Qwen3.x, MiMo, and MiniMax
on opencode-go front the same Zen gateway as Kimi (https://opencode.ai/go).
The thinking-state invariant — reasoning_content required on assistant
tool-call history when thinking is enabled, rejected when off — is
gateway-wide, not Kimi-specific.

Drop the `isKimiModelId` gate from the buildParams override so every
opencode request in thinking mode flips
requiresReasoningContentForToolCalls=true (with
allowsSyntheticReasoningContentForToolCalls=false and
reasoningContentField="reasoning_content" pinned the same way). The
existing #1071 guard for thinking-off and the
disableReasoningOnForcedToolChoice guard remain intact, so non-thinking
and forced-tool turns never inject the field.

Added parametrized regression tests covering GLM-5.1, Qwen3.7 Max, and
MiMo-V2 Pro through `streamOpenAICompletions` + `onPayload` — three
distinct thinkingFormat paths ("openai", "qwen", "openai") — to
prove the override fires regardless of model family. Expanded the
CHANGELOG entry to list every catalog model now covered.
2026-05-28 18:56:23 +00:00
roboomp 4b29b1229b style: bun run fix 2026-05-28 18:48:56 +00:00
roboomp 0b1d4b1e28 test(ai): cover opencode-go deepseek-v4 reasoning_content replay
@yofriadi reports the same OpenCode Zen 'reasoning_content is missing'
400 on `opencode-go/deepseek-v4-flash` and `deepseek-v4-pro`. The
gateway is the same Zen instance and the wire-body invariant matches:
the streamed-signature path in convertMessages previously emitted both
`reasoning` and `reasoning_content` on DeepSeek turns, which the
strict schema flags exactly like the Kimi case.

The line-1488 fix from 4215228b8 already coerces the replay onto the
configured `reasoningContentField` whenever
`allowsSyntheticReasoningContentForToolCalls=false` — DeepSeek family
sets that flag — so deepseek-v4 payloads now carry only
`reasoning_content`. Add a streamOpenAICompletions + onPayload
regression test that pins the shape.
2026-05-28 18:48:50 +00:00
roboomp 707a8fbdc5 style: bun run fix 2026-05-28 16:47:07 +00:00
roboomp 4215228b81 fix(ai): coerce opencode kimi reasoning replay onto reasoning_content
The opencode-kimi thinking-mode override flipped
`requiresReasoningContentForToolCalls` on but left the rest of compat
at its default: `allowsSyntheticReasoningContentForToolCalls=true` and
the streamed-signature path in `convertMessages` echoed whichever
recognized field the upstream emitted. Opencode Kimi streams reasoning
under `reasoning`, so a follow-up replay landed `reasoning` on the
assistant message and left `reasoning_content` empty — the gateway
still 400s with 'reasoning_content is missing in assistant tool call
message at index N'.

Force `reasoning_content` as the wire field for this override:

- `buildParams` now also sets
  `allowsSyntheticReasoningContentForToolCalls=false` and
  `reasoningContentField="reasoning_content"` on the same gated
  branch (kimi + opencode + thinking-on + not forced-tool).

- `convertMessages` thinking-block branch now respects
  `allowsSyntheticReasoningContentForToolCalls`: when false, replay
  always uses the configured `reasoningContentField` instead of the
  streamed signature, so we never simultaneously write to both
  `reasoning` and `reasoning_content`. DeepSeek already runs through
  the same code with `allowsSynthetic=false` and existing tests
  continue to pass under the cleaner output.

Updated the #1484 regression test to use the upstream's actual
`thinkingSignature: "reasoning"` shape and to additionally assert
that `reasoning` is absent from the wire body so a future regression
to dual-key emission would fail.
2026-05-28 16:47:01 +00:00
roboomp f8ab2eaf78 style: bun run fix 2026-05-28 16:39:44 +00:00
roboomp b5ea19a156 fix(ai): suppress opencode-kimi reasoning_content replay on forced-tool turns
When OpenCode Kimi receives a forced `tool_choice`, the existing
`disableReasoningOnForcedToolChoice` guard at the bottom of
`buildParams` strips `reasoning_effort` (and sets `thinking: disabled`
for zai-format paths) from the wire body so Kimi does not 400 with
'tool_choice specified is incompatible with thinking enabled'. The
per-request reasoning_content override added for #1484 ran earlier in
`buildParams` and ignored that suppression, so the resulting payload
combined a thinking-disabled request with replayed reasoning_content on
prior assistant tool-call turns — reviving the #1071 'Extra inputs are
not permitted' failure.

Mirror the suppression in the override: skip flipping
`requiresReasoningContentForToolCalls` whenever
`compat.disableReasoningOnForcedToolChoice` would erase thinking on
this turn. New regression test exercises the forced-tool path through
`streamOpenAICompletions` + `onPayload` and asserts both the absence
of `reasoning_content` on the assistant message and the absence of
`reasoning_effort` on the request body.
2026-05-28 16:39:33 +00:00
roboomp 3b3a78fce2 fix(ai): replay reasoning_content for opencode kimi when thinking is on
OpenCode Zen's Kimi gateway gates reasoning_content on the request's
thinking state: it 400s with 'Extra inputs are not permitted' when
thinking is off but the field is supplied (#1071), and 400s with
'thinking is enabled but reasoning_content is missing in assistant tool
call message at index N' (#1484) when thinking is on and the field is
absent. Static compat detection from #1071 kept the field off
unconditionally, so reasoning-mode requests now 400 on the follow-up
turn after any tool call.

Override compat.requiresReasoningContentForToolCalls in buildParams when
the request itself is in thinking mode (options.reasoning set,
!options.disableReasoning, model.reasoning true), so prior tool-call
turns replay reasoning_content while thinking-disabled requests keep
the #1071 guard intact. Regression tests exercise both states through
streamOpenAICompletions + onPayload to assert on the wire body.

Fixes #1484
2026-05-28 16:34:48 +00:00
Brit 9cae7b823f fix(tui): refreshed scrollback synchronously 2026-05-28 15:57:04 +02:00
Brit a8dabe2cf8 fix(tui): deferred native scrollback rebuilds 2026-05-28 15:45:33 +02:00
can1357 3f073b82de chore: bump version to 15.5.10 2026-05-28 14:50:02 +02:00
can1357 3327d51b4c fix(pi-natives): coalesced shell pipe output into capped batches
- Changed `bridge_chunks` to drain all currently queued output chunks into one string before invoking the JS callback.
- Added a 64 KiB batch cap with a small initial buffer so each N-API dispatch stays bounded while reducing callback churn from chatty processes.
2026-05-28 14:33:58 +02:00
can1357 5bed80785a feat(coding-agent): added /drop-images support to strip images
- Added `/drop-images` slash command handling for runtime and TUI to drop images and report results.
- Added `stripImagesFromMessage` utilities to remove image blocks from message content and return removal counts.
- Added `AgentSession.dropImages()` to prune image blocks, rewrite history when needed, and rebuild session context.
- Added tests for user, toolResult, fileMention, and assistant image-stripping, placeholders, and zero-removal cases.
2026-05-28 13:03:45 +02:00
can1357 c4f93eca20 fix(agent): patched compaction 401/403 fallback to copy error status
- Centralized compaction stop-reason error throws via createSummarizationError().
- Set compaction thrown errors to copy response.errorStatus into Error.status.
- Expanded compaction auth detection to treat HTTP 401/403 as auth failures with regex fallback preserved.
- Added regression tests for 401/403 status propagation and compaction fallback auth behavior.
- Documented both package fixes in Unreleased Fixed changelog entries.
2026-05-28 12:50:52 +02:00
can1357 1191fdedc0 fix(scripts): added fetch.pruneTags=false to git wrapper to
- Added fetch.pruneTags=false to git wrapper to prevent tag deletion during concurrent maintenance.
- Implemented atomic tag creation and push with retry logic to defend against tags being pruned by background git maintenance processes.
- Changed push strategy to use --atomic flag and retry up to 3 times on refspec mismatch errors.
2026-05-28 12:37:26 +02:00
can1357 eca3a08d25 chore: bump version to 15.5.9 2026-05-28 12:09:01 +02:00
can1357 cc258b1757 feat(natives): added embedded addon tarball extraction in natives
- Added embedded addon tarball output in `embed-native.ts` using `embedded-addons.<platform>.tar.gz` artifacts.
- Added metadata-rich addon types with `size`, `filePath`, and optional `archive` fields.
- Updated extraction to prioritize archive unpacking and skip cached `.node` files when sizes match.
- Added `extractEmbeddedAddonArchive()` with archive parsing and safe validation of archive entry names and kinds.
- Adjusted release profile to disable line-table generation and strip symbols in `Cargo.toml`.
- Added CI-only ELF validation for forbidden sections and regression coverage for issue-823 archive extraction.
2026-05-28 11:48:32 +02:00