Files
Multica Eve 1ae0a1f5bf fix(agents): defend AccessPicker against undefined invocation_targets (GH #4915) (#4924)
Opening the agent detail page in v0.3.37 crashed the whole route with
"Cannot read properties of undefined (reading 'some')" whenever the
cached agent record's `invocation_targets` was missing at runtime — even
though the TypeScript type declares it a required `AgentInvocationTarget[]`.

Root cause: `AccessPicker`'s `hasWorkspaceTarget` / `selectedMemberIds` /
`selectedTeamIds` helpers called `.some()` / `.filter()` directly on the
prop, and the same unguarded pattern was mirrored in `AgentMcpTab` and
the `canAssignAgentToIssue` permission gate. The field can legitimately
be undefined at runtime because:

- `packages/core/api/schemas.ts` declares `invocation_targets` as
  `.optional()`, and `MinimalAgentSchema` (used for the create-from-
  template response) also marks it optional.
- `api.listAgents` / `api.getAgent` return raw JSON without running
  through the schema, so an older self-host backend that predates
  MUL-3963 (permission_mode + invocation_targets) — the exact scenario
  in GH #4915 — yields an Agent with the field missing.

Fix (`?? []`) at every site that indexes into the list, matching the
already-established pattern in `create-agent-dialog.tsx`:

- `access-picker.tsx`: coerce inside the three helpers and widen the
  prop type to `AgentInvocationTarget[] | undefined` so the accepted
  runtime shape is documented.
- `agent-mcp-tab.tsx`: `(agent.invocation_targets ?? []).some(...)`.
- `permissions/rules.ts`: `agent.invocation_targets ?? []` before the
  workspace / member membership checks.

Adds three regression tests (AccessPicker owner + read-only paths,
AgentMcpTab shared-warning path, canAssignAgentToIssue) that pass
`undefined` for invocation_targets and assert the UI degrades to the
private / empty-allowlist state instead of throwing.

Co-authored-by: Eve <eve@multica-ai.local>
Co-authored-by: multica-agent <github@multica.ai>
2026-07-04 18:07:03 +08:00
..