mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-10 02:16:45 +08:00
main
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3b08423684 |
MUL-6260 fix(daemon): treat custom runtime fixed_args as the argv prefix (#7052)
* fix(daemon): treat custom runtime fixed_args as the argv prefix (MUL-6260) A custom runtime profile configured as `ccms start q36` failed every task with `unknown option '-p'`. The profile's fixed_args were merged into ExecOptions.ExtraArgs, which each backend appends *after* the protocol flags it hardcodes, so the wrapper saw `-p` before its own `start` subcommand had been selected and rejected it (GH #7046). Ordering was only half the defect. ExtraArgs is opt-in — six of the twenty-one backends read it — so on the other fifteen families, including every ACP one, fixed_args were silently discarded rather than misordered. Model discovery and `--version` probing carried the profile's path but not its arguments, so even a fixed launch would have left the model picker and the reported version describing the wrapper instead of the CLI behind it. fixed_args now travel as agent.Config.LaunchPrefix and are spliced in directly after the executable, ahead of everything a backend builds. The prefix is applied by a new Command boundary in launch.go through which every runtime process in the package is constructed — launches, version probes and discovery alike — so a backend cannot forget it. A guard test fails the build if any file outside launch.go calls os/exec directly; distributed opt-in is what let ExtraArgs rot, and repeating it would rot the same way. Flag-style commands (`agent --model composer-2.5`) are unaffected: a CLI takes its own flags in any position, which is why prefix-first can be the single order rather than a per-runtime setting. One deliberate behaviour change. The prefix used to sit last and win every last-wins parse, so a profile pinning `--model` silently overrode the model chosen on the agent — the UI showed one model and ran another. Prefix-first inverts that: the more specific per-agent choice is the later token and wins. Overlaps are logged. Protocol-critical flags are filtered out of the prefix once in New(), which knows the family; positional tokens always pass through. Codex additionally strips `-c` overrides aimed at daemon-managed config namespaces, since those beat config.toml from any argv position. The order was never documented, and every shipped fixed_args example is flag-style, so this fills in a contract rather than breaking one. Co-authored-by: multica-agent <[email protected]> * fix(daemon): close the launch-prefix gaps found in review (MUL-6260) Four defects from the first round of review on the fixed_args-as-argv-prefix change. Hermes could escape its own task overlay. The profile selection was resolved from custom_args alone and stripped from custom_args alone, so a profile configured as `hermes -p research` kept that flag in the launch prefix and re-pointed HERMES_HOME past the overlay the daemon had just built. Resolution now parses the argv hermes actually sees — launch prefix then custom args, in process order — and the strip covers both regions. It also removes every selection rather than the first: taking out the first promotes the second, and two separately-configured argv regions make "two selections" an ordinary configuration rather than a user mistake. Positional tokens were not passing through as documented. filterLaunchPrefix delegated to filterCustomArgs, whose blocklists deliberately carry positional tokens — hermes and qwenpaw block `acp`, traecli blocks `acp`/`serve`, grok blocks `agent`/`stdio`/`serve` — because in custom_args those are someone re-issuing the backend's own subcommand. In a launch prefix the same token is the command's identity, so `hermes-wrapper acp tenant` was being rewritten to `tenant`. Only a leading `-` now makes a token eligible for the blocklist; a blocked flag still consumes its separate value so no stray value survives to be read as a subcommand. Codex fast mode lost to the prefix. `--disable fast_mode` beats `--enable fast_mode` regardless of argv order and `-c features.fast_mode=false` beats config.toml from any position, so prefix-first does not protect an explicitly selected priority tier. The removal half of enforceCodexFastMode is now a separate helper applied to the prefix too; the managed enable is still appended once, on the final args. Windows CI could not compile the daemon tests: the Command migration left an unused `path := runtimeCmd.Path` in a hook whose body never referenced it. Verified with GOOS=windows and GOOS=linux vet, which is what should have caught it the first time. Also softens the docs and the Command doc comment: flag-style prefixes usually parse the same in either position, but a CLI that separates global from subcommand flags can care, so the runtime docs now name the position change and tell operators with existing fixed_args to re-run one task after upgrading instead of promising the move is invisible. Co-authored-by: multica-agent <[email protected]> * fix(daemon): resolve and strip the Hermes profile from the real launch argv (MUL-6260) Second-round review found the Hermes profile chain still reasoning about a hand-assembled approximation of the command line instead of the command line itself. The backend launches `<prefix> acp <filtered custom args>`, but the daemon assembled `<prefix> <custom args>` — no `acp`, no filtering — and that token participates in Hermes' own argv scan. With fixed_args `--model` and custom_args `-p research`, the approximation reads `-p` as `--model`'s value and finds no selection, so the overlay is seeded from the default home; the real `--model acp -p research` skips `--model acp` and selects `research`. The selector was then stripped, so the task stayed inside the overlay — but an overlay built from the wrong profile, silently. Stripping had the matching defect, and this one was still an escape rather than a mismatch. A launch prefix ending in a bare `-p` captures the backend's `acp` as its profile value, so neither region holds a complete selection and per-region stripping removes nothing: `-p acp research --yolo` reaches Hermes intact and re-points HERMES_HOME straight out of the overlay. Both halves now go through one assembly. agent.HermesLaunchArgv builds exactly what hermesBackend.Execute builds — the backend calls the same helper, so they cannot drift — and the daemon resolves from it. StripHermesProfileSelectors strips against that same argv and hands surviving tokens back to the region they came from, iterating to a fixed point because removing one selection promotes the next. The `acp` token is never removed; the backend re-adds it, and dropping the flag that captured it is what breaks the selection. StripAllHermesProfileArgs, hermesLaunchArgs and hermesEffectiveArgs are gone: each was only ever correct on a complete argv, and keeping them would leave the same footgun for the next caller. Tests cover the case the review named (prefix ending in a value-taking flag, custom args opening with a selector), the straddling-selection escape, multiple occurrences across both regions, and an invalid value left untouched because Hermes discards it anyway. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: J <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
75c11db048 |
MUL-5549: feat(agent): discover codebuddy models over ACP instead of scraping --help (#6203)
* feat(agent): discover codebuddy models over ACP instead of scraping --help (MUL-5549) CodeBuddy speaks ACP, and `session/new` answers with a structured catalog under models.availableModels plus a currentModelId — exactly the shape the shared parseACPSessionNewModels already reads for Copilot / Kimi / Kiro / Qoder / Grok / TRAE. Scraping the `--model` line out of `codebuddy --help` was never necessary. The help text carried IDs and nothing else, which cost us three things: - Labels were guessed from the ID and were simply wrong. `kimi-k3-1` rendered as "Kimi K3 1" where the CLI says Kimi-K3; `deepseek-v3-2-volc` as "Deepseek V3 2 Volc" where the CLI says DeepSeek-V3.2. - The default model was a "first entry wins" guess rather than the advertised currentModelId. - The effort catalog needed a second regex over the same output. All three come from the handshake now. The effort catalog rides along in the same session/new response as the `thought_level` config option, so it costs no extra process — which also retires the "at most one --help per request" constraint added in #6196, because --help is no longer run at all. One trap worth naming: thought_level advertises `enabled` ("On (default)") alongside the six real levels, but `--effort enabled` is not a valid command line — the daemon passes the selected level straight to the flag. Advertised levels are filtered against the flag's accepted set, and a currentValue outside that set (the default `enabled`) becomes an empty DefaultLevel, which the UI renders as a generic "Default" instead of a value we cannot pass through. Two adjacent inaccuracies surfaced while confirming the real level set against CodeBuddy 2.130.0, both fixed here: the static effort fallback omitted `minimal` and `max`, and so did the server-side IsKnownThinkingValue gate — so the server rejected two levels the CLI genuinely accepts. Discovery keeps its fallback, still marked Fallback so it can never be cached as authoritative (#6196). That covers the not-logged-in case, which is deliberately NOT special-cased with an auth step: the catalog came back without calling authenticate on a logged-in CLI, and inventing an auth branch we cannot exercise would be speculation. Removes codebuddyModelRe, parseCodebuddyModels, codebuddyModelLabel, codebuddyModelProvider, codebuddyEffortRe, parseCodebuddyEffortHelp, codebuddyEffortSuperset, codebuddyHelpOutput and its 60s help cache. Co-authored-by: multica-agent <[email protected]> * fix(agent): keep codebuddy's vendor grouping after the ACP migration (MUL-5549) Review nit, and a real regression in the previous commit. Dropping codebuddyModelProvider looked like removing dead code, but it was the only thing populating Model.Provider for CodeBuddy — and the picker groups on that field. acpModelEntry can only recover a vendor from a `vendor:model` id. CodeBuddy's are bare (`glm-5.2`, `kimi-k3-1`), so every model came back with an empty Provider, and model-dropdown renders the empty group with no header at all: all 16 models would have collapsed into one unlabelled list where main shows Zhipu / Kimi / MiniMax / DeepSeek / Hunyuan sections. Restores the prefix inference as a post-pass over the ACP catalog, exactly the shape discoverCopilotModels already uses for the same reason. Verified against the real CLI: all 16 models land in five vendor groups with none ungrouped. Tests assert the vendor for every id CodeBuddy 2.130.0 advertises plus the static fallback ids, and that the fallback entries' hardcoded providers agree with the inference. Removing the post-pass fails them. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Bohan-J <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
44ce16d9b8 |
MUL-5549: fix(agent): stop reporting a failed model discovery as a real catalog (#6196)
* fix(agent): stop reporting a failed model discovery as a real catalog (MUL-5549) Selecting the CodeBuddy runtime showed a model list that shares no IDs with what the CLI actually supports, so every pick was an ID codebuddy rejects (GH #6180). The list in the report is codebuddyStaticModels() verbatim: the daemon had fallen back, but nothing downstream could tell. discoverCodebuddyModels returned (staticModels, nil) on all three failure paths, and copilot/cursor/grok do the same. A failed discovery therefore arrived as a successful one, which defeated every guard built to catch it: the daemon reported status "completed", the picker's discovery_failed hint only renders on isError, and cacheableModelCatalog — whose own comment says an empty list means transient failure — waves through a non-empty stand-in and stores it as last-known-good for the full 24h serve window. One blip got pinned as the answer for a day. Discovery now returns a Catalog carrying a Fallback marker, which the daemon forwards as an additive `fallback` field (older servers ignore it; an older daemon omitting it keeps the previous behaviour). A fallback catalog is still rendered — the picker stays populated and manual entry still works — but it is kept out of both the daemon's 60s discovery cache and the server's catalog cache. On the server it maps to Keep rather than Drop: a stand-in is no grounds to evict a real catalog, matching how a `failed` report is treated. Also stop codebuddyHelpOutput swallowing the exec error. CombinedOutput folds in stderr, so a codebuddy whose `#!/usr/bin/env node` interpreter is missing from a GUI-launched daemon's PATH had `env: node: No such file or directory` parsed as help text — and cached as such for 60s. Verified against CodeBuddy CLI v2.130.0: the parser itself is fine (16 models from real --help), so this fixes the reporting of the failure, not the parse. Co-authored-by: multica-agent <[email protected]> * fix(agent): run codebuddy --help at most once per model-list request (MUL-5549) Review catch on the previous commit. Model discovery and effort discovery both read `codebuddy --help`, and the effort pass called it independently. That was free while a failed --help was (wrongly) memoised, but once failures correctly stopped being cached, the failure path ran the 35s command twice in a single request — past the server's 60s running timeout, so the request timed out and the late report was then discarded as stale. The user got nothing, not even the fallback list the previous commit exists to preserve. discoverCodebuddyModels now owns the thinking annotation, so the one help capture feeds both catalogs, and the failure path uses codebuddyFallbackCatalog to apply the static effort levels without exec'ing at all: whatever broke --help for the model catalog breaks it for the effort catalog too. Also strengthen the handler tests. They decoded into a struct declared in the test rather than calling ReportModelListResult, so a wrong JSON tag or a mis-wired cache branch would have passed. They now drive the real endpoint with daemon auth and chi params, covering: a fallback report leaving a previously discovered catalog intact, an older daemon omitting the field still warming the cache, and an authoritative empty catalog still dropping the snapshot. Both fixes are mutation-tested — reverting either makes the new tests fail. Co-authored-by: multica-agent <[email protected]> * docs(agent): correct codebuddy --help comments after the single-capture refactor (MUL-5549) Review nit. The comments still described the pre-refactor call graph, where both discoverCodebuddyModels and codebuddyEffortSuperset called codebuddyHelpOutput and the cache was what stopped the duplicate run. The effort parser now takes an already-captured string, and the single-invocation guarantee is structural rather than cache-dependent — which matters, because a failed --help is deliberately not cached, so a second caller would re-run the full 35s timeout. Also note on codebuddyHelpOutput that it has exactly one caller and why a new one would reintroduce the bug. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Bohan-J <[email protected]> Co-authored-by: multica-agent <[email protected]> |