@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.
- package/dist/components/new-agent-chat.d.ts +14 -0
- package/dist/components/new-agent-chat.d.ts.map +1 -1
- package/dist/components/new-agent-chat.js +204 -80
- package/dist/hooks/agent-chat-own-runs.d.ts +3 -0
- package/dist/hooks/agent-chat-own-runs.d.ts.map +1 -0
- package/dist/hooks/agent-chat-own-runs.js +8 -0
- package/dist/hooks/use-agent-conversation.d.ts +7 -1
- package/dist/hooks/use-agent-conversation.d.ts.map +1 -1
- package/dist/hooks/use-agent-conversation.js +27 -3
- package/dist/hooks/use-agent-threads.d.ts +1 -0
- package/dist/hooks/use-agent-threads.d.ts.map +1 -1
- package/dist/hooks/use-agent-threads.js +1 -0
- package/dist/utils/agent-admin.d.ts +28 -0
- package/dist/utils/agent-admin.d.ts.map +1 -0
- package/dist/utils/agent-admin.js +48 -0
- package/dist/utils/agui-interrupts.d.ts +179 -0
- package/dist/utils/agui-interrupts.d.ts.map +1 -0
- package/dist/utils/agui-interrupts.js +351 -0
- package/package.json +2 -2
|
@@ -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
|
|
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
|
|
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":"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"}
|