@robota-sdk/agent-ui-web 3.0.0-beta.94 → 3.0.0-beta.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,90 @@
1
1
  # @robota-sdk/agent-ui-web
2
2
 
3
+ ## 3.0.0-beta.95
4
+ ### Minor Changes
5
+
6
+ - 0ba247b: A tool result can now carry a view its source declared (an MCP app), and a surface can invoke a
7
+ runtime tool through the session's permission gate with a prompt. This is the contract and wiring
8
+ layer: nothing produces a view yet, and the GUI does not yet host one.
9
+
10
+ - `agent-core` — `IToolResult.view` carries an `IToolAppView` (source, `ui://` resource, mime type,
11
+ HTML, structured content, callable tools, the call's input). `view` is now a typed key of
12
+ `IToolResult`, so an extension that already used a `view` key with another type must rename it.
13
+ The view is display data: it never enters model context or the size that decides a spill, and a
14
+ result replaced by its reference keeps it.
15
+ - `agent-interface-session` — `invokeRuntimeTool` takes `permissionInteraction` (`'interactive'` or
16
+ the default `'deny'`), a `driverId` (a host that attributes prompts names it as the requester) and
17
+ an `executionId` its events carry. A finished model call's `tool_end` names its view with
18
+ `IToolState.appView` (`viewId`, source, resource), and the new
19
+ `ISessionToolAppViews.readToolAppView(viewId)` reads the document. A permission handler may take
20
+ `{ signal }`, and aborting it withdraws the prompt.
21
+ - `agent-session` — a direct call asks a person only when its caller says so, and the handler is
22
+ given the call's own signal; the tool end event carries the view, never in the logged result data.
23
+ - `agent-framework` — the view of a model's call is kept under a `viewId` the session mints, in a
24
+ bounded per-session store (16 views, 4 MiB each, 16 MiB in all, measured on the whole serialized
25
+ view), and read on demand, so the document never rides `tool_end` to every surface, never enters
26
+ the recorded history, and a repeated provider tool-call id cannot overwrite another turn's view.
27
+ A malformed view is dropped. A direct call keeps and names no view, recognised by the id it was
28
+ started with. A submission or agent wakeup that arrives while a direct call holds the session is
29
+ queued behind it, as during a turn, instead of refused. A direct call acting for a driver
30
+ attributes its permission prompt and tool events to that driver, and aborting its signal withdraws
31
+ an open prompt from every surface.
32
+ - `agent-transport` — a driving connection sends `call-app-tool` (answered by `app_tool_result`) and
33
+ `read-app-view` (answered by `app_view`). A call names its view and reaches only the tools that
34
+ view's source declared; a call or read that decodes but cannot be served answers `protocol_error`
35
+ echoing the `requestId`, while an observer's attempt is refused like any non-read. A call still
36
+ waiting on its prompt is cancelled when its connection goes away (for the resume bridge, when the
37
+ bridge is disposed). `maxFrameBytes` bounds an app answer to what a carrier's channel carries;
38
+ the WebRTC carrier uses a history page's worth. `IProtocolSession` now includes the runtime-tool
39
+ and app-view roles.
40
+ - `agent-ui-web` — the two new server messages are recorded as not rendered until the app-view host
41
+ consumes them.
42
+
43
+ An implementation of `IInteractiveSession` or `IProtocolSession` outside this repository must add
44
+ `readToolAppView` (and, for `IProtocolSession`, `listRuntimeTools` and `invokeRuntimeTool`); the
45
+ members are required so a host cannot silently lack them.
46
+
47
+ ### Patch Changes
48
+
49
+ - 09e7e21: **An MCP server's form-mode elicitation during a tool call becomes a Robota ask prompt.**
50
+
51
+ `@robota-sdk/agent-mcp` opens a session with `elicitation: true` to declare form-mode elicitation and
52
+ answer it: a request the server raises while a tool call is in flight (a server→client
53
+ `elicitation/create` on the legacy era, an `input_required` round on 2026-07-28) is put to a person
54
+ through that call's ask port (`IMCPToolCallOptions.ask`, which the discovered tool fills from
55
+ `IToolExecutionContext.ask`) as one question titled with the configured server id and carrying the
56
+ server's message as one bounded line, with Respond and Decline, then one question per field
57
+ (choices, multi-select, yes/no, or free text validated against the field and re-asked once). The
58
+ answer continues the same call; the re-sent `tools/call` that carries it is the protocol's
59
+ continuation, not a replay, and a prompt is withdrawn when its call ends (an abort, or the call's
60
+ own timeout) — when the last in-flight call to that server ends, if there are several, since a
61
+ request names none of them. A request outside an in-flight call, or during a call that has no ask port, is
62
+ declined; a dismissal, a failing port or a second rejected answer cancels; a field named like a
63
+ credential is shown unmasked with a warning. URL mode is not offered. Without the opt-in nothing
64
+ changes: no capability is declared and an `input_required` result still closes the carrier. An
65
+ embedded request of another kind (sampling, roots) or more rounds than the client allows closes the
66
+ carrier as `input_required` does; an embedded elicitation the client refuses on its face (URL mode,
67
+ a malformed form) fails the call and leaves the carrier open.
68
+
69
+ `@robota-sdk/agent-cli` turns the opt-in on for the interactive terminal and the serve host driven by
70
+ the desktop app or the web GUI, which show the prompt, and leaves it off for print mode and for the
71
+ two serve-runtime hosts with no prompt surface, `mcp serve` and the ACP editor agent.
72
+
73
+ `@robota-sdk/agent-ui-web` renders an ask with `maxSelect` above 1 as a multi-select: options toggle
74
+ (click or 1–9), Submit answers with the ticked values once `minSelect` is met, and a toggle beyond
75
+ `maxSelect` is ignored, as in the terminal.
76
+ - Updated dependencies [c967c57]
77
+ - Updated dependencies [60f3965]
78
+ - Updated dependencies [115e104]
79
+ - Updated dependencies [04719a9]
80
+ - Updated dependencies [04a6de4]
81
+ - Updated dependencies [0ba247b]
82
+ - @robota-sdk/agent-transport@3.0.0-beta.95
83
+ - @robota-sdk/agent-interface-session@3.0.0-beta.95
84
+ - @robota-sdk/agent-interface-command@3.0.0-beta.95
85
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.95
86
+ - @robota-sdk/agent-interface-transport@3.0.0-beta.95
87
+
3
88
  ## 3.0.0-beta.94
4
89
  ### Patch Changes
5
90
 
@@ -505,6 +505,12 @@ declare function AgentSwitcherSheet({ state }: {
505
505
  * lives only in `FreeTextField`, keyed by `prompt.id`: a cancelled or answered prompt's text can
506
506
  * never reach the next prompt's render, masked or not, because the field is a fresh component
507
507
  * instance rather than a value carried over in this component's own state (#3280 §3 follow-up).
508
+ *
509
+ * An ask whose `maxSelect` is above 1 is a multi-select: each option is a toggle (a click or 1–9 ticks
510
+ * it, nothing answers yet), and Submit — or Enter at the prompt, once the selection is allowed —
511
+ * answers with the ticked values in option order. Unlike the free-text field, the ticks live in this
512
+ * component, because the dock's keys act on them; they are tagged with `prompt.id`, so a prompt never
513
+ * reads the ticks of another.
508
514
  */
509
515
  interface IPermissionPromptProps {
510
516
  prompts: readonly TPendingPrompt[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/client/ws-session-client.ts","../../src/hooks/prompt-state.ts","../../src/hooks/session-client-types.ts","../../src/hooks/useSessionClient.ts","../../src/hooks/use-session-directory.ts","../../src/components/composer-attachments.ts","../../src/components/Composer.tsx","../../src/client/runtime-host.ts","../../src/hooks/ui-intent-state.ts","../../src/components/ConversationView.tsx","../../src/components/AgentActivityPanel.tsx","../../src/components/AgentSwitcherSheet.tsx","../../src/components/PermissionPrompt.tsx","../../src/components/personal-usage-dashboard-types.ts","../../src/components/PersonalUsageDashboard.tsx","../../src/components/SessionSurface.tsx","../../src/components/SessionSidebar.tsx","../../src/components/SessionMonitor.tsx","../../src/components/Dialog.tsx","../../src/components/SettingsScreen.tsx","../../src/components/HelpSheet.tsx","../../src/components/Brand.tsx","../../src/product-identity.tsx"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/client/ws-session-client.ts","../../src/hooks/prompt-state.ts","../../src/hooks/session-client-types.ts","../../src/hooks/useSessionClient.ts","../../src/hooks/use-session-directory.ts","../../src/components/composer-attachments.ts","../../src/components/Composer.tsx","../../src/client/runtime-host.ts","../../src/hooks/ui-intent-state.ts","../../src/components/ConversationView.tsx","../../src/components/AgentActivityPanel.tsx","../../src/components/AgentSwitcherSheet.tsx","../../src/components/PermissionPrompt.tsx","../../src/components/personal-usage-dashboard-types.ts","../../src/components/PersonalUsageDashboard.tsx","../../src/components/SessionSurface.tsx","../../src/components/SessionSidebar.tsx","../../src/components/SessionMonitor.tsx","../../src/components/Dialog.tsx","../../src/components/SettingsScreen.tsx","../../src/components/HelpSheet.tsx","../../src/components/Brand.tsx","../../src/product-identity.tsx"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { decodeFrame, decodeServerMessage } from "@robota-sdk/agent-transport/cl
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  import ReactMarkdown from "react-markdown";
5
5
  import remarkGfm from "remark-gfm";
6
- import { ArrowDown, ArrowUp, Bot, Check, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CircleDashed, CircleX, Copy, ExternalLink, FileText, Gauge, GitBranch, Globe, LoaderCircle, MessageCircleQuestion, MoreHorizontal, PanelLeftClose, PanelLeftOpen, Paperclip, Pause, Pencil, Play, RefreshCw, Search, Settings, Shield, ShieldAlert, Sparkles, Square, SquarePen, SquareTerminal, Target, Trash2, Wrench, X } from "lucide-react";
6
+ import { ArrowDown, ArrowUp, Bot, Check, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CircleDashed, CircleX, Copy, ExternalLink, FileText, Gauge, GitBranch, Globe, LoaderCircle, MessageCircleQuestion, MoreHorizontal, PanelLeftClose, PanelLeftOpen, Paperclip, Pause, Pencil, Play, RefreshCw, Search, Settings, Shield, ShieldAlert, Sparkles, Square, SquareCheck, SquarePen, SquareTerminal, Target, Trash2, Wrench, X } from "lucide-react";
7
7
  import { AGENT_DRIVER_ID, OWNER_DRIVER_ID } from "@robota-sdk/agent-interface-session";
8
8
  //#region src/hooks/excluded-commands.ts
9
9
  /**
@@ -285,6 +285,8 @@ const SERVER_MESSAGE_HANDLING = {
285
285
  project_status: "reducer-state",
286
286
  project_diff: "reducer-state",
287
287
  project_memory: "reducer-state",
288
+ app_view: "intentionally-not-rendered",
289
+ app_tool_result: "intentionally-not-rendered",
288
290
  background_task_event: "intentionally-not-rendered",
289
291
  background_job_group_event: "intentionally-not-rendered",
290
292
  plan_event: "intentionally-not-rendered",
@@ -3211,6 +3213,26 @@ function isEditableElement(element) {
3211
3213
  function isDestructiveAskOption(requestId, value) {
3212
3214
  return requestId === "provider-profile-action" && value === "delete";
3213
3215
  }
3216
+ /**
3217
+ * The multi-select shape of an ask, or undefined for every other ask (which answers on click). The
3218
+ * rules mirror the terminal checklist (`MultiSelectList` in agent-ui-terminal): `minSelect` (default 1)
3219
+ * gates the submit, and `maxSelect` caps the ticks — a toggle beyond the cap is ignored, never swapped
3220
+ * for the oldest tick. `default.values` pre-select; a default that names no option is dropped, and
3221
+ * more defaults than the cap keep the first ones in option order, so the answer never breaks the cap.
3222
+ */
3223
+ function readMultiSelect(request) {
3224
+ const max = request.maxSelect ?? 1;
3225
+ if (max <= 1) return void 0;
3226
+ const options = (request.options ?? []).filter((opt) => !isDestructiveAskOption(request.id, opt.value));
3227
+ const wanted = new Set(request.default?.values ?? []);
3228
+ const defaults = options.filter((opt) => wanted.has(opt.value)).slice(0, max);
3229
+ return {
3230
+ min: request.minSelect ?? 1,
3231
+ max,
3232
+ options,
3233
+ defaults: new Set(defaults.map((opt) => opt.value))
3234
+ };
3235
+ }
3214
3236
  function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverId = null, layout = "modal", armDelayMs = 450, onFocusReturn }) {
3215
3237
  const prompt = prompts[0];
3216
3238
  const promptId = prompt?.id;
@@ -3222,6 +3244,7 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3222
3244
  const [fieldFocused, setFieldFocused] = useState(false);
3223
3245
  const fieldHandleRef = useRef(null);
3224
3246
  const pendingFocusReturnRef = useRef(false);
3247
+ const [selection, setSelection] = useState(void 0);
3225
3248
  useEffect(() => {
3226
3249
  if (promptId === void 0 || armDelayMs <= 0) return void 0;
3227
3250
  const timer = setTimeout(() => setArmedId(promptId), armDelayMs);
@@ -3286,6 +3309,28 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3286
3309
  fieldHandleRef.current?.clear();
3287
3310
  onAnswerAsk(id, response);
3288
3311
  };
3312
+ const multi = prompt.kind === "ask" ? readMultiSelect(prompt.request) : void 0;
3313
+ const ticks = selection?.promptId === prompt.id ? selection.values : multi?.defaults;
3314
+ const selectedValues = multi && ticks ? multi.options.map((opt) => opt.value).filter((value) => ticks.has(value)) : [];
3315
+ const canSubmit = multi !== void 0 && selectedValues.length >= multi.min;
3316
+ const toggleOption = (value) => {
3317
+ if (!multi) return;
3318
+ setSelection((current) => {
3319
+ const next = new Set(current?.promptId === prompt.id ? current.values : multi.defaults);
3320
+ if (next.has(value)) next.delete(value);
3321
+ else if (next.size < multi.max) next.add(value);
3322
+ return {
3323
+ promptId: prompt.id,
3324
+ values: next
3325
+ };
3326
+ });
3327
+ };
3328
+ const submitSelection = () => {
3329
+ if (canSubmit) answerAsk(prompt.id, {
3330
+ type: "answer",
3331
+ values: selectedValues
3332
+ });
3333
+ };
3289
3334
  /** A click anywhere in the prompt that isn't on a button or the field itself focuses the field. */
3290
3335
  const onContainerClick = (event) => {
3291
3336
  if (!hasFreeText) return;
@@ -3305,6 +3350,13 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3305
3350
  return;
3306
3351
  }
3307
3352
  if (!armed) return;
3353
+ if (multi && event.key === "Enter") {
3354
+ if (event.target === event.currentTarget) {
3355
+ event.preventDefault();
3356
+ submitSelection();
3357
+ }
3358
+ return;
3359
+ }
3308
3360
  const index = Number(event.key) - 1;
3309
3361
  if (!Number.isInteger(index) || index < 0) return;
3310
3362
  if (prompt.kind === "permission") {
@@ -3312,7 +3364,9 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3312
3364
  return;
3313
3365
  }
3314
3366
  const option = (prompt.request.options ?? []).filter((opt) => !isDestructiveAskOption(prompt.request.id, opt.value))[index];
3315
- if (option) answerAsk(prompt.id, {
3367
+ if (!option) return;
3368
+ if (multi) toggleOption(option.value);
3369
+ else answerAsk(prompt.id, {
3316
3370
  type: "answer",
3317
3371
  values: [option.value]
3318
3372
  });
@@ -3324,7 +3378,7 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3324
3378
  const askOptions = prompt.kind === "ask" ? prompt.request.options ?? [] : [];
3325
3379
  const destructiveAskOption = askOptions.find((opt) => isDestructiveAskOption(askRequestId, opt.value));
3326
3380
  const primaryAskOptions = destructiveAskOption ? askOptions.filter((opt) => opt !== destructiveAskOption) : askOptions;
3327
- const askArmedHint = hasFreeText && fieldFocused ? "Enter to submit · Esc to cancel" : askOptions.length > 0 ? "1–9 choose · Esc cancel" : "Esc cancels";
3381
+ const askArmedHint = hasFreeText && fieldFocused ? "Enter to submit · Esc to cancel" : multi && askOptions.length > 0 ? "1–9 toggle · Enter submit · Esc cancel" : askOptions.length > 0 ? "1–9 choose · Esc cancel" : "Esc cancels";
3328
3382
  return /* @__PURE__ */ jsx("div", {
3329
3383
  className: dock ? "agent-ui gui-rise flex-shrink-0" : "agent-ui fixed inset-0 z-50 flex items-center justify-center bg-black/55 p-4 backdrop-blur-[2px]",
3330
3384
  children: /* @__PURE__ */ jsx("div", {
@@ -3476,12 +3530,23 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3476
3530
  children: [/* @__PURE__ */ jsxs("button", {
3477
3531
  type: "button",
3478
3532
  "aria-keyshortcuts": dock && index < 9 ? String(index + 1) : void 0,
3479
- className: index === 0 ? PRIMARY_BUTTON$1 : SECONDARY_BUTTON$1,
3480
- onClick: onButton(() => answerAsk(prompt.id, {
3533
+ "aria-pressed": multi ? selectedValues.includes(opt.value) : void 0,
3534
+ className: (multi ? selectedValues.includes(opt.value) : index === 0) ? PRIMARY_BUTTON$1 : SECONDARY_BUTTON$1,
3535
+ onClick: onButton(() => multi ? toggleOption(opt.value) : answerAsk(prompt.id, {
3481
3536
  type: "answer",
3482
3537
  values: [opt.value]
3483
3538
  })),
3484
- children: [/* @__PURE__ */ jsx("span", { children: opt.label }), dock && index < 9 && /* @__PURE__ */ jsx(Kbd, { children: index + 1 })]
3539
+ children: [
3540
+ multi && (selectedValues.includes(opt.value) ? /* @__PURE__ */ jsx(SquareCheck, {
3541
+ size: 15,
3542
+ strokeWidth: 2
3543
+ }) : /* @__PURE__ */ jsx(Square, {
3544
+ size: 15,
3545
+ strokeWidth: 2
3546
+ })),
3547
+ /* @__PURE__ */ jsx("span", { children: opt.label }),
3548
+ dock && index < 9 && /* @__PURE__ */ jsx(Kbd, { children: index + 1 })
3549
+ ]
3485
3550
  }), opt.description && /* @__PURE__ */ jsx("p", {
3486
3551
  className: "pl-0.5 text-[11.5px] leading-snug text-subtle",
3487
3552
  children: opt.description
@@ -3523,16 +3588,26 @@ function PermissionPrompt({ prompts, onAnswerPermission, onAnswerAsk, ownDriverI
3523
3588
  }),
3524
3589
  /* @__PURE__ */ jsxs("div", {
3525
3590
  className: "flex flex-wrap items-center gap-2",
3526
- children: [/* @__PURE__ */ jsx("button", {
3527
- type: "button",
3528
- className: GHOST_BUTTON,
3529
- onClick: onButton(() => answerAsk(prompt.id, { type: "cancelled" })),
3530
- children: "Cancel"
3531
- }), dock && /* @__PURE__ */ jsx(KeyHint, {
3532
- hasFocus,
3533
- armed,
3534
- armedText: askArmedHint
3535
- })]
3591
+ children: [
3592
+ multi && /* @__PURE__ */ jsx("button", {
3593
+ type: "button",
3594
+ className: `${PRIMARY_BUTTON$1} disabled:opacity-60`,
3595
+ disabled: !canSubmit,
3596
+ onClick: onButton(submitSelection),
3597
+ children: canSubmit ? "Submit" : `Submit (min ${multi.min})`
3598
+ }),
3599
+ /* @__PURE__ */ jsx("button", {
3600
+ type: "button",
3601
+ className: GHOST_BUTTON,
3602
+ onClick: onButton(() => answerAsk(prompt.id, { type: "cancelled" })),
3603
+ children: "Cancel"
3604
+ }),
3605
+ dock && /* @__PURE__ */ jsx(KeyHint, {
3606
+ hasFocus,
3607
+ armed,
3608
+ armedText: askArmedHint
3609
+ })
3610
+ ]
3536
3611
  })
3537
3612
  ]
3538
3613
  })] })