@robota-sdk/agent-ui-web 3.0.0-beta.93 → 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 +94 -0
- package/dist/browser/index.d.ts +6 -0
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +91 -16
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +90 -15
- package/dist/node/index.d.cts +6 -0
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +6 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +91 -16
- package/dist/node/index.js.map +1 -1
- package/docs/SPEC.md +2 -1
- package/package.json +6 -6
- package/src/components/PermissionPrompt.tsx +108 -7
- package/src/hooks/server-message-handling.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
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
|
+
|
|
88
|
+
## 3.0.0-beta.94
|
|
89
|
+
### Patch Changes
|
|
90
|
+
|
|
91
|
+
- @robota-sdk/agent-interface-session@3.0.0-beta.94
|
|
92
|
+
- @robota-sdk/agent-transport@3.0.0-beta.94
|
|
93
|
+
- @robota-sdk/agent-interface-command@3.0.0-beta.94
|
|
94
|
+
- @robota-sdk/agent-interface-execution@3.0.0-beta.94
|
|
95
|
+
- @robota-sdk/agent-interface-transport@3.0.0-beta.94
|
|
96
|
+
|
|
3
97
|
## 3.0.0-beta.93
|
|
4
98
|
### Minor Changes
|
|
5
99
|
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -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":";;;;;;;KAWY;UAEK;EACf,YAAY,KAAK;EACjB,iBAAiB,QAAQ;;;;;EAKzB;;UAGe;EACf;EACA;EACA,OAAO,KAAK;EACZ,cAAc;;iBAMA,sBACd,aACA,WAAW,4BACV;;;;KCjBS;WACI;IAAuB;WACvB;IAAgB;;;;;;iBAOhB,iBACd,kBAAkB,kBAClB,KAAK,0BACK;;iBA4CI,mBAAmB,YAAY,QAAQ,yBAAyB;;iBAKhE,YAAY,YAAY,UAAU,kBAAkB;;;KC9DxD,uBAAuB,QACjC;EACE;;KAEQ,4BAA4B,QACtC;EACE;;;KAGQ,kBAAkB,KAAK,QAAQ;EAAkB;;;KAEjD,iBAAiB,QAAQ;EAAkB;;;;;;KAM3C,qBAAqB,KAC/B,QAAQ;EAAkB;;;KAKhB,kBAAkB,QAAQ;EAAkB;;;KAE5C,iBAAiB,KAC3B,QAAQ;EAAkB;;KAIhB,6BAA6B,QACvC;EACE;;;;KAKQ,qBAAqB,QAAQ;EAAkB;;KAC/C,mBAAmB,QAAQ;EAAkB;;KAC7C,qBAAqB,QAAQ;EAAkB;;UAE1C;EACf;EACA;EACA;EACA;;EAEA;;;;;;UAOe;EACf;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;EACA,gBAAgB;;;UAID;EACf;EACA;EACA;EACA,oBAAoB;;;UAIL;EACf;EACA;EACA,gBAAgB;;KAGN,qBACV,uBAAuB,sBAAsB,kBAAkB;UAEhD;EACf;EACA;EACA;EACA;EACA,SAAS;;EAET;;EAEA,qBAAqB;;EAErB;;EAEA;;EAEA,kBAAkB;;EAElB;;EAEA;;EAEA;;;;;;;UAQe;EACf;EACA;;UAGe;EACf;;;;;;;;EAQA;EAMA;;;;;;EAMA;EACA;EACA;;;;;;;EAOA;;UAGe;EACf;EACA;EACA,OAAO,KAAK;;KAGF,mBAAmB,yBAAyB,sBAAsB;EAC5E,YAAY,KAAK;EACjB,iBAAiB,QAAQ;MACrB;UAEW,gBAAgB,yBAAyB;EACxD,QAAQ;;;;;;EAMR;EACA,UAAU;EACV,aAAa;EACb;EACA;EACA,oBAAoB;EACpB;;EAEA,aAAa;;EAEb,gBAAgB;;EAEhB,eAAe;;;;;EAKf,WAAW;;EAEX;;EAEA,gBAAgB;;EAEhB,eAAe;EACf;;EAEA,gBAAgB;;EAEhB;;EAEA,sBAAsB,mBAAmB;;EAEzC,gBAAgB;;EAEhB;EACA,wBAAwB;EACxB,OAAO,KAAK;;;;;;EAMZ,sBAAsB,cAAc;EACpC,yBAAyB;;EAEzB,cAAc;EACd,mBAAmB,YAAY,QAAQ;EACvC,YAAY,YAAY,UAAU;EAClC;EACA,qBAAqB;EACrB;EACA,uBAAuB;EACvB;EACA,0BAA0B;EAC1B;EACA;EACA,4BAA4B;EAC5B;EACA,2BAA2B;EAC3B;EACA,yBAAyB;EACzB,uBAAuB;;EAEvB;EACA;;EAEA,kBAAkB;;EAElB;;EAEA;;;;;;EAMA,eAAe;EACf;;EAEA,iBAAiB,OAAO;;EAExB;EACA;EACA;;EAEA;EACA;EACA,iCAAiC;EACjC;;EAEA;EACA,sBAAsB;EACtB;EACA;;EAEA;EACA,eAAe;EACf;;EAEA;EACA;EACA,aAAa;EACb,qBAAqB;;EAErB;EACA,eAAe;EACf;;;;;EAKA;EACA;;EAEA,2BAA2B;;EAE3B;;EAEA;;EAEA;EACA;;EAEA,cAAc;;;;;EAKd,yBAAyB;;EAEzB,gBAAgB;EAChB,iBAAiB;;;;;;EAMjB,iBAAiB;;;;iBC7DH,iBAAiB,yBAAyB,mBACxD,YAAY,mBAAmB,WAC9B,gBAAgB;;iBAmsBH,aACd,cACC,gBAAgB;EAAuB;;;;;;;;;;iBCp6B1B,0BAA0B,mBAAmB;;;;;;;;;UCY5C;WACN;WACA;WACA;;;;;UCnCM;;EAEf;;;;;KCxBU;;UAGK;WACN;WACA;;KAGC;;;;;UAMK;WACN;EACT,eAAe;EACf;EACA,QAAQ,WAAW,OAAO,qBAAqB;EAC/C,kBAAkB;EAClB,iBAAiB,QAAQ;EACzB,YAAY,QAAQ,qBAAqB;IAAU;;EACnD,cAAc,iBAAiB;EAC/B,gBAAgB,MAAM;EACtB,gBAAgB;EAChB,UAAU,eAAe;IAAU;;;;UAIpB;WACN;EACT,eAAe;EACf;EACA,QAAQ,WAAW,OAAO,qBAAqB;WACtC,uBAAuB;WACvB,sBAAsB,QAAQ;WAC9B,eAAe,QAAQ,uBAAuB;IAAU;;WACxD,kBAAkB,iBAAiB;WACnC,kBAAkB,MAAM;EACjC,eAAe;WACN,sBAAsB;;UAGhB;WACN,SAAS;WACT,UAAU,KAAK;WACf,UAAU,KAAK;;;iBAIV,yBAAyB,aAAa,4BAA4B;;;;iBChBlE,qBACd,QAAQ;;;;;;;;;;iBAoBM,uBAAuB,QAAQ;;;UC6DrC;EACR,mBAAmB;EACnB,aAAa;EACb;EACA;;EAEA,aAAa;;iBAmgBC,mBACd,UACA,aACA,eACA,YACA,eACC,yBAAyB,QAAM;;;UCvmBxB;EACR,gBAAgB;;EAEhB,qBAAqB;;EAErB,OAAO;EACP,mBAAmB;EACnB,oBAAoB;EACpB,oBAAoB;EACpB;EACA;;EAEA,YAAY,OAAO;;EAEnB;;EAEA,UAAU,OAAO;;EAEjB;;iBAGc,qBACd,OACA,WACA,MACA,iBACA,kBACA,kBACA,cACA,WACA,UACA,wBACA,QACA,mBACC,2BAA2B,QAAM;;;;;;;;;;;iBChDpB,qBAAqB;EAAW,OAAO;IAAoB,QAAM;;;;;;;;;;;;;;;;;;;;;;;;UCwBvE;EACR,kBAAkB;EAClB,qBAAqB,YAAY;EACjC,cAAc,YAAY,UAAU;;EAEpC,cAAc;EACd;;EAEA;;;;;;;EAOA;;iBAiEc,mBACd,SACA,oBACA,aACA,aACA,QACA,YACA,iBACC,yBAAyB,QAAM;;;KC7HtB,+BAA+B,KACzC;;;iBCQc,yBACd;EAEA,OAAO;IACL,MAAM;;;;;;;iBCoFM,iBACd,OACA,SACA,sBACA,aACA,WACA,gBACA;EAEA,OAAO;EACP;;EAEA;;;;;EAKA,oBAAoB;;EAEpB,kBAAkB,iBAAiB;;EAEnC,kBAAkB,MAAM;;;;;;EAMxB,wBAAwB;IACtB,MAAM;;;;;;;;iBAuSM,iBACd,MACA;EAEA;EACA,UAAU,MAAM;IACd,MAAM;;;;;;;;;;;;;iBCrWM,iBACd,OACA,OACA;EAEA,OAAO;;EAEP,QAAQ,MAAM;EACd;IACE,MAAM;;;UCtDA;;EAER;EACA;;iBAGc,iBAAiB,OAAO,aAAa,uBAAuB,QAAM;;;;;;;;;;;;;;UCnBjE;EACf;;EAEA;EACA;EACA,UAAU,QAAM;;EAEhB;;EAEA;;EAEA;;;;;;;;EAQA,iBAAiB;;;;;;EAMjB;;iBAiBc,SACd,MACA,SACA,OACA,UACA,aACA,gBACA,eACA,gBACA,QACC,eAAe,QAAM;UAqGP;EACf;EACA;EACA,MAAM,QAAM;EACZ;EACA;;EAEA;EACA;EACA;;EAEA,iBAAiB;;;;;;;iBAQH,gBACd,MACA,OACA,MACA,cACA,aACA,aACA,WACA,UACA,kBACC,sBAAsB,QAAM;;;;;;;;;;iBCzJf,iBAAiB;EAAW,OAAO;IAAoB,QAAM;;;;;;;;;;;iBCb7D,YACd,MACA,SACA;EAEA;EACA;EACA,SAAS;IACP,MAAM;;;;iBCrCM,cAAc;EAAe;IAAkB,MAAM;;iBAiBrD,kBAAkB;EAAa;IAAqB,MAAM;;;;UChBzD;WACN;aAAqB;aAA8B;;WACnD;aAAoB;;;iBAKf,0BAA0B,OAAO;WACtC,OAAO;WACP,WAAW;IAClB,MAAM;iBAQM,sBAAsB"}
|
package/dist/browser/index.js
CHANGED
|
@@ -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)
|
|
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
|
-
|
|
3480
|
-
|
|
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: [
|
|
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: [
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
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
|
})] })
|