Commit Graph
986 Commits
Author SHA1 Message Date
Bohan Jiangandmultica-agent 374b6f3db4 fix: respect omp profiles when discovering runtime skills (#9711)
Co-authored-by: multica-agent <[email protected]>
2026-10-30 11:36:14 +08:00
2083970b51 MUL-8374: fix: keep private chat content to the session owner (realtime + REST) (#9677)
* MUL-8374: fix(realtime): deliver private chat content only to the session owner

Chat events and chat-task transcript (task:message) frames were fanned out
to every connection in the workspace. Route every chat:* event, and
task:message for chat tasks, to the chat session creator's user scope
instead. Producers stamp the owner on the bus event (from the same
chat_session row they already read); an event without an owner is dropped
rather than widened. Chat-task lifecycle events keep workspace fanout for
agent presence.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(server): keep chat-task content private on REST task reads

The transcript endpoint now 404s chat tasks for anyone but the chat
session's creator, and the agent run list and workspace task snapshot keep
foreign chat-task rows but blank their result and error.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(realtime): scope private chat delivery to the owner's workspace connections

User-scope delivery reached the chat creator's connections to every
workspace. Those are authorized against their own workspace only, so a
creator removed from the chat's workspace kept receiving its transcript
and reply through a socket to another workspace. Chat content now goes to
a workspace_member scope each connection joins at connect time; it is
re-authorized against the chat's workspace on every write.

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]>
2026-10-29 19:13:45 +08:00
Multica Eveandmultica-agent f2a6398d6e MUL-7257: refactor(server): remove unused compatibility queries and capabilities (#9671)
* refactor(comments): drop redundant RFC3339 fallback parse

RFC3339Nano parsing already accepts timestamps without fractional
seconds, so the second time.Parse(time.RFC3339) attempt can never
succeed where the first failed. Keep the existing 400 responses and add
a test pinning second-precision since and the invalid since/before cases.

Co-authored-by: multica-agent <[email protected]>

* refactor(daemon): stop advertising unread plugin capabilities

execution-manifest-v1, agent-skill-v1 and remote-mcp-v1 have had no
server-side reader since the Plugin V1 gates were removed in #7144.
Drop the constants and the daemon advertisement.

Co-authored-by: multica-agent <[email protected]>

* refactor(autopilot): remove legacy no-reservation terminal queries

UpdateAutopilotRunCompleted, UpdateAutopilotRunFailed and
UpdateAutopilotRunSkippedWithResult have no production callers; terminal
transitions go through UpdateAutopilotRunTerminalWithQuota. Their
generated Params structs were still used as service argument types, so
replace them with service-local structs. The reconciler test now seeds
its crash window with an explicit fixture UPDATE.

Co-authored-by: multica-agent <[email protected]>

* refactor(tasks): remove unused StartAgentTask query

Production start paths use StartAgentTaskWithSupplement. Move the seven
test fixtures to the same query with both capability flags off, which
performs the same running transition. The empty-body start handler
branch is unchanged.

Co-authored-by: multica-agent <[email protected]>

* refactor(channels): remove unused pending_fresh queries

MarkChannelChatSessionPendingFresh, LockChannelChatSessionPendingFresh
and ClearChannelChatSessionPendingFresh have no callers. The context
generation path and ClearChannelChatSessionPendingFreshForRevision
remain.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-29 16:49:57 +08:00
Basuotianandmultica-agent e7dfbe83bd MUL-7995: fix(openclaw): report actionable state ownership lock error (#9222)
* fix(daemon): give OpenClaw tasks a private per-agent state dir (INFRA-70)

Co-authored-by: multica-agent <[email protected]>

* fix(openclaw): report actionable state ownership lock error (INFRA-70)

* fix(openclaw): handle resident gateway local refusal (INFRA-70)

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-29 15:16:43 +08:00
Bohan Jiangandmultica-agent 46d4e26712 MUL-8347: fix Hermes compatibility with gateway-backed and older ACP (#9666)
* fix(hermes): support gateway-backed and in-process ACP

Co-authored-by: multica-agent <[email protected]>

* fix(hermes): interrupt active task gateways during cleanup

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-29 14:59:57 +08:00
375b23247b fix(codex): price GPT-6.1 Terra and add it to the fallback catalog (#9668)
gpt-6.1-terra runs through Codex but has no row in either price table,
so its usage estimates at $0 and shows up as an unmapped model. Add
OpenAI's standard short-context rates ($1 input, $0.05 cached input,
$1.25 cache write, $5 output per 1M) to the backend metrics table and
the frontend estimate table.

The model is live-only on codex-cli 0.164.0-alpha.11.1 (absent from
`codex debug models --bundled`), so also add it to the static fallback
catalog with the observed `low` default and low..ultra efforts, and
normalize its label alongside the rest of the GPT-6 family.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Multica Eve <[email protected]>
2026-10-29 14:20:27 +08:00
inoisyandEvgeniy Yakutov 828e0c927e MUL-8346: fix(agent): handle Claude Code session and weekly limits (#9652)
* fix(taskfailure): classify Claude Code session and weekly limits as provider quota

Claude Code reports a spent subscription window as "You've hit your session limit · resets 2pm (UTC)" or "You've hit your weekly limit · resets <date>". Neither matched the quota patterns, so these runs were classified as agent_error.unknown and quota-aware handling never saw them.

* fix(agent): stop waiting for claude after an error result

With stdin closed, the Claude Code CLI stays alive while any background task it started is running, then opens a new turn when the task ends. After an error result (a spent session limit, an API failure) that turn cannot change the outcome, yet the daemon kept the run open for the background task's lifetime. Terminate the process group 10s after an error result, the same way cancellation does, so the run fails with the result's error.

---------

Co-authored-by: Evgeniy Yakutov <[email protected]>
2026-10-29 10:47:54 +08:00
bb3747186e feat: let agents steer running turns they could start (MUL-8285) (#9630)
* feat(server): let agents steer running turns they could start (MUL-8285)

An agent comment can now be added to another agent's running turn, the way
a member steers from the composer: exactly when the comment could start that
agent (canInvokeAgent, judged on the human at the top of the chain), never
its own turn.

- steer_task_ids now work for agent authors; steer: true asks the server to
  add the comment to the current running turn of every recipient without a
  named turn.
- Agent-authored bindings are capped per turn (10) and per authoring agent
  (3). The task row is locked in its own statement before the bind, so the
  cap count sees what an earlier lock holder committed.
- An agent comment that steered a turn but was never read is replayed on
  completion like the mention it replaced. Member receipts keep today's
  behaviour (the member sees the failure and can retry or resend).
- The supplement claim returns author_type and the agent's name. A daemon
  that does not send task-supplement-author-v1 gets the attribution in the
  content, so an agent message never reads as a human's.
- can_supplement on task-runs is computed for an agent caller by the same
  rule.

Co-authored-by: Tim Smart <[email protected]>
Co-authored-by: WitMiao <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* feat(daemon): present an agent's added message as an agent's (MUL-8285)

Claims send the task-supplement-author-v1 capability and render agent
messages as peer input that cannot replace the objective or override humans.

Co-authored-by: Tim Smart <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* feat(cli): add --steer and --steer-active to issue comment add (MUL-8285)

Docs: CLI help, CLI_AND_DAEMON.md, the CLI docs in every locale, the squad
leader briefing, and a steering section in the multica-platform mentions
reference.

Co-authored-by: Tim Smart <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix: close the review gaps in agent steering (MUL-8285)

- Replay an unread agent steer even when it reached the turn through an
  implicit route (a worker's reply to its leader): a comment bound to the
  completing run counts as planned input for the replay filter.
- Drop the receipt of an agent steer once completion has replayed it, so no
  client (old or new) offers to resend what the follow-up already handles.
- Never hand an agent's message to a daemon without
  task-supplement-author-v1: it would frame it as a human's. The message
  stays pending, settles when the turn ends, and is replayed as a mention.
- Tell a squad leader about --steer only when its daemon advertises
  cli-comment-steer-v1, since an older CLI rejects the flag; the skill
  reference says to drop the flag on 'unknown flag'.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Tim Smart <[email protected]>
Co-authored-by: WitMiao <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 17:09:59 +08:00
7d02596fc3 fix(agent): MUL-8307 drive OpenCode over ACP so long tools and subagents are not force-stopped (#9619)
* fix(agent): drive OpenCode over ACP so long tools and subagents are not force-stopped

`opencode run --format json` reports a tool only when it finishes, with the
call and its result in one event. The daemon never saw a tool in flight, so a
long silent tool or a delegated subagent was judged by the 10-minute OpenCode
idle window instead of the tool budget and force-stopped (GH #9614).

Built-in OpenCode 1.15+ and 2.x runtimes now run `opencode acp`, which on both
majors announces a tool when it starts executing. MessageToolUse is emitted
from that in_progress frame, so the daemon applies AgentToolWatchdog for the
whole tool. One code path covers both majors:

- model via session/set_config_option (2.x has no session/set_model); effort
  via the advertised `effort` option, splitting 2.x `model#variant`
- resume via session/load; a missing session is reported as ResumeRejected
- cancel via session/cancel, which aborts the running tool on both majors
- MCP: 1.x keeps OPENCODE_CONFIG_CONTENT; 2.x gets servers in session/new,
  which lifts the 2.x MCP refusal on this transport
- 2.x subagent text (`_meta["opencode/child-session"]`) stays out of the
  parent's output; its tool calls are kept
- usage summed from the session export over this turn's assistant messages,
  since the prompt result's usage is not per-turn on either major

The run transport stays as the fallback for custom profiles, older or
unknown versions, agents with custom_args, and MULTICA_OPENCODE_TRANSPORT=run.

Also fix the run transport on 2.x: tool_use parts carry the call id as `id`
(1.x: `callID`), so every 2.x tool message had an empty CallID.

Co-authored-by: multica-agent <[email protected]>

* fix(agent): bound OpenCode ACP teardown when the runtime stops reading

A runtime that stops reading stdin mid-prompt left the prompt write blocked
holding the client's write lock. The cancel path then waited on that lock to
send session/cancel, and the cancel grace and the process-group kill only ran
after the write, so the process could outlive the task indefinitely.

- session/cancel is sent only once the prompt is fully delivered, from its own
  goroutine, so the grace starts immediately and a stalled pipe cannot hold it
- a turn OpenCode never answered (or a cancelled/timed-out setup) is torn
  down forcibly: stdin closed first to release a blocked write, then SIGTERM to
  the group and SIGKILL after the grace; an answered turn still exits on EOF

Regression tests cover a stalled prompt write under a 1s timeout and a runtime
that ignores session/cancel.

Co-authored-by: multica-agent <[email protected]>

* fix(agent): bound OpenCode ACP teardown when a setup write stalls

Setup requests (initialize, session/new, session/load, set_config_option)
are synchronous stdin writes that check their context only after the write
returns. A runtime that stops reading after initialize, with a large MCP
payload in session/new, left the run goroutine blocked in that write, so
the deferred teardown never ran and the process outlived the timeout.

A watcher now force-stops the process as soon as the run ends before the
prompt is fully delivered; closing stdin releases the blocked write. Once
the prompt is delivered the existing session/cancel path owns shutdown.

Regression test: 256 KiB MCP env, runtime stalls after initialize, 1s
timeout; returns in ~1s (60s before the fix).

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 15:11:27 +08:00
Multica Eveandmultica-agent 55be334864 fix(taskfailure): classify Kiro dispatch failure as retryable provider_network (MUL-8314) (#9621)
Co-authored-by: multica-agent <[email protected]>
2026-10-28 15:01:37 +08:00
mrlonely 84e56b6b00 MUL-8256 fix(runtime): recover stalled HTTP/2 connections (#9551)
* fix(daemon): recover stalled HTTP/2 control-plane connections

* fix(daemon): recover stalled skill bundle connections

* fix(runtime): share HTTP/2 recovery across persistent clients
2026-10-28 13:08:35 +08:00
Bohan Jiangandmultica-agent d7d1831fcf feat(cli): add run-targeted retries with a fresh option (#9592)
Co-authored-by: multica-agent <[email protected]>
2026-10-27 18:18:32 +08:00
16a067f30a MUL-8270: fix(db): keep lease claims within query limits (#9563)
* fix(storage): claim one cleanup object per statement

* fix(tasks): bound stale dispatch recovery candidates

* fix(db): restore English lease claim documentation

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-27 12:59:48 +08:00
73f5664ca4 MUL-8263 fix(agents): reject reserved custom arguments on save (#9560)
* fix(agents): reject reserved custom arguments on save

* fix(agents): validate OMP session arguments before saving

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-27 12:59:25 +08:00
bcf40040e0 MUL-8233: fix Pi cancellation and guard unconfirmed cleanup (#9557)
* fix(agent): join Pi cancellation cleanup and guard continuation

Co-authored-by: multica-agent <[email protected]>

* fix(agent): preserve Pi completion and negotiate cleanup

Co-authored-by: multica-agent <[email protected]>

* perf(agent): avoid Pi exit delay and index cleanup guards

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-27 12:37:13 +08:00
小七 ff6d3207c8 fix(agent): keep per-run usage when Claude resume baseline capture fails (#9567)
When a resume's baseline capture fails, the result event's modelUsage
was stored as the task's usage as-is. On newer Claude Code a resumed
session restores its cumulative counters, so that reported total spans
every prior task in the session: the #8781 inflation returned for every
baseline-unavailable mode. The reported trigger is a custom runtime
profile whose command is a wrapper script that sets CLAUDE_CONFIG_DIR
internally - the daemon resolves the transcript from its own env
(os.Environ() + agent custom_env) and never sees it, so every resume
logged 'claude usage baseline unavailable' and stored the running
session total (observed ~10x on a session's 7th task).

The code already distinguishes a transcript that exists but has no
cost-state (older Claude Code reports per-run totals there; behavior
preserved, pinned by existing tests) from one that cannot be found at
all. For the latter the reported modelUsage is now treated as
non-authoritative: usage keeps the stream-derived per-run totals, and
the reported totals are only recorded for the resume-rejected recapture
where the run is known to have started a fresh session of its own.
Affected modes now degrade to a conservative per-run approximation
instead of silently storing a cumulative total; the WRN stays, reworded
to say what actually happens.

Out of scope, per the adjudication on the issue: per-profile env vars
(schema/feature) and expanding $HOME/~ in custom_env values (makes the
manual workaround portable but leaves the default inflation path live).

Ablation: reverting only server/pkg/agent/claude.go on this branch makes
both new tests fail again with the cumulative total stored
(700/30/800/80 instead of the per-run 70/0/80/8).

Fixes #9564

Generated-by: GLM-5.3-Flash (ZCode)
2026-10-27 12:27:02 +08:00
Dante 2de89ff46e MUL-8244: fix(agent): preserve recovered Antigravity stream responses (#9534)
* fix(agent): tolerate recovered Antigravity stream interruptions

* fix(agent): preserve failed Antigravity interruptions
2026-10-26 16:30:18 +08:00
小七 f9b3065ae1 fix(handler): serialize project resource read-modify-write with a row lock (#9240)
UpdateProjectResource derives every column it writes back from the row
read at the top of the request, but the read and the write ran outside
any transaction. Two concurrent partial updates could interleave as
read-read-write-write, and the second writer's stale snapshot silently
reverted the first writer's change: a label-only PUT reverted a racing
ref update to an old Git ref, and a label-only PUT on a local_directory
restored a stale execution mode (reported in #9238 with a deterministic
interleaving that fails 15/15 under -race -count=3).

Serialize the flow with SELECT ... FOR UPDATE inside a short transaction
(GetProjectResourceInWorkspaceForUpdate + Begin/WithTx, same shape as
CreateAgent). Competing updates block on the row until the write lands,
then re-read fresh. This keeps the local_directory legacy label-mirror
writeback intact, which a presence-aware column rewrite alone would have
broken for mirror-triggered ref updates.

Review follow-ups:

- The regression test no longer leaves the race to the scheduler. Before
  resuming the paused label request, it waits until the ref request has
  either completed outright (the only exit on the pre-fix code, which
  never blocks) or is blocked waiting for the label request's row lock
  (the only exit with the fix, seen as wait_event_type='Lock' on the
  backend running the FOR UPDATE query, checked via pg_stat_activity).
  The two signals are mutually exclusive, so the test fails
  deterministically without the lock and passes with it.
- findLocalDirectoryConflict and requireWorktreeCapableDaemon now read
  through caller-provided queries instead of the handler's pool: on the
  update path they run inside the transaction, so a locked request no
  longer borrows a second pooled connection per request.
- Added a local_directory concurrency case: a label-only update racing
  an execution_mode update through the label-mirror ref rewrite.

The regression tests fail on the pre-fix code ("stored ref = main, want
the concurrent ref update (release)" / "stored execution_mode = worktree,
want the concurrent mode update (cleared = in_place)") and pass with the
lock, 20/20 runs each way.

Fixes #9238

Generated-by: GLM-5.3-Flash (ZCode)
2026-10-26 15:20:52 +08:00
e8fdcfd226 MUL-6623 feat(agent): add host-local Devin CLI over ACP (#7485)
* feat(agent): add host-local Devin CLI over ACP

Spawn `devin acp` via the shared ACP client. Local CLI only — not
cloud Devin VMs/Playbooks/Secrets. Model via `devin acp --model`.
Catalog from `devin models list --format json` (families/variants).

* fix: skip Devin ACP handshake when browser auth is also offered

* fix: close dim case string so Devin compiles

Missing quote after dim broke runtime_config.go and every Go CI job.

* fix: stop runtimeConfigPath recursion on Devin

Devin is a builtin whose ProtocolFamily is itself. Recursing on that
overflowed the stack and killed backend-tests.

* test(agent): cover Devin model failures and final-answer delivery

Co-authored-by: multica-agent <[email protected]>

* fix(agent): honor Devin model aliases and stored login (MUL-6623)

Co-authored-by: multica-agent <[email protected]>

* fix(agent): drain Kiro panic details before terminating runtime (MUL-6623)

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 15:11:05 +08:00
90a88519df fix(daemon): defer issue status rules to project workflow (MUL-8145) (#9415)
* fix(daemon): defer issue status rules to the project workflow (MUL-8145)

When the claim carries a project workflow, the runtime brief no longer
tells the agent to set in_progress first and in_review on delivery. Those
statuses may be outside the workflow (the server rejects them), and
entering a handoff step reassigns the issue. The brief now points at the
per-turn [Project workflow] block, and the workflow brief carries the
entry/exit checks in workflow terms. Briefs without a workflow are
byte-identical to before.

Co-authored-by: multica-agent <[email protected]>

* fix(squad): word the owning leader's status moves by the project workflow (MUL-8145)

The squad protocol (Agent Identity, which outranks the runtime brief) still
told an owning leader to move the parent to in_progress and then in_review,
which a workflow may not list and which can hand the parent to another
step's handler. When the claim carries a project workflow, responsibility 6
now keeps the ownership grant but moves the parent only through the
[Project workflow] commands. The claim resolves the workflow before the
briefing to choose the wording. Guest leaders and issues without a
workflow are unchanged.

Co-authored-by: multica-agent <[email protected]>

* refactor(daemon): list no status keys in the brief for a workflow issue (MUL-8145)

With a project workflow, [Project workflow] already lists the issue's
statuses and the commands that move it, and the built-in keys may not be
accepted there. The status command line now keeps only the command and
points at that block; other issues learn valid statuses from the error.

Co-authored-by: multica-agent <[email protected]>

* refactor(workflow): stop forbidding status moves nothing asks for (MUL-8145)

Under a project workflow the current runtime brief no longer states the
built-in in_progress / in_review moves, so the lines that forbade them
(in [Project workflow], the runtime brief and the squad protocol) only
named statuses the agent had no reason to use. Drop them, and the exit
check the runtime brief already states.

Older daemons still state the built-in rules, so the daemon now
advertises workflow-status-rules-v1; without it the claim keeps the
override lines in [Project workflow] and the squad protocol. The
multica-platform skill notes that [Project workflow] supersedes its
built-in status arc.

Co-authored-by: multica-agent <[email protected]>

* refactor(workflow): shorten the step's moves in the workflow brief (MUL-8145)

Replace the handoff preamble with a plain "Your moves:" heading, name
who each move hands off to on its own line, and drop the "this
workflow has no blocked status" explanations from Can't proceed.

Co-authored-by: multica-agent <[email protected]>

* refactor(workflow): state each step outcome as the status to set (MUL-8145)

The moves block read like raw CLI ('Step done → multica issue status MUL-7 x').
Each outcome now says which status to set and that the server assigns the
next handler; the CLI form is given once.

Co-authored-by: multica-agent <[email protected]>

* Revert "refactor(workflow): state each step outcome as the status to set (MUL-8145)"

This reverts commit 2d82d2d342a99afe88cc40c48516b7ea8e860d1e.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 14:27:09 +08:00
b5477490e4 MUL-7376: fix(openclaw): preserve agent identity with persistent model overrides (#9223)
* fix(openclaw): carry per-run model override on the run input (INFRA-71)

Reimplement MUL-7376 (#8419) on this fork and address the review points.

Resolve runtime_config.model_override once, at claim time, and carry it on the run input (model_override); the daemon no longer decodes it from mutable agent config.

OpenClaw keeps agent.model as the registered agent id (--agent) and the override as the underlying model (--model); arbitrary --model from custom_args stays blocked. Usage attribution falls back runtime model -> per-run override -> unknown, never the agent id.

Round-trip model_override through the runtime-config schema, serializer, equality check and the runtime-config tab (i18n in all locales). Docs updated.

Co-authored-by: multica-agent <[email protected]>

* docs(openclaw): clarify persistent agent model overrides

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
Co-authored-by: Multica Eve <[email protected]>
2026-10-26 13:41:04 +08:00
Andrei a47a1ced0c MUL-8240: fix(agent): keep Codex commentary out of output on empty final answer (#9521)
* fix(agent): keep Codex commentary out of output on empty final answer

* test: pin empty-output completion and single result delivery
2026-10-26 12:37:34 +08:00
Multica Eveandmultica-agent b51f42c54b MUL-8200: fix(autopilot): don't fail create_issue runs on issue blocked (#9472)
* fix(autopilot): settle create_issue runs by first task outcome, not issue blocked (MUL-8200)

Co-authored-by: multica-agent <[email protected]>

* fix(autopilot): settle create_issue runs only from their own dispatch chain (MUL-8200 review)

Co-authored-by: multica-agent <[email protected]>

* fix(autopilot): root create_issue dispatch chain at the recorded task and let its outcome win (MUL-8200 re-review)

Co-authored-by: multica-agent <[email protected]>

* fix(autopilot): resolve unlinked create_issue dispatch by agent and wait for pending enqueue (MUL-8200 review)

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-26 10:19:38 +08:00
Multica Eveandmultica-agent 4dc39434ef MUL-8198: fix(daemon): keep pre-588 Remote MCP tokens working for their issuing owner (#9469)
Co-authored-by: multica-agent <[email protected]>
2026-10-23 16:47:53 +08:00
76dfd4a58b MUL-8186: treat process exit as terminal signal on OpenCode 2.x (#9463)
* fix(opencode): treat process exit as the terminal signal on 2.x

OpenCode 2.x stops consuming step events once the session settles, so the
final step_finish is routinely never written. The daemon failed those
completed runs as 'step still open at EOF' / 'continuation never started',
classified them provider_network and auto-retried, repeating side effects.

On built-in 2.x runtimes, waive the two step-bracketing guards and let the
process outcome decide: exit code, error events, prompt write, cancel /
timeout and scanner errors still fail the run. The void-step guard stays.
1.x and custom runtimes are unchanged.

Also decode the 2.x error payload ({type, message}) so failures surface
their real cause instead of 'unknown opencode error'.

Refs #8892, #9456

Co-authored-by: multica-agent <[email protected]>

* fix(opencode): address review on 2.x terminal-signal relaxation

- Clear the void-step flag on 2.x once later text or a tool call shows the
  run recovered, since the recovering step may never report step_finish.
  1.x still requires that step to close.
- Never report stream-level completion (sawTerminalSignal) on 2.x: an
  intermediate step_finish is not proof the run finished, so a failed
  prompt write keeps failing the run.

Refs #9463

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-23 14:45:50 +08:00
04931df162 MUL-8174: fix OpenCode resume after host clock rollback (#9460)
* fix(opencode): retire future-dated resume sessions (MUL-8174)

Co-authored-by: multica-agent <[email protected]>

* fix(opencode): check resume clocks across CLI versions

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-23 14:41:13 +08:00
Multica Eveandmultica-agent 79d801f45c MUL-8188: fail fast on Kiro panic and stop resuming undrivable sessions (#9458)
* fix(kiro): fail fast when the runtime panics mid-turn (MUL-8188)

Kiro can panic inside its agent loop while the ACP process stays alive, so
session/prompt never answered and the task hung until the 2h idle watchdog
or a manual cancel. Watch stderr live for a panic header, abort the prompt,
and surface the panic text. A resumed session that panics before its first
message signals ResumeRejected so the daemon retries once on a fresh session.

Co-authored-by: multica-agent <[email protected]>

* fix(resume): stop re-resuming sessions the runtime cannot drive (MUL-8188)

- taskfailure.UnresumableHistory matches "invalid conversation history",
  so the daemon's fresh-session retry, classifyPoisonedError and
  ResumeUnsafeFailure all treat Kiro's panic as resume-unsafe; the
  GetLastTaskSession / GetLastChatTaskSession text guards mirror it for
  rows written by older daemons.
- A resumed run cancelled after >=5 minutes with zero agent output now
  retires its session: the daemon sends retired_session_id on cancel-ack
  and the server records it on the cancelled row (status CAS, never
  overwrites) and clears a chat pointer still naming it.

Co-authored-by: multica-agent <[email protected]>

* fix(resume): address review on retired sessions (MUL-8188)

- Manual retry no longer revives a retired session: the exact-source rerun
  claim path now checks IsTaskSessionRetired (fails closed), still reuses
  the source workdir, and sets PriorSessionResumeUnavailable.
- Silent-resume retirement measures awakeclock time, so host suspend
  (Windows monotonic clock counts through sleep) cannot retire a healthy
  session; adds a suspend regression test.
- Handler tests use dbfx.Issue/Task and testutil.Call per AGENTS.md.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-23 12:03:19 +08:00
小七 ebc7c4696b fix(taskfailure): exclude letters in HTTP status code boundaries (#9150)
The failure classifier's status-code regexes guarded against longer
numbers only: `(^|[^0-9])(429|529)([^0-9]|$)` and friends. Workspace
and task IDs are hex, so a path like
~/multica_workspaces_x/<slug>-0000c429f4b/<task>/worktree embeds "429"
between letters, which passed the digit-only guard — and the capacity
rule runs before the process-failure and unknown rules. Every failed
task quoting such a path was labeled
agent_error.provider_capacity_or_rate_limit, sending users to check
their provider accounts for a 429 no provider ever returned. The same
gap misfiled paths containing hex "401"/"402"/"403"/"5xx" into the
auth, quota and server-error buckets.

Widen all five boundary guards (capacity, auth, quota, 5xx, and the
403 usage-limit regex shared with NormalizeDaemonReason) from
`[^0-9]` to `[^0-9a-z]`. The classifier lowercases its input before
matching, so letters are the only remaining embedded context to
exclude. Genuine status codes (space/punctuation-delimited, or bare)
still match.

The MUL-1949 offline backfill SQL these patterns mirror is not in this
repo; regenerating it needs the same widened boundary to stay in
lock-step (noted in the pattern comments).

Fixes #9146

Generated-by: GLM-5.3-Flash (ZCode)
2026-10-23 11:53:49 +08:00
Bohan Jiangandmultica-agent ff674c4e1d MUL-8185: Support sharing runtimes with specific members (#9455)
* feat: share runtimes with selected workspace members

Co-authored-by: multica-agent <[email protected]>

* refactor(runtimes): one-click private/public and popover member picker

Private and Public apply immediately again (restrictions still go through
the reviewed revocation dialog). Specific members opens a draft popover
with search, Cancel and Save; selected recipients are summarized under
the scope control with an Edit entry point. The editor moves to its own
runtime-access-editor component.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-23 09:28:22 +08:00
Tim f9036be46a MUL-8184 Fix Hermes reasoning options for non-default models (#9452)
* fix(agent): discover Hermes reasoning options per model

* refactor(agent): extract per-model ACP effort probe

Move the discovery loop out of discoverACPModels into probeACPModelEffort
beside the other ACP effort helpers, and have acpOptionsAfterModelSwitch
return nil when the runtime exposes no post-switch state so callers no
longer re-check the response. Hermes execution only refreshes options when
a thinking level is set, which is the only consumer of the result.

* test(agent): trim Hermes effort regression tests
2026-10-23 07:54:42 +08:00
Multica Eveandmultica-agent 72d9058cc6 feat(telemetry): add visiting and delegating member counts (MUL-8161) (#9435)
* feat(telemetry): report visiting and delegating member counts in self-host snapshot v2 (MUL-8161)

Co-authored-by: multica-agent <[email protected]>

* fix(telemetry): count delegating members from a human-action ledger, drop v1 fallback (MUL-8161)

- member_delegation_day records (member, UTC day) at the human action itself,
  so retries, system wakeups and creator-fallback runs never count, and a
  comment folded into a queued run keeps both humans and their own days.
- Activity read failures now fail collection and use the existing retry
  instead of silently sending a v1 snapshot.

Co-authored-by: multica-agent <[email protected]>

* fix(telemetry): record create-with-assignee, honor DO_NOT_TRACK, build ledger PK concurrently (MUL-8161)

- A member creating an issue assigned to an agent or squad now records a
  delegation day, on both the immediate and deferred create paths.
- TaskService.RecordMemberActivity gates the ledger and is set from the
  startup telemetry config, so DO_NOT_TRACK stops collection too.
- member_delegation_day's primary key is built with CREATE UNIQUE INDEX
  CONCURRENTLY + PRIMARY KEY USING INDEX (589-591), with cleanup registered.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-23 07:40:05 +08:00
Multica Eveandmultica-agent 88de9d3713 feat(agent): surface Hermes dependency reinstall at launch (MUL-8124) (#9434)
* feat(agent): surface Hermes dependency reinstall at launch (MUL-8124, GH #9390)

Hermes prints its launch-time dependency sync only to stderr, which the
daemon forwards at Debug, so the 30-60s rebuild that the per-task Hermes
home triggers when the user's home enables a memory plugin with Python
deps was invisible. Log one Warn when Hermes starts reinstalling (with
HERMES_HOME and a hint) and one when the ACP handshake returns, with
the measured startup delay. Task outcome is unchanged.

Document the cause and the memory.provider workaround in troubleshooting.

Co-authored-by: multica-agent <[email protected]>

* fix(agent): log Hermes reinstall finish when stderr lags the handshake (MUL-8124)

stdout and stderr are drained independently, so initialize can return
before the stderr copier reaches the reinstall marker Hermes wrote
first. Finish then saw no detection and the finish log was lost.

Record the handshake result and time in Finish, and emit the finish log
when the second of (marker, handshake) arrives. Measure the delay from
launch to handshake so it no longer depends on pipe ordering. Adds the
reviewer's repro as an Execute-level regression test plus a unit test.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-22 18:59:58 +08:00
13eb4bda93 MUL-8154 fix(daemon): enforce runtime ownership on daemon routes (#9423)
* fix(daemon): enforce runtime ownership on daemon routes (MUL-8154)

/api/daemon/* accepts any workspace member's PAT/JWT, and authorization only
checked workspace membership. Any member could claim another member's tasks
(receiving the agent's custom_env, MCP config and an owner-scoped task token),
write task results/messages, and take a runtime over by re-registering its
daemon_id.

- Runtime-level check on every runtime/task daemon route, HTTP heartbeat,
  deregister, batch claim (and so the WS claim RPC) and the WS handshake:
  user credentials must own the runtime (NULL owner fails closed); daemon
  tokens must match a non-empty runtime daemon_id.
- Register: pre-check that every existing row on the daemon_id belongs to the
  caller, plus a required_owner_id fence in both upserts (incl. the
  failed-profile path) so a concurrent registration cannot win the row.
  Daemon-token registration keeps the existing owner.
- Legacy merge: only for user-credential registrations, and only when the
  caller owns both rows, verified on the FOR UPDATE-locked rows.
- Tasks without a runtime are not writable through daemon routes; status
  stays readable.
- GetTaskStatus / WS lease queries carry runtime owner/daemon so the hot
  paths keep one round trip.

Co-authored-by: multica-agent <[email protected]>

* test(daemon): authenticate fixtures as the runtime owner (MUL-8154)

Most handler tests drove daemon routes with a daemon token whose daemon_id
did not match the fixture runtime, relying on the workspace-wide token scope
this fix removes. They now authenticate the way real daemons do, with the
runtime owner's user credential (newOwnerDaemonRequest). Tests about daemon
token scoping keep mdt_ and get fixtures with a matching daemon_id; the
ownerless-runtime tests also assert that a user credential is refused.

Co-authored-by: multica-agent <[email protected]>

* fix(daemon): serialize registration per daemon and keep Qoder WS claims working (MUL-8154)

Review of #9423:

- P1: the owner pre-check and the per-provider/profile upserts hit different
  conflict keys, so two members registering different providers of the same
  daemon could both pass the pre-check and both insert, leaving one daemon
  with two owners (and a daemon token for either runtime reaching the
  other's). Registration now runs the pre-check and every runtime write in one
  transaction under a pg_advisory_xact_lock on (workspace_id, daemon_id), on a
  single connection so queued registrations cannot starve the holder. Legacy
  merges, analytics and the register event run after commit; failed-profile
  records use savepoints so they stay best-effort.
- P2: the Qoder revocation check read the Authorization header, which the WS
  RPC bridge's in-process request does not carry, so valid Qoder WS claims
  silently returned nothing. DaemonAuth now records the mdt_ token hash in the
  request context, the WS identity keeps it, the RPC bridge re-attaches it,
  and the check validates that hash on every call (revocation still applies
  to an open connection).
- Regression tests for cross-provider and provider+profile concurrent
  registration, and for valid/revoked Qoder credentials over WS RPC.

Co-authored-by: multica-agent <[email protected]>

* fix(daemon): bind daemon tokens to the runtime owner they were issued for (MUL-8154)

Second review of #9423: a daemon_id can be re-registered by another member
after its runtimes are deleted, and a daemon token was bound only to
(workspace, daemon_id), so the previous owner's Remote MCP token reached the
new owner's runtime (heartbeat, claim, owner-scoped task token).

- daemon_token.owner_id (migration 588). Remote MCP tokens are bound to the
  locked runtime owner inside FinalizeTaskClaim; live tokens are backfilled
  only where their daemon has exactly one owner.
- DaemonAuth carries the owner binding (DB and cache; cache key bumped to v2
  so pre-upgrade entries are never read), the WS identity keeps it and the
  RPC bridge replays it.
- Daemon-token authorization now also requires token owner == runtime owner.
  Qoder-managed tokens stay unbound (governed by cloud_agent_connection), and
  user credentials can no longer register the reserved qoder-managed-* ids.
- Tests: the reuse lifecycle over HTTP, a new WS handshake and an already
  open WS connection; the reserved daemon_id; the concurrency barrier now
  hooks the registration transaction (TxStarter) so the interleaving is real.

Co-authored-by: multica-agent <[email protected]>

* fix(daemon): owner-bind daemon-token registration; drop unsafe token backfill (MUL-8154)

Third review of #9423:

- Migration 588 no longer backfills daemon_token.owner_id from the daemon's
  current owner: that owner may be a later re-registrant, which re-bound the
  previous owner's live token to them. Existing non-Qoder tokens stay NULL and
  are refused (24h Remote MCP credentials, re-issued on the next claim).
- owner_id is a plain UUID column, no foreign key / cascade (AGENTS.md).
- Register via a non-Qoder daemon token now uses the token's owner for the
  in-transaction pre-check and the SQL owner fence, and refuses unbound
  tokens. Qoder keeps its connection-based check; daemon tokens still never
  trigger legacy merges.
- Tests: an old owner's bound token and an unbound legacy token can neither
  register over nor heartbeat the replacement owner's runtime.

Co-authored-by: multica-agent <[email protected]>

* fix(daemon): grant the Qoder registration exemption only with a live connection (MUL-8154)

Fourth review of #9423: register skipped the token owner binding for any
qoder-managed-* daemon token, but checked the Qoder connection only when the
body declared a qoder_cloud runtime. A pre-upgrade Remote MCP token under that
prefix (no owner, no connection) could register type=claude and rewrite
another member's runtime.

Register now verifies the token against a live cloud_agent_connection before
anything else whenever the token is in the Qoder namespace, regardless of the
declared runtimes, and restricts that namespace to the bridge's own shape: a
built-in qoder_cloud runtime, no custom profiles, no failed_profiles.

Test covers built-in, custom-profile, failed-profiles-only and qoder_cloud
bodies with an unconnected token, plus the connected token's allowed and
refused shapes.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-22 16:47:06 +08:00
4b645a354c fix(agent): clarify opaque Kimi turn failures (MUL-8157) (#9431)
Co-authored-by: Yushen <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-22 16:20:15 +08:00
mrlonely 2b6db0d2b8 fix(cursor): resume stalled provider connections with bounded retries (MUL-7968) (#9180)
* fix(cursor): recover stalled provider connections with session resume

* fix(cursor): exclude diagnostic counts from provider error classification

* fix(cursor): ignore stack locations when classifying transport errors
2026-10-22 09:20:44 +08:00
0fe2ebf02e MUL-8045: feat(runtimes): Qoder Cloud Agent as a managed cloud runtime (#9402)
* feat(runtimes): add Qoder Cloud Agent managed remote execution

* fix(qoder): satisfy migration and localization CI contracts

* fix(qoder): bound execution and scope managed credentials

* fix(qoder): avoid upstream migration number collisions

* fix(qoder): gate issue creation and correlate tool results

* fix(qoder): synchronize guarded issue lifecycle transitions

* test(agent): publish Hermes holder identity atomically

* feat(agents): runtime-first create flow and cloud runtimes section for Qoder Cloud Agent

- Three-step create-agent flow (runtime -> configure -> done) with local,
  remote and cloud sections; Qoder connect form inline in the runtime step
- Runtimes page regrouped into remote and cloud sections with Qoder card
- Generalize Qoder storage to cloud_agent_connection (migrations 586/587)
- Locales for en, zh-Hans, ja, ko, fr; desktop and web routes for done step
- Fix status-picker fixture owner_id and diagnostics route coverage after main merge

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* feat(runtimes): unify runtimes page into machines and cloud services

- One Add menu replaces Add remote runtime, the duplicated Add a computer
  and the web-only Cloud Runtime header button
- Group by machines / cloud services instead of local / remote / cloud, so
  web and desktop share one structure; this device is pinned with a badge
- Cloud services use the machine row anatomy in a single ListGrid table;
  unconnected Qoder is a row with Connect, coming-soon providers are rows
- Empty groups show the next step inline; search and online/offline filter
- Rename computer to machine across runtimes copy in all locales

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* test(runtimes): cover unified runtimes page; pin status and action tracks

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* refactor(runtimes): trim redundant descriptive copy on runtimes page

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(runtimes): keep row actions visible at narrow widths

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* refactor(runtimes): align Qoder add-menu item with other cloud services

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(runtimes): close the Qoder dialog after a first-time connection

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* feat(agents): pick the runtime from one grouped list

The runtime step showed four kinds of cards, a comparison panel and
per-section descriptions. It is now one list in the runtimes-page layout:
machines (this one open, others folded to a row) and cloud services. An
unconnected Qoder opens the runtimes-page connect dialog in place and is
selected once it comes online.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(agents): show owners as 'you' and bare version numbers in the runtime list

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* feat(qoder): disconnect action and dedicated Qoder runtime page

Disconnect removes the encrypted connection and the managed runtime, unbinding
its agents after the admin confirms them. The Qoder row now opens its own page
(status, agents, usage, configuration, pause/resume, disconnect) instead of the
machine layout; generic runtime delete and visibility refuse a managed runtime.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(agents): land on the done page after creating from step 2 on desktop

Desktop's location is the tab URL, which moves to /agents/new/done/<id>
while the configure page is still mounted. Its missing ?runtime= tripped
the skipped-step-1 redirect and replaced the tab back to /agents/new, so
Create looked like it did nothing. Only redirect on the manual route.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(agents): show only settings a Qoder agent can run with

The Qoder bridge fails every task whose agent carries a model, thinking or
speed override, env, custom args, custom skills, MCP config or connected
apps, and it runs issues only. The agent detail page still offered all of
those editors, so one save could break every later run.

For a qoder_cloud agent the page now keeps Instructions under Capabilities,
General / Access / QCA Agent under Settings, drops the model rows and the
header model chip, shows the QCA agent in the summary, and locks the
runtime. Other agents no longer see the Qoder runtime in their picker,
since moving onto it needs a QCA agent the server would otherwise reject.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(agents): hide conversation starters for Qoder agents

Starters only appear in a chat, and the Qoder bridge runs issues only.
The create flow already leaves them out for this runtime.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* feat(runtimes): show the Qoder connection as cards with per-section editing

The Qoder runtime page rendered the whole connection as one always-editable
form. It now summarizes the connection, repositories and limits as read-only
cards; each section opens its own dialog and saves only that section.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(qoder): reuse a follow-up session only with the same repository and credential

Resolve repository credentials before deciding to continue a prior session,
and stamp each session with a fingerprint of its repositories, branches and
tokens. A follow-up continues only when the fingerprint still matches, so a
changed repository, branch or rotated/revoked token never rides into an old
session.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(qoder): keep a paused connection paused when its settings are saved

Saving repositories, limits or the connection no longer re-enables a paused
runtime. Resume goes through a new POST /qoder/resume.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(agents): drop settings a Qoder agent cannot run when creating one

A draft started on another runtime could carry hidden skills, model
overrides and starters into a Qoder agent that then failed every task. The
create request now drops them for Qoder, and the API rejects skills and
execution overrides on Qoder agents at save time.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* chore(db): regenerate sqlc models for cloud_agent_connection

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(runtimes): never list the Qoder runtime under Machines

When the server could not run Qoder (no MULTICA_VCS_SECRET_KEY /
MULTICA_QODER_STATE_DIR), the managed Qoder runtime fell back into the
Machines group as if it were a computer.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* refactor(qoder): drop MULTICA_QODER_STATE_DIR

The managed bridge keeps its run journal encrypted in cloud_agent_connection
and a database advisory lock already elects one supervisor, so the state
directory only held a redundant file lock and acted as a feature switch.
Qoder is now available whenever MULTICA_VCS_SECRET_KEY is set. The
standalone qoder-runtime command still uses its on-disk state_dir.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(qoder): keep the branch in the session fingerprint after a journal restore

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* fix(agents): validate Qoder agents' effective settings on every write

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: 安辰 <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-22 01:33:38 +08:00
e720fe2219 MUL-8135: feat(wakeups): wake on linked PR merge conflicts (--until-pr conflicts) (#9406)
* MUL-8135: feat(wakeups): wake on linked PR merge conflicts (--until-pr conflicts)

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* MUL-8135: fix(wakeups): conflict wakes per PR identity, rotate the watch sweep

- A linked-PR condition only fires for a PR key the rule has not seen; a PR
  leaving the satisfying set no longer re-wakes the agent for the others.
- Conflict keys use the PR id, so same-numbered fork PRs on one head stay
  distinct.
- The conflict-watch sweep rotates an address cursor so failing fetches
  cannot starve the rest.

Co-authored-by: Cursor <[email protected]>
Co-authored-by: multica-agent <[email protected]>

* MUL-8135: fix(wakeups): count repeated linked-PR keys when deduping

Checks and merged keys carry only the PR number, so same-numbered PRs from
two repositories share a key. Compare occurrence counts so the second one
satisfying still wakes the agent.

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]>
2026-10-22 01:23:23 +08:00
Multica Eveandmultica-agent 2b64569138 MUL-8126: feat(agent): steer running Kiro turns via _session/steer (#9396)
* feat(agent): support steering running Kiro turns via _session/steer

Kiro CLI 2.33.0 exposes an undocumented ACP extension, _session/steer,
that queues a message and injects it into the in-flight session/prompt at
the next tool or message boundary. Wire it up as the kiro backend's
Session.Supplement (active only while the prompt is in flight, and only
when the daemon negotiated task supplements), and gate kiro >= 2.33.0 in
SupportsTaskSupplement.

MUL-8126

Co-authored-by: multica-agent <[email protected]>

* fix(supplement): allow kiro in server-side steering whitelists

The capability handshake (StartAgentTaskWithSupplement), direct steering
(CreateTaskSupplement) and composer reply binding (BindCommentTaskSupplement)
each whitelist providers, and none included kiro, so a negotiated Kiro run
never got a capability row and steering stayed unreachable. Add kiro to all
three, regenerate sqlc, and cover kiro in the negotiation and both delivery
path tests. Also widen the kiro supplement test's readiness wait, which was
flaky under full-package parallel load.

MUL-8126

Co-authored-by: multica-agent <[email protected]>

* fix(supplement): allow grok in composer reply binding

BindCommentTaskSupplement was the only steering whitelist without grok, so
a reply from the normal composer to a running Grok turn fell back to the
next run even though direct steering worked. Add grok and cover it in the
composer binding test.

MUL-8126

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-21 19:01:56 +08:00
Multica Eveandmultica-agent 0beaeddc0e MUL-8120 feat(workflows): owner-based workflow edit/delete permissions (#9388)
* MUL-8120 feat(workflows): record workflow owner and let owners edit their workflows

Any workspace member may now create a workflow and becomes its owner.
Editing, deleting and changing handoffs is open to the owner and to
workspace owners/admins. Default has no owner and stays admin-only.
Copying a workflow for one project now also requires managing that
project. Migration 585 adds issue_workflow.owner_id and backfills
existing named workflows with the workspace's earliest owner.

Co-authored-by: multica-agent <[email protected]>

* MUL-8120 feat(workflows): mirror owner-based workflow permissions in the UI

Members can create and duplicate workflows; the editor, column handoff
and flow panel are editable by the workflow's owner and admins. The
save-for-this-project option only shows to admins and the project lead.

Co-authored-by: multica-agent <[email protected]>

* MUL-8120 fix(workflows): only admins add statuses through workflow writes

Workflow create/update could add statuses to the shared workspace
catalog without a role check. Non-admins now get 403
status_create_forbidden when a step names a status that does not exist;
reusing a status by key or by name stays open.

Co-authored-by: multica-agent <[email protected]>

* MUL-8120 fix(workflows): hide new-status for members in the workflow editor

Members pick from existing statuses only. A template that needs statuses
the workspace lacks shows which ones and keeps Save disabled until they
are removed or an admin adds them.

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-21 18:34:21 +08:00
984d8192ad fix(daemon): preserve Claude effort for unlisted models (MUL-8112) (#9392)
Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-21 16:59:16 +08:00
ZIceandmultica-agent 4152fed89f fix(opencode): discover v2 model thinking variants (ZIC-351) (#9365)
Co-authored-by: multica-agent <[email protected]>
2026-10-21 13:40:24 +08:00
Multica Eveandmultica-agent 74281e313d fix(agent): deliver the copilot prompt on stdin (MUL-8105) (#9380)
* fix(agent): deliver the copilot prompt on stdin; name E2BIG start failures (MUL-8105)

Copilot inlined the whole task prompt as -p <prompt>, so a thread above Linux's 131,072-byte MAX_ARG_STRLEN died at fork/exec with E2BIG (#9362). The prompt now rides stdin, mirroring the OpenCode move in #6552. startOwnedProcessTree also wraps oversized-command-line failures in ErrArgvLimitExceeded with an actionable remedy.

Co-authored-by: multica-agent <[email protected]>

* docs(agent): update copilotBackend comment for stdin prompt delivery (MUL-8105)

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-21 12:26:50 +08:00
Basuotianandmultica-agent 5b21b63fa8 fix(codex): attribute default-model usage (#9360)
Co-authored-by: multica-agent <[email protected]>
2026-10-21 09:58:36 +08:00
m2keloopandm2keloop d908e4882d MUL-6710: fix(runtimes): revoke access when making runtime private (#7580)
* fix(runtimes): revoke access when making runtime private

* fix(runtimes): regenerate queries for workflow step

---------

Co-authored-by: m2keloop <[email protected]>
2026-10-20 12:49:37 +08:00
Dante a790bc8c08 fix(comments): retain delivered supplement root owners (#9061) 2026-10-19 22:22:32 -04:00
Riley Rogersandsoulmate 2f247cc92f fix: respect explicit comment-trigger cancellation during reconciliation (#9300)
Co-authored-by: soulmate <[email protected]>
2026-10-19 03:15:40 -04:00
de198cd4c1 feat: allow quick actions without a target (MUL-7990) (#9210)
* test: cover quick actions without an agent

* feat: allow quick actions without a target

* test(quick-actions): cover clearing an existing agent target

* fix(quick-actions): keep existing locale copy

* test: consolidate quick-action regressions in existing test file

* chore(migrations): renumber quick action optional target migration to 584

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-19 14:41:48 +08:00
LinYushenandmultica-agent 6dc20dd314 feat(llm): use GPT-6 Luna as the built-in assist default (#9329)
Co-authored-by: multica-agent <[email protected]>
2026-10-19 14:23:43 +08:00
Dante eb0e0824fd fix(agent): honor Claude supplement handshake budget (#9252) 2026-10-19 02:04:55 -04:00
88f6d6272b MUL-8057: feat(agent): run Meta Muse Code as an MSP runtime (#9309)
* feat(agent): run Meta Muse Code as an MSP runtime

Muse Code speaks MSP (Muse Session Protocol) over `muse serve`: JSON-RPC
2.0 on stdio, like ACP, but with its own method vocabulary. A session opens
with session/start or session/resume, work is submitted with turn/start, and
assistant text, reasoning and tool calls arrive as transcript items.

The adapter maps those items onto the Backend contract, reads the terminal
turn outcome, and reports a notFound resume as ResumeRejected so the daemon
retries on a fresh session instead of losing continuity silently.

Approval is a session property, not a launch flag: `muse serve` has no
--yolo, and the CLI documents --yolo as TUI-only. A fresh session is created
with approvalMode=allowAll and a resumed session re-asserts it with
session/setApprovalMode, which is what lets a claimed task run without
waiting for a human. The container and per-task worktree remain the
isolation boundary, as they are for every other backend.

commandId must be UUIDv7 — Muse derives a turn id from it and rejects
anything else — so the adapter mints time-ordered ids rather than v4.

The model catalog comes from the session-free model/list query and the pick
is applied through session/start modelId.

* feat(runtime-profiles): allow muse as a protocol family

A custom runtime profile may only be based on a protocol family the daemon
supports, and the database enforces the same list. Widening both keeps the
create flow, the server validation and the CHECK constraint in lockstep with
agent.SupportedTypes.

* fix(muse): complete runtime integration and lifecycle handling (MUL-8057)

Co-authored-by: multica-agent <[email protected]>

* docs(muse): document runtime setup and support (MUL-8057)

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: yushen <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-19 13:45:42 +08:00