@blocksdiy/react-common 1.50.1 → 1.52.0

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.
@@ -2,8 +2,9 @@
2
2
  // (useAgentThreads) and the chat runtime (useAgentChat): which conversation is selected and
3
3
  // how a draft becomes a thread; the conversation's row; and the bridge that keeps the index
4
4
  // and the transcript agreeing. UI-free — the agent-layout registry item renders it.
5
- import { useCallback, useEffect, useRef, useState } from "react";
5
+ import { useCallback, useContext, useEffect, useRef, useState } from "react";
6
6
  import { FEEDBACK_MESSAGE_NAME } from "../utils/composer-message.js";
7
+ import { AgentChatOwnRunsContext } from "./agent-chat-own-runs.js";
7
8
  import { agentThreadKey } from "./agent-thread-live-update.js";
8
9
  export const newDraftSelection = (chatId, draftThreadId = crypto.randomUUID()) => ({
9
10
  conversation: { chatId, chatThreadId: draftThreadId },
@@ -106,10 +107,22 @@ export const accountedTurnsAfterOwnSend = (accounted, key, isDraft) => {
106
107
  }
107
108
  return isDraft ? { key, turns: 1 } : accounted;
108
109
  };
110
+ /**
111
+ * The accounting after this client starts `runs` runs on `key` that no send accounted for (a
112
+ * resume: an approval, an answered question). Each is a turn on the server, as a send is.
113
+ */
114
+ export const accountedTurnsAfterOwnRuns = (accounted, key, isDraft, runs) => {
115
+ let next = accounted;
116
+ for (let run = 0; run < runs; run++) {
117
+ next = accountedTurnsAfterOwnSend(next, key, isDraft);
118
+ }
119
+ return next;
120
+ };
109
121
  /**
110
122
  * Keeps the index and the transcript agreeing for the open conversation:
111
123
  * - a run on it this client is not streaming (the listed row's `runningRunId`) reads as the chat's own;
112
- * - a turn this client did not send (`turnCount` ahead of what it accounted for) replays the transcript;
124
+ * - a turn this client did not make (`turnCount` ahead of what it accounted for: its sends, and
125
+ * the runs the chat root started without one) replays the transcript;
113
126
  * - a run mark past the stale ceiling asks the server again (the settle publishes no event);
114
127
  * - refocus re-walks the list (realtime has no replay), throttled.
115
128
  */
@@ -177,9 +190,20 @@ export const useAgentConversation = ({ threads, agentId, conversation, isDraft,
177
190
  window.addEventListener("focus", onFocus);
178
191
  return () => window.removeEventListener("focus", onFocus);
179
192
  }, [refresh]);
180
- // Turns this client did not send (see accountedTurnsAfterRow). `isThinking` is a dependency,
193
+ // Turns this client did not make (see accountedTurnsAfterRow). `isThinking` is a dependency,
181
194
  // so this runs again the moment a run on the conversation settles.
182
195
  const accountedTurnsRef = useRef(null);
196
+ // The chat root's runs without a send, accounted before the row effect below reads a settle.
197
+ const ownRunsWithoutSend = useContext(AgentChatOwnRunsContext);
198
+ const seenOwnRunsRef = useRef(ownRunsWithoutSend);
199
+ useEffect(() => {
200
+ const seen = seenOwnRunsRef.current;
201
+ seenOwnRunsRef.current = ownRunsWithoutSend;
202
+ if (seen === null || ownRunsWithoutSend === null || ownRunsWithoutSend <= seen) {
203
+ return;
204
+ }
205
+ accountedTurnsRef.current = accountedTurnsAfterOwnRuns(accountedTurnsRef.current, conversationKey, isDraft, ownRunsWithoutSend - seen);
206
+ }, [ownRunsWithoutSend, conversationKey, isDraft]);
183
207
  useEffect(() => {
184
208
  if (!knownRow) {
185
209
  return;
@@ -1,5 +1,6 @@
1
1
  import { type AgentThreadItem, type AgentThreadSource, type AgentThreadStatus } from "./agent-thread-live-update.js";
2
2
  export * from "./agent-thread-live-update.js";
3
+ export { type AgentAdminCaller, BUILD_PERMISSION, isAgentAdmin, readAgentAdminRoles } from "../utils/agent-admin.js";
3
4
  export { type AgentConversationChat, type AgentConversationRef, type AgentConversationUrlTarget, agentThreadStandIn, nextRunStaleAt, RUN_STALE_MS, useAgentConversation, type UseAgentConversationOptions, type UseAgentConversationResult, useAgentConversationSelection, type UseAgentConversationSelectionOptions, type UseAgentConversationSelectionResult, } from "./use-agent-conversation.js";
4
5
  export { type AgentConversationContextValue, AgentConversationProvider, type AgentConversationProviderProps, type AgentThreadFilters, useAgentConversationContext, } from "./agent-conversation-context.js";
5
6
  export interface AgentThreadsPage {
@@ -1 +1 @@
1
- {"version":3,"file":"use-agent-threads.d.ts","sourceRoot":"","sources":["../../src/hooks/use-agent-threads.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EAUvB,MAAM,4BAA4B,CAAC;AAEpC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,6BAA6B,EAC7B,KAAK,oCAAoC,EACzC,KAAK,mCAAmC,GACzC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,6BAA6B,EAClC,yBAAyB,EACzB,KAAK,8BAA8B,EACnC,KAAK,kBAAkB,EACvB,2BAA2B,GAC5B,MAAM,8BAA8B,CAAC;AAItC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,oBAAoB,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,YAAY,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzG,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,MAAgD,CAAC;AAEpG,eAAO,MAAM,qBAAqB,GAAI,QAAQ,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,cAAc,CAAC,KAAG,MAIhG,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAC,KAAG,MACpD,CAAC;AAuC1D,0FAA0F;AAC1F,eAAO,MAAM,eAAe,GAAI,SAAS,sBAAsB,KAAG,qBA6UjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"use-agent-threads.d.ts","sourceRoot":"","sources":["../../src/hooks/use-agent-threads.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EAUvB,MAAM,4BAA4B,CAAC;AAEpC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,KAAK,gBAAgB,EAAE,gBAAgB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAClH,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,6BAA6B,EAC7B,KAAK,oCAAoC,EACzC,KAAK,mCAAmC,GACzC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,6BAA6B,EAClC,yBAAyB,EACzB,KAAK,8BAA8B,EACnC,KAAK,kBAAkB,EACvB,2BAA2B,GAC5B,MAAM,8BAA8B,CAAC;AAItC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,oBAAoB,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,YAAY,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzG,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,MAAgD,CAAC;AAEpG,eAAO,MAAM,qBAAqB,GAAI,QAAQ,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,cAAc,CAAC,KAAG,MAIhG,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAC,KAAG,MACpD,CAAC;AAuC1D,0FAA0F;AAC1F,eAAO,MAAM,eAAe,GAAI,SAAS,sBAAsB,KAAG,qBA6UjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -3,6 +3,7 @@ import { websocketsService } from "@blocksdiy/blocks-client-api/websocketService
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { agentThreadKey, applyAgentThreadUpdate, isAgentThreadItem, matchesAgentThreadFilters, optimisticThreadAfterSend, overlayOptimisticThreads, reconcileWalkWithLive, removeAgentThread, retireOptimisticThreadsTakenOver, } from "./agent-thread-live-update.js";
5
5
  export * from "./agent-thread-live-update.js";
6
+ export { BUILD_PERMISSION, isAgentAdmin, readAgentAdminRoles } from "../utils/agent-admin.js";
6
7
  export { agentThreadStandIn, nextRunStaleAt, RUN_STALE_MS, useAgentConversation, useAgentConversationSelection, } from "./use-agent-conversation.js";
7
8
  export { AgentConversationProvider, useAgentConversationContext, } from "./agent-conversation-context.js";
8
9
  const AGENT_THREAD_UPDATED = "AGENT_THREAD_UPDATED";
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Who is an admin of an agent — the client twin of wf-actions-py `agent_admin.py`.
3
+ *
4
+ * A caller is an agent admin when they are signed in AND (they are a builder of the app, OR the
5
+ * agent restricts nothing — `adminRoles` unset or empty — OR their role is one of `adminRoles`,
6
+ * matched by trimmed name, case-sensitive). Anything else is not an admin (fail closed).
7
+ *
8
+ * This is "is this caller an admin of this agent", NOT "does this chat have the admin
9
+ * experience on" (`AgentChat.isAdmin`). The admin experience needs both. The client verdict is
10
+ * display-only; the server decides independently every turn.
11
+ */
12
+ export interface AgentAdminCaller {
13
+ isAuthenticated?: boolean;
14
+ permission?: string;
15
+ role?: string;
16
+ }
17
+ export declare const BUILD_PERMISSION = "build";
18
+ /**
19
+ * `adminRoles`: `undefined` or empty = no restriction; `null` = present but malformed, which makes
20
+ * nobody an admin (the server reads it the same way — garbage must not mean "no restriction").
21
+ */
22
+ export declare const isAgentAdmin: (user: AgentAdminCaller | null | undefined, adminRoles: readonly string[] | null | undefined) => boolean;
23
+ /**
24
+ * The agent block's `adminRoles` as trimmed, non-blank names; `undefined` when unset, `null` when
25
+ * present but not a list. Mirrors `normalize_admin_roles` in wf-actions-py `agent_admin.py`.
26
+ */
27
+ export declare const readAgentAdminRoles: (value: unknown) => string[] | null | undefined;
28
+ //# sourceMappingURL=agent-admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-admin.d.ts","sourceRoot":"","sources":["../../src/utils/agent-admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,gBAAgB,GAAG,IAAI,GAAG,SAAS,EACzC,YAAY,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,KAC/C,OAeF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,OAAO,KAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAWtE,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Who is an admin of an agent — the client twin of wf-actions-py `agent_admin.py`.
3
+ *
4
+ * A caller is an agent admin when they are signed in AND (they are a builder of the app, OR the
5
+ * agent restricts nothing — `adminRoles` unset or empty — OR their role is one of `adminRoles`,
6
+ * matched by trimmed name, case-sensitive). Anything else is not an admin (fail closed).
7
+ *
8
+ * This is "is this caller an admin of this agent", NOT "does this chat have the admin
9
+ * experience on" (`AgentChat.isAdmin`). The admin experience needs both. The client verdict is
10
+ * display-only; the server decides independently every turn.
11
+ */
12
+ export const BUILD_PERMISSION = "build";
13
+ /**
14
+ * `adminRoles`: `undefined` or empty = no restriction; `null` = present but malformed, which makes
15
+ * nobody an admin (the server reads it the same way — garbage must not mean "no restriction").
16
+ */
17
+ export const isAgentAdmin = (user, adminRoles) => {
18
+ if (user?.isAuthenticated !== true || adminRoles === null) {
19
+ return false;
20
+ }
21
+ if (user.permission === BUILD_PERMISSION) {
22
+ return true;
23
+ }
24
+ if (!adminRoles || adminRoles.length === 0) {
25
+ return true;
26
+ }
27
+ const role = typeof user.role === "string" ? user.role.trim() : "";
28
+ if (!role) {
29
+ return false;
30
+ }
31
+ return adminRoles.some((adminRole) => typeof adminRole === "string" && adminRole.trim() === role);
32
+ };
33
+ /**
34
+ * The agent block's `adminRoles` as trimmed, non-blank names; `undefined` when unset, `null` when
35
+ * present but not a list. Mirrors `normalize_admin_roles` in wf-actions-py `agent_admin.py`.
36
+ */
37
+ export const readAgentAdminRoles = (value) => {
38
+ if (value === undefined || value === null) {
39
+ return undefined;
40
+ }
41
+ if (!Array.isArray(value)) {
42
+ return null;
43
+ }
44
+ return value
45
+ .filter((role) => typeof role === "string")
46
+ .map((role) => role.trim())
47
+ .filter((role) => role.length > 0);
48
+ };
@@ -0,0 +1,179 @@
1
+ /**
2
+ * What a parked agent turn waits on, and how the chat answers it.
3
+ *
4
+ * The server ends a parked run with the AG-UI standard `RUN_FINISHED.outcome`
5
+ * (`{type: "interrupt", interrupts}`), live and on connect. Each interrupt carries
6
+ * HumanInTheLoopMiddleware's requests in `metadata.langgraph.raw` -- name, args and
7
+ * description, no ids. One model step batches ask_user and approvals into ONE
8
+ * interrupt, and two paused sub-agents are two interrupts, so the chat collects one
9
+ * answer per request and resumes once with `resume[]`.
10
+ *
11
+ * Cards pair with tool calls BY ORDER, as ask_user cards already do:
12
+ * the middleware builds its requests in the waiting message's tool-call order, so
13
+ * the i-th request of a name is the i-th unanswered call of that name. A request
14
+ * with no such call belongs to a sub-agent, whose calls the parent transcript does
15
+ * not show: it hangs on the waiting `task` call. The server pairs the same way
16
+ * (wf-actions-py `hitl_pairing`). A wrong match can only misplace a card: the card
17
+ * draws the request's own name and args, and decisions stay positional.
18
+ *
19
+ * A past decision comes back on the tool message as `metadata["blocks.toolApprovals"]`.
20
+ * Who decided and when is a server-side audit record and is never shown.
21
+ */
22
+ import type { Interrupt, Message, ResumeEntry } from "@ag-ui/client";
23
+ export declare const TOOL_APPROVALS_METADATA_KEY = "blocks.toolApprovals";
24
+ export declare const APPROVAL_STATUS_LINE: {
25
+ readonly waiting: "Waiting for approval";
26
+ readonly approved: "Approved";
27
+ readonly rejected: "Rejected";
28
+ };
29
+ /** Appended to a decided card's status while another request of the pause is open. */
30
+ export declare const WAITING_FOR_OTHER_SUFFIX = " \u00B7 waiting for your decision on the other request";
31
+ export type ApprovalDecision = "approve" | "reject";
32
+ export type InterruptAnswer = {
33
+ type: "respond";
34
+ message: unknown;
35
+ } | {
36
+ type: ApprovalDecision;
37
+ };
38
+ export interface InterruptRequest {
39
+ interruptId: string;
40
+ index: number;
41
+ key: string;
42
+ name: string;
43
+ args: Record<string, unknown>;
44
+ allowedDecisions: string[];
45
+ /** The parent transcript call this request paired with; null for a sub-agent's request. */
46
+ toolCallId: string | null;
47
+ /** The transcript call the card hangs on: the call itself, or the waiting `task` call. */
48
+ anchorToolCallId: string | null;
49
+ /** The tool's describe name (`InsertItemsToTasksTable`); `name` is lowercased for the model. */
50
+ displayName: string | null;
51
+ }
52
+ export interface ToolApprovalStamp {
53
+ toolCallId: string;
54
+ decision: ApprovalDecision;
55
+ toolName: string;
56
+ /** Absent on records written before display names. */
57
+ displayName?: string | null;
58
+ args: Record<string, unknown>;
59
+ }
60
+ export interface ApprovalCardView {
61
+ key: string;
62
+ title: string;
63
+ /** The tool input as given; the cards show it as YAML. */
64
+ args: Record<string, unknown>;
65
+ status: "waiting" | "approved" | "rejected";
66
+ statusLine: string;
67
+ /** Set only while this card can still be decided. */
68
+ request: {
69
+ interruptId: string;
70
+ index: number;
71
+ } | null;
72
+ /** Decided here but not sent yet: another card of the same pause is still open. */
73
+ waitingForOthers: boolean;
74
+ }
75
+ export declare const requestKey: (interruptId: string, index: number) => string;
76
+ /**
77
+ * Every request of the open interrupts, in the order the server needs decisions,
78
+ * each paired with its transcript call by order.
79
+ */
80
+ export declare const requestsOf: (interrupts: readonly Interrupt[], messages: readonly Message[]) => InterruptRequest[];
81
+ export declare const isApprovalRequest: (request: InterruptRequest) => boolean;
82
+ /** Thrown with fixed text when an answer pairs with no open interrupt and is not the welcome seed. */
83
+ export declare const INTERRUPT_NOT_OPEN_ERROR = "answerInterrupt: nothing is waiting for this answer";
84
+ /**
85
+ * A question's answer as HumanInTheLoopMiddleware's `respond` message -- and as the welcome
86
+ * seed's tool result, so both read the same. `?? null`: JSON.stringify(undefined) drops the
87
+ * key, which the server refuses.
88
+ */
89
+ export declare const respondMessageOf: (answer: unknown) => string;
90
+ /**
91
+ * The welcome seed (`initialUserChoices`): connect writes an ask_user call that no run made,
92
+ * so nothing is parked behind it. Its signature is the one the server used
93
+ * (`answer_orphan_pause`): no user message yet, and the call still waits on the newest
94
+ * assistant message.
95
+ */
96
+ export declare const isWelcomeSeedCall: (messages: readonly Message[], toolCallId: string) => boolean;
97
+ type AnswerRoute = {
98
+ kind: "respond";
99
+ request: InterruptRequest;
100
+ } | {
101
+ kind: "seed";
102
+ } | {
103
+ kind: "refuse";
104
+ };
105
+ /**
106
+ * Where a question card's answer goes: the open request it pairs with by order; the seed's
107
+ * tool result when nothing is open; otherwise nowhere -- the caller
108
+ * throws INTERRUPT_NOT_OPEN_ERROR. Never `command.resume`.
109
+ */
110
+ export declare const answerRouteOf: (interrupts: readonly Interrupt[], messages: readonly Message[], toolCallId: string) => AnswerRoute;
111
+ /**
112
+ * The deprecated `resolveInterrupt(resume)`: a `{decisions}` payload for the ONE
113
+ * open interrupt, as a standard resolved entry. Null when it cannot be routed.
114
+ */
115
+ export declare const singleInterruptResume: (interrupts: readonly Interrupt[], payload: unknown) => ResumeEntry[] | null;
116
+ /**
117
+ * After a run that carried `resume[]`: anything but RUN_FINISHED (a RUN_ERROR such as a refused
118
+ * resume, a stop, a dropped stream) may have consumed the resume on the server, while
119
+ * @ag-ui/client changes `pendingInterrupts` only on RUN_FINISHED. The chat then forgets them and
120
+ * reconnects; the connect re-sends what is really open.
121
+ */
122
+ export declare const needsReconnectAfter: (sentResume: boolean, finished: boolean) => boolean;
123
+ /** One `resolved` entry per open interrupt, or null while any request is unanswered. */
124
+ export declare const buildResumeEntries: (interrupts: readonly Interrupt[], requests: readonly InterruptRequest[], answers: ReadonlyMap<string, InterruptAnswer>) => ResumeEntry[] | null;
125
+ /**
126
+ * Typing while the turn is parked: the typed text goes out as a normal
127
+ * message, and each open interrupt gets the protocol's own `cancelled` entry, with no payload.
128
+ * The server rejects every waiting approval with the standard text, skips every question with
129
+ * one fixed marker, and appends the message after them.
130
+ */
131
+ export declare const cancelledResumeEntries: (interrupts: readonly Interrupt[]) => ResumeEntry[];
132
+ /**
133
+ * Forgets the agent's open interrupts. CopilotKit 1.70.2 keeps
134
+ * `pendingInterrupts` across a thread swap and a reconnect, and @ag-ui/client 0.0.59
135
+ * then refuses the next run AND connect ("Thread has N pending interrupt(s) not
136
+ * addressed by resume"). Call it on a thread swap and right before every connect
137
+ * the chat starts; the connect's own RUN_FINISHED re-sends what is still open.
138
+ */
139
+ export declare const forgetOpenInterrupts: (agent: unknown) => void;
140
+ /** This browser's own approval decisions, by anchor, until a reload brings the record. */
141
+ export declare const localStampsByAnchor: (requests: readonly InterruptRequest[], answers: ReadonlyMap<string, InterruptAnswer>) => Map<string, ToolApprovalStamp[]>;
142
+ export declare const mergeStamps: (previous: ReadonlyMap<string, ToolApprovalStamp[]>, next: ReadonlyMap<string, ToolApprovalStamp[]>) => ReadonlyMap<string, ToolApprovalStamp[]>;
143
+ /**
144
+ * The decided-here stamps after the chat forgets what is open. A same-thread reload keeps them:
145
+ * the connect's snapshot brings the record, and until it lands nothing else draws the card. A
146
+ * thread or chat swap, or a reconnect after a failed run, clears them.
147
+ */
148
+ export declare const stampsAfterInterruptReset: (previous: ReadonlyMap<string, ToolApprovalStamp[]>, { keepStamps }: {
149
+ keepStamps: boolean;
150
+ }) => ReadonlyMap<string, ToolApprovalStamp[]>;
151
+ /** Takes back exactly the stamps `mergeStamps` added (by identity), when their send did not go through. */
152
+ export declare const dropStamps: (previous: ReadonlyMap<string, ToolApprovalStamp[]>, added: ReadonlyMap<string, ToolApprovalStamp[]>) => ReadonlyMap<string, ToolApprovalStamp[]>;
153
+ export declare const toolApprovalsOf: (message: unknown) => ToolApprovalStamp[];
154
+ /** `insert_items_in_orders` → `insert items in orders`. */
155
+ export declare const toolWords: (name: string) => string;
156
+ export declare const toolCallOf: (messages: readonly Message[], toolCallId: string) => {
157
+ name: string;
158
+ args: Record<string, unknown>;
159
+ } | null;
160
+ export declare const approvalCardsForToolCall: ({ toolCallId, toolName, toolArgs, toolResult, toolMessage, requests, answers, localStamps, }: {
161
+ toolCallId: string;
162
+ /** The transcript call the card hangs on (`task` for a sub-agent). */
163
+ toolName: string;
164
+ toolArgs: unknown;
165
+ toolResult: string | null;
166
+ toolMessage: unknown;
167
+ requests: readonly InterruptRequest[];
168
+ answers: ReadonlyMap<string, InterruptAnswer>;
169
+ localStamps: ReadonlyMap<string, readonly ToolApprovalStamp[]>;
170
+ }) => ApprovalCardView[];
171
+ /**
172
+ * Whether the tool's normal step renders under its cards: a sub-agent's `task` step
173
+ * always does; a parent call's only once approved AND sent (while waiting it has not
174
+ * run; a rejected call never runs; an approval waiting for the pause's other cards has
175
+ * not been sent yet).
176
+ */
177
+ export declare const toolStepVisibleBelowCards: (toolName: string, cards: readonly ApprovalCardView[]) => boolean;
178
+ export {};
179
+ //# sourceMappingURL=agui-interrupts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agui-interrupts.d.ts","sourceRoot":"","sources":["../../src/utils/agui-interrupts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAErE,eAAO,MAAM,2BAA2B,yBAAyB,CAAC;AASlE,eAAO,MAAM,oBAAoB;;;;CAIvB,CAAC;AACX,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,2DAAsD,CAAC;AAE5F,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,CAAC;AACpD,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEjG,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,2FAA2F;IAC3F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,0FAA0F;IAC1F,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gGAAgG;IAChG,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvD,mFAAmF;IACnF,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAwBD,eAAO,MAAM,UAAU,GAAI,aAAa,MAAM,EAAE,OAAO,MAAM,KAAG,MAAmC,CAAC;AAoDpG;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,YAAY,SAAS,SAAS,EAAE,EAAE,UAAU,SAAS,OAAO,EAAE,KAAG,gBAAgB,EAgC3G,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,SAAS,gBAAgB,KAAG,OAAuD,CAAC;AAEtH,sGAAsG;AACtG,eAAO,MAAM,wBAAwB,wDAAwD,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,OAAO,KAAG,MAAwC,CAAC;AAK5F;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,SAAS,OAAO,EAAE,EAAE,YAAY,MAAM,KAAG,OACkC,CAAC;AAExH,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE1G;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,SAAS,SAAS,EAAE,EAChC,UAAU,SAAS,OAAO,EAAE,EAC5B,YAAY,MAAM,KACjB,WAWF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,YAAY,SAAS,SAAS,EAAE,EAAE,SAAS,OAAO,KAAG,WAAW,EAAE,GAAG,IAGjG,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,YAAY,OAAO,EAAE,UAAU,OAAO,KAAG,OAAkC,CAAC;AAEhH,wFAAwF;AACxF,eAAO,MAAM,kBAAkB,GAC7B,YAAY,SAAS,SAAS,EAAE,EAChC,UAAU,SAAS,gBAAgB,EAAE,EACrC,SAAS,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,KAC5C,WAAW,EAAE,GAAG,IAiBlB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,YAAY,SAAS,SAAS,EAAE,KAAG,WAAW,EACS,CAAC;AAE/F;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,OAAO,KAAG,IAIrD,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,gBAAgB,EAAE,EACrC,SAAS,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,KAC5C,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAmBjC,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,UAAU,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EAClD,MAAM,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,KAC7C,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAOzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EAClD,gBAAgB;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,KACtC,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAA+D,CAAC;AAE1G,2GAA2G;AAC3G,eAAO,MAAM,UAAU,GACrB,UAAU,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,EAClD,OAAO,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,KAC9C,WAAW,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAazC,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,iBAAiB,EAwBnE,CAAC;AAKF,2DAA2D;AAC3D,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAMvB,CAAC;AAEnB,eAAO,MAAM,UAAU,GACrB,UAAU,SAAS,OAAO,EAAE,EAC5B,YAAY,MAAM,KACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAWpD,CAAC;AAUF,eAAO,MAAM,wBAAwB,GAAI,8FAStC;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACtC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAAC;CAChE,KAAG,gBAAgB,EAoDnB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAU,MAAM,EAAE,OAAO,SAAS,gBAAgB,EAAE,KAAG,OACe,CAAC"}