@jini-ai/chat 0.5.4 → 0.5.6
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 +8 -0
- package/dist/core/ag-ui/entry.d.ts +33 -0
- package/dist/core/ag-ui/entry.js +80 -0
- package/dist/core/agentic/chat-capabilities.d.ts +2 -4
- package/dist/core/agentic/index.d.ts +4 -17
- package/dist/core/agentic/index.js +4 -17
- package/dist/core/assistant-client/a2ui-action-poster.d.ts +46 -0
- package/dist/core/assistant-client/a2ui-action-poster.js +113 -0
- package/dist/core/assistant-client/ag-ui-transport.d.ts +68 -0
- package/dist/core/assistant-client/ag-ui-transport.js +147 -0
- package/dist/core/assistant-client/attachment-liveness.d.ts +37 -0
- package/dist/core/assistant-client/attachment-liveness.js +93 -0
- package/dist/core/assistant-client/durable-run-subscription.d.ts +39 -0
- package/dist/core/assistant-client/durable-run-subscription.js +96 -0
- package/dist/core/assistant-client/entry.d.ts +13 -0
- package/dist/core/assistant-client/entry.js +7 -0
- package/dist/core/assistant-client/messages.d.ts +73 -0
- package/dist/core/assistant-client/messages.js +68 -0
- package/dist/core/assistant-client/transport.d.ts +164 -0
- package/dist/core/assistant-client/transport.js +734 -0
- package/dist/core/browser/page-actions.d.ts +121 -0
- package/dist/core/browser/page-actions.js +113 -0
- package/dist/core/durable-runs/continuation.d.ts +18 -0
- package/dist/core/durable-runs/continuation.js +61 -0
- package/dist/core/durable-runs/ledger-contracts.d.ts +53 -0
- package/dist/core/durable-runs/ledger-contracts.js +2 -0
- package/dist/core/durable-runs/policies.d.ts +6 -0
- package/dist/core/durable-runs/policies.js +6 -0
- package/dist/core/durable-runs/ports.d.ts +123 -0
- package/dist/core/durable-runs/ports.js +2 -0
- package/dist/core/durable-runs/run-contracts.d.ts +17 -0
- package/dist/core/durable-runs/run-contracts.js +2 -0
- package/dist/core/durable-runs/run-lock.d.ts +4 -0
- package/dist/core/durable-runs/run-lock.js +4 -0
- package/dist/core/index.d.ts +6 -19
- package/dist/core/index.js +6 -19
- package/dist/core/messages.d.ts +2 -0
- package/dist/core/question-form/format.d.ts +0 -9
- package/dist/core/question-form/format.js +16 -2
- package/dist/core/question-form/normalize.js +1 -0
- package/dist/core/question-form/secret-answers.d.ts +38 -0
- package/dist/core/question-form/secret-answers.js +45 -0
- package/dist/core/question-form/types.d.ts +2 -0
- package/dist/core/question-form.d.ts +1 -0
- package/dist/core/question-form.js +1 -0
- package/dist/core/run-events/entry.d.ts +208 -16
- package/dist/core/run-events/entry.js +273 -39
- package/dist/core/transcript.d.ts +3 -2
- package/dist/core/transcript.js +19 -3
- package/dist/core/user-text-redaction.d.ts +56 -0
- package/dist/core/user-text-redaction.js +89 -0
- package/dist/embed-widget/browser/page-actions.d.ts +1 -120
- package/dist/embed-widget/browser/page-actions.js +2 -112
- package/dist/embed-widget/react/embed.d.ts +1 -1
- package/dist/embed-widget/react/embed.js +1 -1
- package/dist/react/artifact-types.d.ts +9 -15
- package/dist/react/components/QuestionForm.d.ts +2 -1
- package/dist/react/components/QuestionForm.js +18 -12
- package/dist/react/components/QuestionsPanel.d.ts +3 -2
- package/dist/react/components/QuestionsPanel.js +2 -2
- package/dist/react/features/chat-pane/agent-tools.d.ts +1 -1
- package/dist/react/features/chat-pane/agent-tools.js +0 -1
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +5 -2
- package/dist/react/features/chat-pane/components/ChatPane.d.ts +1 -1
- package/dist/react/features/chat-pane/components/ChatPane.js +5 -2
- package/dist/react/features/chat-pane/create-typed-answer-poster.d.ts +2 -1
- package/dist/react/features/chat-pane/create-typed-answer-poster.js +33 -1
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +3 -2
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.d.ts +4 -1
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +43 -22
- package/dist/react/features/chat-pane/model-options.d.ts +12 -0
- package/dist/react/features/chat-pane/model-options.js +55 -0
- package/dist/react/features/chat-pane/rules.d.ts +3 -2
- package/dist/react/features/chat-pane/rules.js +12 -4
- package/dist/react/features/chat-pane/types.d.ts +25 -1
- package/dist/react/hooks/assistant-chats-contracts.d.ts +164 -0
- package/dist/react/hooks/assistant-chats-contracts.js +2 -0
- package/dist/react/hooks/assistant-chats.d.ts +7 -0
- package/dist/react/hooks/assistant-chats.js +960 -0
- package/dist/react/hooks/attachment-preview-cache.d.ts +1 -1
- package/dist/react/hooks/attachment-preview-cache.js +1 -1
- package/dist/react/hooks/composer-draft-cache.d.ts +2 -2
- package/dist/react/hooks/composer-draft-cache.js +2 -2
- package/dist/react/hooks/fab-position.d.ts +90 -0
- package/dist/react/hooks/fab-position.js +271 -0
- package/dist/react/hooks/useConversation.d.ts +4 -1
- package/dist/react/hooks/useConversation.js +14 -12
- package/dist/react/hooks/useUserTextGuard.d.ts +11 -0
- package/dist/react/hooks/useUserTextGuard.js +19 -0
- package/dist/react/index.d.ts +12 -21
- package/dist/react/index.js +7 -0
- package/dist/server/durable-runs/accept.d.ts +25 -0
- package/dist/server/durable-runs/accept.js +21 -0
- package/dist/server/durable-runs/entry.d.ts +5 -0
- package/dist/server/durable-runs/entry.js +4 -0
- package/dist/server/durable-runs/recover.d.ts +5 -0
- package/dist/server/durable-runs/recover.js +147 -0
- package/dist/server/run-finalizer/ports.d.ts +2 -16
- package/dist/store/legacy/sqlite/messages.d.ts +24 -18
- package/dist/store/legacy/sqlite/messages.js +12 -2
- package/dist/store/pglite/index.d.ts +2 -1
- package/dist/store/postgres/index.d.ts +2 -1
- package/dist/store/runtime/chat-expiry-sweep.d.ts +40 -0
- package/dist/store/runtime/chat-expiry-sweep.js +70 -0
- package/dist/store/runtime/chat-history-store.d.ts +20 -0
- package/dist/store/runtime/chat-history-store.js +50 -0
- package/dist/store/runtime/durable-run-store.d.ts +21 -0
- package/dist/store/runtime/durable-run-store.js +342 -0
- package/dist/store/runtime/entry.d.ts +7 -0
- package/dist/store/runtime/entry.js +6 -0
- package/dist/store/runtime/kernel.d.ts +29 -0
- package/dist/store/runtime/kernel.js +2 -0
- package/dist/store/runtime/run-guarded-chat-store.d.ts +10 -0
- package/dist/store/runtime/run-guarded-chat-store.js +42 -0
- package/dist/store/runtime/run-ledger.d.ts +15 -0
- package/dist/store/runtime/run-ledger.js +206 -0
- package/dist/store/sql/boundary.d.ts +6 -0
- package/dist/store/sql/boundary.js +7 -1
- package/dist/store/sql/store.d.ts +3 -2
- package/dist/store/sql/store.js +9 -2
- package/dist/store/sqlite/index.d.ts +3 -2
- package/package.json +75 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.5.6 — 2026-10-08
|
|
2
|
+
|
|
3
|
+
- Desktop 0.1.13 release fixes: see commits a2659d24 (admin), 5695a7c3 (chat, agent-runtime), 8ad4ac5c (devops).
|
|
4
|
+
|
|
5
|
+
## 0.5.5 — 2026-10-08
|
|
6
|
+
|
|
7
|
+
- Tovu clean-up release: code Tovu moved into Jini, plus the Jini clean-up (see the commit log).
|
|
8
|
+
|
|
1
9
|
## 0.5.4 — 2026-10-06
|
|
2
10
|
|
|
3
11
|
- Prompt history in the composer: ↑ with the caret on the first line recalls earlier sent messages and ↓ on the last line walks forward; the first ↑ stashes the current draft (empty or not) and ↓ past the newest entry (or Escape) restores it exactly. Recalled entries are never mutated; consecutive duplicates collapse. New pure `createComposerHistoryState` / `transitionComposerHistory` / `composerHistoryKeyAction` / `mergeComposerHistory` / `normalizeComposerHistory` (core) and `createBrowserComposerHistoryStorage` (react, a `ComposerHistoryStoragePort` default). `useComposer`/`ChatPane` take `historyScope`, `historyStorage` and `historyMessages`.
|
|
@@ -50,4 +50,37 @@ export declare function translateAgentEventToAgUi({ event, state }: {
|
|
|
50
50
|
export declare function closeAgUiRun({ state }: {
|
|
51
51
|
state: AgUiTranslationState;
|
|
52
52
|
}): AgUiEvent[];
|
|
53
|
+
/**
|
|
54
|
+
* Accumulates `TOOL_CALL_ARGS` deltas by `toolCallId` between a call's `TOOL_CALL_START` and
|
|
55
|
+
* `TOOL_CALL_END` — the inverse of `assistant-ag-ui.ts`'s server-side translator, which emits all
|
|
56
|
+
* three tool-call events back-to-back for one chat `tool_use` event today, but this side is written
|
|
57
|
+
* to accumulate real streamed deltas too (a future daemon driver that streams `tool_input_delta`
|
|
58
|
+
* incrementally needs no transport-layer change to render correctly). One instance per run, NOT a
|
|
59
|
+
* module-level singleton — the same reasoning `assistant-ag-ui.ts`'s `AgUiTranslationState` gives.
|
|
60
|
+
*/
|
|
61
|
+
export interface AgUiToAgentTranslationState {
|
|
62
|
+
toolCalls: Map<string, {
|
|
63
|
+
name: string;
|
|
64
|
+
argsJson: string;
|
|
65
|
+
}>;
|
|
66
|
+
readonly customEventNames: CustomEventNames;
|
|
67
|
+
}
|
|
68
|
+
export declare function createAgUiToAgentTranslationState({ customEventNames }: {
|
|
69
|
+
customEventNames: CustomEventNames;
|
|
70
|
+
}, _options?: Record<string, never>): AgUiToAgentTranslationState;
|
|
71
|
+
/**
|
|
72
|
+
* Translates one AG-UI event into zero or more chat-core `AgentEvent`s, threading `state` across
|
|
73
|
+
* calls within a single run for tool-call argument accumulation.
|
|
74
|
+
*
|
|
75
|
+
* `TEXT_MESSAGE_START`/`END` and the `REASONING_*` boundary markers translate to nothing: chat-core
|
|
76
|
+
* groups renderable output by a change in `AgentEvent.kind` alone (no message-boundary concept),
|
|
77
|
+
* the same asymmetry `translateRunAgentPayload` already has reducing the OTHER leg of this round
|
|
78
|
+
* trip (daemon wire -> `AgentEvent`) — this function is that reduction's mirror image. The two cases
|
|
79
|
+
* with real internal branching (`TOOL_CALL_END`, `CUSTOM`) and the one with a guard (`TOOL_CALL_ARGS`)
|
|
80
|
+
* are pulled into their own named functions above so this switch's own cost is just its case count.
|
|
81
|
+
*/
|
|
82
|
+
export declare function translateAgUiEventToAgentEvent({ event, state }: {
|
|
83
|
+
event: AgUiEvent;
|
|
84
|
+
state: AgUiToAgentTranslationState;
|
|
85
|
+
}, _options?: Record<string, never>): AgentEvent[];
|
|
53
86
|
//# sourceMappingURL=entry.d.ts.map
|
package/dist/core/ag-ui/entry.js
CHANGED
|
@@ -132,4 +132,84 @@ export function translateAgentEventToAgUi({ event, state }) {
|
|
|
132
132
|
export function closeAgUiRun({ state }) {
|
|
133
133
|
return closeOpenMessages(state);
|
|
134
134
|
}
|
|
135
|
+
export function createAgUiToAgentTranslationState({ customEventNames }, _options = {}) {
|
|
136
|
+
return { toolCalls: new Map(), customEventNames: { ...customEventNames } };
|
|
137
|
+
}
|
|
138
|
+
/** The `TOOL_CALL_ARGS` case of {@link translateAgUiEventToAgentEvent} — accumulates one delta onto
|
|
139
|
+
* the in-flight call's buffer, a silent no-op for an id with no matching `TOOL_CALL_START`. Split
|
|
140
|
+
* out so this `if` is scored in its own complexity budget rather than the switch's. */
|
|
141
|
+
function accumulateToolCallArgs(toolCallId, delta, state) {
|
|
142
|
+
const call = state.toolCalls.get(toolCallId);
|
|
143
|
+
if (call)
|
|
144
|
+
call.argsJson += delta;
|
|
145
|
+
}
|
|
146
|
+
/** The `TOOL_CALL_END` case of {@link translateAgUiEventToAgentEvent} — parses the accumulated
|
|
147
|
+
* args buffer (already removed from `state` by the caller) into one `tool_use` event, or `[]` for
|
|
148
|
+
* an id with no matching `TOOL_CALL_START`. */
|
|
149
|
+
function finalizeToolCallAgentEvent(toolCallId, call) {
|
|
150
|
+
if (!call)
|
|
151
|
+
return [];
|
|
152
|
+
let input = {};
|
|
153
|
+
try {
|
|
154
|
+
input = call.argsJson.length > 0 ? JSON.parse(call.argsJson) : {};
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// A malformed/partial args buffer must not throw and drop the whole tool call — the raw
|
|
158
|
+
// string is still more useful to a human than nothing.
|
|
159
|
+
input = call.argsJson;
|
|
160
|
+
}
|
|
161
|
+
return [{ kind: "tool_use", id: toolCallId, name: call.name, input }];
|
|
162
|
+
}
|
|
163
|
+
/** The `CUSTOM` case of {@link translateAgUiEventToAgentEvent}. */
|
|
164
|
+
function translateAgUiCustomEvent(event, names) {
|
|
165
|
+
// Host-supplied usage/status names: the server's own translator put the ORIGINAL `AgentEvent`
|
|
166
|
+
// straight into `.value` (see `assistant-ag-ui.ts`'s `translateAgentEventToAgUi`), so this is
|
|
167
|
+
// an exact round trip, not a re-derivation.
|
|
168
|
+
if (event.name === names.usage || event.name === names.status)
|
|
169
|
+
return [event.value];
|
|
170
|
+
if (event.name.startsWith(names.extensionPrefix))
|
|
171
|
+
return [{ kind: "ext", name: event.name.slice(names.extensionPrefix.length), data: event.value }];
|
|
172
|
+
return [{ kind: "ext", name: event.name, data: event.value }];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Translates one AG-UI event into zero or more chat-core `AgentEvent`s, threading `state` across
|
|
176
|
+
* calls within a single run for tool-call argument accumulation.
|
|
177
|
+
*
|
|
178
|
+
* `TEXT_MESSAGE_START`/`END` and the `REASONING_*` boundary markers translate to nothing: chat-core
|
|
179
|
+
* groups renderable output by a change in `AgentEvent.kind` alone (no message-boundary concept),
|
|
180
|
+
* the same asymmetry `translateRunAgentPayload` already has reducing the OTHER leg of this round
|
|
181
|
+
* trip (daemon wire -> `AgentEvent`) — this function is that reduction's mirror image. The two cases
|
|
182
|
+
* with real internal branching (`TOOL_CALL_END`, `CUSTOM`) and the one with a guard (`TOOL_CALL_ARGS`)
|
|
183
|
+
* are pulled into their own named functions above so this switch's own cost is just its case count.
|
|
184
|
+
*/
|
|
185
|
+
export function translateAgUiEventToAgentEvent({ event, state }, _options = {}) {
|
|
186
|
+
switch (event.type) {
|
|
187
|
+
case EventType.TEXT_MESSAGE_CONTENT:
|
|
188
|
+
return [{ kind: "text", text: event.delta }];
|
|
189
|
+
case EventType.REASONING_MESSAGE_CONTENT:
|
|
190
|
+
return [{ kind: "thinking", text: event.delta }];
|
|
191
|
+
case EventType.TOOL_CALL_START:
|
|
192
|
+
state.toolCalls.set(event.toolCallId, { name: event.toolCallName, argsJson: "" });
|
|
193
|
+
return [];
|
|
194
|
+
case EventType.TOOL_CALL_ARGS:
|
|
195
|
+
accumulateToolCallArgs(event.toolCallId, event.delta, state);
|
|
196
|
+
return [];
|
|
197
|
+
case EventType.TOOL_CALL_END: {
|
|
198
|
+
const call = state.toolCalls.get(event.toolCallId);
|
|
199
|
+
state.toolCalls.delete(event.toolCallId);
|
|
200
|
+
return finalizeToolCallAgentEvent(event.toolCallId, call);
|
|
201
|
+
}
|
|
202
|
+
case EventType.TOOL_CALL_RESULT:
|
|
203
|
+
// AG-UI's `ToolCallResultEvent` carries no `isError` field (verified against the real schema)
|
|
204
|
+
// — a genuine protocol-level fidelity gap, not a translator bug: chat's `isError` flag cannot
|
|
205
|
+
// survive the round trip through AG-UI's wire shape, so it always reconstructs as `false`.
|
|
206
|
+
return [{ kind: "tool_result", toolUseId: event.toolCallId, content: event.content, isError: false }];
|
|
207
|
+
case EventType.RAW:
|
|
208
|
+
return [{ kind: "raw", line: asString(event.event) }];
|
|
209
|
+
case EventType.CUSTOM:
|
|
210
|
+
return translateAgUiCustomEvent(event, state.customEventNames);
|
|
211
|
+
default:
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
135
215
|
//# sourceMappingURL=entry.js.map
|
|
@@ -8,10 +8,8 @@
|
|
|
8
8
|
* Lives here rather than in a React package on purpose: a Node MCP server or HTTP route table
|
|
9
9
|
* hosting this list must not drag a browser component graph into its process.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* non-chat consumer could depend on the vocabulary without depending on chat. This file stayed
|
|
14
|
-
* behind on purpose: it's the proof the split is real (see `@jini-ai/agentic`'s archived provenance ledger).
|
|
11
|
+
* Chat outcomes belong here; generic capability vocabulary belongs to @jini-ai/agentic so
|
|
12
|
+
* non-chat consumers can use it independently of chat.
|
|
15
13
|
*/
|
|
16
14
|
import type { CapabilityDef } from '@jini-ai/agentic';
|
|
17
15
|
/** The bounded, explicit set of chat-pane capabilities every transport surface hosts. */
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Everything that used to live here besides `chat-capabilities.ts` (the framework-free
|
|
7
|
-
* `CapabilityDef` vocabulary, the two shipped manifests' shared machinery, the `data-agent-*`
|
|
8
|
-
* markup convention, and the protocol projections) moved to `@jini-ai/agentic` on 2026-07-26 — see
|
|
9
|
-
* `packages/agentic/archived provenance ledger` for the extraction and why. This barrel now only exports
|
|
10
|
-
* `CHAT_CAPABILITIES`, the seven `chat.*` verbs that are a genuine chat product surface rather
|
|
11
|
-
* than generic vocabulary.
|
|
12
|
-
*
|
|
13
|
-
* The `CapabilityDef` re-export below is a pure back-compatibility alias with **no remaining
|
|
14
|
-
* in-repo consumer**: `chat-react`'s `agent-tools.ts` shim did import it through this package when
|
|
15
|
-
* that comment was written, but now imports it from `@jini-ai/agentic` directly. It stays only so
|
|
16
|
-
* an external `import type { CapabilityDef } from '@jini-ai/chat-core'` (this layer's predecessor
|
|
17
|
-
* package, retired 2026-08-03 — see `../index.ts`'s file doc) keeps compiling; new code should
|
|
18
|
-
* import it from `@jini-ai/agentic`.
|
|
2
|
+
* Internal chat capability barrel, re-exported by chat/core rather than a public ./agentic subpath.
|
|
3
|
+
* CHAT_CAPABILITIES belongs to chat; generic capability vocabulary belongs to @jini-ai/agentic.
|
|
4
|
+
* The type re-exports preserve public compatibility. New code should import vocabulary from its
|
|
5
|
+
* owner, @jini-ai/agentic.
|
|
19
6
|
*/
|
|
20
7
|
export { CHAT_CAPABILITIES } from './chat-capabilities.js';
|
|
21
8
|
export type { CapabilityDef, CapabilityInputSchema, CapabilityRisk } from '@jini-ai/agentic';
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Everything that used to live here besides `chat-capabilities.ts` (the framework-free
|
|
7
|
-
* `CapabilityDef` vocabulary, the two shipped manifests' shared machinery, the `data-agent-*`
|
|
8
|
-
* markup convention, and the protocol projections) moved to `@jini-ai/agentic` on 2026-07-26 — see
|
|
9
|
-
* `packages/agentic/archived provenance ledger` for the extraction and why. This barrel now only exports
|
|
10
|
-
* `CHAT_CAPABILITIES`, the seven `chat.*` verbs that are a genuine chat product surface rather
|
|
11
|
-
* than generic vocabulary.
|
|
12
|
-
*
|
|
13
|
-
* The `CapabilityDef` re-export below is a pure back-compatibility alias with **no remaining
|
|
14
|
-
* in-repo consumer**: `chat-react`'s `agent-tools.ts` shim did import it through this package when
|
|
15
|
-
* that comment was written, but now imports it from `@jini-ai/agentic` directly. It stays only so
|
|
16
|
-
* an external `import type { CapabilityDef } from '@jini-ai/chat-core'` (this layer's predecessor
|
|
17
|
-
* package, retired 2026-08-03 — see `../index.ts`'s file doc) keeps compiling; new code should
|
|
18
|
-
* import it from `@jini-ai/agentic`.
|
|
2
|
+
* Internal chat capability barrel, re-exported by chat/core rather than a public ./agentic subpath.
|
|
3
|
+
* CHAT_CAPABILITIES belongs to chat; generic capability vocabulary belongs to @jini-ai/agentic.
|
|
4
|
+
* The type re-exports preserve public compatibility. New code should import vocabulary from its
|
|
5
|
+
* owner, @jini-ai/agentic.
|
|
19
6
|
*/
|
|
20
7
|
export { CHAT_CAPABILITIES } from './chat-capabilities.js';
|
|
21
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module a2ui-action-poster
|
|
3
|
+
* Client delivery for A2uiSurfaceCard's onAgentAction: routes, fetch and failure reporting are
|
|
4
|
+
* host-supplied. Correlate by message.action/error.surfaceId, which names the exchange, rather
|
|
5
|
+
* than the chat runId. functionResponse instead correlates by functionCallId and is not addressed
|
|
6
|
+
* by this poster. The server validates the full renderer-to-agent envelope; checking an address
|
|
7
|
+
* here does not replace that boundary.
|
|
8
|
+
* Report a failed POST both through the injected reporter and the card's delivery outcome so a
|
|
9
|
+
* click cannot fail silently. Status alone provides actionable copy without coupling to each
|
|
10
|
+
* server error code; a 409 means the exchange closed, never that the person made a mistake.
|
|
11
|
+
*/
|
|
12
|
+
/** Delivery result compatible with A2uiSurfaceCard's onAgentAction outcome. Structural typing
|
|
13
|
+
* keeps this module independent of React; assigning the poster to the prop checks compatibility. */
|
|
14
|
+
export type A2uiActionDeliveryOutcome = {
|
|
15
|
+
readonly ok: true;
|
|
16
|
+
} | {
|
|
17
|
+
readonly ok: false;
|
|
18
|
+
readonly reason: string;
|
|
19
|
+
};
|
|
20
|
+
export interface CreateA2uiActionPosterOptions {
|
|
21
|
+
/** Host path appended to baseUrl. The factory requires it explicitly. */
|
|
22
|
+
readonly path?: string;
|
|
23
|
+
/** Abandon a call after this many ms. Defaults to 30s, matching `createMcpUiToolCaller`'s own default. */
|
|
24
|
+
readonly timeoutMs?: number;
|
|
25
|
+
/** Extra headers per request. `content-type` is always set and cannot be overridden. */
|
|
26
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Builds an `A2uiSurfaceCardProps["onAgentAction"]` handler that POSTs `{exchangeId, message}` to
|
|
30
|
+
* `baseUrl + path` and resolves to the delivery outcome, which the card uses to show a
|
|
31
|
+
* delivery-failure notice instead of leaving a click that looks like it did nothing.
|
|
32
|
+
*
|
|
33
|
+
* @param baseUrl - Origin to call. `""` for same-origin, the common case for an admin UI proxied to
|
|
34
|
+
* its own API.
|
|
35
|
+
* @complexity O(1) — one request per call.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createA2uiActionPoster({ baseUrl, path, fetch, reportFailure }: A2uiActionPosterInput, options?: Omit<CreateA2uiActionPosterOptions, "path">): (runId: string | undefined, message: unknown) => Promise<A2uiActionDeliveryOutcome>;
|
|
38
|
+
export interface A2uiActionPosterInput {
|
|
39
|
+
readonly baseUrl: string;
|
|
40
|
+
readonly path: string;
|
|
41
|
+
readonly fetch: typeof fetch;
|
|
42
|
+
readonly reportFailure: (required: {
|
|
43
|
+
args: readonly unknown[];
|
|
44
|
+
}, optional: Record<string, never>) => void;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=a2ui-action-poster.d.ts.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module a2ui-action-poster
|
|
3
|
+
* Client delivery for A2uiSurfaceCard's onAgentAction: routes, fetch and failure reporting are
|
|
4
|
+
* host-supplied. Correlate by message.action/error.surfaceId, which names the exchange, rather
|
|
5
|
+
* than the chat runId. functionResponse instead correlates by functionCallId and is not addressed
|
|
6
|
+
* by this poster. The server validates the full renderer-to-agent envelope; checking an address
|
|
7
|
+
* here does not replace that boundary.
|
|
8
|
+
* Report a failed POST both through the injected reporter and the card's delivery outcome so a
|
|
9
|
+
* click cannot fail silently. Status alone provides actionable copy without coupling to each
|
|
10
|
+
* server error code; a 409 means the exchange closed, never that the person made a mistake.
|
|
11
|
+
*/
|
|
12
|
+
const NO_SURFACE_ID_REASON = "This action doesn't say which surface it answers, so there's nowhere to send it.";
|
|
13
|
+
/**
|
|
14
|
+
* Maps `a2ui-actions-route.ts`'s real non-2xx status codes to wording a non-technical person can
|
|
15
|
+
* act on. Deliberately keyed on status alone, not the route's `code`/`error` fields — every 400
|
|
16
|
+
* cause (bad JSON shape, a schema-rejected envelope, a `surfaceId`/`exchangeId` mismatch) reduces to
|
|
17
|
+
* the same actionable advice for a human, and a coarser mapping is less to keep in sync as the
|
|
18
|
+
* route's validation grows new failure modes.
|
|
19
|
+
*
|
|
20
|
+
* @param status - The response's HTTP status. Only called for a non-`ok` response.
|
|
21
|
+
* @complexity O(1).
|
|
22
|
+
* @overallScore 100
|
|
23
|
+
*/
|
|
24
|
+
function reasonForStatus(status) {
|
|
25
|
+
switch (status) {
|
|
26
|
+
case 409:
|
|
27
|
+
// `a2ui-actions-route.ts`'s own comment on this status: "no such exchange" and "already
|
|
28
|
+
// closed" both mean "this surface is no longer the one waiting on you" — the common case, not
|
|
29
|
+
// a mistake the human just made, so the wording must not read as one.
|
|
30
|
+
return "This surface is no longer waiting for a response — the agent has already moved on.";
|
|
31
|
+
case 400:
|
|
32
|
+
return "The agent didn't recognize this action. Reloading the conversation may fix it.";
|
|
33
|
+
case 401:
|
|
34
|
+
return "Your session couldn't be verified. Try reloading the page.";
|
|
35
|
+
default:
|
|
36
|
+
return `The action couldn't be delivered (server returned ${status}).`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
40
|
+
/**
|
|
41
|
+
* The exchange id a renderer→agent message declares, or `undefined` if it declares none.
|
|
42
|
+
*
|
|
43
|
+
* Only `action` and `error` carry `surfaceId` on the wire — `functionResponse` correlates by
|
|
44
|
+
* `functionCallId` instead (see `interpreter.ts`'s module doc, decision 2). `buildAction`'s
|
|
45
|
+
* agent-directed branch only ever produces an `ActionMessage`, so the `functionResponse` case is
|
|
46
|
+
* unreachable from this call site today; handled anyway so this function's contract does not
|
|
47
|
+
* silently depend on that.
|
|
48
|
+
*
|
|
49
|
+
* @complexity O(1).
|
|
50
|
+
* @overallScore 100
|
|
51
|
+
*/
|
|
52
|
+
function surfaceIdOf(message) {
|
|
53
|
+
if (typeof message !== "object" || message === null)
|
|
54
|
+
return undefined;
|
|
55
|
+
const { action, error } = message;
|
|
56
|
+
const candidate = typeof action?.surfaceId === "string" ? action.surfaceId : error?.surfaceId;
|
|
57
|
+
return typeof candidate === "string" && candidate.length > 0 ? candidate : undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Builds an `A2uiSurfaceCardProps["onAgentAction"]` handler that POSTs `{exchangeId, message}` to
|
|
61
|
+
* `baseUrl + path` and resolves to the delivery outcome, which the card uses to show a
|
|
62
|
+
* delivery-failure notice instead of leaving a click that looks like it did nothing.
|
|
63
|
+
*
|
|
64
|
+
* @param baseUrl - Origin to call. `""` for same-origin, the common case for an admin UI proxied to
|
|
65
|
+
* its own API.
|
|
66
|
+
* @complexity O(1) — one request per call.
|
|
67
|
+
*/
|
|
68
|
+
export function createA2uiActionPoster({ baseUrl, path, fetch, reportFailure }, options = {}) {
|
|
69
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
70
|
+
const endpoint = `${baseUrl.replace(/\/$/u, "")}${path}`;
|
|
71
|
+
return async (runId, message) => {
|
|
72
|
+
const exchangeId = surfaceIdOf(message);
|
|
73
|
+
if (!exchangeId) {
|
|
74
|
+
// Not reachable from `A2uiSurfaceCard`'s own call site today (see this module's doc), but a
|
|
75
|
+
// future `wantResponse`/`callFunction` path could reach here with a message this poster has no
|
|
76
|
+
// address for — reported rather than silently dropped, so a real gap is visible in devtools
|
|
77
|
+
// instead of looking like an action that quietly did nothing.
|
|
78
|
+
reportFailure({ args: [`[a2ui] cannot deliver an action with no surfaceId (run ${runId ?? "unknown"})`, message] }, {});
|
|
79
|
+
return { ok: false, reason: NO_SURFACE_ID_REASON };
|
|
80
|
+
}
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
83
|
+
try {
|
|
84
|
+
const response = await fetch(endpoint, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
credentials: "same-origin",
|
|
87
|
+
headers: { ...options.headers, "content-type": "application/json" },
|
|
88
|
+
body: JSON.stringify({ exchangeId, message }),
|
|
89
|
+
signal: controller.signal,
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
const detail = await response.text().catch(() => "");
|
|
93
|
+
reportFailure({ args: [`[a2ui] action delivery failed (${response.status}) for surface ${exchangeId}`, detail] }, {});
|
|
94
|
+
return { ok: false, reason: reasonForStatus(response.status) };
|
|
95
|
+
}
|
|
96
|
+
return { ok: true };
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const timedOut = error instanceof Error && error.name === "AbortError";
|
|
100
|
+
reportFailure({ args: [`[a2ui] action delivery failed for surface ${exchangeId}`, timedOut ? `timed out after ${timeoutMs}ms` : error] }, {});
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
reason: timedOut
|
|
104
|
+
? "This took too long to deliver and was given up on."
|
|
105
|
+
: "Couldn't reach the server to deliver this action.",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=a2ui-action-poster.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module assistant-transport-ag-ui
|
|
3
|
+
* ADR-059: a host-injected official HttpAgent owns HTTP, SSE framing and event validation for a
|
|
4
|
+
* projection of the same daemon lifecycle. No second run lifecycle or local SSE parser lives here.
|
|
5
|
+
* HttpAgent.run returns a cold Observable: subscribe to start it, then resolve startAgUiRun on
|
|
6
|
+
* the first notification, rather than await the Observable or wait for the whole run to finish.
|
|
7
|
+
* Mid-stream abort arrives as RUN_ERROR{code:"abort"} on the normal event path and finishes cleanly.
|
|
8
|
+
* Before headers, abort instead rejects fetch and reaches subscription.error; inspect the signal
|
|
9
|
+
* there so an intentional stop cannot become a user-facing failure.
|
|
10
|
+
*/
|
|
11
|
+
import type { RunAgentInput } from "@ag-ui/core";
|
|
12
|
+
import type { AgUiEvent, AgUiToAgentTranslationState, CustomEventNames } from "../ag-ui/entry.js";
|
|
13
|
+
import type { AgentEvent } from "../events.js";
|
|
14
|
+
import type { RunHandlers, StartRunInput } from "../transport.js";
|
|
15
|
+
export interface AgUiClient {
|
|
16
|
+
readonly abortController: AbortController;
|
|
17
|
+
abortRun(): void;
|
|
18
|
+
run(input: RunAgentInput): {
|
|
19
|
+
subscribe(observer: {
|
|
20
|
+
next: (event: unknown) => void;
|
|
21
|
+
error: (error: unknown) => void;
|
|
22
|
+
complete: () => void;
|
|
23
|
+
}): unknown;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface AgUiClientPorts {
|
|
27
|
+
readonly endpoint: string;
|
|
28
|
+
readonly runIdPrefix: string;
|
|
29
|
+
readonly customEventNames: CustomEventNames;
|
|
30
|
+
readonly mintId: (required: Record<string, never>, optional: Record<string, never>) => string;
|
|
31
|
+
readonly createAgent: (required: {
|
|
32
|
+
url: string;
|
|
33
|
+
threadId: string;
|
|
34
|
+
}, optional: Record<string, never>) => AgUiClient;
|
|
35
|
+
}
|
|
36
|
+
export interface AgUiEventContext {
|
|
37
|
+
collected: AgentEvent[];
|
|
38
|
+
handlers: RunHandlers;
|
|
39
|
+
state: AgUiToAgentTranslationState;
|
|
40
|
+
finish: () => void;
|
|
41
|
+
}
|
|
42
|
+
export interface AgUiRunClient {
|
|
43
|
+
isAgUiRunId(required: {
|
|
44
|
+
runId: string;
|
|
45
|
+
}, optional?: Record<string, never>): boolean;
|
|
46
|
+
handleAgUiEvent(required: {
|
|
47
|
+
event: AgUiEvent;
|
|
48
|
+
ctx: AgUiEventContext;
|
|
49
|
+
}, optional?: Record<string, never>): void;
|
|
50
|
+
startAgUiRun(required: {
|
|
51
|
+
input: StartRunInput;
|
|
52
|
+
handlers: RunHandlers;
|
|
53
|
+
}, optional?: Record<string, never>): Promise<{
|
|
54
|
+
runId: string;
|
|
55
|
+
}>;
|
|
56
|
+
reattachAgUiRun(required: {
|
|
57
|
+
handlers: RunHandlers;
|
|
58
|
+
}, optional?: Record<string, never>): Promise<void>;
|
|
59
|
+
fetchAgUiRunStatus(required: Record<string, never>, optional?: Record<string, never>): Promise<null>;
|
|
60
|
+
stopAgUiRun(required: {
|
|
61
|
+
runId: string;
|
|
62
|
+
}, optional?: Record<string, never>): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/** Bind the official client without adding its dependency to every chat consumer. */
|
|
65
|
+
export declare function createAgUiRunClient({ ports }: {
|
|
66
|
+
ports: AgUiClientPorts;
|
|
67
|
+
}, _options?: Record<string, never>): AgUiRunClient;
|
|
68
|
+
//# sourceMappingURL=ag-ui-transport.d.ts.map
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { EventType } from "@ag-ui/core";
|
|
2
|
+
import { createAgUiToAgentTranslationState, translateAgUiEventToAgentEvent } from "../ag-ui/entry.js";
|
|
3
|
+
/** Bind the official client without adding its dependency to every chat consumer. */
|
|
4
|
+
export function createAgUiRunClient({ ports }, _options = {}) {
|
|
5
|
+
/** In-flight AG-UI turns' driving `HttpAgent`, keyed by the client-minted runId — the ONLY way
|
|
6
|
+
* {@link stopAgUiRun} can cancel a turn: like BYOK, there is no server-side run record on THIS
|
|
7
|
+
* path to `POST .../cancel` against. Storing the agent (not a bare `AbortController`) lets
|
|
8
|
+
* `stopAgUiRun` call its own `abortRun()`, which both aborts the fetch AND (per the package's own
|
|
9
|
+
* convention) surfaces a clean `RUN_ERROR{code:"abort"}` through the normal event path rather than
|
|
10
|
+
* a raw network error. */
|
|
11
|
+
const agUiAgents = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Dispatches one already-parsed AG-UI event. `HttpAgent` owns SSE framing and per-event zod
|
|
14
|
+
* validation entirely, and hands us finished event objects. `RUN_ERROR` with `code: "abort"` is the
|
|
15
|
+
* real package's own convention for a mid-stream abort (see module doc) — routed to `finish()`, not
|
|
16
|
+
* `onError`. Every other event is reduced through {@link translateAgUiEventToAgentEvent} and
|
|
17
|
+
* forwarded to both `collected` (the final transcript `onDone` receives) and `handlers.onEvent`
|
|
18
|
+
* (live rendering).
|
|
19
|
+
*/
|
|
20
|
+
function handleAgUiEvent(event, ctx) {
|
|
21
|
+
if (event.type === EventType.RUN_ERROR) {
|
|
22
|
+
if (event.code === "abort") {
|
|
23
|
+
ctx.finish();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
ctx.handlers.onError(new Error(event.message || "AG-UI run failed"));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (event.type === EventType.RUN_FINISHED) {
|
|
30
|
+
ctx.finish();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const translated of translateAgUiEventToAgentEvent({ event, state: ctx.state }, {})) {
|
|
34
|
+
ctx.collected.push(translated);
|
|
35
|
+
ctx.handlers.onEvent(translated);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Every AG-UI message role requires an id; preserve ChatMessage.id across translation. */
|
|
39
|
+
function toAgUiMessage(message) {
|
|
40
|
+
if (message.role === "user")
|
|
41
|
+
return { id: message.id, role: "user", content: message.content };
|
|
42
|
+
return { id: message.id, role: "assistant", content: message.content };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The AG-UI canary run path (ADR-059) — drives a real `@ag-ui/client` `HttpAgent` against
|
|
46
|
+
* `assistant-ag-ui.ts`'s route, same one-turn-per-call shape as `startByokRun`. `credentials:
|
|
47
|
+
* "same-origin"` is explicit even though modern `fetch()` already defaults to it for same-origin
|
|
48
|
+
* requests, matching this transport's other paths' explicitness about the session cookie.
|
|
49
|
+
*/
|
|
50
|
+
async function startAgUiRun(input, handlers) {
|
|
51
|
+
const runId = `${ports.runIdPrefix}${ports.mintId({}, {})}`;
|
|
52
|
+
// The conversation-level id, stable across turns — a genuine AG-UI `threadId`, distinct from the
|
|
53
|
+
// per-turn `runId` minted fresh above. Falls back to minting one only for a conversation that has
|
|
54
|
+
// none yet (e.g. the very first turn).
|
|
55
|
+
const threadId = input.conversationId ?? ports.mintId({}, {});
|
|
56
|
+
const agent = ports.createAgent({ url: ports.endpoint, threadId }, {});
|
|
57
|
+
agUiAgents.set(runId, agent);
|
|
58
|
+
input.signal?.addEventListener("abort", () => agent.abortRun());
|
|
59
|
+
const messages = input.history.filter((message) => message.content.trim().length > 0).map(toAgUiMessage);
|
|
60
|
+
const runAgentInput = {
|
|
61
|
+
threadId,
|
|
62
|
+
runId,
|
|
63
|
+
state: null,
|
|
64
|
+
messages,
|
|
65
|
+
tools: [],
|
|
66
|
+
context: [],
|
|
67
|
+
forwardedProps: {
|
|
68
|
+
...(input.agentId ? { agentId: input.agentId } : {}),
|
|
69
|
+
...(input.history.some(message => message.role === "user" && message.secretRedaction?.secretRedacted) ? { secretRedacted: true } : {}),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const collected = [];
|
|
73
|
+
let settled = false;
|
|
74
|
+
const finish = () => {
|
|
75
|
+
if (settled)
|
|
76
|
+
return;
|
|
77
|
+
settled = true;
|
|
78
|
+
agUiAgents.delete(runId);
|
|
79
|
+
handlers.onDone(collected);
|
|
80
|
+
};
|
|
81
|
+
const state = createAgUiToAgentTranslationState({ customEventNames: ports.customEventNames }, {});
|
|
82
|
+
// Deliberately racing the Observable's first `next`/`error` against this Promise rather than
|
|
83
|
+
// awaiting it directly — `HttpAgent.run()` returns a cold Observable, never a Promise (module
|
|
84
|
+
// doc). The subscription itself keeps running after this Promise settles, driving `handlers`
|
|
85
|
+
// through to `finish()` in the background — matching `startByokRun`'s "resolves once STARTED, not
|
|
86
|
+
// once finished" contract.
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
let startSettled = false;
|
|
89
|
+
agent.run(runAgentInput).subscribe({
|
|
90
|
+
next: (event) => {
|
|
91
|
+
if (!startSettled) {
|
|
92
|
+
startSettled = true;
|
|
93
|
+
resolve({ runId });
|
|
94
|
+
}
|
|
95
|
+
handleAgUiEvent(event, { collected, handlers, state, finish });
|
|
96
|
+
},
|
|
97
|
+
error: (error) => {
|
|
98
|
+
agUiAgents.delete(runId);
|
|
99
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
100
|
+
if (!startSettled) {
|
|
101
|
+
startSettled = true;
|
|
102
|
+
reject(err);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Aborting BEFORE headers arrive rejects the underlying fetch() itself, surfacing here
|
|
106
|
+
// rather than through `handleAgUiEvent`'s `code: "abort"` check (module doc).
|
|
107
|
+
if (agent.abortController.signal.aborted) {
|
|
108
|
+
finish();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// Error THEN finish: an errored Observable never calls `complete`, so without this the turn
|
|
112
|
+
// is never settled and the events collected before the failure never reach `onDone`. Same
|
|
113
|
+
// order as `subscribeToRun`'s `end` listener, so the run is still recorded as failed.
|
|
114
|
+
handlers.onError(err);
|
|
115
|
+
finish();
|
|
116
|
+
},
|
|
117
|
+
complete: () => {
|
|
118
|
+
finish();
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** No server-side run record exists on this path (module doc) — a reload has already discarded the
|
|
124
|
+
* original `fetch()`'s response body, so there is nothing to resume. Same honest "already over"
|
|
125
|
+
* answer `assistant-transport.ts`'s BYOK branch gives for the identical situation. */
|
|
126
|
+
async function reattachAgUiRun(handlers) {
|
|
127
|
+
handlers.onDone([]);
|
|
128
|
+
}
|
|
129
|
+
/** Same reasoning as {@link reattachAgUiRun} — no server-side run record to fetch status for. */
|
|
130
|
+
async function fetchAgUiRunStatus() {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
/** An AG-UI run's only cancellation handle is the `HttpAgent` {@link startAgUiRun} registered for
|
|
134
|
+
* this exact id — same shape as BYOK's `stopRun` branch. */
|
|
135
|
+
async function stopAgUiRun(runId) {
|
|
136
|
+
agUiAgents.get(runId)?.abortRun();
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
isAgUiRunId: ({ runId }, _options = {}) => runId.startsWith(ports.runIdPrefix),
|
|
140
|
+
handleAgUiEvent: ({ event, ctx }, _options = {}) => handleAgUiEvent(event, ctx),
|
|
141
|
+
startAgUiRun: ({ input, handlers }, _options = {}) => startAgUiRun(input, handlers),
|
|
142
|
+
reattachAgUiRun: ({ handlers }, _options = {}) => reattachAgUiRun(handlers),
|
|
143
|
+
fetchAgUiRunStatus: (_required, _options = {}) => fetchAgUiRunStatus(),
|
|
144
|
+
stopAgUiRun: ({ runId }, _options = {}) => stopAgUiRun(runId),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=ag-ui-transport.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ChatAttachment } from "../messages.js";
|
|
2
|
+
export interface ChatAttachmentValidatorOptions {
|
|
3
|
+
/** Injected `fetch` for tests; defaults to the page's own. */
|
|
4
|
+
readonly fetchImpl?: typeof fetch;
|
|
5
|
+
/** In-flight probe cap. Defaults to {@link DEFAULT_CONCURRENCY}. */
|
|
6
|
+
readonly concurrency?: number;
|
|
7
|
+
/** Per-probe abort deadline in ms. Defaults to {@link DEFAULT_TIMEOUT_MS}. */
|
|
8
|
+
readonly timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Builds the `validateAttachments` callback `<ChatPane>` calls when it restores a persisted draft.
|
|
12
|
+
*
|
|
13
|
+
* @param input.fetch injected request implementation; the host supplies it explicitly.
|
|
14
|
+
* @param input.endpoint resolves a reference to the host's HEAD-capable read endpoint.
|
|
15
|
+
* @param input.isSupportedRef validates the host's staged-reference grammar before a request.
|
|
16
|
+
* @param input.maxProbedAttachments bounds request fan-out from malformed or hand-edited drafts.
|
|
17
|
+
* @param options.concurrency in-flight probe cap; defaults to {@link DEFAULT_CONCURRENCY}.
|
|
18
|
+
* @param options.timeoutMs per-probe abort deadline; defaults to {@link DEFAULT_TIMEOUT_MS}.
|
|
19
|
+
* @returns a validator taking the cached references and resolving to the subset still served, in
|
|
20
|
+
* the order they were given. Never rejects: a caller's only sane response to a rejection is to
|
|
21
|
+
* restore nothing, which is what an empty subset already means.
|
|
22
|
+
* @complexity O(n) requests bounded by input.maxProbedAttachments, at most concurrency at once.
|
|
23
|
+
* @example
|
|
24
|
+
* <ChatPane validateAttachments={createChatAttachmentValidator({ fetch, endpoint, isSupportedRef, maxProbedAttachments })} />
|
|
25
|
+
*/
|
|
26
|
+
export declare function createChatAttachmentValidator({ fetch, endpoint, isSupportedRef, maxProbedAttachments }: ChatAttachmentValidatorInput, options?: Omit<ChatAttachmentValidatorOptions, "fetchImpl">): (attachments: readonly ChatAttachment[]) => Promise<readonly ChatAttachment[]>;
|
|
27
|
+
export interface ChatAttachmentValidatorInput {
|
|
28
|
+
readonly fetch: typeof fetch;
|
|
29
|
+
readonly endpoint: (required: {
|
|
30
|
+
ref: string;
|
|
31
|
+
}, optional: Record<string, never>) => string;
|
|
32
|
+
readonly isSupportedRef: (required: {
|
|
33
|
+
ref: string;
|
|
34
|
+
}, optional: Record<string, never>) => boolean;
|
|
35
|
+
readonly maxProbedAttachments: number;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=attachment-liveness.d.ts.map
|