@tangle-network/agent-app 0.43.25 → 0.43.26
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/app-auth/index.d.ts +1 -1
- package/dist/app-auth/index.js +1 -1
- package/dist/assistant/index.d.ts +1 -0
- package/dist/assistant/index.js +2 -1
- package/dist/assistant/index.js.map +1 -1
- package/dist/chat-routes/index.d.ts +276 -0
- package/dist/chat-routes/index.js +564 -0
- package/dist/chat-routes/index.js.map +1 -0
- package/dist/chat-store/index.d.ts +3 -2
- package/dist/chat-store/index.js +7 -3
- package/dist/chat-store/index.js.map +1 -1
- package/dist/{chunk-4H77LX3V.js → chunk-5EQCITY3.js} +2 -20
- package/dist/chunk-5EQCITY3.js.map +1 -0
- package/dist/chunk-5SV5PSU7.js +80 -0
- package/dist/chunk-5SV5PSU7.js.map +1 -0
- package/dist/chunk-7LNGJDNA.js +1 -0
- package/dist/chunk-7LNGJDNA.js.map +1 -0
- package/dist/{chunk-77RLNLFP.js → chunk-ATRJULKZ.js} +41 -5
- package/dist/chunk-ATRJULKZ.js.map +1 -0
- package/dist/{chunk-PEPXQTJ3.js → chunk-FCQP75JT.js} +16 -5
- package/dist/chunk-FCQP75JT.js.map +1 -0
- package/dist/chunk-I2R2XT4M.js +62 -0
- package/dist/chunk-I2R2XT4M.js.map +1 -0
- package/dist/{chunk-AVBANQ67.js → chunk-TKVJE63N.js} +10 -1
- package/dist/{chunk-AVBANQ67.js.map → chunk-TKVJE63N.js.map} +1 -1
- package/dist/{chunk-U7DLCPJ6.js → chunk-Y4QHNQ75.js} +1 -1
- package/dist/core-7qIM7svy.d.ts +21 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +49 -44
- package/dist/interactions/index.js +2 -1
- package/dist/{parts-BeRnK54I.d.ts → parts-BcbitSNp.d.ts} +12 -21
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +3 -1
- package/dist/platform/index.js.map +1 -1
- package/dist/{sso-Df4wtL8D.d.ts → sso-CNOsARMJ.d.ts} +16 -1
- package/dist/stream/index.js +1 -1
- package/dist/web-react/index.d.ts +24 -4
- package/dist/web-react/index.js +5 -1
- package/dist/wire-BaUF66AS.d.ts +61 -0
- package/package.json +6 -1
- package/dist/chunk-4H77LX3V.js.map +0 -1
- package/dist/chunk-77RLNLFP.js.map +0 -1
- package/dist/chunk-PEPXQTJ3.js.map +0 -1
- /package/dist/{chunk-U7DLCPJ6.js.map → chunk-Y4QHNQ75.js.map} +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { C as ChatTurnRequestPayload, a as ChatTurnPartInput, b as ChatTurnFilePartInput } from '../wire-BaUF66AS.js';
|
|
2
|
+
export { c as ChatTurnInputError, d as ChatTurnTextPartInput, I as INLINE_PARTS_MAX_BYTES, e as assertPromptPartsWithinCap, f as chatTurnRequestInit, p as parseChatTurnParts, g as promptPartsByteSize } from '../wire-BaUF66AS.js';
|
|
3
|
+
import { ChatTurnIdentity, ChatTurnProducer } from '@tangle-network/agent-runtime';
|
|
4
|
+
import { c as ChatMessagePart } from '../parts-BcbitSNp.js';
|
|
5
|
+
import { InteractionAnswerRoute, InteractionAnswerRouteOptions } from '../interactions/index.js';
|
|
6
|
+
import { PersistedChatMessageForTurn, TurnEventStore } from '../stream/index.js';
|
|
7
|
+
import '@tangle-network/agent-interface';
|
|
8
|
+
import '../contract-DYbTzEDf.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `createChatTurnRoutes` — the assembled server chat vertical (issue #188
|
|
12
|
+
* Phase 1). One factory composing the pieces every product re-wired by hand:
|
|
13
|
+
*
|
|
14
|
+
* body parse/validate → `/web` `parseJsonObjectBody` + `./wire`
|
|
15
|
+
* turn identity → `/stream` `resolveChatTurn` + agent-runtime
|
|
16
|
+
* `deriveExecutionId`
|
|
17
|
+
* producer → injected seam (sandbox lane via
|
|
18
|
+
* `createSandboxChatProducer`; router lane is the
|
|
19
|
+
* product's own `ChatTurnProducer`)
|
|
20
|
+
* turn engine → agent-runtime `handleChatTurn` (verbatim)
|
|
21
|
+
* durability → `/stream` turn-buffer tap, wired BY DEFAULT
|
|
22
|
+
* (tee + drain keeps the turn running after a
|
|
23
|
+
* client drop; replay serves the buffered tail)
|
|
24
|
+
* persistence → injected `/chat-store`-shaped store
|
|
25
|
+
* (user row on send, assistant row on completion)
|
|
26
|
+
* interactions answer → `/interactions` `createInteractionAnswerRoute`
|
|
27
|
+
*
|
|
28
|
+
* Handlers are web-standard `Request → Response` (Workers, Node 18+, Deno) —
|
|
29
|
+
* no router import. Auth/access is one injected `authorize` seam, composable
|
|
30
|
+
* with `/app-auth` guards but not coupled to them.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** Usage receipt persisted onto the assistant message (the flattened
|
|
34
|
+
* `step-finish` shape `/chat-store`'s columns mirror). */
|
|
35
|
+
interface ChatTurnUsage {
|
|
36
|
+
inputTokens?: number;
|
|
37
|
+
outputTokens?: number;
|
|
38
|
+
reasoningTokens?: number;
|
|
39
|
+
cacheReadTokens?: number;
|
|
40
|
+
cacheWriteTokens?: number;
|
|
41
|
+
costUsd?: number;
|
|
42
|
+
}
|
|
43
|
+
/** What the route persists — a structural subset of `/chat-store`'s
|
|
44
|
+
* `ChatStore`, so `createChatStore(db, tables)` satisfies it directly and a
|
|
45
|
+
* product with its own persistence adapts without importing drizzle. */
|
|
46
|
+
interface ChatTurnMessageStore {
|
|
47
|
+
listMessages(threadId: string): Promise<Array<{
|
|
48
|
+
id: string;
|
|
49
|
+
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
50
|
+
content: string;
|
|
51
|
+
parts?: ChatMessagePart[] | null;
|
|
52
|
+
}>>;
|
|
53
|
+
appendMessage(input: {
|
|
54
|
+
threadId: string;
|
|
55
|
+
role: 'user' | 'assistant';
|
|
56
|
+
content: string;
|
|
57
|
+
parts?: ChatMessagePart[];
|
|
58
|
+
model?: string | null;
|
|
59
|
+
inputTokens?: number | null;
|
|
60
|
+
outputTokens?: number | null;
|
|
61
|
+
reasoningTokens?: number | null;
|
|
62
|
+
cacheReadTokens?: number | null;
|
|
63
|
+
cacheWriteTokens?: number | null;
|
|
64
|
+
costUsd?: number | null;
|
|
65
|
+
}): Promise<unknown>;
|
|
66
|
+
}
|
|
67
|
+
/** `ChatTurnProducer` plus the persisted projection the assembly reads after
|
|
68
|
+
* drain. `createSandboxChatProducer` returns this; a router-lane producer
|
|
69
|
+
* may omit the optional members (finalText persists as a single text part). */
|
|
70
|
+
interface ChatTurnRouteProducer extends ChatTurnProducer {
|
|
71
|
+
assistantParts?(): Array<Record<string, unknown>>;
|
|
72
|
+
usage?(): ChatTurnUsage;
|
|
73
|
+
model?: string;
|
|
74
|
+
}
|
|
75
|
+
type ChatTurnAuthorization<TContext> = {
|
|
76
|
+
ok: true;
|
|
77
|
+
tenantId: string;
|
|
78
|
+
userId: string;
|
|
79
|
+
context: TContext;
|
|
80
|
+
} | {
|
|
81
|
+
ok: false;
|
|
82
|
+
response: Response;
|
|
83
|
+
};
|
|
84
|
+
interface ChatTurnAuthorizeArgs {
|
|
85
|
+
request: Request;
|
|
86
|
+
intent: 'turn' | 'replay';
|
|
87
|
+
/** Parsed, validated POST body (turn intent only). */
|
|
88
|
+
body?: ChatTurnRequestPayload;
|
|
89
|
+
/** The buffered turn id being replayed (replay intent only). */
|
|
90
|
+
turnId?: string;
|
|
91
|
+
}
|
|
92
|
+
interface ChatTurnProduceArgs<TContext> {
|
|
93
|
+
request: Request;
|
|
94
|
+
body: ChatTurnRequestPayload;
|
|
95
|
+
identity: ChatTurnIdentity;
|
|
96
|
+
context: TContext;
|
|
97
|
+
/** The message to send: plain text, or parts when the client attached
|
|
98
|
+
* files (a text part is prepended from `content` when present). */
|
|
99
|
+
prompt: string | ChatTurnPartInput[];
|
|
100
|
+
/** Stable id for cross-process reconnect (`deriveExecutionId`). */
|
|
101
|
+
executionId: string;
|
|
102
|
+
/** The turn-buffer id announced to the client for replay. */
|
|
103
|
+
turnStreamId: string;
|
|
104
|
+
priorMessages: PersistedChatMessageForTurn[];
|
|
105
|
+
}
|
|
106
|
+
interface CreateChatTurnRoutesOptions<TContext = void> {
|
|
107
|
+
/** Names the product in `deriveExecutionId` so retries land on the same
|
|
108
|
+
* substrate execution. */
|
|
109
|
+
projectId: string;
|
|
110
|
+
/** Authenticate + authorize the caller for a turn or a replay. The only
|
|
111
|
+
* product-supplied access step: session auth, thread/workspace access,
|
|
112
|
+
* seat/balance gates, rate limits all live here. */
|
|
113
|
+
authorize(args: ChatTurnAuthorizeArgs): Promise<ChatTurnAuthorization<TContext>>;
|
|
114
|
+
/** Thread/message persistence (`/chat-store`'s store or a product adapter). */
|
|
115
|
+
store: ChatTurnMessageStore;
|
|
116
|
+
/** Turn-event buffer (`createD1TurnEventStore(env.DB)` in production,
|
|
117
|
+
* `createMemoryTurnEventStore()` in tests). Wired by default — every turn
|
|
118
|
+
* is buffered and replayable. */
|
|
119
|
+
turnStore: TurnEventStore;
|
|
120
|
+
/** Build the turn's event stream. Sandbox lane: `streamSandboxPrompt(...)`
|
|
121
|
+
* wrapped in `createSandboxChatProducer`. Router/openai-compat lane: the
|
|
122
|
+
* product's own producer. May be async (box resolution). */
|
|
123
|
+
produce(args: ChatTurnProduceArgs<TContext>): ChatTurnRouteProducer | Promise<ChatTurnRouteProducer>;
|
|
124
|
+
/** Pre-persist transform of the final text (e.g. `/redact`'s `redactPII`).
|
|
125
|
+
* Live stream is never altered. */
|
|
126
|
+
transformFinalText?(text: string): string | Promise<string>;
|
|
127
|
+
/** Post-processing after a successful turn (billing, titles, audit). Errors
|
|
128
|
+
* are swallowed by the engine — they never fail a streamed turn. */
|
|
129
|
+
onTurnComplete?(input: {
|
|
130
|
+
identity: ChatTurnIdentity;
|
|
131
|
+
finalText: string;
|
|
132
|
+
context: TContext;
|
|
133
|
+
}): Promise<void>;
|
|
134
|
+
/** Per-event side channel (product broadcast). The turn-buffer tap is
|
|
135
|
+
* already wired; this runs in addition. */
|
|
136
|
+
onEvent?(event: {
|
|
137
|
+
type: string;
|
|
138
|
+
data?: Record<string, unknown>;
|
|
139
|
+
}, context: TContext): void | Promise<void>;
|
|
140
|
+
/** Trace flush handed to `waitUntil` (OTLP export). */
|
|
141
|
+
traceFlush?(context: TContext): Promise<void>;
|
|
142
|
+
/** Compose the interaction-answer endpoints (`/interactions`). Omit when the
|
|
143
|
+
* product has no sidecar ask channel. */
|
|
144
|
+
interactions?: InteractionAnswerRouteOptions;
|
|
145
|
+
/** Byte budget for inline prompt parts. Default `INLINE_PARTS_MAX_BYTES`. */
|
|
146
|
+
maxInlinePartBytes?: number;
|
|
147
|
+
/** Per-flush coalescer for the turn buffer. Default `coalesceDeltas` (this
|
|
148
|
+
* assembly streams the client vocabulary's `{type:'text'|'reasoning',
|
|
149
|
+
* text}` lines, which it merges). A producer streaming raw
|
|
150
|
+
* `message.part.updated` events passes `coalesceChatStreamEvents`. */
|
|
151
|
+
coalesceTurnEvents?: (events: unknown[]) => unknown[];
|
|
152
|
+
replay?: {
|
|
153
|
+
pollMs?: number;
|
|
154
|
+
timeoutMs?: number;
|
|
155
|
+
};
|
|
156
|
+
log?: (message: string, meta?: Record<string, unknown>) => void;
|
|
157
|
+
}
|
|
158
|
+
interface ChatTurnRoutes {
|
|
159
|
+
/** POST — run one turn, streaming NDJSON. First line is
|
|
160
|
+
* `{type:'turn', turnId}` (the replay handle); the rest is the engine's
|
|
161
|
+
* event protocol. Pass the platform's `waitUntil` so the turn keeps
|
|
162
|
+
* running (and buffering) after a client disconnect. */
|
|
163
|
+
turn(request: Request, ctx?: {
|
|
164
|
+
waitUntil?(p: Promise<unknown>): void;
|
|
165
|
+
}): Promise<Response>;
|
|
166
|
+
/** GET — replay a buffered turn from `?fromSeq=` (0 = everything), then
|
|
167
|
+
* follow it live until it completes. */
|
|
168
|
+
replay(request: Request, params: {
|
|
169
|
+
turnId: string;
|
|
170
|
+
}): Promise<Response>;
|
|
171
|
+
/** list/answer endpoints from `/interactions`; null when not configured. */
|
|
172
|
+
interactions: InteractionAnswerRoute | null;
|
|
173
|
+
}
|
|
174
|
+
declare function createChatTurnRoutes<TContext = void>(options: CreateChatTurnRoutesOptions<TContext>): ChatTurnRoutes;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Sandbox lane: bridge a raw sandbox event stream (`streamSandboxPrompt`) into
|
|
178
|
+
* the `ChatTurnProducer` shape agent-runtime's `handleChatTurn` consumes AND
|
|
179
|
+
* the client vocabulary `/web-react`'s `dispatchChatStreamLine` already parses
|
|
180
|
+
* (`text` / `reasoning` / `tool_call` / `tool_result` / `usage` /
|
|
181
|
+
* `interaction`). Legal and tax each hand-rolled this mapping differently;
|
|
182
|
+
* this is that middle, composed from `/stream`'s normalizers — no new loop
|
|
183
|
+
* logic, no SDK import (the event source is an injected `AsyncIterable`).
|
|
184
|
+
*
|
|
185
|
+
* Alongside the live mapping it accumulates the PERSISTED projection — the
|
|
186
|
+
* `message.parts` rows `/chat-store` stores — via `normalizePersistedPart` /
|
|
187
|
+
* `mergePersistedPart` / `finalizeAssistantParts`, plus the usage receipt from
|
|
188
|
+
* `step-finish` parts. `createChatTurnRoutes` reads both after drain.
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
interface SandboxChatProducerOptions {
|
|
192
|
+
/** The raw sandbox event stream (e.g. `streamSandboxPrompt(...)`). */
|
|
193
|
+
events: AsyncIterable<unknown>;
|
|
194
|
+
/** Recorded on the persisted assistant message. */
|
|
195
|
+
model?: string;
|
|
196
|
+
/** Which ask kinds the product renders a card for. Anything else is
|
|
197
|
+
* auto-declined (see `declineInteraction`) so the run never hangs in the
|
|
198
|
+
* broker waiting on a card no client will show. Default: question/plan. */
|
|
199
|
+
isRenderableInteraction?: (kind: string) => boolean;
|
|
200
|
+
/** Resolve a non-renderable ask (wire `respondToSessionInteraction` with the
|
|
201
|
+
* session's sidecar connection). Without it, non-renderable asks are only
|
|
202
|
+
* logged — the run stays blocked until the broker times out. */
|
|
203
|
+
declineInteraction?: (id: string) => Promise<void>;
|
|
204
|
+
log?: (message: string, meta?: Record<string, unknown>) => void;
|
|
205
|
+
}
|
|
206
|
+
declare function createSandboxChatProducer(options: SandboxChatProducerOptions): ChatTurnRouteProducer;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* `createUploadRoute` — the multimodal middle. Accepts multipart file uploads
|
|
210
|
+
* and returns `PromptInputPart`-shaped descriptors the client echoes back on
|
|
211
|
+
* send (`ChatTurnRequestPayload.parts`):
|
|
212
|
+
*
|
|
213
|
+
* ≤ inlineMaxBytes (700 KiB default) → inline `data:` URI part — rides the
|
|
214
|
+
* turn body directly, no sandbox round trip.
|
|
215
|
+
* > inlineMaxBytes → written into the sandbox workspace (base64 through the
|
|
216
|
+
* structural `write` seam — `box.fs` satisfies it) and referenced by
|
|
217
|
+
* `path`. Mandatory two-step: the gateway caps request bodies at ~1 MiB,
|
|
218
|
+
* so a large file can never ride the prompt POST.
|
|
219
|
+
*
|
|
220
|
+
* The sink is structural (no sandbox-SDK import); products pass `box.fs`.
|
|
221
|
+
*/
|
|
222
|
+
|
|
223
|
+
/** 700 KiB: base64 inflates ~4/3, so an inline part stays comfortably under
|
|
224
|
+
* the ~1 MiB gateway body cap alongside the JSON envelope. */
|
|
225
|
+
declare const UPLOAD_INLINE_MAX_BYTES: number;
|
|
226
|
+
/** 8 MiB default ceiling per file — one base64 `write` call handles it. Raise
|
|
227
|
+
* it only with a sink that can take the bigger single write. */
|
|
228
|
+
declare const UPLOAD_MAX_FILE_BYTES: number;
|
|
229
|
+
/** Structural match of the sandbox SDK's `box.fs` write surface (v0.10.5+:
|
|
230
|
+
* `encoding: 'base64'` is the worker-safe binary path). */
|
|
231
|
+
interface SandboxUploadSink {
|
|
232
|
+
write(path: string, content: string, options?: {
|
|
233
|
+
encoding?: 'utf8' | 'base64';
|
|
234
|
+
}): Promise<unknown>;
|
|
235
|
+
}
|
|
236
|
+
type UploadAuthorization = {
|
|
237
|
+
ok: true;
|
|
238
|
+
/** Where large files land. Absent/null: only inline uploads are
|
|
239
|
+
* accepted and an over-inline-cap file is rejected with 413. */
|
|
240
|
+
sink?: SandboxUploadSink | null;
|
|
241
|
+
/** Per-request override of the workspace directory large files go to. */
|
|
242
|
+
uploadDir?: string;
|
|
243
|
+
} | {
|
|
244
|
+
ok: false;
|
|
245
|
+
response: Response;
|
|
246
|
+
};
|
|
247
|
+
interface CreateUploadRouteOptions {
|
|
248
|
+
/** Authenticate the caller and resolve the sandbox file sink (usually
|
|
249
|
+
* `ensureWorkspaceSandbox(...)` → `box.fs`). */
|
|
250
|
+
authorize(args: {
|
|
251
|
+
request: Request;
|
|
252
|
+
}): Promise<UploadAuthorization>;
|
|
253
|
+
/** Inline-vs-sandbox threshold. Default {@link UPLOAD_INLINE_MAX_BYTES}. */
|
|
254
|
+
inlineMaxBytes?: number;
|
|
255
|
+
/** Hard per-file cap. Default {@link UPLOAD_MAX_FILE_BYTES}. */
|
|
256
|
+
maxFileBytes?: number;
|
|
257
|
+
/** Workspace directory for path-ref files. Default `'uploads'`. */
|
|
258
|
+
uploadDir?: string;
|
|
259
|
+
}
|
|
260
|
+
/** One uploaded file, ready for the composer chip and the turn body. */
|
|
261
|
+
interface UploadedChatFile {
|
|
262
|
+
id: string;
|
|
263
|
+
name: string;
|
|
264
|
+
size: number;
|
|
265
|
+
mediaType: string;
|
|
266
|
+
/** True when the part carries the bytes inline (`data:` URI). */
|
|
267
|
+
inline: boolean;
|
|
268
|
+
/** Echo this back verbatim in `ChatTurnRequestPayload.parts`. */
|
|
269
|
+
part: ChatTurnFilePartInput;
|
|
270
|
+
}
|
|
271
|
+
/** Path-safe file name: basename only, conservative charset, length-capped. */
|
|
272
|
+
declare function sanitizeUploadFilename(name: string): string;
|
|
273
|
+
declare function bytesToBase64(bytes: Uint8Array): string;
|
|
274
|
+
declare function createUploadRoute(options: CreateUploadRouteOptions): (request: Request) => Promise<Response>;
|
|
275
|
+
|
|
276
|
+
export { type ChatTurnAuthorization, type ChatTurnAuthorizeArgs, ChatTurnFilePartInput, type ChatTurnMessageStore, ChatTurnPartInput, type ChatTurnProduceArgs, ChatTurnRequestPayload, type ChatTurnRouteProducer, type ChatTurnRoutes, type ChatTurnUsage, type CreateChatTurnRoutesOptions, type CreateUploadRouteOptions, type SandboxChatProducerOptions, type SandboxUploadSink, UPLOAD_INLINE_MAX_BYTES, UPLOAD_MAX_FILE_BYTES, type UploadAuthorization, type UploadedChatFile, bytesToBase64, createChatTurnRoutes, createSandboxChatProducer, createUploadRoute, sanitizeUploadFilename };
|