mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-08 17:36:45 +08:00
main
9
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
74ff8aabd7 |
MUL-7983: fix(agent): handle CodeBuddy startup errors without aborting active runs (#9214)
* fix(agent): fail codebuddy runs that emit a top-level error event
CodeBuddy's startup-failure shape is one top-level {"type":"error"}
line followed by a process that stays alive and silent: with an
inherited SERVER__PORT (a user-scope config shared by several tools),
a second concurrent run of the same agent fails to listen, prints
{"type":"error","error":"listen EADDRINUSE: ..."} and never emits
anything again. The parser had no branch for that event type, so the
run sat at "waiting for agent response" until the idle watchdog
stopped it - 19 of 48 runs hung this way on the reporter's machine.
- type=error is now fatal when no terminal result has been seen: the
CLI's own message becomes the run error and the hung process is torn
down immediately instead of idling. A result already seen keeps
governing the outcome, so a late informational error line cannot
flip a finished run.
- buildCodebuddyEnv now also forces SERVER__PORT=0 (OS-assigned port
per run, so concurrent runs never share one) and
CODEBUDDY_BASH_AUTO_BACKGROUND_DISABLED=1 (CodeBuddy's PowerShell
tool moves timed-out commands to the background and only honors that
variable). Both are appended last like the existing background-task
disable so a caller-provided value cannot outvote them.
Fixes #9200
Generated-by: GLM-5.3-Flash (ZCode)
* fix(agent): keep CodeBuddy running after recoverable errors
MUL-7983
Co-authored-by: multica-agent <[email protected]>
---------
Co-authored-by: Yushen <[email protected]>
Co-authored-by: multica-agent <[email protected]>
|
||
|
|
4d4cae7753 |
MUL-7312 LARI-10: Desktop PATH fix + CodeBuddy Claude-parity stream-json guards (#8340)
* fix(desktop): do not prepend PATH fallbacks over login-shell Node Prepending /usr/local/bin after fix-path let a stale system Node 12 shadow nvm/fnm, breaking shebang CLIs (CodeBuddy/OpenClaw) on --version. Append only missing fallback dirs so recovered shell PATH keeps precedence. Co-authored-by: Cursor <[email protected]> Co-authored-by: multica-agent <[email protected]> * fix(agent): align CodeBuddy stream-json guards with Claude Pass stderr into resume rejection, fail on prompt_too_long terminal_reason, and force foreground when Bash requests run_in_background — the same failure modes Claude already handles for Multica-managed headless runs. Co-authored-by: Cursor <[email protected]> Co-authored-by: multica-agent <[email protected]> * fix(agent): align CodeBuddy guards with real CLI protocol Address review on #8340: force CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS, fail on system/task_* background events, and drop Claude-only prompt_too_long / async_launched handling that CodeBuddy 2.150.0 never emits. Co-authored-by: Cursor <[email protected]> Co-authored-by: multica-agent <[email protected]> * fix(agent): update CodeBuddy handleUser test after signature change Co-authored-by: Cursor <[email protected]> Co-authored-by: multica-agent <[email protected]> * fix(agent): force CodeBuddy background-disable env last for Windows Append CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS=1 so os/exec's case-insensitive last-wins dedup keeps it over lowercase custom_env. Also extract Desktop PATH fallback helper with unit tests. Co-authored-by: Cursor <[email protected]> Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Cursor <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
c26da76c42 |
fix(codebuddy): deduplicate fallback usage by response ID (#8395)
CodeBuddy is a Claude Code fork on the same stream-json protocol, and its adapter carried the same usage-accounting defect #8382 fixed for Claude: one response can emit several assistant events sharing a message ID and usage, and the adapter summed every one of them. A run that ends without usable final usage therefore reported inflated input and cache tokens. Count each identified main-loop response once within an execution. Keep forwarding every text and tool block, and keep the existing precedence of the result's modelUsage over result-level usage over the fallback. The fallback also stops summing the assistant output_tokens placeholder and excludes nested-agent events, matching claude.go and the documented crash recovery procedure. It recovers main-loop input/cache usage, not a full bill. Co-authored-by: J <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
9914d51040 |
MUL-5846 fix(agent): stop launching CodeBuddy with MCP disabled (#6556)
* fix(agent): stop launching CodeBuddy with MCP disabled (MUL-5846) `--strict-mcp-config` means "only use MCP servers from --mcp-config". buildCodebuddyArgs passed it unconditionally, so every CodeBuddy agent without a Multica-managed mcp_config was launched in strict mode with no config at all — zero MCP servers, and the user's own ~/.codebuddy.json silently ignored. claude.go already gates the flag on hasManagedMcpConfig; do the same here, and gate the --mcp-config temp file on the same three-state check so a JSON `null` no longer counts as a managed set. Also split CodeBuddy off Claude in runtime_mcp.go. CodeBuddy is a Claude Code fork but keeps its own config file and plugin root (~/.codebuddy.json, ~/.workbuddy/), so reading ~/.claude.json leaked Claude's servers into CodeBuddy launches while dropping CodeBuddy's own. Add kimi to the runtime MCP inventory (<KIMI_CODE_HOME>/mcp.json), which previously reported this runtime as not supporting MCP. Inventory only: `kimi acp` already merges that file with the ephemeral `mcpServers` array the ACP backend sends in session/new, and a duplicate name spawns the server twice, so the task-local merge stays a passthrough for kimi. Verified against CodeBuddy 2.x and kimi-code 0.33.0 with a local stdio MCP probe server: before, the strict launch line answered NO_MCP_TOOL and never spawned the server; after, it returns the probe's payload. Co-authored-by: multica-agent <[email protected]> * fix(daemon): resolve CodeBuddy's real MCP config path (MUL-5846) Review follow-up. The previous commit pointed CodeBuddy at ~/.codebuddy.json, which is only the last fallback in its chain. Verified against the installed CodeBuddy CLI: - the config dir is $CODEBUDDY_CONFIG_DIR, defaulting to ~/.codebuddy - user-scope MCP is the FIRST existing of <configDir>/.mcp.json -> <configDir>/mcp.json -> ~/.codebuddy.json (a fallback chain, not a merge); `codebuddy mcp add --scope user` writes the first - those files are JSONC: comments and trailing commas parse fine - plugins live under <configDir>/plugins, not ~/.workbuddy This is not just a missing inventory row. When an agent has a managed mcp_config, codebuddy.go turns on --strict-mcp-config, so the merged document the daemon writes is the entire world CodeBuddy sees. Reading the wrong file meant "add one cloud MCP server" silently dropped every server the user had configured locally, which is exactly what mergeRuntimeAndAgentMcpConfig exists to prevent. stripJSONC rewrites comments to spaces and drops trailing commas without touching string literals, so a `//` or a comma inside a command argument survives. Also adds the session/new counterpart to TestKimiResumeIncludesMcpServers: Kimi takes MCP over ACP rather than as a CLI flag, so a bare `kimi acp` launch line is not evidence the servers were dropped. Regressions added: path precedence, CODEBUDDY_CONFIG_DIR, JSONC (including comment-like text inside strings), managed + local merge, same-name override, explicit empty set, JSON null passthrough. Co-authored-by: multica-agent <[email protected]> * fix(agent): let CodeBuddy merge its own MCP scopes natively (MUL-5846) Round-2 review follow-up. Pointing the daemon at CodeBuddy's user-scope file only fixed one of three scopes: --strict-mcp-config drops user, project AND local config, so an agent with a managed mcp_config still lost every server the user had configured locally. Measured against CodeBuddy 2.x with one real MCP server registered per scope, using process spawns as the oracle (the model's own tool list is not trustworthy here — it happily names servers that failed to connect): --mcp-config only ....... managed + user + local --mcp-config + strict ... managed only strict only ............. nothing at all So stop passing --strict-mcp-config entirely and let CodeBuddy build the union itself. A managed entry already wins a same-name collision natively (verified), which is exactly what mergeRuntimeAndAgentMcpConfig promises, so codebuddy also drops out of the daemon-side merge and becomes a passthrough like kimi. This removes the class of bugs the previous approach kept generating: the daemon no longer has to reproduce CodeBuddy's config-root resolution, scope precedence, or JSONC parsing on the launch path, and the review's second must-fix goes away with it — agent custom_env CODEBUDDY_CONFIG_DIR is now read by the CLI itself, so the daemon resolving a different directory can no longer desync the launch. Project-scope servers also keep their native approval gate instead of being rewritten into daemon-generated CLI config. (Measured: a project-scope server sits at "Needs approval" and never starts headless, with or without our flags.) codebuddyUserMcpConfigPath and the JSONC reader stay, now used only by the read-only runtime inventory the Agent > MCP tab renders. stripJSONC also tightened per the review: only the last comma before a closer is dropped, so `[1,,,]` stays invalid instead of being silently repaired, and output is now exactly the same length as input so parse-error offsets line up. Co-authored-by: multica-agent <[email protected]> * test(agent): pin kimi MCP delivery against the real CLI (MUL-5846) Users reported that MCP configured in Multica never reaches kimi, citing the bare `kimi acp` launch line as evidence. That line carries no MCP flags because the CLI has none — `kimi acp --help` lists only --login and --help — so kimi takes MCP over ACP session/new instead, and only an end-to-end run against the real binary can settle the claim. Drives this package's own kimi backend with a Multica-shaped agent.mcp_config. The oracle is the MCP server process itself: a stdio fixture that appends to a log when spawned and returns a sentinel from its one tool, so neither a hand-written ACP fixture nor the model's own account of its tools can fake a pass. Verified against kimi-code 0.33.0: server spawned, tools/list served, tools/call answered, sentinel in the task output. Behind the agentintegration tag and MULTICA_RUN_REAL_AGENT_SMOKE, so the default suites and CI are unaffected. Co-authored-by: multica-agent <[email protected]> * fix(daemon): reject unterminated JSONC block comments (MUL-5846) Review nits. stripJSONC blanked an unterminated `/*` all the way to EOF, so `{"mcpServers":{}} /* oops` became valid JSON plus whitespace, and the `/*/` near-miss let the opener's own `*` double as the closer's. Either could make the Agent > MCP tab list servers out of a file CodeBuddy itself rejects — verified: the CLI answers "No MCP servers configured" for both. It now consumes the opener before scanning and returns an error when no closer is found. Only the inventory is affected; the launch path stopped depending on this reader last commit. Also refreshes the launch-path comment, which still described the managed file as a "controlled set" gated by a strict-mode three-state check that buildCodebuddyArgs no longer performs. The flag is gone; --mcp-config now adds to CodeBuddy's own user/project/local scopes. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Bohan-J <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
3eff25401d |
MUL-5785 fix(agent): return an empty output when a stream-json run has no final text (#6557)
A successful stream-json run with no deliverable text returned the sentence "The agent completed without a final response." as its output. That string is a signal, not a message to a user, and shipping it as content defeated every no-response decision the delivery layer already owns — all three branch on the output being EMPTY: an issue task skips the synthesized fallback comment, a direct chat writes a localized no_response outcome, and a Slack/Lark channel drops the turn instead of pushing anything out. Return the empty string instead, and classify each assistant event explicitly so the fallback answer only survives turns we positively understood: a tool-using turn clears it, an unparseable or unknown-shape event clears it (fail closed), and a genuinely silent thinking-only turn leaves it alone. The decision lives in one shared assistantTurn.resolveFallback across claude, codebuddy and qwen. Unreadable events are counted as unreadable_assistant_count so a CLI schema drift surfaces as a number rather than silently empty outputs. Status stays completed: an empty output is a legitimate terminal result for a turn that ended on a tool call, and re-running it would repeat side effects that already happened. Fixes #6462 |
||
|
|
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]> |
||
|
|
280fa28e0d |
fix(agent): deny CodeBuddy's interactive plan-mode tools in headless runs (MUL-5383) (#6104)
CodeBuddy exempts AskUserQuestion and ExitPlanMode from permission-mode finalization, so `--permission-mode bypassPermissions` never auto-approves them. Once the model entered plan mode the session mode is Plan, not BypassPermissions, so ExitPlanMode also missed the daemon's bypass fast-path and went to the SDK permission bridge — which waits with no timeout for a confirmation the headless runtime cannot render. The task sat in-flight until the 2h tool watchdog, and users killed it by hand. Deny EnterPlanMode/ExitPlanMode alongside the AskUserQuestion we already deny. Each tool is passed as its own argv value because CodeBuddy matches disallowedTools entries exactly and does not split on commas. Also send `allowed: true` on control_response: CodeBuddy's SdkPermissionClient reads `allowed`, not Claude Code's `behavior`, so the daemon's "auto-approve" was being read as a denial. Fixes #6012 Co-authored-by: Bohan-J <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
cf1fc64671 |
MUL-4824: fail closed on incomplete Claude-style result streams (#5522)
* fix(agent): fail closed on incomplete stream results Co-authored-by: multica-agent <[email protected]> * fix(agent): tighten empty result fallback Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Eve <[email protected]> Co-authored-by: multica-agent <[email protected]> |
||
|
|
4594c776e1 |
feat(agent): add CodeBuddy as first-class CLI backend (#3186)
* feat(agent): add codebuddyBackend struct and buildCodebuddyArgs Introduces the codebuddy agent backend skeleton with args builder that mirrors claudeBackend's protocol flags (stream-json, bypass permissions, blocked args filtering) for the codebuddy CLI fork. * feat(agent): implement codebuddyBackend.Execute with stream-json parsing * feat(agent): wire codebuddy into New() factory and launchHeaders * feat(agent): add codebuddy dynamic model discovery from --help * feat(agent): add codebuddy thinking/effort discovery and providerThinkingEnums * feat(daemon): add codebuddy CLI probe, env vars, and args support * fix(agent): use len(models)==0 for default model instead of loop index * fix(agent): increase codebuddy --help timeout to 35s for slow CLI startup * fix(agent): address codebuddy PR review feedback - Wire codebuddy into execenv: reuse claude's CLAUDE.md, .claude/skills, and ~/.claude/skills paths since CodeBuddy is a Claude Code fork - Replace hardcoded 20-min timeout with runContext for zero-timeout = no-deadline semantics matching all other backends - Restore runContext regression tests lost in rebase merge - Mirror claude.go execution model: concurrent stdin write to prevent pipe deadlock, sync.Once for stdin closure, keep stdin open for control_request auto-approval mid-run - Add control_request handling with auto-approve behavior - Add RequestID/Request fields to codebuddySDKMessage - Add codebuddy to metrics knownRuntimeProviders - Add codebuddy to provider-logo.tsx (reuses ClaudeLogo) - Consolidate --help discovery: shared codebuddyHelpOutput cache eliminates duplicate cold-start invocations --------- Co-authored-by: krislliu <[email protected]> |