Commit Graph
2371 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
Xichang(Seacen) Zhao bf8970aa33 fix(wecom): ask again before a queued reply is written to a revoked installation (#9694)
The installation's status is read once, when a reply is addressed. The
reply then waits for the chat's turn and the socket's writer, and a
revocation in between was written straight through: the answer, the
closing frame of its bubble, a failed run's notice, an inbox push.

replyWriteGuard puts the check on each of those frames, the way
attachmentWriteGuard already does for files. Stream frames now consult
the guard too, so a bubble is held to the same check as the message it
would fall back to. A revoked installation is a skip
(installation_inactive), not a drop; a permission that cannot be read
is a drop on the direct path and another offer on the relay.

A retried closing frame that the guard refuses was written nowhere,
which says nothing about the first attempt; seal now keeps the first
attempt's unknown instead of reporting the bubble provably empty.
2026-10-30 10:53:54 +08:00
c066f7ea61 MUL-8382: fix(wecom): write the unreadable-message receipt in the sender's language (#9693)
* fix(wecom): write the unreadable-message receipt in the sender's language

The one line the read loop sends back for a message it cannot read (a
location card, an image callback with no url) was a zh-Hans literal in
wecom_channel.go, so a sender whose Multica profile says English got every
other notice in English and this one in Chinese. It was the last copy #8831
left as a literal; the lint's pending list counted it.

It is now copyPack.UnsupportedMsgType, resolved the way the Replier resolves
its notices: the sender's profile language in a 1:1, the deployment's in a
room. The read loop gets the lookup through ChannelDeps.Languages, which
router.go sets, and RegisterWecom warns when it is nil, the way
NewOutboundReplier does, so the boot-path wiring test covers both.

The lookup runs only for a message nothing here can read; readable messages
take no extra query.

* fix(wecom): resolve the receipt copy after the dedup claim

A redelivery stopped at the claim no longer pays for the language lookup.
Also hoist the logger fallback in RegisterWecom so both warnings share it.

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

---------

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-30 10:47: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
ec72a00ac3 MUL-8342 fix(daemon): reject legacy DSH profiles (ZIC-374) (#9649)
* fix(daemon): reject legacy DSH runtime profiles

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

* fix(dsh): show bridge migration steps in refusal notices

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

---------

Co-authored-by: multica-agent <[email protected]>
Co-authored-by: Sol-Boy <[email protected]>
2026-10-29 13:39:35 +08:00
07221fbc64 docs(skills): keep theme text tokens off fixed light fills in html blocks (#9664)
Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-29 11:00:12 +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
f0c361ebca feat(ui): Multica icons, roomier menus and typography pass (MUL-8334, MUL-8338) (#9640)
* refactor(ui): add @multica/ui/icons as the single icon entry point (MUL-8334)

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

* refactor: import icons from @multica/ui/icons instead of lucide-react (MUL-8334)

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

* chore(lint): ban direct lucide-react imports outside @multica/ui/icons (MUL-8334)

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

* feat(ui): draw Multica icons and enlarge primitive icon sizes (MUL-8334)

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

* feat(ui): roomier menu and sidebar rhythm (MUL-8334)

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

* feat(ui): mark body and detail layers in icon glyphs (MUL-8334)

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

* feat(ui): Inter optical sizing, lighter titles, CJK leading and zh-TW font stack (MUL-8338)

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

* feat(ui): 13px for in-place reading text, regular weight for descriptive labels (MUL-8338)

Issue detail timeline, comment headers, properties panel, wakeup and PR rows
move from 12px to 13px; sub-issue identifiers match list/board (12px regular);
sidebar group labels drop to regular weight; board card titles get more
leading under a CJK UI via a new cjk: variant.

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

* feat(ui): tint the active sidebar icon's body with a light fill (MUL-8334)

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

* feat(ui): draw every remaining icon and drop lucide-react (MUL-8334)

All 286 icon names now render Multica drawings. The drawings, their
construction helpers and the generator live in packages/ui/icons/drawings;
glyphs.ts and index.ts are generated and a test fails when they drift.
Search loses its lens highlight and Inbox its arrow.

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

* chore: guard against icon libraries and document drawing new icons (MUL-8334)

Lint bans the common React icon libraries, AGENTS.md points to a new
multica-icons skill, route icons must mark a body for the active tint,
and comments no longer describe product icons as Lucide.

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

* feat(ui): fill the active sidebar icon solid with its details knocked out (MUL-8334)

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

* fix(lint): ban icon library subpaths too (MUL-8334)

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-28 23:52:28 +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
4a0c147c50 fix(storage): support GCS S3 XML API signing (MUL-8232) (#9513)
* fix(storage): omit unsigned headers from SigV4 to support GCS S3 XML API

Google Cloud Storage through its S3-compatible XML API mutates the
Accept-Encoding request header in transit (identity -> identity,gzip(gfe)).
Because aws-sdk-go-v2 signs Accept-Encoding into SignedHeaders by default,
this mutation causes HTTP 403 SignatureDoesNotMatch on storage calls.

This commit:
- Automatically excludes accept-encoding from SigV4 signing when
  AWS_ENDPOINT_URL points to Google Cloud Storage (storage.googleapis.com).
- Adds S3_UNSIGNED_HEADERS to configure additional unsigned headers,
  preserving accept-encoding when targeting GCS.
- Strips unsigned headers prior to SigV4 signing while restoring captured
  headers (including Accept-Encoding: identity) on the wire via an HTTP
  client wrapper.
- Documents S3_UNSIGNED_HEADERS across all 5 documentation translations
  (en, zh, ja, ko, fr) with an integrity protection note.
- Adds regression tests for SigV4 omission, wire transmission, and presigned
  X-Amz-SignedHeaders.

Closes #9509

* fix(storage): scope GCS signing workaround to Accept-Encoding (MUL-8232)

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

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 17:02:10 +08:00
1eb4b5d1f8 MUL-8203: record permission-blocked mentions as system replies (#9624)
* fix(comments): leave system replies for denied mentions (MUL-8203)

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

* fix(comments): address refusal notice review nits (MUL-8203)

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

---------

Co-authored-by: Yushen <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 15:30:58 +08:00
b20cea33ad fix(desktop): wait for daemon shutdown before quitting (MUL-8290) (#9590)
* fix(desktop): wait for daemon shutdown before quitting

* fix(desktop): clarify daemon quit progress and dialogs

* fix(desktop): preserve stopped daemon after cancelling quit

* fix(desktop): suppress deferred restart after cancelled quit

* fix(daemon): require explicit cleanup confirmation before quit

Record a profile-scoped, PID-matched shutdown result before releasing the daemon lock. Keep cleanup timeouts and provider cleanup_unconfirmed results sticky, and reject absent, malformed, stale or negative results in the forced stop path.

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

* fix(daemon): keep unconfirmed cleanup sticky across repeated stops

When a stopped daemon left no matching shutdown result (for example a daemon started by an older CLI, or a stale record from an earlier daemon), the first forced stop correctly failed, but a repeated stop saw an idle profile with no result file and reported success. Record the unconfirmed outcome on failure so cancelling the quit dialog and quitting again still requires an explicit ignore. A profile that never ran a daemon still stops as an idle no-op, and the next daemon start replaces the record.

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

---------

Co-authored-by: Bohan-J <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 15:29:05 +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
FrezcandFrezc a8e7561421 [MUL-8300] fix(lark): resolve outbound references to workspace links (#9604)
* fix(lark): resolve outbound references to workspace links

* test(wecom): use normal budget for no-holder state assertion

* fix(channel): preserve Markdown reference source boundaries

* fix(lark): format references with one workspace lookup

* fix(deps): update x/net for HTML parser advisory

---------

Co-authored-by: Frezc <[email protected]>
2026-10-28 14:06:16 +08:00
ca593b3103 MUL-8302: fix(daemon): preserve task environment in Hermes tool shells (#9607)
* fix(daemon): preserve task environment in Hermes tool shells

* fix(daemon): complete Hermes task env and preserve derived isolation (MUL-8302)

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

* fix(deps): patch x/net HTML vulnerability (MUL-8302)

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

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 13:45:15 +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
6388272a8a fix(github): skip PR merge status move when the project workflow lacks the target (#9598)
A merged PR moved its issue to the workspace's pr_merge_status even when the
issue's project workflow does not list that status, bypassing the check a
manual status change goes through. The decision now loads the project
workflow and returns not_in_workflow instead; the issue page renders nothing
for it, so the issue silently stays where it is. Default workflows and issues
outside any project are unchanged.

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-28 10:04:38 +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
Multica Eveandmultica-agent a008d893dd MUL-8292: refactor(brief): move Available Commands detail behind --help (#9596)
* MUL-8292: refactor(brief): move Available Commands detail behind --help pointers

Each bullet keeps its signature and the behaviour needed at the call site;
wakeup condition catalogue, PR snapshot mechanics, actor filters and the
repeated file rules now live only in --help and the multica-platform
references. Issue brief 17,300 -> 16,372 bytes (-928); chat and autopilot
briefs drop by the same amount. New TestAvailableCommandsKeepsCompressedContracts
pins the kept contracts and guards the moved detail from drifting back.

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

* MUL-8292: fix(brief): keep Available Commands rules self-contained in every kind

Review follow-up on #9596:
- comment list / issue create / comment add pointed at Workflow step 2 and
  Comment Formatting, which chat and autopilot briefs do not have; the
  bounded-read recipe and the workdir file rule are inline again.
- repo checkout restores both keep conditions and the clean-checkout case.
- wakeup scopes last_error to missing PR links/snapshots; a pending check or
  unmet condition records nothing.
Contract test now runs every kind x provider, and a new test fails when the
shared section references a heading or workflow step the kind lacks.

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

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-27 18:17:27 +08:00
188971168d fix(runtimes): spell out Qoder Cloud Agents instead of QCA (MUL-8282) (#9581)
* fix(runtimes): spell out Qoder Cloud Agents instead of QCA

The UI, docs, landing copy and server messages called the product "QCA"
in labels such as "QCA Agent", "QCA runtime" and API errors like "QCA
token is required". Use the full name Qoder Cloud Agents everywhere a
person reads it, and add it to the brand list in the naming conventions
so the abbreviation does not come back.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(runtimes): refine Qoder Cloud Agents copy (MUL-8282)

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

---------

Co-authored-by: 安辰 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-27 14:06:52 +08:00
ac673fbf19 MUL-7384: fix(onboarding): require confirmed daemon setup targets (#8907)
* fix(onboarding): show self-host setup command when daemon URLs configured (fixes #8425)

* fix(onboarding): fail closed until daemon setup target is confirmed (MUL-7384)

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

* fix(onboarding): preserve legacy self-host setup commands (MUL-7384)

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

* fix(i18n): restore Traditional Chinese locale parity (MUL-7384)

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

* test(daemon): pin Pi upstream cancellation handoff (MUL-7384)

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

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-27 13:19:05 +08:00
c11b3375f5 MUL-8269: fix(runtimes): price Bedrock-served Anthropic ids and DeepSeek-V4.1-Flash (#9561)
* fix(runtimes): price Bedrock-served Anthropic ids and DeepSeek-V4.1-Flash

Bedrock reports Anthropic models as `<region>.anthropic.<id>` with an
inference-profile version on snapshots (`us.anthropic.claude-sonnet-5`,
`eu.anthropic.claude-sonnet-4-5-20250929-v1:0`). Neither resolver accepted
that shape: the backend alias rules anchor on `/`, `:` or start-of-string,
and the frontend `canonicalCandidates` only strips `/` and `:` routing
prefixes, so the vendor and region prefixes survived into the lookup. Every
Bedrock-served turn therefore missed the rate table and rendered as $0.00
plus an "unmapped models" warning, while the tokens were still counted in
`task_usage` (cost_usd_ticks is provider-reported and NULL for Anthropic, so
nothing else was pricing them either).

Strip the Bedrock vendor/region prefix and the `-v<digit>:<digit>` profile
version on both sides, before the existing dot↔dash normalisation. Only
`anthropic.`-prefixed ids are rewritten, so non-Anthropic Bedrock models
(`us.amazon.nova-*`) stay unmapped rather than borrowing a Claude rate.

DeepSeek-V4.1-Flash is also missing: the catalog lists v4-flash and v4-pro
only, and there is deliberately no family fallback, so `deepseek-v4.1-flash`
and OpenRouter's dated `deepseek-v4.1-flash-1017` both went unpriced. Add the
official `deepseek-flash` sheet rate ($0.15/$0.60, cache read $0.003, cache
write mirrors input) and one alias rule that admits the dated snapshot —
DeepSeek documents that id as the model actually served for the undated slug,
so it is the same SKU at the same rate, not a second tier.

Both tables are updated together (server/internal/metrics/pricing.go drives
the Prometheus counters, packages/views/runtimes/utils.ts drives the
dashboard) and both suites pin the new ids, including the negative cases: a
later SKU, a `-preview` qualifier or a non-Anthropic Bedrock id must stay
unmapped.

* ci: re-run (previous backend-tests failure was in channel-media reconciler timing tests, unrelated)

* fix(runtimes): align Flash pricing and constrain Bedrock aliases (MUL-8269)

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

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-27 13:02:58 +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
Multica Eveandmultica-agent 7c50af7b66 MUL-8094: feat(wakeups): accept blocked in --until-issue-state (#9553)
* feat(wakeups): accept blocked in --until-issue-state

Lets a coordinator wait for a specific child to reach blocked, alongside the
existing in_review handoff, without waiting for the child to close.
Exact status key match, same as in_review.

Refs #9344

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

* fix(i18n): keep blocked state key in lowercase English in zh wakeup copy

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

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-26 18:20:16 +08:00
Frezc e30ae35301 fix(search): treat out-of-range issue numbers as text (#9501) 2026-10-26 16:49:59 +08:00
Shi Peipei f4250e4298 MUL-8215: fix(runtimes): show Qoder Cloud Agents without encryption setup
Merged via Multica issue MUL-8215 approval.
2026-10-26 16:49:04 +08:00
9543a0c65a MUL-6546 fix(util): ignore mentions inside markdown code blocks and inline code (#7397)
* test(util): mentions inside markdown code should not trigger agent runs

Failing tests for upstream #7237 suggestion 4: fenced code blocks,
inline code spans, and unterminated fences must suppress mention
parsing; blockquote mentions deliberately stay active.

Signed-off-by: Sanjay <[email protected]>
Signed-off-by: Sanjay Ramadugu <[email protected]>

* fix(util): ignore mentions inside markdown code

ParseMentions now suppresses mentions inside fenced code blocks
(backtick and tilde fences, info strings, fences longer than three
characters) and inline code spans, including multi-backtick spans.
An unterminated fence suppresses everything after it.

Blockquote mentions are deliberately still returned: quoting a mention
in a reply is a real notification, not documentation of the syntax.

Upstream #7237, suggestion 4.

Signed-off-by: Sanjay Ramadugu <[email protected]>

* fix(util): parse mentions from goldmark link nodes

Drop the hand-rolled fence scanner. Walk CommonMark Link nodes so code
spans, nested fences, and longer closers stay inert, and update the
squad briefing contract to prove pasted roster syntax still triggers.

* fix(util): require canonical visible mention links

* fix(util): ignore sanitized HTML in mention labels

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

* fix(util): exclude inert template mention labels

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

---------

Signed-off-by: Sanjay <[email protected]>
Signed-off-by: Sanjay Ramadugu <[email protected]>
Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 16:34:39 +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
ac963e9b08 MUL-7981: fix(execenv): fork past a re-dispatched task's fallback branch (#9547)
* fix(execenv): let a re-dispatched task fork past its own busy-branch fallback (#9198)

When the conversation branch is held by another worktree, a local_directory worktree task forks onto <branch>-<task key>. That name is deterministic, so the same task re-dispatched while the branch is still busy hit 'a branch named ... already exists' and failed every attempt. Fork a fresh timestamped branch instead, leaving the earlier attempt's branch (and any partial work on it) untouched.

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

* fix(execenv): keep picking an unused fallback branch name on repeated re-dispatch

A second-granular suffix still collides when the same task is prepared more than twice within one second. Try a bounded sequence of fallback names (<alt>, <alt>-<unix>, <alt>-<unix>-N) instead of failing on the first collision; earlier attempts' branches stay untouched. Addresses review on #9547.

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

---------

Co-authored-by: multica-eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 16:19:37 +08:00
Multica Eveandmultica-agent a53cbab942 fix(workflow): brief handler-less steps as one span (MUL-8231) (#9546)
* fix(workflow): brief a handler-less step as the assignee's span to the next handoff (MUL-8231)

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

* fix(workflow): leave done to a human from an unconfigured in_review (MUL-8231)

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

---------

Co-authored-by: multica-agent <[email protected]>
2026-10-26 16:04:52 +08:00
ZIceandmultica-agent 1ad7fa1f94 fix(lark): preserve rich-text post file attachments (#9302)
Co-authored-by: multica-agent <[email protected]>
2026-10-26 15:24:10 +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
苗大 25086ae73b MUL-8220: fix(issues): stop repeating "wake" in time wakeup entries; remove unused KEEP_ENV setting (#9497)
* fix(issues): stop repeating "wake" in a time wakeup's timeline entry

A time rule's label already reads "wake at ..." (or "every hour", "每小时唤醒"),
so the created entry said "…09:00 唤醒唤醒 Agent" in Chinese and
"Wake at 09:00 · wake Agent" elsewhere. Time rules now use a sentence that
names the agent first: "为 Agent 添加了唤醒:…09:00 唤醒".

* refactor(daemon): remove the unused MULTICA_KEEP_ENV_AFTER_TASK setting

Its only reader went away when run directories stopped being removed at the
end of a run so later runs on the same issue can reuse them (ce2b263ea).
Retention is controlled by the MULTICA_GC_* settings.
2026-10-26 15:18:37 +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
21e7299707 MUL-8230: feat(i18n): add Traditional Chinese (zh-Hant) locale (#9507)
* feat(i18n): add zh-Hant locale to web and desktop

Add Traditional Chinese (zh-Hant) as a supported locale with a full
translation of the shared views bundles. Browser tags zh-TW/zh-HK/
zh-Hant now resolve to zh-Hant instead of collapsing to zh-Hans; the
document lang is zh-TW, and docs/use-case links reuse the /zh pages.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit a6b3f6ba53a605c3e06fd6c4d30fd9df6fca8645)

* feat(mobile): add zh-Hant locale

Ship Traditional Chinese bundles for mobile and resolve zh-Hant/TW/HK/MO
device locales to them instead of falling back to English.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 04563c22662bdb735a9a6c04be784abd9f87da06)

* feat(ui-lab): add zh-Hant locale

Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 1351ea572ed5d885d8a29034d6c0317de58641ea)

* feat(server): accept zh-Hant as user language

Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 50dfe77a4c45452fc877c62497aba226d5aaa426)

* fix(i18n): sync zh-Hant with upstream copy changes

Upstream added conversation-starter, instruction-preview and board column
strings, removed restated descriptions (MUL-8162) and renamed Qoder Cloud
Agents. Mirror those key additions, removals and rewordings in zh-Hant so
the locale parity test passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
(cherry picked from commit 3a97dfc7e0bbf7568925f735c00fc69b6d94313d)

* fix(i18n): add zh-Hant copy for member-scoped runtime visibility

Mirror the runtime visibility "members" choice and the reworded revoke
dialog in zh-Hant so the locale parity test keeps passing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(i18n): replace Mainland terms in zh-Hant copy with Taiwan usage

Several zh-Hant strings were converted character by character from
zh-Hans and kept Mainland vocabulary, which reads wrong to Traditional
Chinese users: 郵箱 → 信箱, 賬單/賬號 → 帳單/帳號, and similar. Values
only; no keys added or removed.

* fix(i18n): polish zh-Hant copy from review

- 分割槽 → 分區 and 許可權 → 權限 (OpenCC phrase mis-conversions)
- drop stray blank lines before zh-Hant workspace names

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

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 15:09:38 +08:00
8a95f0d3b9 MUL-8205 feat(lark): deliver reply images and files (#9477)
* feat(lark): deliver reply images and files

Based on #8332 by @zprial, addressing its review of bounded delivery,
resource uploads, uncertain sends, file fallback and HTTP boundary tests.

Render bound images with the reply text in one card, pair video/audio
uploads with their message types, preserve pending-send uncertainty and
normalize Markdown destinations before matching bound attachments.

Keep runtime artifact ingestion and deployment-specific configuration
outside this change. Add transport, ownership and rendering regressions
and document the behavior in all supported languages.

* refactor(lark): scope attachment transfer slots to the patcher

The concurrency semaphore was a package-level global while the admission
and pending tiers lived on each Patcher. Move it onto the Patcher so all
three limits share one scope and tests no longer mutate global state.

MUL-8205

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

---------

Co-authored-by: multica-eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 15:05:40 +08:00
Multica Eveandmultica-agent 56d9e98f17 docs(skill): state workflow step scope and handler-less steps in projects reference (MUL-8231) (#9543)
Co-authored-by: multica-agent <[email protected]>
2026-10-26 14:53:16 +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
601786123b fix(server): preserve workflow assignees on description updates (MUL-8229) (#9506)
Preserve workflow-selected assignees when description updates refresh untouched nullable fields under the issue row lock. Apply the same behavior to single and batch updates while retaining explicit-assignee precedence.

Add regression coverage for single and batch handoffs, unchanged-status retries, and explicit member assignments. All applicable PR CI checks passed on 3c5f8d4.

Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 14:18:25 +08:00
Soda 2a1f393ad2 fix(skills): enforce portable supporting-file paths (#7743)
Use one slash-delimited path contract for skill authoring endpoints and daemon bundle validation. Cover canonical path handling and all public file-write routes with regression tests.
2026-10-26 13:49:05 +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
802f0894e0 refactor(attachments): generate text preview whitelist (MUL-8248) (#9527)
* refactor(attachments): generate text preview whitelist

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

* fix(attachments): gate text previews on shared whitelist (MUL-8248)

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

---------

Co-authored-by: Cursor <[email protected]>
Co-authored-by: Multica Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-26 13:38:42 +08:00