Commit Graph

18644 Commits

Author SHA1 Message Date
ata 4509c128df style: biome-format HUD and task-label files
CI lint failed on line wrapping and extra blank lines in the HUD
role/label changes. No behavior change.
2026-08-18 13:48:00 +10:00
ata 8a83fb0e5d fix(task): stop using the spawn handle as the HUD description
The first HUD commit hid Name: Name. The cause was earlier: task
name was copied into identity.label, which became progress.description
and skipped generateTaskLabel. Keep the handle for id allocation, but
only treat eval label as a real UI description so the tiny-model
summary can run.
2026-08-18 13:48:00 +10:00
ata 94417ec99b test(tui): use generic names in subagent HUD fixtures
Keep the role-badge and echoed-id cases, but drop the session-specific
spawn handle from the source tree.
2026-08-18 13:48:00 +10:00
ata 54ba7fa4ab fix(tui): treat Name-N HUD labels as echoed spawn ids
Collision suffixes such as HindsightMcpFunnel-3 were still shown as
Name-3: Name because the first pass only compared the raw id.
2026-08-18 13:48:00 +10:00
ata aacf42c7eb fix(tui): show subagent role and drop echoed HUD labels
The anchored Subagents list printed only `Id: description` and treated a
label that repeated the spawn handle as a real description. Show the same
⟨role⟩ badge as inline task rows and omit descriptions that only echo the id.
2026-08-18 13:48:00 +10:00
z80 e3475e6353 fix(config): make live settings reload safe 2026-08-17 21:56:21 -04:00
User 70857d1839 Preserve MCP tools across PlanYolo handoff 2026-08-17 18:28:23 -07:00
re2zero 00f5d4cfca fix: correct defaults.json blob (previous upload stored filename instead of content) 2026-08-18 09:19:21 +08:00
re2zero 1fefedce14 fix(biome): add .css to default fileTypes for CSS language support; add changelog entry
Addresses review feedback on the initial commit:
- restore the trailing newline at EOF stripped by the first edit
- add a Fixed entry for this change under ## [Unreleased] in the coding-agent CHANGELOG
2026-08-18 09:17:34 +08:00
ranxianglei 9aefdb5f81 Merge branch 'main' into fix/onpayload-replacement-completions-bedrock-cursor 2026-08-18 09:13:09 +08:00
z80 ced78801ba fix(task): refresh model roles before agent discovery 2026-08-17 20:43:06 -04:00
Andrey Kuznetsov 8d34d1bc2e fix(ai): accept Perplexity OTP challenge token 2026-08-17 23:08:54 +00:00
Sunil Srivatsa b8dbf68613 fix(tiny): match title stop string against generated tokens only
StopOnTextCriteria decoded the last STOP_DECODE_WINDOW_TOKENS of the whole
sequence, so prompt tokens were eligible for matching. A prompt that itself
contains the stop string stops generation at the first generated token and
yields an empty title.

Anchor the window to the generation boundary by recording the first
generated index per batch entry. Existing local title models are
unaffected: with the assistant-prefill prompt shape, the example `</title>`
tags sit outside the 32-token window for normal messages, so no shipping
model changes behavior. The bug becomes reachable with any chat-level
few-shot prompt that places the stop string near the generation boundary.
2026-08-17 15:19:06 -07:00
Sunil Srivatsa f294d1b177 fix(auth): rotate when a ChatGPT account lacks the requested Codex model
A Codex request to a model the signed-in ChatGPT account is not entitled
to fails with "The '<model>' model is not supported when using Codex with
a ChatGPT account." That was classified as a plain provider error, so the
request failed outright even when a sibling account was signed in and
entitled to the model.

Classify that exact denial as an account-policy error, the same category
`cyber_policy` already uses, so the existing credential-rotation path can
reach an entitled account.

The match is deliberately narrow: it fires only for provider
`openai-codex`, only when the denied model in the message is the model that
was requested, and only for a bounded, non-null model identity. A denial
naming some other model does not trigger rotation, so an unrelated mention
cannot burn sibling credentials.
2026-08-17 15:07:53 -07:00
Sunil Srivatsa 49415712f2 fix(memory): separate extraction instructions from user input
The memory-extraction prompt concatenated its instructions, few-shot
examples, and the user message into a single user turn, so a small local
model could not distinguish instructions from input and frequently echoed
the Globex/weather examples instead of extracting facts.

Send the instructions as a real system turn and the raw text as the user
turn. The tiny worker protocol gains a systemPrompt field, and Mnemopi
completion input carries task metadata so the backend selects the right
prompt per call.

Drop the code-built MEMORY_EXTRACTION_TEMPLATE rather than porting it:
prompt text belongs in .md files, and resolveMemoryCompletionInput already
overrides that template for every extraction call, so Mnemopi rendered it
only for the result to be discarded.

Measured on ONNX q4 CPU, LFM2.5-1.2B memory extraction improved from 1/8
to 5/8 once the roles were separated.
2026-08-17 15:06:37 -07:00
Daniel Young 4dbb11b190 fix(discovery): honor Claude Code enabledPlugins for marketplace plugins
The claude-plugins provider read installed_plugins.json but never the
`enabledPlugins` map Claude Code keeps in ~/.claude/settings.json and
<project>/.claude/settings(.local).json. Two consequences: a plugin the
user switched off for a project still loaded there, and a local-scope
install enabled for a project never loaded unless the project directory
matched the install's recorded projectPath exactly.

Merge enabledPlugins across the same layers Claude Code consults (user
settings, then the active project root's and cwd's .claude/settings.json
and settings.local.json; later wins) and apply it in
listClaudePluginRoots: `false` hides the plugin, `true` opts a
local-scope install in regardless of projectPath. Untouched ids keep the
existing behavior. Contributing settings files join the cache key.

Solves: Claude marketplace plugins loading in the wrong projects
Tests: claude-plugins.test.ts — per-project off switch (local wins over
settings.json, other projects unaffected) and enabledPlugins:true
opt-in for a local install recorded under a parent directory
2026-08-17 17:50:10 -04:00
Sunil Srivatsa 5e4757f187 refactor(read): sniff the bytes before decoding them
Independent review noted that a file at or below the snapshot cap with a
text-like extension but binary content was fully decoded into three string
views and a line array before the sniff rejected it — roughly three times
the file size in transient allocations for output that is thrown away.

Split the loader: read the bytes, sniff those bytes, and derive the views
only for what survives. A refused 4MiB binary now costs one read and no
decode.

No observable change: the 966-case differential against the base commit is
byte-identical to the run before this split, still differing only in the four
intended BOM snapshot tags.

Also name in BlockContextSource.text the one shape that would violate its
same-content contract — a source object reused across two different line
arrays — since the contract is documented rather than enforced.
2026-08-17 14:44:02 -07:00
Tommy Liu 42171bf16e fix(catalog): add deepseek-v4-pro-0813 discovery limits
Alibaba Token Plan advertises both dated DeepSeek V4 snapshots, but only
deepseek-v4-flash-0731 had an entry in ALIBABA_TOKEN_PLAN_DISCOVERED_MODEL_LIMITS.
deepseek-v4-pro-0813 is not in ALIBABA_TOKEN_PLAN_STATIC_MODELS either (only the
undated deepseek-v4-pro is), so it fell through to `contextWindow: null` /
`maxTokens: null` — the #7486 symptom, still live for this one id.

Reasoning already worked: the `normalizedId.startsWith("deepseek-v4")` branch
gives it reasoning: true and the high/max effort ladder. Only the limits were
missing, so this is a one-entry fix at 1M context / 384K output, matching both
deepseek-v4-pro and deepseek-v4-flash-0731.

Extends the existing discovery test to advertise the id and assert its limits
and thinking config. Verified the test fails without the source change
(contextWindow/maxTokens come back null) and passes with it.

Refs #8847
2026-08-17 17:27:17 -04:00
Sunil Srivatsa bce0b35e44 docs(changelog): record the read single-pass change 2026-08-17 14:15:16 -07:00
Sunil Srivatsa 301908560e perf(read): materialize a local file once per read
The local text read path opened the same file for every consumer. A ranged
read of a file within the snapshot cap cost four opens and three decodes:
an 8KiB binary sniff, a streaming scan for the rendered window, a whole-file
read for bracket context, and another whole-file read to hash the snapshot.
Whole-file reads under the structural summarizer paid a fifth. Two of those
readers also ran normalizeToLF over the same bytes.

Read the bytes once at or below SNAPSHOT_MAX_BYTES and derive every view
from them: sniff the leading 8KiB of the buffer, slice the rendered window
out of it under the identical line and byte budgets, index bracket context
into its addressable lines, and hand the normalized text to the snapshot
store and the summarizer. Past the cap nothing wants the whole file, so the
streaming reader stays.

Line byte lengths are walked out of the buffer rather than measured on the
decoded strings, so reported byte counts and the truncation boundary stay
exact for content that is not valid UTF-8.

The buffered text is BOM-stripped for hashing, matching the decoder the
patcher's live read uses. A whole-file read of a BOM file previously hashed
its tag from BOM-bearing text, so the following edit only applied through
stale-hash recovery and told the model the file had changed externally when
it had not.

Also stop rejoining lines into a fresh whole-file string on the way to
tree-sitter when the caller still holds that text, and drop the unread
selectedBytesTotal accounting from the streaming reader.

Measured on 966 differential cases across CRLF, BOM, lone-CR, invalid-UTF-8,
oversized-line, empty, no-trailing-newline, multi-range and raw shapes: the
spurious recovery warning is the only behavioral difference. Raw reads, which
skip the tree-sitter parse that dominates everything else, get 30-45% faster
(2.7MB: 10.3ms -> 5.7ms); non-raw reads 1-3%.
2026-08-17 14:15:15 -07:00
can1357 644ad30d6e chore: bump version to 17.3.7
Retry: fixed changelog bundle probe asserting latest release equals VERSION (fails on releases with no coding-agent changelog content); widened issue-4593 watchdog test budgets from 5ms to 50ms against CI runner scheduling noise.
2026-08-17 23:55:09 +03:00
Sunil Srivatsa 0e9f4dab52 docs(changelog): record the tree cache and boundary prune 2026-08-17 13:03:16 -07:00
Sunil Srivatsa 9169ac5c52 perf(pi-ast): prune subtrees that cannot hold a block boundary
collect_boundaries walked every node in the file even though the answer is
bounded by the visible window, which cost roughly twice the parse: on an
81KB source the walk was 8.95ms against a 4.32ms parse, and on 1MB it was
138.8ms against 87.6ms.

A node contributes a boundary only when one of its own endpoint lines is
visible, and both of those lines lie inside its raw row span. Every
descendant's span is contained in its ancestor's, so a span holding no
visible line rules out that node and everything beneath it. Skip such
subtrees with a binary search over the merged visible ranges.

The test is the raw span, not endpoint visibility: a node whose span merely
straddles the window has both endpoints outside it yet can contain a child
that opens exactly on a visible line. The raw span is also conservative
relative to node_content_end_line, so the prune needs no reasoning about
that newline adjustment.

Equivalence is proven differentially rather than argued: the pre-prune walk
is retained under cfg(test) and compared for exact Option<Vec<u32>> equality
across 4827 .ts/.py/.rs files and 38,616 comparisons over eight window
shapes, including whole-file-visible, past-EOF, disjoint ranges, empty range
lists and files that fail to parse. Zero mismatches. root.has_error() is
still evaluated on the whole tree before the walk, so pruning cannot change
a None verdict.

Measured on the built addon with a mid-file 40-line window, medians of 20,
against the parse cache alone: 81KB 13.4ms -> 4.45ms cold and 9.04ms ->
0.149ms warm; 1.06MB 188.1ms -> 55.8ms cold and 131.7ms -> 0.440ms warm.
2026-08-17 12:57:59 -07:00
Sunil Srivatsa 010eda7834 perf(pi-ast): cache parsed trees by content and language
`enclosing_block_boundaries`, `block_range_at` and `summarize_code` each
re-parsed the whole file on every call. The results are not cacheable —
boundaries depend on the caller's visible ranges, which differ per call —
but the `tree_sitter::Tree` is, so cache that instead and hand out
`ts_tree_copy` clones.

Keyed on (xxh64 of the source, source length, language). The hash is a
bucket selector only: a hit re-verifies the stored source against the
request byte-for-byte before returning the tree, so a collision costs a
re-parse and can never yield a tree built from other content. Language is
in the key because the same bytes parsed as TypeScript and as Python are
different trees.

Bounded at 12 slots and 4 MiB of retained source with LRU eviction;
sources above 4 MiB are parsed but never retained. `Tree` is `Send` but
not `Sync`, so entries sit behind a `Mutex` that is held only for a map
probe, a byte compare and a refcount bump, never across a parse or walk.

Error trees are cached like any other: `has_error()` is a property of the
tree, so the callers' own checks reach an identical verdict from a cached
tree, and repeated "does this parse" probes get the speedup too.

Measured (M4 Max, bazel-built .node, median of 20, 1-40 visible):
read.ts 81 KB 13.34 ms -> 8.86 ms on repeat; 1 MB synthetic 225.7 ms ->
138.3 ms. Parser::new + set_language measured at 0.30 us against a
3.91 ms parse, so no parser pooling.
2026-08-17 12:39:22 -07:00
can1357 0a912cc467 chore: bump version to 17.3.7 2026-08-17 22:29:25 +03:00
Hayden Evan 02533ff770 ci: retrigger checks after unrelated runner flakes
The previous CI reds were a truncated rust-overlay fetch in Evaluate
flake and a Julia kernel shutdown in julia-prelude.test.ts. Neither
path is in this change.
2026-08-18 02:19:42 +07:00
Pedro Paulo Vezza Campos ae804857dd test(lsp): isolate config tests from the developer's user lsp.json
`lsp regressions > detects pyright and pylsp in Windows virtualenv Scripts for
Python-only roots` fails on any machine that has ~/.omp/agent/lsp.json:

  expect(config.servers[server]?.resolvedCommand).toBe(localBin)
  Expected: ".../.venv/Scripts/pyright-langserver.exe"
  Received: undefined

The test was not asserting against the packaged defaults at all. loadConfig
walks the user config dirs (~/.omp/agent, ~/.pi/agent, ~/.claude) via
getConfigDirPaths, which resolves from os.homedir(). Any user lsp.json with a
`servers` block sets hasOverrides, which takes loadConfig off its auto-detect
branch and onto the override branch, where the user's rootMarkers replace the
packaged ones.

On this machine that file overrides pyright with

  rootMarkers: ["pyproject.toml", "uv.lock", "requirements.txt", "setup.py"]

which contains neither `pyrightconfig.json` nor `setup.cfg` — precisely the
two markers the test creates. loadConfig therefore returned zero servers.
`ruff` is absent from that file, keeps the packaged rootMarkers, and its
sibling tests pass, which is why only this one failed.

Confirmed by probing inside the test: hasRootMarkers() true and
resolveCommand() returning the .exe, while loadConfig().servers was {} — the
detection helpers were fine, the branch was not.

Point os.homedir() at an empty directory for every test in the file so they
see a pristine environment. Bun's os.homedir() reads the passwd entry rather
than $HOME, so the env var alone does not redirect the walk; both are set.

Verification: 76 pass / 0 fail (was 75 / 1) on a machine with a user lsp.json.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 11:59:45 -07:00
Can Bölük 7913d70254 Merge pull request #8840 from Jaaneek/fix/openai-compat-user-agent
fix(ai): send omp User-Agent on xAI chat only
2026-08-17 20:52:46 +02:00
Jaaneek 7affc3d402 fix(ai): send omp User-Agent on xAI chat only
xAI chat was inheriting Bun's default UA. Set USER_AGENT on xai and
xai-oauth unless the request already supplied one.
2026-08-17 18:40:57 +00:00
Samuel Reed ba472a8e24 fix: keep provider-qualified selectors from shadowing onto aggregator ids
A selector like anthropic/claude-opus-5 is both the anthropic provider's
canonical selector and, verbatim, an OpenRouter model id. When the named
provider is out of the candidate set (disabled, missing creds at boot), the
exact provider-scoped reference misses and the raw-id flat match re-binds the
request onto OpenRouter's same-named model. Requests that should fail closed
instead bill the aggregator at per-token Claude prices.

Raw-id fallback is only legitimate when the named provider does not carry the
id (openai/gpt-4o:extended). Lock the reference when it does by checking the
bundled catalog, then fail rather than shadow. openrouter/anthropic/claude-opus-5
still selects OpenRouter explicitly.
2026-08-17 12:44:45 -04:00
Hayden Evan 1b220a4f65 fix(ai): answer Cursor hosted WebFetch permission queries
Cursor grok-4.6-xhigh stalled after a short "I'll fetch the page"
preamble because interaction_query frames (including proto field 9)
were dropped and the server waited until the 300s idle watchdog fired.
2026-08-17 23:06:39 +07:00
can1357 54e1a8c900 chore: bump version to 17.3.6 2026-08-17 17:16:40 +03:00
can1357 f97a002dfa Merge PR #8772: feat(catalog): default paid xAI and SuperGrok to grok-4.6 (@geraint0923) 2026-08-17 16:00:42 +03:00
can1357 bf8537015e Merge branch 'main' into pr-8772 2026-08-17 15:55:20 +03:00
Huang-404-Q 099ca42749 fix(tests): isolate TUI scrollback tests from terminal multiplexers
isMultiplexerSession() treats TMUX, STY, ZELLIJ, HERDR_ENV=1, the CMUX_*
markers and a tmux/screen TERM as authoritative, and routes rendering down the
path that cannot rebuild scrollback. Nine tests across four files assert the
destructive full-paint behavior and fail for anyone running the suite inside
tmux, screen, Zellij or CMUX.

component-render.test.ts already cleared HERDR_ENV for exactly this reason but
covered only one of the nine signals. Replace it with a shared helper that
clears the whole family and restores it afterwards, and call it from the other
three files.
2026-08-17 17:56:12 +08:00
Huang-404-Q cdbee5814b fix(tests): stop the checkout location and system zshrc from failing tests
Three tests fail on a clean checkout depending on where the repo lives and
which terminal runs the suite:

- status-line-path builds its fake home inside the checkout, so a clone under
  /tmp lands in a SCRATCH_ROOTS prefix and renders the scratch icon.
- status-line/component renders a fixed 120 columns, so a long checkout path
  or branch name pushes the cost segment out of the assertion.
- bash-executor runs an interactive login zsh, which loads the system
  /etc/zshrc; under Apple Terminal that appends session-save lines to the
  captured output. HOME does not isolate a system-level file.
2026-08-17 16:23:51 +08:00
can1357 d4249537a3 Merge PR #8052: feat(extensions): broker denied file writes and deletes (@psyrendust) 2026-08-17 11:16:08 +03:00
can1357 ba71a0aa6c docs(extensions): included sessionId in delete fallback request shape 2026-08-17 11:06:16 +03:00
can1357 9913c58ec1 Merge branch 'main' into pr-8052 2026-08-17 11:00:58 +03:00
can1357 d187249375 Merge PR #7824: fix(stats): restore configurable dashboard bind host (@anatoli-tsinovoy) 2026-08-17 10:47:48 +03:00
can1357 d8c5659d9a feat(catalog): updated context window floor and pricing parameters for gpt models
- Updated GPT-5.6 context window floor to 1,000,000 tokens across discovery, policies, and tests.
- Updated model configurations and pricing parameters in catalog models JSON.
2026-08-17 10:47:30 +03:00
Anatoli Tsinovoy 16ad301117 fix(stats): restore configurable dashboard bind host 2026-08-17 09:46:49 +03:00
Huang-404-Q 34135632fc fix(tests): stop ANTHROPIC_BASE_URL from failing the Anthropic suites
A developer shell with ANTHROPIC_BASE_URL set reroutes the effective endpoint
away from official, switching off eager tool-input streaming, long cache
retention, the Cowork TLS profile, the Claude Code session header and priority
service tier. 14 tests across 6 files assert those behaviors and fail on a
clean checkout.

Add withOfficialAnthropicEndpoint(), a beforeEach/afterEach pair that removes
the variable and restores it, and call it from the six affected files.
2026-08-17 14:35:32 +08:00
hzliangzhi 316c118680 fix(collab-web): render the user-added note in ask tool cards
The ask tool stores the user-attached note in result details (note on the
single-question shape, per-item note inside results[]), but the shared
tool renderer dropped it: AskAnswer carried no note field and the card
never rendered one. Extract and render it as a muted row so HTML exports
and the collab guest view keep the user's context.
2026-08-17 11:55:26 +08:00
roboomp 42cbee962f fix(update): surface actionable message for unsupported proxy schemes
omp update re-threw Bun's raw fetch() UnsupportedProxyProtocol error, telling CLI users to pass verbose:true to fetch() — an instruction unavailable through the CLI. The update fetch catches now detect this failure and report which proxy env var uses an unsupported scheme plus the http/https requirement.

Fixes #8784
2026-08-17 03:08:38 +00:00
ChangZhuo Chen (陳昌倬) a7dc534598 fix(cli): exit cleanly after printing shell completions
Force process termination via `postmortem.quit(0)` in
`Completions.run()` after writing completion scripts to stdout. Loading
all command modules during completion generation leaves open event loop
handles (sockets, timers) that prevent natural process exit, causing
tools like chezmoi to hang.
2026-08-17 10:09:06 +08:00
ranxianglei 91e27ebe9a fix(pi-ai): cursor — apply customSystemPrompt before onPayload so the replacement is final
Per review on #8717: the customSystemPrompt assignment ran after the hook,
so when both options.customSystemPrompt and an extension payload
replacement were set, the option silently won. Now the option is applied
before the hook (the extension can inspect or drop it in its replacement),
matching anthropic, where the hook runs right before serialization and is
the last word on the wire body.

Adds regression tests: replacement drops customSystemPrompt, replacement
overrides it, and the option still applies when the hook returns undefined.
2026-08-17 09:33:12 +08:00
roboomp 1441fdb28b fix(discovery): expanded OpenCode {env:} and {file:} config tokens
OpenCode substitutes {env:VAR} and {file:path} in config text at load
time, but OMP's OpenCode discovery ran the generic ${VAR}-only
expandEnvVarsDeep, leaving those tokens literal. An MCP header like
`Bearer {env:MCP_KEY}` reached the server verbatim and returned 401.

The OpenCode loader now applies OpenCode's own substitution to raw
config text before parsing: {env:VAR} -> env value or empty string,
{file:path} -> trimmed, JSON-escaped file contents resolved relative to
the config dir / ~ / absolute, skipping tokens on // comment lines.

Fixes #8778
2026-08-17 01:31:00 +00:00
roboomp 5d5c901c21 fix(nix): install writable home-manager config instead of store symlink
The Home Manager module symlinked ~/.omp/agent/config.yml to a read-only
/nix/store path. OMP acquires an advisory lock on and atomically rewrites
its config when persisting runtime changes; on macOS the lock backend
creates an flock sidecar next to the target, so the first startup save
failed with "Failed to acquire native file lock ... Permission denied
(os error 13)", breaking every launch once programs.omp.settings was set.

Copy the generated config into place as a writable regular file via
home.activation instead. OMP can now lock and rewrite it, and the next
home-manager switch reapplies the declared settings. The DAG entry is
written literally so the home-manager-free module evaluation in flake.nix
keeps working; that check now asserts the activation entry.

Fixes #8775
2026-08-17 00:44:52 +00:00
roboomp 7af29b47cc fix(ai): honored Fable/Mythos tier usage in reserve health
usageReservePct scoped limits through scopeClaudeLimitsForModelHardBlock,
which drops a Fable/Mythos weekly tier row until confirmed exhaustion
(>=100% or server exhausted). That guard is correct for credential-wide
hard blocks but wrong for the opt-in, non-destructive reserve fallback:
a tier row at 96% was removed before reserve health, so the model stayed
healthy and kept serving past the configured margin.

Added a scopeLimitsForReserve strategy hook (falls back to scopeLimits)
and pointed the Claude strategy at scopeClaudeLimitsForModel, so reserve
health honors the mapped tier row while credential hard blocks and all
other providers are unchanged.

Fixes #8773
2026-08-16 23:51:38 +00:00