18666 Commits

Author SHA1 Message Date
can1357 0cdd37fc15 feat(pi-natives/tools): implemented utok tokenizer for multiple models
- Replaced the `ctok` implementation with the `utok` universal tokenizer supporting multiple model families and UTF text encodings.
- Added tokenizer support and embedding data for Qwen3, DeepSeek V3, Kimi K2, and GLM-5 model variants.
- Added fixture generation scripts, vocabulary packers, and golden test suites for validating tokenization parity.
- Updated dependency requirements and Bazel workspace definitions for new crates and tools.
2026-08-20 01:45:04 +02:00
can1357 37fd2dbbe1 feat(coding-agent): restored cancelled or preflight-denied prompts to editor
- Add `setPromptDropped` hook and `DroppedPrompt` type to return prompts that were cancelled during turn setup before dispatch.
- Restore dropped prompt text and image attachments to the interactive mode editor and remove the optimistic transcript row.
2026-08-20 00:02:41 +02:00
can1357 12238f55ca feat: implemented native ctok tokenization engine with model scopes
- Implemented the `ctok` Rust native tokenization engine with offline support for Claude V3, V47, V5, and V5Sonnet families.
- Replaced global token estimation with model-scoped `Tokenizer` instances and provider-anchored transcript accounting across packages.
- Added vocabulary generation scripts, test fixtures, and comprehensive unit tests for tokenizer routing and matching modes.
2026-08-19 23:27:29 +02:00
can1357 c39004063e feat(coding-agent): formatted multiline descriptions and tasks in subagent HUD
- Replace newline characters with visual indicators in subagent HUD descriptions and task previews.
- Add unit tests verifying multiline description and task rendering.
2026-08-19 22:58:25 +02:00
can1357 74bc1f442e feat(ai): implemented fallback handling and option for qwen reasoning effort
- Added `qwenTemplateReasoningEffort` model compatibility option to disable Qwen chat template kwargs for strict local servers.
- Implemented fallback handling to strip rejected `chat_template_kwargs.reasoning_effort` and hoist values to top-level fields.
- Added comprehensive test coverage for Qwen reasoning effort fallback and keyword rejections.
2026-08-19 17:40:39 +02:00
can1357 7099457f84 fix(catalog): resolved model routing and fallback failures in catalog
- Fixed `muse-spark-1.2` and `muse-spark-1.2-contributor` failing on tool-call turns by mapping them to `openai-responses` in `OPENCODE_GO_API_ID_OVERRIDES`.
- Added automatic fallback routing to borrow `openai-responses` routes from sibling gateways or billing-variant base IDs for gateway-first models.
- Configured `dropCachedModelIdsOnStaticMismatch` to ensure cached models holding stale static metadata are invalidated on discovery.
2026-08-19 16:40:50 +02:00
can1357 416b30a8d5 feat(tui): supported risk notes with warning glyphs in settings lists
- Add support for risk notes and warning markers on setting items in the TUI settings list component.
- Update the external thinking setting schema and help command to include a warning about provider abuse enforcement.
2026-08-19 16:26:57 +02:00
can1357 5cbdd740bf feat(stats): added token aggregation and updated window grouping logic
- Added `fetchUsageData` and fleet token summation to aggregate token burn across clients.
- Changed window grouping logic from window labels to limit IDs for distinct separation.
- Updated `ProviderWindowInsight` properties and added tests for label suffixing and token summation.
2026-08-19 16:00:13 +02:00
can1357 858f7dd91f test(export): re-pinned html template bytes for regenerated tool-views
The ask-card note renderer (#8786) grew tool-views.generated.js by 126 bytes; CI regenerates the asset so the byte-pinned template contract (bytes/chars/sha256) moved. Values verified identical between CI and a fresh local gen:tool-views.
2026-08-19 12:48:11 +02:00
can1357 2c9b3bb31d fix(pi-ast): skip repo-corpus differential when the corpus is not staged
bazel test sandboxes stage only the crate's declared inputs, so the repository sweep found zero sources and tripped its own evidence guard ('corpus sample too small to be evidence: 0'). Skip on a missing or empty corpus; any non-empty scan still enforces the >40-file evidence floor.
2026-08-19 12:48:11 +02:00
can1357 22b40b47e1 chore: bump version to 17.3.8 2026-08-19 12:35:37 +02:00
can1357 5fb8d1f8bf Merge PR #8995: fix(cli): strip launch-global flags before non-launch subcommands (@roboomp) 2026-08-19 12:21:02 +02:00
can1357 0001e389bb Merge PR #8993: fix(commit): preserve binary patch terminators in split-commit round-trip (@roboomp) 2026-08-19 12:21:02 +02:00
can1357 a54d19efba Merge PR #8991: fix(catalog): recover gmi-cloud model params from canonical index (@roboomp) 2026-08-19 12:13:16 +02:00
roboomp ec56f8d4cf fix(cli): strip launch-global flags before non-launch subcommands
`resolveCliArgv` hoisted a subcommand hidden behind leading global launch
flags to the front and forwarded those flags to the subcommand's own
parser (#2970). Launch-shaped commands (`launch`/`acp`) share the launch
flag surface, but strict-parsing subcommands like `update` declare only
their own flags, so a leading `--cwd` reached `node:util.parseArgs` and
threw `Unknown option '--cwd'`. This bit users whose shell alias/wrapper
runs `omp --cwd <dir> update`.

Leading launch-global flags are now stripped when the hoisted subcommand
is not launch-shaped, and still forwarded for `launch`/`acp`. Shared the
launch-command set with the profile bootstrap to keep one source of truth.

Fixes #8891
2026-08-19 10:10:16 +00:00
roboomp 985e4ad515 fix(commit): preserve binary patch terminators in split-commit round-trip
parseFileDiffs split the captured `git diff --cached --binary` on
"
diff --git ", consuming the newline that terminates each file block, and
patch.join ended with `.replace(/\n+$/, "")`. Both dropped the blank line
that terminates a `GIT binary patch` block, so rebuilding a split-commit
patch produced a corrupt binary patch rejected by `git apply --binary`.

Split on a line-start lookahead so blocks keep their terminators verbatim,
and concatenate join parts without stripping trailing newlines. Both
trailing and mid-diff binary blocks now round-trip byte-exact.

Fixes #8899
2026-08-19 10:08:40 +00:00
can1357 5d18fd814d chore(changelog): normalized entries and added /mcp reauth OAuth discovery note
Covers merged PR #8989, whose branch omitted a CHANGELOG entry (issue #8922).
2026-08-19 12:00:15 +02:00
can1357 a349650bac Merge PR #8990: fix(tui): scroll the /model Roles view so clipped rows stay reachable (@roboomp) 2026-08-19 11:59:55 +02:00
can1357 f2e11a3d72 Merge PR #8989: fix(mcp): run oauth discovery on reauth when handshake needs no auth (@roboomp) 2026-08-19 11:59:55 +02:00
can1357 46c019fd6c Merge PR #8988: fix(catalog): collapse Cursor Grok 4.5/4.6 effort siblings (@roboomp) 2026-08-19 11:59:55 +02:00
roboomp 8fc4555914 fix(catalog): recover gmi-cloud model params from canonical index
GMI Cloud's /v1/models returns only bare {id} rows, so dynamic discovery
resolved every model except the single bundled DeepSeek-V4-Flash seed with
a null context window, zero pricing, and no reasoning/thinking config.

Give the gmi-cloud mapper the same cross-provider canonical fallback that
SiliconFlow uses for the identical open-weight models: recover context
window, output limit, reasoning, and thinking ladder from the bundled
reference index while never borrowing another provider's pricing.

Fixes #8890
2026-08-19 09:57:19 +00:00
roboomp 8ea64a6a8d fix(mcp): run oauth discovery on reauth when handshake needs no auth
`/mcp reauth <name>` probed the server with `{ oauth: false }` and treated a
successful unauthenticated `initialize` as proof that OAuth was unnecessary,
hard-erroring with "Server connection succeeded without OAuth; reauthorization
is not required." Per the MCP spec a server may allow unauthenticated
`initialize` while requiring a bearer token for `tools/call`, so this left no
way to acquire a credential for such servers.

When the handshake succeeds without an in-band tool challenge, fall back to
`discoverOAuthEndpoints(config.url)` and proceed with the flow if the server
advertises OAuth metadata; only refuse when no OAuth endpoint is discoverable.

Fixes #8922
2026-08-19 09:53:26 +00:00
can1357 3a01e97953 chore(changelog): normalized catalog entries after merges 2026-08-19 11:53:17 +02:00
can1357 a720b8d6ac fix(coding-agent): bound TinyFish locale regex to whole subtags
Unanchored regex mapped BCP-47 script subtags to bogus regions
(lang:zh-hans -> location=HA) and prefix-matched 3+ letter codes
(lang:eng -> language=en). Require a subtag boundary, matching the
Perplexity provider's parsing.
2026-08-19 11:52:55 +02:00
can1357 d61c33349a Merge branch farm/5a737841/tinyfish-honor-lang-directive: fix(coding-agent): honor lang: directive in TinyFish search (@roboomp) 2026-08-19 11:52:55 +02:00
can1357 0253c85026 Merge PR #8985: fix(sdk): thread response model into after_provider_response context (@roboomp) 2026-08-19 11:52:55 +02:00
can1357 e966b4aa4d Merge PR #8983: fix(mcp): refresh broker-backed MCP OAuth credentials (@roboomp) 2026-08-19 11:52:54 +02:00
can1357 45d8bca2ee Merge PR #8982: fix(ai): serve IPv4-only OAuth callback when IPv6 is disabled (@roboomp) 2026-08-19 11:52:54 +02:00
can1357 d6d7e0f56c Merge PR #8981: fix(catalog): route copilot grok-4.6 through responses api (@roboomp) 2026-08-19 11:52:54 +02:00
can1357 3319e8bbad Merge PR #8980: fix(catalog): route opencode-go muse-spark to responses api (@roboomp) 2026-08-19 11:52:54 +02:00
can1357 8557366401 Merge PR #8979: fix(coding-agent): paint optimistic row for idle /skill submits (@roboomp) 2026-08-19 11:52:54 +02:00
can1357 9ffc0b2a17 Merge PR #8978: fix(compaction): reject stale pre-compaction anchor in context breakdown (@roboomp) 2026-08-19 11:52:53 +02:00
can1357 43f7b09348 Merge PR #8977: fix(tui): honor tui.input.submit remap onto ctrl+enter (@roboomp) 2026-08-19 11:52:53 +02:00
can1357 b4c04ef0b7 Merge PR #8976: fix(commit): fail loudly when staged binary truncates split-commit diff (@roboomp) 2026-08-19 11:52:53 +02:00
can1357 31b97de9f4 Merge PR #8975: fix(catalog): self-heal a corrupt models.db model cache (@roboomp) 2026-08-19 11:52:53 +02:00
can1357 53a7da5e4c Merge PR #8973: fix(ai): surface litellm concurrency-admission 429 immediately (@roboomp) 2026-08-19 11:52:53 +02:00
can1357 0b20c251eb Merge PR #8970: fix(tui): pin anchored regions under an unpinned streaming seam (@roboomp) 2026-08-19 11:52:52 +02:00
can1357 17faeb0cda Merge PR #8968: fix(ai): hoist assistant message interleaved in responses tool batch (@roboomp) 2026-08-19 11:52:52 +02:00
can1357 9a8b0ef80a Merge PR #8967: docs: clarify bash.patterns gates the bash tool only, not eval (@roboomp) 2026-08-19 11:52:52 +02:00
can1357 764afb8cbb Merge PR #8966: fix(task): initialize extension runtime on subagent revival (@roboomp) 2026-08-19 11:52:52 +02:00
roboomp 466f769cc8 fix(catalog): collapse Cursor Grok 4.5/4.6 effort siblings
Cursor advertises Grok 4.5/4.6 as per-effort sibling ids
(cursor-grok-4.6-low|-medium|-high|-xhigh plus -fast variants), but
VARIANT_COLLAPSE_TABLES had no cursor entry, so the model hub showed 14
unrouted siblings instead of one logical model with effort routing.
GetUsableModels ships no thinkingDetails and the bundled references read
reasoning:false, so the picker also treated them as non-reasoning.

- Add CURSOR_VARIANT_COLLAPSE_TABLE folding each service-tier lane
  (standard + -fast) into one logical model with effort routing onto the
  live wire ids, mirroring Devin's grok-4-5 collapse.
- Rename the generic devinTierFamily/DevinTierRoutes helper to
  tierFamily/TierRoutes now that both Devin and Cursor tables use it.
- Mark versioned cursor-grok-<version> ids as reasoning during discovery
  (grok-code-* coding models stay non-reasoning).

Fixes #8803
2026-08-19 09:52:51 +00:00
roboomp aed63e7bd5 fix(tui): scroll the /model Roles view so clipped rows stay reachable
The Roles panel renderer looped from the first row with a hard height cap and no scroll offset, so roles and model-keyed fallback chains past the visible height were never drawn and unreachable by keyboard, with no truncation indicator. Unlike the sibling provider list (model-browser windows via #windowStart/#ensureSelectedVisible), the Roles panel had no equivalent.

Window #renderRolesView around #roleIndex via #ensureRoleVisible, offset mouse hit-testing by the scroll start bounded to the visible count, and draw an up/down '+N more' hint when the list is clipped.

Fixes #8817
2026-08-19 09:52:41 +00:00
roboomp 78ef6805f3 fix(sdk): thread response model into after_provider_response context
ExtensionRunner.emitAfterProviderResponse accepted the response model but
discarded it, calling createContext() with no model. Response-scoped hooks
therefore saw the primary session model in ctx.model and ctx.models.current()
even when the response came from a cross-provider side request, so an extension
that revokes a credential on an HTTP 402 could target the wrong provider.

Call createContext(model) to match emitBeforeProviderRequest, plus a regression
test asserting both fields expose the response model.

Fixes #8955
2026-08-19 09:44:22 +00:00
roboomp 7150f122f5 fix(coding-agent): honor lang: directive in TinyFish search
The shared query pipeline parses a lang:/language: directive into StructuredQuery.lang, which sibling providers (DuckDuckGo, Perplexity, SearXNG) map onto their native locale params. The TinyFish provider dropped parsed.lang entirely, so every request fell back to the API's US/English default and non-US locales were silently lost.

Map parsed.lang onto TinyFish location (ISO 3166-1 alpha-2) and language (ISO 639-1): lang:it-it yields location=IT&language=it, lang:it yields language=it only. Behaviour is unchanged when no locale directive is present.

Fixes #8913
2026-08-19 09:43:54 +00:00
roboomp 9cc881ce5b fix(mcp): refresh broker-backed MCP OAuth credentials
Remote OAuth MCP servers dropped out of /mcp under `omp auth-broker
serve` once their access token expired: neither the client nor the
broker could complete the refresh.

- Client: the MCP manager threw on the broker-redacted refresh sentinel
  (REMOTE_REFRESH_SENTINEL) instead of asking the broker to refresh. It
  now routes redacted MCP refreshes through
  AuthStorage.forceRefreshCredentialById, which calls back to the broker
  (the real refresh token never leaves the broker host).
- Broker: the serve process had no mcp_oauth:* refresh path, so
  POST /v1/credential/:id/refresh answered "Unknown OAuth provider". Its
  AuthStorage is now built with a refreshOAuthCredential override that
  refreshes MCP credentials with a generic refresh_token grant from the
  credential's embedded token endpoint and client id. The background
  refresher keeps MCP tokens live through the same path.

Extract shared refreshManagedMcpOAuthCredential and
mcpOAuthServerUrlFromCredentialId helpers so both paths use identical
refresh material selection and RFC 8707 fallback-resource logic.

Fixes #8933
2026-08-19 09:34:51 +00:00
roboomp 8ae547091f fix(ai): serve ipv4-only oauth callback when ipv6 is disabled
The `::1` companion listener added in #8081 cannot bind on hosts with
IPv6 disabled at the kernel (ipv6.disable=1). Bun reports that failure
with its generic "Is port X in use?" message (oven-sh/bun#7187), which
isAddressInUse misread as a real collision, tearing down the healthy
IPv4 listener and throwing a bogus "port 1455 is in use"
ConfigurationError that blocked Codex login.

#createServer now probes os.networkInterfaces() for an internal IPv6
loopback up front and serves IPv4 alone when none exists, instead of
relying on Bun error classification the message ambiguity defeats.

Fixes #8814
2026-08-19 09:33:46 +00:00
roboomp 565d09b13a fix(catalog): route copilot grok-4.6 through responses api
GitHub Copilot serves grok-4.6 / grok-4.6-1m only via /responses, but
isCopilotResponsesModelId matched grok-4.5 exactly, so both the static
generator and dynamic discovery classified grok-4.6 as openai-completions
and requests 400d with unsupported_api_for_model.

- match grok-4.6 in isCopilotResponsesModelId
- add grok-4.6 / grok-4.6-1m to COPILOT_CACHE_INVALIDATED_MODEL_IDS so
  stale cached completion routes drop on refresh
- regenerate github-copilot/grok-4.6 to api openai-responses (compat
  block dropped, xhigh effort added by the responses policy)
- cover discovery routing and cache migration in tests

Fixes #8807
2026-08-19 09:27:16 +00:00
roboomp 1b65e471fb fix(catalog): route opencode-go muse-spark to responses api
The OpenCode Go gateway serves muse-spark-1.2 and
muse-spark-1.2-contributor only at /zen/go/v1/responses, but the
/zen/go/v1/models discovery omits the provider.npm hint, so the
resolver fell through to openai-completions. The completions parser
then closed the stream without a finish_reason on every tool-call turn.

Pin both ids to openai-responses in OPENCODE_GO_API_RESOLUTION, mirroring
the existing deepseek-v4-flash override, and add a resolver regression.

Fixes #8957
2026-08-19 09:24:54 +00:00
roboomp 0808226ca3 fix(coding-agent): paint optimistic row for idle /skill submits
InputController.#invokeSkillCommand cleared the draft and awaited the full
promptCustomMessage dispatch with no transcript render. AgentSession.#promptWithMessage
runs awaited preflight (memory recall, before_agent_start hooks, auto-thinking
classification, pre-prompt compaction) before the message reaches the agent, so a slow
step such as a Hindsight auto-recall timeout left the composer cleared with no pending
row, unlike a normal prompt's optimistic row from startPendingSubmission.

Idle skill submissions now paint an optimistic skill row before the awaited dispatch;
the canonical message_start reconciles it in place via EventController instead of
appending a duplicate. Streaming submissions still queue and show their chip.

Fixes #8895
2026-08-19 09:19:47 +00:00
roboomp e6c0cf90a4 fix(compaction): reject stale pre-compaction anchor in context breakdown
getContextBreakdown used message position (anchorIndex >= pending.cutoffCount) as a proxy for usage freshness. After a mid-run compaction rebased the in-flight snapshot, an in-flight provider response whose request predated the compaction landed past the rebase cutoff carrying pre-compaction usage, so it out-ranked the rebased estimate and reported the pre-compaction token count (~2.6x the real one). That phantom overflow tripped the "freed too little context to make progress" guard and drove the frame-rescue path on a byte-identical tokensBefore.

Assistant context snapshots now carry a monotonic compaction epoch, bumped in rebaseAfterCompaction and stamped at message-record time. A post-cutoff anchor whose epoch predates the pending snapshot's epoch is no longer trusted over the rebased estimate.

Fixes #8887
2026-08-19 09:13:33 +00:00