@frontera-sdk/chat 1.52.45 → 1.52.46
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/auth.d.ts +20 -0
- package/dist/auth.js +11 -0
- package/dist/callback-page.d.ts +49 -0
- package/dist/callback-page.js +84 -0
- package/dist/chat-client.d.ts +221 -0
- package/dist/chat-client.js +5 -0
- package/dist/chat-errors.d.ts +30 -0
- package/dist/chat-errors.js +3 -0
- package/dist/chunk-CMMWTCYS.js +116 -0
- package/dist/chunk-KZEGEV3P.js +35 -0
- package/dist/chunk-LS26G2N6.js +120 -0
- package/dist/chunk-RLHHRJWS.js +371 -0
- package/dist/chunk-UCUVHMJC.js +62 -0
- package/dist/chunk-VWUR3ECR.js +115 -0
- package/dist/chunk-W25Q2DQA.js +32 -0
- package/dist/chunk-YKQ5Z5EK.js +32 -0
- package/dist/connect-popup.d.ts +150 -0
- package/dist/connect-popup.js +138 -0
- package/dist/doctor.d.ts +71 -0
- package/dist/doctor.js +3 -0
- package/dist/element.d.ts +23 -0
- package/dist/element.js +175 -0
- package/dist/frontera-chat.iife.js +27 -0
- package/dist/hooks.d.ts +88 -0
- package/dist/hooks.js +3 -0
- package/dist/provider.d.ts +20 -0
- package/dist/provider.js +13 -0
- package/dist/public-chat.d.ts +50 -0
- package/dist/public-chat.js +6 -0
- package/dist/public-token.d.ts +46 -0
- package/dist/public-token.js +3 -0
- package/dist/reply-text.d.ts +25 -0
- package/dist/reply-text.js +3 -0
- package/dist/stream.d.ts +25 -0
- package/dist/stream.js +3 -0
- package/dist/token-session.d.ts +66 -0
- package/dist/token-session.js +99 -0
- package/dist/transport.d.ts +60 -0
- package/dist/transport.js +103 -0
- package/dist/types.d.ts +361 -0
- package/dist/types.js +3 -0
- package/dist/ui-stream.d.ts +25 -0
- package/dist/ui-stream.js +26 -0
- package/package.json +70 -30
- package/src/chat-errors.ts +43 -0
- package/src/element.ts +201 -0
- package/src/frontera-chat.global.ts +13 -0
- package/src/public-chat.ts +154 -0
- package/src/public-token.ts +36 -4
- package/src/reply-text.ts +49 -0
- package/src/transport.ts +7 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { chatDoctor } from './chunk-VWUR3ECR.js';
|
|
2
|
+
import { DefaultChatTransport } from 'ai';
|
|
3
|
+
import { authHeaders } from '@frontera-sdk/core/transport';
|
|
4
|
+
import { errorFromResponse } from '@frontera-sdk/core/errors';
|
|
5
|
+
|
|
6
|
+
var OPENING_MESSAGE_ID = "frontera-opening";
|
|
7
|
+
async function readErrorBody(response) {
|
|
8
|
+
try {
|
|
9
|
+
const text = await response.text();
|
|
10
|
+
if (!text) return void 0;
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(text);
|
|
13
|
+
} catch {
|
|
14
|
+
return text;
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function createChatTransport(client, options = {}) {
|
|
21
|
+
const current = typeof client === "function" ? client : () => client;
|
|
22
|
+
let conversationId = options.conversationId;
|
|
23
|
+
let runId;
|
|
24
|
+
const wrappedFetch = (async (input, init) => {
|
|
25
|
+
const send = async () => {
|
|
26
|
+
const merged = {};
|
|
27
|
+
new Headers(init?.headers).forEach((value, name) => {
|
|
28
|
+
merged[name] = value;
|
|
29
|
+
});
|
|
30
|
+
Object.assign(merged, authHeaders(current().config));
|
|
31
|
+
return fetch(input, { ...init, headers: merged });
|
|
32
|
+
};
|
|
33
|
+
let response = await send();
|
|
34
|
+
if (response.status === 401) {
|
|
35
|
+
if (options.onUnauthorized) {
|
|
36
|
+
await options.onUnauthorized();
|
|
37
|
+
response = await send();
|
|
38
|
+
} else {
|
|
39
|
+
chatDoctor.noticed("unauthorized");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
throw errorFromResponse(response.status, await readErrorBody(response));
|
|
44
|
+
}
|
|
45
|
+
const headerConversationId = response.headers.get("x-conversation-id");
|
|
46
|
+
const headerRunId = response.headers.get("x-workflow-run-id");
|
|
47
|
+
if (headerConversationId && headerRunId) {
|
|
48
|
+
conversationId = headerConversationId;
|
|
49
|
+
runId = headerRunId;
|
|
50
|
+
options.onStart?.({
|
|
51
|
+
conversationId: headerConversationId,
|
|
52
|
+
runId: headerRunId,
|
|
53
|
+
runtime: response.headers.get("x-agent-runtime") ?? "pi",
|
|
54
|
+
quotaWarning: response.headers.get("x-quota-warning") ?? void 0
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return chatDoctor.observe(response);
|
|
58
|
+
});
|
|
59
|
+
return new DefaultChatTransport({
|
|
60
|
+
// Resolved per request, not here. The client may not exist yet: a caller
|
|
61
|
+
// that fetches its token asynchronously has nothing to give until the
|
|
62
|
+
// first exchange returns, and reading `.config` at construction would
|
|
63
|
+
// throw before anything could render.
|
|
64
|
+
api: "",
|
|
65
|
+
fetch: wrappedFetch,
|
|
66
|
+
/*
|
|
67
|
+
`body` here is the PER-CALL one — `sendMessage(message, { body })`.
|
|
68
|
+
|
|
69
|
+
It was dropped, and the loss was silent: attachments upload fine, the
|
|
70
|
+
composer shows them, the send succeeds, and the agent simply never
|
|
71
|
+
receives the file. Anything a caller attaches to one message travels this
|
|
72
|
+
way, so the same omission also swallowed per-send `modelMode` and any
|
|
73
|
+
custom field a host passes for a single turn.
|
|
74
|
+
|
|
75
|
+
Merged AFTER the transport-level `options.body` on purpose: that one is
|
|
76
|
+
the standing configuration for every send, and a value supplied for one
|
|
77
|
+
message is the more specific statement.
|
|
78
|
+
*/
|
|
79
|
+
prepareSendMessagesRequest: ({ messages, body }) => {
|
|
80
|
+
const lastUserMessage = [...messages].reverse().find((m) => m.role === "user");
|
|
81
|
+
const before = lastUserMessage ? messages[messages.indexOf(lastUserMessage) - 1] : void 0;
|
|
82
|
+
const opening = !conversationId && before?.role === "assistant" && before.id === OPENING_MESSAGE_ID ? [before] : [];
|
|
83
|
+
const trimmed = options.lastMessageOnly === false ? messages : lastUserMessage ? [...opening, lastUserMessage] : messages.slice(-1);
|
|
84
|
+
return {
|
|
85
|
+
api: `${current().config.apiBaseUrl}/v1/chat`,
|
|
86
|
+
body: {
|
|
87
|
+
messages: trimmed,
|
|
88
|
+
...conversationId ? { conversationId } : {},
|
|
89
|
+
...typeof options.body === "function" ? options.body() : options.body,
|
|
90
|
+
...body
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
prepareReconnectToStreamRequest: () => {
|
|
95
|
+
if (!runId) throw new Error("no run to reconnect to \u2014 no send has completed yet");
|
|
96
|
+
return { api: `${current().config.apiBaseUrl}/v1/chat/${encodeURIComponent(runId)}/stream` };
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { OPENING_MESSAGE_ID, createChatTransport };
|
|
102
|
+
//# sourceMappingURL=transport.js.map
|
|
103
|
+
//# sourceMappingURL=transport.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request/response shapes for the chat surface, mirrored from the service's
|
|
3
|
+
* TypeBox schemas (chat-router.ts, session-router.ts). Mirrored by hand rather
|
|
4
|
+
* than imported: the SDK publishes source and must not depend on the service
|
|
5
|
+
* package.
|
|
6
|
+
*/
|
|
7
|
+
type ChatRole = 'user' | 'assistant' | 'system';
|
|
8
|
+
/**
|
|
9
|
+
* A message as `POST /v1/chat` accepts it. `parts` is deliberately untyped:
|
|
10
|
+
* the server persists parts opaquely (a narrow schema on the wire stripped
|
|
11
|
+
* part fields once — see the comment in chat-router.ts), and the SDK follows.
|
|
12
|
+
*/
|
|
13
|
+
interface ChatInputMessage {
|
|
14
|
+
id: string;
|
|
15
|
+
role: ChatRole;
|
|
16
|
+
content?: string;
|
|
17
|
+
parts: unknown[];
|
|
18
|
+
}
|
|
19
|
+
interface ContextAttachment {
|
|
20
|
+
type: string;
|
|
21
|
+
id: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
meta?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
interface FileAttachment {
|
|
26
|
+
/** Publicly reachable URL — under API-key auth there is no upload endpoint. */
|
|
27
|
+
url: string;
|
|
28
|
+
storagePath?: string;
|
|
29
|
+
filename: string;
|
|
30
|
+
mediaType: string;
|
|
31
|
+
size: number;
|
|
32
|
+
pageCount?: number;
|
|
33
|
+
isScanned?: boolean;
|
|
34
|
+
}
|
|
35
|
+
type ReasoningEffort = 'max' | 'xhigh' | 'high' | 'medium' | 'low' | 'minimal' | 'none';
|
|
36
|
+
interface StartChatRequest {
|
|
37
|
+
/** 1–5 messages; the server rehydrates earlier history from the conversation. */
|
|
38
|
+
messages: ChatInputMessage[];
|
|
39
|
+
conversationId?: string;
|
|
40
|
+
editMessageId?: string;
|
|
41
|
+
contextAttachments?: ContextAttachment[];
|
|
42
|
+
fileAttachments?: FileAttachment[];
|
|
43
|
+
analysisMode?: string;
|
|
44
|
+
webSearchAugment?: boolean;
|
|
45
|
+
modelMode?: string | null;
|
|
46
|
+
thinkingEnabled?: boolean;
|
|
47
|
+
reasoningEffort?: ReasoningEffort;
|
|
48
|
+
/** Ignored under sak_/cht_ auth — the credential's agent always wins. */
|
|
49
|
+
agentName?: string;
|
|
50
|
+
surface?: 'web' | 'mobile' | 'console';
|
|
51
|
+
}
|
|
52
|
+
/** What `startChat` extracts from the response before handing over the stream. */
|
|
53
|
+
interface StartChatResult {
|
|
54
|
+
conversationId: string;
|
|
55
|
+
runId: string;
|
|
56
|
+
runtime: string;
|
|
57
|
+
quotaWarning?: string;
|
|
58
|
+
/** The raw response; `response.body` is the AI SDK v6 UI-message SSE stream. */
|
|
59
|
+
response: Response;
|
|
60
|
+
}
|
|
61
|
+
interface ExchangeTokenRequest {
|
|
62
|
+
externalUserId: string;
|
|
63
|
+
name?: string;
|
|
64
|
+
metadata?: Record<string, unknown>;
|
|
65
|
+
ttlSeconds?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Which agent the token reaches. Accepted when minting with a workspace key
|
|
68
|
+
* scoped for chat; an agent key is fixed to its own agent and refuses a
|
|
69
|
+
* different one. Omit with a workspace key for a token that reaches every
|
|
70
|
+
* agent, the way a platform user does.
|
|
71
|
+
*/
|
|
72
|
+
agentId?: string;
|
|
73
|
+
agentName?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Limit this token to a SUBSET of the workspace's agents — ids or slugs.
|
|
76
|
+
*
|
|
77
|
+
* Omit and it reaches every agent the minting credential can (an agent key
|
|
78
|
+
* always fixes exactly one). Naming a subset is how a product that exposes
|
|
79
|
+
* two of five agents stops the other three from being reachable by a guessed
|
|
80
|
+
* id, not merely hidden from the picker.
|
|
81
|
+
*/
|
|
82
|
+
agentIds?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* What YOUR product authorises this person to do beyond chatting. Everything
|
|
85
|
+
* here is DENIED unless asked for:
|
|
86
|
+
*
|
|
87
|
+
* - `plugin-connect` — connect their own account (Gmail, Drive, …) for a plugin
|
|
88
|
+
* that needs one. All-or-nothing across the plugins the workspace has
|
|
89
|
+
* opened to external users; a per-plugin scope is planned (see the TODO in
|
|
90
|
+
* the service's `chat-token.ts`).
|
|
91
|
+
* - `schedule` — read and manage the agent's scheduled tasks.
|
|
92
|
+
* - `agent-mode` — agent work items, exchanges, handoffs, agent conversations.
|
|
93
|
+
*
|
|
94
|
+
* The base token chats and nothing more: it sends, reads its own history and
|
|
95
|
+
* answers what the agent parks. Decide the rest against your own roles — we
|
|
96
|
+
* never model them. The decision rides on the token and expires with it, so
|
|
97
|
+
* withdrawing it on your side takes effect with nothing to synchronise.
|
|
98
|
+
*/
|
|
99
|
+
capabilities?: string[];
|
|
100
|
+
}
|
|
101
|
+
interface ChatToken {
|
|
102
|
+
token: string;
|
|
103
|
+
expiresAt: string;
|
|
104
|
+
}
|
|
105
|
+
/** What an upload returns — the shape `fileAttachments` expects. */
|
|
106
|
+
interface UploadedFile {
|
|
107
|
+
url: string;
|
|
108
|
+
storagePath?: string;
|
|
109
|
+
filename: string;
|
|
110
|
+
mediaType: string;
|
|
111
|
+
size: number;
|
|
112
|
+
pageCount?: number;
|
|
113
|
+
isScanned?: boolean;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* A document, image or deck the agent produced.
|
|
117
|
+
*
|
|
118
|
+
* The named fields are the ones a viewer reads; the index signature carries
|
|
119
|
+
* whatever else the deployment returns. Naming them matters — under an index
|
|
120
|
+
* signature alone every read is `unknown`, and a renderer cannot tell a title
|
|
121
|
+
* from a MIME type.
|
|
122
|
+
*/
|
|
123
|
+
/**
|
|
124
|
+
* One revision of an artifact, as the version picker needs it.
|
|
125
|
+
*
|
|
126
|
+
* Metadata only — no `content`, no `storageKey`. Drawing a menu does not
|
|
127
|
+
* require every revision's bytes, and the preview route serves them when a
|
|
128
|
+
* revision is actually opened.
|
|
129
|
+
*/
|
|
130
|
+
interface ArtifactVersionMeta {
|
|
131
|
+
version: number;
|
|
132
|
+
createdAt?: string;
|
|
133
|
+
title?: string | null;
|
|
134
|
+
/** Who saved it — an agent turn, or the person editing in the viewer. */
|
|
135
|
+
createdBy?: string | null;
|
|
136
|
+
sizeBytes?: number | null;
|
|
137
|
+
}
|
|
138
|
+
interface ChatArtifact {
|
|
139
|
+
id: string;
|
|
140
|
+
title?: string | null;
|
|
141
|
+
kind?: string | null;
|
|
142
|
+
/** Rendered format: markdown, csv, sheet, pdf, image, htmldeck, canvas. */
|
|
143
|
+
format?: string | null;
|
|
144
|
+
mimeType?: string | null;
|
|
145
|
+
/** The artifact's text, when it has one. */
|
|
146
|
+
content?: string | null;
|
|
147
|
+
/** Source language for a code artifact, used to pick a subtitle and lexer. */
|
|
148
|
+
language?: string | null;
|
|
149
|
+
conversationId?: string | null;
|
|
150
|
+
/** Where the bytes live, for artifacts stored as files rather than text. */
|
|
151
|
+
storageKey?: string | null;
|
|
152
|
+
/**
|
|
153
|
+
* A rendered PDF of this artifact, when the format needs one to be shown.
|
|
154
|
+
*
|
|
155
|
+
* Set for `.docx`/`.pptx` and anything else a browser cannot open. Present
|
|
156
|
+
* means `getArtifactPreview(id)` will answer; absent means it will not.
|
|
157
|
+
*/
|
|
158
|
+
previewKey?: string | null;
|
|
159
|
+
createdAt?: string;
|
|
160
|
+
updatedAt?: string;
|
|
161
|
+
[key: string]: unknown;
|
|
162
|
+
}
|
|
163
|
+
/** An agent the current credential may talk to — enough to draw a picker. */
|
|
164
|
+
/**
|
|
165
|
+
* One model choice an agent offers.
|
|
166
|
+
*
|
|
167
|
+
* `/v1/chat-agents` omits `modelId`, `model` and `provider` on purpose: those
|
|
168
|
+
* are the exact checkpoint the deployment runs, and nothing a chat needs to
|
|
169
|
+
* draw a picker. `name` is a LABEL, not that identifier — the operator's own
|
|
170
|
+
* wording when they set one, and the catalog's when they did not, which does
|
|
171
|
+
* name a vendor ("Claude Sonnet 5") and is what a vendor glyph is chosen from.
|
|
172
|
+
* Nothing here can be sent back to pin a request to a model.
|
|
173
|
+
*
|
|
174
|
+
* `reasoning` is what decides whether an effort control appears beside the
|
|
175
|
+
* model: a mode without it offers a model and nothing else.
|
|
176
|
+
*/
|
|
177
|
+
interface ChatAgentMode {
|
|
178
|
+
key: string;
|
|
179
|
+
name: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
style?: string;
|
|
182
|
+
reasoning?: {
|
|
183
|
+
style?: string;
|
|
184
|
+
supportedEfforts?: string[];
|
|
185
|
+
defaultEffort?: string;
|
|
186
|
+
[key: string]: unknown;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
interface ChatAgent {
|
|
190
|
+
id: string;
|
|
191
|
+
agentId: string;
|
|
192
|
+
name: string;
|
|
193
|
+
description?: string | null;
|
|
194
|
+
avatarConfig?: unknown;
|
|
195
|
+
/** The agent's own model choices. Empty or single → nothing to pick between. */
|
|
196
|
+
modes?: ChatAgentMode[];
|
|
197
|
+
/** The mode the agent starts in, as configured on the deployment. */
|
|
198
|
+
defaultMode?: string | null;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* A tool call the agent has parked, waiting for a person to decide.
|
|
202
|
+
*
|
|
203
|
+
* The run is BLOCKED while this exists: an agent whose approval mode is `ask`
|
|
204
|
+
* (or whose tool the safety reviewer would not clear on its own) streams a
|
|
205
|
+
* `tool-approval-request` chunk carrying `approvalId` and then stops until
|
|
206
|
+
* `respondToApproval` settles it or `expiresAt` passes. An integration that
|
|
207
|
+
* never answers looks like an agent that silently stopped mid-sentence.
|
|
208
|
+
*
|
|
209
|
+
* Named fields are what a card needs to render; the index signature carries
|
|
210
|
+
* whatever else the deployment reports.
|
|
211
|
+
*/
|
|
212
|
+
interface PendingApproval {
|
|
213
|
+
id: string;
|
|
214
|
+
/** `pending` while it waits; then `approved`, `denied` or `expired`. */
|
|
215
|
+
status: string;
|
|
216
|
+
/** `needs_approval` for a human gate; `needs_connect` for a missing account. */
|
|
217
|
+
pauseReason: string;
|
|
218
|
+
/** Which app the agent was reaching for — pass it to `startAppConnection`. */
|
|
219
|
+
installId?: string | null;
|
|
220
|
+
toolCallId?: string | null;
|
|
221
|
+
toolName?: string | null;
|
|
222
|
+
/** Where the tool came from: an app, an MCP server, the platform. */
|
|
223
|
+
toolSource?: string | null;
|
|
224
|
+
risk?: string | null;
|
|
225
|
+
/** A short, secret-safe description of what the tool is about to do. */
|
|
226
|
+
actionSummary?: unknown;
|
|
227
|
+
/** Why the policy asked rather than allowing. */
|
|
228
|
+
policyReason?: string | null;
|
|
229
|
+
expiresAt?: string;
|
|
230
|
+
[key: string]: unknown;
|
|
231
|
+
}
|
|
232
|
+
type ApprovalDecision = 'approve' | 'deny';
|
|
233
|
+
/**
|
|
234
|
+
* Starting a connect for a tool that needs the END USER's own account.
|
|
235
|
+
*
|
|
236
|
+
* `redirectUri` is a callback on YOUR domain, registered both with your OAuth
|
|
237
|
+
* client and on the workspace's embed allowlist. It has to be yours: a
|
|
238
|
+
* provider only authorises redirect URIs under a domain the OAuth project's
|
|
239
|
+
* owner has verified, and you cannot verify ours.
|
|
240
|
+
*/
|
|
241
|
+
interface StartAppConnectionRequest {
|
|
242
|
+
/** From the parked call's `installId`; or name the app with `catalogKind`. */
|
|
243
|
+
installId?: string;
|
|
244
|
+
catalogKind?: string;
|
|
245
|
+
redirectUri: string;
|
|
246
|
+
/** Where your page sends the user afterwards — origin must be allowlisted. */
|
|
247
|
+
returnTo?: string;
|
|
248
|
+
}
|
|
249
|
+
interface StartAppConnectionResult {
|
|
250
|
+
/** Open this in a popup or a full-page redirect. */
|
|
251
|
+
authUrl: string;
|
|
252
|
+
installId: string;
|
|
253
|
+
}
|
|
254
|
+
/** What your callback forwards to us: the provider's `code` and our `state`. */
|
|
255
|
+
interface CompleteAppConnectionRequest {
|
|
256
|
+
code: string;
|
|
257
|
+
state: string;
|
|
258
|
+
}
|
|
259
|
+
interface CompleteAppConnectionResult {
|
|
260
|
+
installId: string;
|
|
261
|
+
/** The account's email, when the provider reports one. */
|
|
262
|
+
email: string | null;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The re-run of a parked call. `ok: false` with `reason: 'no_account'` means
|
|
266
|
+
* the connection still is not usable — the row stays parked, so the same card
|
|
267
|
+
* can retry.
|
|
268
|
+
*/
|
|
269
|
+
type ResumeToolCallResult = {
|
|
270
|
+
ok: true;
|
|
271
|
+
[key: string]: unknown;
|
|
272
|
+
} | {
|
|
273
|
+
ok: false;
|
|
274
|
+
reason: string;
|
|
275
|
+
error?: string;
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* The chunk that announces a parked tool call, as it arrives on the stream.
|
|
279
|
+
*
|
|
280
|
+
* Not exported by the AI SDK's own chunk union, so it is declared here for
|
|
281
|
+
* consumers switching on chunk types from `chatChunkStream`.
|
|
282
|
+
*/
|
|
283
|
+
interface ToolApprovalRequestChunk {
|
|
284
|
+
type: 'tool-approval-request';
|
|
285
|
+
approvalId: string;
|
|
286
|
+
toolCallId: string;
|
|
287
|
+
}
|
|
288
|
+
interface CreateSessionRequest {
|
|
289
|
+
agentName?: string;
|
|
290
|
+
modelMode?: string | null;
|
|
291
|
+
approvalMode?: 'ask' | 'auto' | 'full';
|
|
292
|
+
workspaceId?: string;
|
|
293
|
+
}
|
|
294
|
+
interface UpdateSessionRequest {
|
|
295
|
+
title?: string;
|
|
296
|
+
status?: string;
|
|
297
|
+
pinned?: boolean;
|
|
298
|
+
group?: string | null;
|
|
299
|
+
modelMode?: string | null;
|
|
300
|
+
approvalMode?: 'ask' | 'auto' | 'full';
|
|
301
|
+
}
|
|
302
|
+
interface ListSessionsQuery {
|
|
303
|
+
cursor?: string;
|
|
304
|
+
limit?: number;
|
|
305
|
+
status?: string;
|
|
306
|
+
label?: string;
|
|
307
|
+
group?: string;
|
|
308
|
+
search?: string;
|
|
309
|
+
pinned?: boolean;
|
|
310
|
+
source?: 'chat' | 'automation' | 'all';
|
|
311
|
+
agentName?: string;
|
|
312
|
+
agentId?: string;
|
|
313
|
+
updatedAfter?: string;
|
|
314
|
+
updatedBefore?: string;
|
|
315
|
+
surface?: string;
|
|
316
|
+
}
|
|
317
|
+
interface Paginated<T> {
|
|
318
|
+
data: T[];
|
|
319
|
+
nextCursor?: string;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Loose by design: these are the fields the server guarantees today; anything
|
|
323
|
+
* else rides in the index signature until the service exposes a shared
|
|
324
|
+
* contract.
|
|
325
|
+
*/
|
|
326
|
+
interface Session {
|
|
327
|
+
id: string;
|
|
328
|
+
title?: string | null;
|
|
329
|
+
status?: string;
|
|
330
|
+
agentName?: string | null;
|
|
331
|
+
pinned?: boolean;
|
|
332
|
+
createdAt?: string;
|
|
333
|
+
updatedAt?: string;
|
|
334
|
+
[key: string]: unknown;
|
|
335
|
+
}
|
|
336
|
+
/** UIMessage-shaped: feed straight into `useChat({ messages })`. */
|
|
337
|
+
interface SessionMessage {
|
|
338
|
+
id: string;
|
|
339
|
+
role: ChatRole;
|
|
340
|
+
parts: unknown[];
|
|
341
|
+
metadata?: Record<string, unknown>;
|
|
342
|
+
createdAt: string;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Custom data parts the server streams alongside text. Payloads are `unknown`
|
|
346
|
+
* in v1; the names are stable and safe to switch on in `onData`.
|
|
347
|
+
*/
|
|
348
|
+
type ChatDataPartName = 'data-context' | 'data-context-estimate' | 'data-context-observed' | 'data-context-maintenance' | 'data-compaction' | 'data-work-queued' | 'data-desktop';
|
|
349
|
+
/**
|
|
350
|
+
* Called before any method that touches an existing conversation. Under
|
|
351
|
+
* API-key auth the server skips conversation ownership checks entirely, so a
|
|
352
|
+
* consumer serving multiple end-users MUST decide here whether the current
|
|
353
|
+
* user may touch `conversationId` — typically a lookup in their own
|
|
354
|
+
* user↔conversation store.
|
|
355
|
+
*/
|
|
356
|
+
type AuthorizeConversation = (conversationId: string) => boolean | Promise<boolean>;
|
|
357
|
+
interface ChatClientOptions {
|
|
358
|
+
authorizeConversation?: AuthorizeConversation;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export type { ApprovalDecision, ArtifactVersionMeta, AuthorizeConversation, ChatAgent, ChatAgentMode, ChatArtifact, ChatClientOptions, ChatDataPartName, ChatInputMessage, ChatRole, ChatToken, CompleteAppConnectionRequest, CompleteAppConnectionResult, ContextAttachment, CreateSessionRequest, ExchangeTokenRequest, FileAttachment, ListSessionsQuery, Paginated, PendingApproval, ReasoningEffort, ResumeToolCallResult, Session, SessionMessage, StartAppConnectionRequest, StartAppConnectionResult, StartChatRequest, StartChatResult, ToolApprovalRequestChunk, UpdateSessionRequest, UploadedFile };
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { UIMessageChunk, UIMessage } from 'ai';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Decode a chat SSE `Response` into the AI SDK's typed chunk stream.
|
|
5
|
+
*
|
|
6
|
+
* `readUIMessageStream` consumes chunks, not responses, so this is the bridge
|
|
7
|
+
* for server-side consumers holding the raw `Response` from `startChat`/
|
|
8
|
+
* `resumeStream`. The SSE layer (including the server's `: ping` keepalive
|
|
9
|
+
* comments and the `[DONE]` terminator) is handled by the AI SDK's own parser
|
|
10
|
+
* — the SDK never hand-parses SSE.
|
|
11
|
+
*/
|
|
12
|
+
declare function chatChunkStream(response: Response): ReadableStream<UIMessageChunk>;
|
|
13
|
+
/**
|
|
14
|
+
* Iterate assembled `UIMessage` snapshots from a chat response:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const run = await chat.startChat({ messages: [...] })
|
|
18
|
+
* for await (const message of readChatStream(run.response)) {
|
|
19
|
+
* // message.parts grows as the agent streams
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare function readChatStream(response: Response): AsyncIterable<UIMessage>;
|
|
24
|
+
|
|
25
|
+
export { chatChunkStream, readChatStream };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { parseJsonEventStream, readUIMessageStream } from 'ai';
|
|
2
|
+
|
|
3
|
+
// src/ui-stream.ts
|
|
4
|
+
function chatChunkStream(response) {
|
|
5
|
+
if (!response.body) {
|
|
6
|
+
throw new Error("chat response has no body to stream");
|
|
7
|
+
}
|
|
8
|
+
return parseJsonEventStream({
|
|
9
|
+
stream: response.body,
|
|
10
|
+
schema: void 0
|
|
11
|
+
}).pipeThrough(
|
|
12
|
+
new TransformStream({
|
|
13
|
+
transform(result, controller) {
|
|
14
|
+
if (!result.success) throw result.error;
|
|
15
|
+
controller.enqueue(result.value);
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function readChatStream(response) {
|
|
21
|
+
return readUIMessageStream({ stream: chatChunkStream(response) });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { chatChunkStream, readChatStream };
|
|
25
|
+
//# sourceMappingURL=ui-stream.js.map
|
|
26
|
+
//# sourceMappingURL=ui-stream.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontera-sdk/chat",
|
|
3
|
-
"version": "1.52.
|
|
3
|
+
"version": "1.52.46",
|
|
4
4
|
"description": "Typed client and React hooks for chatting with a Frontera agent from your own application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"frontera",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"!dist/**/*.map",
|
|
15
17
|
"src",
|
|
16
18
|
"!src/__tests__",
|
|
17
19
|
"!src/**/*.test.ts",
|
|
@@ -23,65 +25,101 @@
|
|
|
23
25
|
},
|
|
24
26
|
"exports": {
|
|
25
27
|
"./types": {
|
|
26
|
-
"types": "./
|
|
27
|
-
"
|
|
28
|
+
"types": "./dist/types.d.ts",
|
|
29
|
+
"bun": "./src/types.ts",
|
|
30
|
+
"import": "./dist/types.js"
|
|
28
31
|
},
|
|
29
32
|
"./chat-client": {
|
|
30
|
-
"types": "./
|
|
31
|
-
"
|
|
33
|
+
"types": "./dist/chat-client.d.ts",
|
|
34
|
+
"bun": "./src/chat-client.ts",
|
|
35
|
+
"import": "./dist/chat-client.js"
|
|
32
36
|
},
|
|
33
37
|
"./auth": {
|
|
34
|
-
"types": "./
|
|
35
|
-
"
|
|
38
|
+
"types": "./dist/auth.d.ts",
|
|
39
|
+
"bun": "./src/auth.ts",
|
|
40
|
+
"import": "./dist/auth.js"
|
|
36
41
|
},
|
|
37
42
|
"./stream": {
|
|
38
|
-
"types": "./
|
|
39
|
-
"
|
|
43
|
+
"types": "./dist/stream.d.ts",
|
|
44
|
+
"bun": "./src/stream.ts",
|
|
45
|
+
"import": "./dist/stream.js"
|
|
40
46
|
},
|
|
41
47
|
"./ui-stream": {
|
|
42
|
-
"types": "./
|
|
43
|
-
"
|
|
48
|
+
"types": "./dist/ui-stream.d.ts",
|
|
49
|
+
"bun": "./src/ui-stream.ts",
|
|
50
|
+
"import": "./dist/ui-stream.js"
|
|
44
51
|
},
|
|
45
52
|
"./doctor": {
|
|
46
|
-
"types": "./
|
|
47
|
-
"
|
|
53
|
+
"types": "./dist/doctor.d.ts",
|
|
54
|
+
"bun": "./src/doctor.ts",
|
|
55
|
+
"import": "./dist/doctor.js"
|
|
48
56
|
},
|
|
49
57
|
"./token-session": {
|
|
50
|
-
"types": "./
|
|
51
|
-
"
|
|
58
|
+
"types": "./dist/token-session.d.ts",
|
|
59
|
+
"bun": "./src/token-session.ts",
|
|
60
|
+
"import": "./dist/token-session.js"
|
|
52
61
|
},
|
|
53
62
|
"./public-token": {
|
|
54
|
-
"types": "./
|
|
55
|
-
"
|
|
63
|
+
"types": "./dist/public-token.d.ts",
|
|
64
|
+
"bun": "./src/public-token.ts",
|
|
65
|
+
"import": "./dist/public-token.js"
|
|
56
66
|
},
|
|
57
67
|
"./callback-page": {
|
|
58
|
-
"types": "./
|
|
59
|
-
"
|
|
68
|
+
"types": "./dist/callback-page.d.ts",
|
|
69
|
+
"bun": "./src/callback-page.ts",
|
|
70
|
+
"import": "./dist/callback-page.js"
|
|
60
71
|
},
|
|
61
72
|
"./connect-popup": {
|
|
62
|
-
"types": "./
|
|
63
|
-
"
|
|
73
|
+
"types": "./dist/connect-popup.d.ts",
|
|
74
|
+
"bun": "./src/connect-popup.ts",
|
|
75
|
+
"import": "./dist/connect-popup.js"
|
|
64
76
|
},
|
|
65
77
|
"./transport": {
|
|
66
|
-
"types": "./
|
|
67
|
-
"
|
|
78
|
+
"types": "./dist/transport.d.ts",
|
|
79
|
+
"bun": "./src/transport.ts",
|
|
80
|
+
"import": "./dist/transport.js"
|
|
68
81
|
},
|
|
69
82
|
"./hooks": {
|
|
70
|
-
"types": "./
|
|
71
|
-
"
|
|
83
|
+
"types": "./dist/hooks.d.ts",
|
|
84
|
+
"bun": "./src/hooks.ts",
|
|
85
|
+
"import": "./dist/hooks.js"
|
|
72
86
|
},
|
|
73
87
|
"./provider": {
|
|
74
|
-
"types": "./
|
|
75
|
-
"
|
|
76
|
-
|
|
88
|
+
"types": "./dist/provider.d.ts",
|
|
89
|
+
"bun": "./src/provider.tsx",
|
|
90
|
+
"import": "./dist/provider.js"
|
|
91
|
+
},
|
|
92
|
+
"./chat-errors": {
|
|
93
|
+
"types": "./dist/chat-errors.d.ts",
|
|
94
|
+
"bun": "./src/chat-errors.ts",
|
|
95
|
+
"import": "./dist/chat-errors.js"
|
|
96
|
+
},
|
|
97
|
+
"./public-chat": {
|
|
98
|
+
"types": "./dist/public-chat.d.ts",
|
|
99
|
+
"bun": "./src/public-chat.ts",
|
|
100
|
+
"import": "./dist/public-chat.js"
|
|
101
|
+
},
|
|
102
|
+
"./reply-text": {
|
|
103
|
+
"types": "./dist/reply-text.d.ts",
|
|
104
|
+
"bun": "./src/reply-text.ts",
|
|
105
|
+
"import": "./dist/reply-text.js"
|
|
106
|
+
},
|
|
107
|
+
"./element": {
|
|
108
|
+
"types": "./dist/element.d.ts",
|
|
109
|
+
"bun": "./src/element.ts",
|
|
110
|
+
"import": "./dist/element.js"
|
|
111
|
+
},
|
|
112
|
+
"./frontera-chat.iife.js": "./dist/frontera-chat.iife.js"
|
|
77
113
|
},
|
|
78
114
|
"scripts": {
|
|
79
115
|
"test": "bun test",
|
|
80
116
|
"typecheck": "bunx tsc --noEmit",
|
|
81
|
-
"smoke": "bun run scripts/smoke.ts"
|
|
117
|
+
"smoke": "bun run scripts/smoke.ts",
|
|
118
|
+
"build": "bunx tsup",
|
|
119
|
+
"prepack": "bun run build"
|
|
82
120
|
},
|
|
83
121
|
"dependencies": {
|
|
84
|
-
"@frontera-sdk/core": "1.52.
|
|
122
|
+
"@frontera-sdk/core": "1.52.46"
|
|
85
123
|
},
|
|
86
124
|
"peerDependencies": {
|
|
87
125
|
"@ai-sdk/react": "^3.0.0",
|
|
@@ -104,11 +142,13 @@
|
|
|
104
142
|
}
|
|
105
143
|
},
|
|
106
144
|
"devDependencies": {
|
|
145
|
+
"@happy-dom/global-registrator": "^20.11.1",
|
|
107
146
|
"@tanstack/react-query": "^5.90.21",
|
|
108
147
|
"@types/bun": "^1.3.14",
|
|
109
148
|
"@types/react": "^19",
|
|
110
149
|
"ai": "^6.0.116",
|
|
111
150
|
"react": "19.2.5",
|
|
151
|
+
"tsup": "^8.5.1",
|
|
112
152
|
"typescript": "^5.9.3"
|
|
113
153
|
}
|
|
114
154
|
}
|