@tangle-network/agent-app 0.43.23 → 0.43.25

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.
Files changed (50) hide show
  1. package/dist/app-auth/index.d.ts +163 -0
  2. package/dist/app-auth/index.js +166 -0
  3. package/dist/app-auth/index.js.map +1 -0
  4. package/dist/assets/index.d.ts +2 -2
  5. package/dist/assistant/index.d.ts +1 -0
  6. package/dist/assistant/index.js +2 -1
  7. package/dist/assistant/index.js.map +1 -1
  8. package/dist/chat-store/index.d.ts +193 -0
  9. package/dist/chat-store/index.js +194 -0
  10. package/dist/chat-store/index.js.map +1 -0
  11. package/dist/chunk-4H77LX3V.js +38 -0
  12. package/dist/chunk-4H77LX3V.js.map +1 -0
  13. package/dist/chunk-4TXDD6P2.js +163 -0
  14. package/dist/chunk-4TXDD6P2.js.map +1 -0
  15. package/dist/chunk-AVBANQ67.js +295 -0
  16. package/dist/chunk-AVBANQ67.js.map +1 -0
  17. package/dist/{chunk-UKYZ4O2O.js → chunk-JJGZ54EB.js} +64 -5
  18. package/dist/chunk-JJGZ54EB.js.map +1 -0
  19. package/dist/{chunk-VMY4TKMN.js → chunk-PEPXQTJ3.js} +921 -432
  20. package/dist/chunk-PEPXQTJ3.js.map +1 -0
  21. package/dist/chunk-U7DLCPJ6.js +203 -0
  22. package/dist/chunk-U7DLCPJ6.js.map +1 -0
  23. package/dist/{chunk-SAOAAA3S.js → chunk-UHXQ3KNX.js} +1 -22
  24. package/dist/chunk-UHXQ3KNX.js.map +1 -0
  25. package/dist/contract-DYbTzEDf.d.ts +122 -0
  26. package/dist/index.d.ts +5 -2
  27. package/dist/index.js +172 -88
  28. package/dist/interactions/index.d.ts +141 -0
  29. package/dist/interactions/index.js +59 -0
  30. package/dist/interactions/index.js.map +1 -0
  31. package/dist/parts-BeRnK54I.d.ts +185 -0
  32. package/dist/platform/index.d.ts +2 -270
  33. package/dist/platform/index.js +12 -278
  34. package/dist/platform/index.js.map +1 -1
  35. package/dist/preset-cloudflare/index.d.ts +0 -10
  36. package/dist/preset-cloudflare/index.js +1 -1
  37. package/dist/profile/index.d.ts +33 -2
  38. package/dist/profile/index.js +37 -1
  39. package/dist/profile/index.js.map +1 -1
  40. package/dist/sandbox/index.d.ts +61 -5
  41. package/dist/sandbox/index.js +13 -1
  42. package/dist/sso-Df4wtL8D.d.ts +270 -0
  43. package/dist/teams/index.js +9 -9
  44. package/dist/teams/invitations-api.js +3 -3
  45. package/dist/web-react/index.d.ts +206 -96
  46. package/dist/web-react/index.js +68 -22
  47. package/package.json +21 -2
  48. package/dist/chunk-SAOAAA3S.js.map +0 -1
  49. package/dist/chunk-UKYZ4O2O.js.map +0 -1
  50. package/dist/chunk-VMY4TKMN.js.map +0 -1
@@ -1,6 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { InteractionField, InteractionRequest, InteractionData } from '@tangle-network/agent-interface';
3
+ import { C as ChatInteraction, a as ChatInteractionField, b as ChatInteractionStatus, c as ChatSelectField, g as InteractionCancelData, i as InteractionRequestWire } from '../contract-DYbTzEDf.js';
4
+ export { d as ComposerAnswerDelivery, I as INTERACTION_CANCEL_EVENT, e as INTERACTION_EVENT, f as INTERACTION_RESOLVED_EVENT, h as InteractionPersistedPart, N as NoticeKind, j as NoticePersistedPart, P as ParseInteractionResult, k as canTransitionInteractionStatus, l as cancelStatusFor, m as composerAnswerData, n as composerAnswerDeliveries, o as dedupeQuestionInteractionsByContent, p as fieldAcceptsFreeText, q as interactionFromWireRequest, r as interactionPartKey, s as interactionToPersistedPart, t as isRenderableInteractionKind, u as isSafeInteractionFieldKey, v as isTerminalInteractionStatus, w as noticePart, x as noticePartKey, y as parseInteractionCancel, z as parseInteractionRequest, A as persistedPartToInteraction, B as questionInteractionContentSignature } from '../contract-DYbTzEDf.js';
5
+ import { InteractionData } from '@tangle-network/agent-interface';
4
6
  export { InteractionData, InteractionOutcome, InteractionRequest } from '@tangle-network/agent-interface';
5
7
  import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
6
8
  import { a as FlowTrace } from '../flow-types-Cb_AblZs.js';
@@ -8,99 +10,6 @@ export { S as SandboxTerminalConnection, a as SandboxTerminalConnectionResponse,
8
10
  import { CatalogModel } from '../catalog/index.js';
9
11
  import { Harness } from '../harness/index.js';
10
12
 
11
- /** Sidecar → client: the agent raised an ask; data = `{ request }`. */
12
- declare const INTERACTION_EVENT: "interaction";
13
- /** Sidecar → client: the ask was withdrawn; data = `{ id, reason? }`. */
14
- declare const INTERACTION_CANCEL_EVENT: "interaction.cancel";
15
- /** An ask was answered; data = `{ id, status }`. In the wire contract so a
16
- * server broadcast and a client-local mark share one event name. */
17
- declare const INTERACTION_RESOLVED_EVENT: "interaction.resolved";
18
- declare function isRenderableInteractionKind(kind: string): boolean;
19
- /** Answer/field keys the sidecar will accept: identifier-safe and never a
20
- * prototype-pollution vector. */
21
- declare function isSafeInteractionFieldKey(key: string): boolean;
22
- type ChatSelectField = Extract<InteractionField, {
23
- type: 'select';
24
- }> & {
25
- allowCustom?: boolean;
26
- };
27
- type ChatInteractionField = Exclude<InteractionField, {
28
- type: 'select';
29
- }> | ChatSelectField;
30
- /** `InteractionRequest` whose select fields may carry `allowCustom`. */
31
- type InteractionRequestWire = Omit<InteractionRequest, 'answerSpec'> & {
32
- answerSpec: {
33
- fields: ChatInteractionField[];
34
- };
35
- };
36
- type ChatInteractionStatus = 'pending' | 'answered' | 'declined' | 'cancelled' | 'expired';
37
- /** The client/persisted view of one ask. `fields` come verbatim off the wire. */
38
- interface ChatInteraction {
39
- id: string;
40
- kind: string;
41
- title: string;
42
- body?: string;
43
- fields: ChatInteractionField[];
44
- status: ChatInteractionStatus;
45
- /** Set when status came from an `interaction.cancel` (e.g. "timeout"). */
46
- cancelReason?: string;
47
- }
48
- declare function isTerminalInteractionStatus(status: ChatInteractionStatus): boolean;
49
- /** Statuses only move forward (pending → terminal); a replayed/stale `pending`
50
- * must never resurrect a resolved card. */
51
- declare function canTransitionInteractionStatus(from: ChatInteractionStatus, to: ChatInteractionStatus): boolean;
52
- /** Maps an `interaction.cancel` reason to the card's terminal status. */
53
- declare function cancelStatusFor(reason: string | undefined): ChatInteractionStatus;
54
- /** Content identity for duplicate safety nets. Excludes volatile ids/statuses. */
55
- declare function questionInteractionContentSignature(interaction: ChatInteraction): string | null;
56
- declare function dedupeQuestionInteractionsByContent(interactions: ChatInteraction[]): ChatInteraction[];
57
- type ParseInteractionResult = {
58
- succeeded: true;
59
- value: InteractionRequestWire;
60
- } | {
61
- succeeded: false;
62
- error: string;
63
- };
64
- /** Parses an `interaction` event's data (`{ request }`). Validates the shape
65
- * with the agent-interface schema but returns the raw request so a field a
66
- * pinned schema predates (`allowCustom`) survives. */
67
- declare function parseInteractionRequest(data: Record<string, unknown> | undefined): ParseInteractionResult;
68
- interface InteractionCancelData {
69
- id: string;
70
- reason?: string;
71
- }
72
- declare function parseInteractionCancel(data: Record<string, unknown> | undefined): {
73
- succeeded: true;
74
- value: InteractionCancelData;
75
- } | {
76
- succeeded: false;
77
- error: string;
78
- };
79
- declare function fieldAcceptsFreeText(field: ChatInteractionField): boolean;
80
- interface ComposerAnswerDelivery {
81
- interactionId: string;
82
- field: ChatInteractionField;
83
- }
84
- /** One delivery per pending ask: the first free-text-capable field, else the
85
- * first field. Zero-field asks are skipped (nothing to carry the text). */
86
- declare function composerAnswerDeliveries(pending: ChatInteraction[]): ComposerAnswerDelivery[];
87
- /** Shapes composer text into the respond payload for the routed field
88
- * (select answers are string arrays on the wire; text answers are strings). */
89
- declare function composerAnswerData(field: ChatInteractionField, text: string): InteractionData;
90
- declare function interactionPartKey(id: string): string;
91
- declare function noticePartKey(id: string): string;
92
- type NoticeKind = 'warning' | 'auto-declined';
93
- /** Builds the persisted/streamed `notice` part — a one-line transcript notice
94
- * explaining an out-of-band event (warning, auto-declined interaction). */
95
- declare function noticePart(noticeKind: NoticeKind, id: string, text: string): Record<string, unknown>;
96
- /** Reads a wire request into the client's pending `ChatInteraction`. */
97
- declare function interactionFromWireRequest(request: InteractionRequestWire): ChatInteraction;
98
- /** Builds the persisted/streamed `interaction` part from a wire request. */
99
- declare function interactionToPersistedPart(request: InteractionRequestWire, status: ChatInteractionStatus, cancelReason?: string): Record<string, unknown>;
100
- /** Reads a persisted/streamed `interaction` part back into a `ChatInteraction`.
101
- * Returns null (caller logs) when the part is not one of ours. */
102
- declare function persistedPartToInteraction(part: Record<string, unknown>): ChatInteraction | null;
103
-
104
13
  /**
105
14
  * Client-side chat-stream consumption — the NDJSON parse loop every agent
106
15
  * app's chat UI hand-rolls (and breaks). Normalizes the three line shapes the
@@ -143,7 +52,10 @@ interface ChatStreamCallbacks {
143
52
  completionTokens: number;
144
53
  }) => void;
145
54
  onMetadata?: (data: Record<string, unknown>) => void;
146
- /** A loop-level error event (the turn failed server-side). */
55
+ /** A loop-level error event (the turn failed server-side). Optional, but the
56
+ * error never vanishes: when omitted, the message is synthesized into the
57
+ * transcript via `onText` (rendered by ChatMessages as a text segment) and
58
+ * logged with `console.error`. */
147
59
  onErrorEvent?: (message: string) => void;
148
60
  /** A sidecar interaction ask (kind: "question"/"plan"/…). The run is BLOCKED
149
61
  * in the broker until the user answers; a pending ask is "waiting on the
@@ -227,6 +139,204 @@ interface ChatComposerProps {
227
139
  }
228
140
  declare function ChatComposer({ onSend, onCancel, isStreaming, disabled, placeholder, value, onValueChange, initialValue, controls, controlsPlacement, onAttach, onAttachFolder, pendingFiles, onRemoveFile, accept, dropTitle, dropDescription, focusShortcut, sendLabel, className, }: ChatComposerProps): react.JSX.Element;
229
141
 
142
+ /**
143
+ * Shared answer-building + submit plumbing for the interaction cards
144
+ * (question, plan). Client-safe, no React: cards own their state, this owns
145
+ * the wire. Lifted from the gtm-agent fork (the most fix-absorbed of the three
146
+ * product copies), including the 30s submit timeout that keeps a dead route
147
+ * from wedging a card in "Submitting…".
148
+ */
149
+
150
+ /** Status-badge labels for an interaction card. `cancelled`/`expired` read the
151
+ * same across cards; each card supplies its own verbs for the other states
152
+ * (a question is answered/declined; a plan is approved/rejected). */
153
+ declare function interactionStatusLabels(labels: {
154
+ pending: string;
155
+ answered: string;
156
+ declined: string;
157
+ }): Record<ChatInteractionStatus, string>;
158
+ /** Terminal-state notes for an interaction card. The expiry/withdrawal lines
159
+ * share one shape around the card's noun ("question"/"plan"); any extra notes
160
+ * (e.g. a plan's `declined` revision line) merge on top. */
161
+ declare function interactionTerminalNotes(noun: string, extra?: Partial<Record<ChatInteractionStatus, string>>): Partial<Record<ChatInteractionStatus, string>>;
162
+ type FieldValues = Record<string, {
163
+ selected?: string[];
164
+ text?: string;
165
+ custom?: string;
166
+ }>;
167
+ /** The submitted value for one field, or null when it has no answer yet. */
168
+ declare function fieldAnswer(field: ChatInteractionField, values: FieldValues): InteractionData[string] | null;
169
+ /** All required fields answered → the respond payload; else null (not
170
+ * submittable yet). Optional unanswered fields are omitted. */
171
+ declare function buildAnswerData(fields: ChatInteractionField[], values: FieldValues): InteractionData | null;
172
+ declare function isLateAnswerableStatus(status: ChatInteractionStatus): boolean;
173
+ /** Secrets must never leave the sidecar answer channel for the visible chat
174
+ * transcript, so a secret-bearing ask cannot be late-answered. */
175
+ declare function hasSecretField(fields: ChatInteractionField[]): boolean;
176
+ /** Renders the late answer as a self-contained chat message: the original
177
+ * question, its context, and the user's answer(s). */
178
+ declare function lateAnswerMessage(interaction: ChatInteraction, data: InteractionData): string;
179
+ declare const INTERACTION_SUBMIT_TIMEOUT_MS = 30000;
180
+ declare const INTERACTION_SUBMIT_TIMEOUT_MESSAGE = "Could not reach the agent. Try again.";
181
+ /** One card submission: which ask, resolved how, with what answers. */
182
+ interface InteractionAnswerSubmission {
183
+ id: string;
184
+ outcome: 'accepted' | 'declined';
185
+ data?: InteractionData;
186
+ }
187
+ type InteractionSubmitResult = {
188
+ ok: true;
189
+ } | {
190
+ ok: false;
191
+ expired: boolean;
192
+ message: string;
193
+ };
194
+ /** The cards' only side-effect seam: POST one resolution, report the normalized
195
+ * outcome. Products bind their route URL + routing fields (workspaceId,
196
+ * threadId, session path param) via `createInteractionAnswerSubmitter` or a
197
+ * hand-rolled implementation. */
198
+ type SubmitInteractionAnswer = (submission: InteractionAnswerSubmission) => Promise<InteractionSubmitResult>;
199
+ /** Extracts the most specific error message a route returned. */
200
+ declare function responseErrorMessage(res: Response): Promise<{
201
+ code?: string;
202
+ message: string;
203
+ }>;
204
+ interface InteractionAnswerSubmitterOptions {
205
+ /** The product's answer route (the POST half of `createInteractionAnswerRoute`).
206
+ * A function when the URL carries the session (e.g. `/api/sessions/${id}/interactions`). */
207
+ url: string | ((submission: InteractionAnswerSubmission) => string);
208
+ /** Extra routing fields merged into the POST body (e.g. workspaceId, threadId). */
209
+ body?: Record<string, unknown> | ((submission: InteractionAnswerSubmission) => Record<string, unknown>);
210
+ timeoutMs?: number;
211
+ fetchImpl?: typeof fetch;
212
+ }
213
+ /**
214
+ * Builds the `SubmitInteractionAnswer` the cards consume: POSTs
215
+ * `{ ...routingFields, id, outcome, data? }` with an abortable timeout and
216
+ * normalizes the outcome. `expired` is the 410 path — the ask is gone
217
+ * (answered elsewhere, timed out, or the session moved on) and the card must
218
+ * flip to the same dead state a cancel event produces.
219
+ */
220
+ declare function createInteractionAnswerSubmitter(options: InteractionAnswerSubmitterOptions): SubmitInteractionAnswer;
221
+
222
+ type InteractionBadgeVariant = 'outline' | 'default' | 'destructive';
223
+ declare function InteractionBadge({ variant, children }: {
224
+ variant: InteractionBadgeVariant;
225
+ children: string;
226
+ }): react.JSX.Element;
227
+ declare function InteractionActionButton({ variant, onClick, disabled, children, }: {
228
+ variant?: 'primary' | 'outline';
229
+ onClick: () => void;
230
+ disabled?: boolean;
231
+ children: string;
232
+ }): react.JSX.Element;
233
+ interface QuestionOptionListProps {
234
+ /** Radio/checkbox group name — unique per field so selection is isolated. */
235
+ groupName: string;
236
+ /** Stable prefix for per-option input ids (label htmlFor pairing). */
237
+ idPrefix: string;
238
+ options: ChatSelectField['options'];
239
+ /** Checkbox (multi-select) vs radio (single). */
240
+ multi: boolean;
241
+ selectedValues: string[];
242
+ disabled: boolean;
243
+ onToggle: (value: string) => void;
244
+ }
245
+ /** The radio/checkbox option rows for a select field. Renders a fragment of
246
+ * option `<label>` rows so a card keeps its own wrapping layout and appends
247
+ * its own write-in input. */
248
+ declare function QuestionOptionList({ groupName, idPrefix, options, multi, selectedValues, disabled, onToggle, }: QuestionOptionListProps): react.JSX.Element;
249
+ interface InteractionQuestionCardProps {
250
+ interaction: ChatInteraction;
251
+ /** Viewer-vs-editor gate: false renders everything read-only. */
252
+ canWrite: boolean;
253
+ /** POST one resolution to the product's answer route (see
254
+ * `createInteractionAnswerSubmitter`). Never called for late answers. */
255
+ submitAnswer: SubmitInteractionAnswer;
256
+ /** Fired when this card resolves locally (answered, or discovered expired
257
+ * via a 410) so the stream/route state stays in sync. */
258
+ onResolved?: (id: string, status: Exclude<ChatInteractionStatus, 'pending'>) => void;
259
+ /** Delivers a late answer (the ask expired/was withdrawn) as a fresh chat
260
+ * turn. Return/resolve `false` when the send was rejected so the card stays
261
+ * retryable. Omit to hide the late-answer affordance entirely. */
262
+ onLateAnswer?: (message: string) => boolean | void | Promise<boolean | void>;
263
+ className?: string;
264
+ }
265
+ declare function InteractionQuestionCard({ interaction, canWrite, submitAnswer, onResolved, onLateAnswer, className, }: InteractionQuestionCardProps): react.JSX.Element;
266
+
267
+ interface InteractionPlanCardProps {
268
+ interaction: ChatInteraction;
269
+ /** Viewer-vs-editor gate: false renders everything read-only. */
270
+ canWrite: boolean;
271
+ /** POST one resolution to the product's answer route (see
272
+ * `createInteractionAnswerSubmitter`). */
273
+ submitAnswer: SubmitInteractionAnswer;
274
+ /** Fired when this card resolves locally (approved/rejected, or discovered
275
+ * expired via a 410) so the stream/route state stays in sync. */
276
+ onResolved?: (id: string, status: Exclude<ChatInteractionStatus, 'pending'>) => void;
277
+ /** Renders the plan body (markdown). Falls back to pre-wrapped plain text. */
278
+ renderMarkdown?: (markdown: string) => ReactNode;
279
+ className?: string;
280
+ }
281
+ declare function InteractionPlanCard({ interaction, canWrite, submitAnswer, onResolved, renderMarkdown, className, }: InteractionPlanCardProps): react.JSX.Element;
282
+
283
+ /**
284
+ * useChatInteractions — the interaction-state wiring every consumer of
285
+ * `ChatStreamCallbacks.onInteraction` re-implements: an id-keyed,
286
+ * insertion-ordered list with
287
+ *
288
+ * - forward-only status transitions (a replayed/stale `pending` never
289
+ * resurrects a resolved card),
290
+ * - pending-question content dedupe (a re-emitted duplicate ask never renders
291
+ * a second card),
292
+ * - cancel-event application (`interaction.cancel` → cancelled/expired),
293
+ * - local resolution marking (the card's `onResolved`),
294
+ * - reload restore from the answer route's GET list (sidecar registry is the
295
+ * source of truth after a reload),
296
+ * - turn-end settling (client mirror of the server's finalize pass: a turn
297
+ * that completed without a cancel was answered; a failed turn can make no
298
+ * such claim).
299
+ *
300
+ * The reducer functions are pure and exported for non-React consumers/tests;
301
+ * the hook is a thin `useState` shell over them.
302
+ */
303
+
304
+ /** Insert or update one interaction. A terminal existing entry wins over any
305
+ * incoming state for the same id; a new pending ask that duplicates another
306
+ * pending ask's content is dropped. Returns the same array when unchanged. */
307
+ declare function upsertChatInteraction(list: ChatInteraction[], interaction: ChatInteraction): ChatInteraction[];
308
+ /** Applies an `interaction.cancel` event: only a pending ask moves, to
309
+ * `expired` (reason:"timeout") or `cancelled`. */
310
+ declare function cancelChatInteraction(list: ChatInteraction[], cancel: InteractionCancelData): ChatInteraction[];
311
+ /** Marks one ask resolved locally (the card's `onResolved`). Forward-only. */
312
+ declare function resolveChatInteraction(list: ChatInteraction[], id: string, status: Exclude<ChatInteractionStatus, 'pending'>): ChatInteraction[];
313
+ /** Settles every still-pending ask when the turn ends: `answered` for a turn
314
+ * that completed cleanly, `expired` for one that failed. */
315
+ declare function terminalizePendingChatInteractions(list: ChatInteraction[], status: Extract<ChatInteractionStatus, 'answered' | 'expired'>): ChatInteraction[];
316
+ /** Reload restore from the answer route's GET list: every listed ask is
317
+ * outstanding (upserted pending), and every previously-pending ask the sidecar
318
+ * no longer lists was resolved while we were away (settled as answered). */
319
+ declare function restoreChatInteractions(list: ChatInteraction[], outstanding: InteractionRequestWire[]): ChatInteraction[];
320
+ interface UseChatInteractionsResult {
321
+ /** All known interactions, insertion-ordered. */
322
+ interactions: ChatInteraction[];
323
+ /** The asks currently blocking the run (waiting on the user). */
324
+ pending: ChatInteraction[];
325
+ /** Wire to `ChatStreamCallbacks.onInteraction` (and persisted-part replay). */
326
+ upsert: (interaction: ChatInteraction) => void;
327
+ /** Wire to `interaction.cancel` events. */
328
+ applyCancel: (cancel: InteractionCancelData) => void;
329
+ /** Wire to the cards' `onResolved`. */
330
+ markResolved: (id: string, status: Exclude<ChatInteractionStatus, 'pending'>) => void;
331
+ /** Wire to the answer route's GET list after a reload/reconnect. */
332
+ restore: (outstanding: InteractionRequestWire[]) => void;
333
+ /** Settle still-pending asks when the turn ends. */
334
+ terminalizePending: (status: Extract<ChatInteractionStatus, 'answered' | 'expired'>) => void;
335
+ /** Drop everything (thread switch). */
336
+ reset: () => void;
337
+ }
338
+ declare function useChatInteractions(): UseChatInteractionsResult;
339
+
230
340
  /**
231
341
  * Provider brand marks — real logo path data (simple-icons / SVG Logos, both
232
342
  * CC0) inlined so the picker shows actual provider identity instead of
@@ -656,4 +766,4 @@ declare function useThinkingSeconds(active: boolean): number;
656
766
  */
657
767
  declare function ChatMessages({ messages, models, renderMarkdown, renderExtras, userLabel, agentLabel, loading, approval, onToolCallClick, toolRenderers, error, onRetry, renderEmpty, emptyState, header, }: ChatMessagesProps): react.JSX.Element;
658
768
 
659
- export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, CatalogModel, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, type ChatInteraction, type ChatInteractionField, type ChatInteractionStatus, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, type ChatSelectField, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerAnswerDelivery, type ComposerFile, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, type EffortLevel, EffortPicker, type EffortPickerProps, FlowWaterfall, type FlowWaterfallProps, INTERACTION_CANCEL_EVENT, INTERACTION_EVENT, INTERACTION_RESOLVED_EVENT, type InteractionCancelData, type InteractionRequestWire, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type NoticeKind, type ParseInteractionResult, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type WaterfallRow, activityTone, canTransitionInteractionStatus, cancelStatusFor, composerAnswerData, composerAnswerDeliveries, consumeChatStream, dedupeQuestionInteractionsByContent, dispatchChatStreamLine, fieldAcceptsFreeText, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, interactionFromWireRequest, interactionPartKey, interactionToPersistedPart, isRenderableInteractionKind, isSafeInteractionFieldKey, isTerminalInteractionStatus, mergeActivityPages, nextRevealCount, noticePart, noticePartKey, parseInteractionCancel, parseInteractionRequest, pendingApprovalOf, persistedPartToInteraction, questionInteractionContentSignature, streamChatTurn, usePending, usePopover, useSmoothText, useThinkingSeconds, waterfallLayout };
769
+ export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, CatalogModel, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, ChatInteraction, ChatInteractionField, ChatInteractionStatus, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, ChatSelectField, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, type EffortLevel, EffortPicker, type EffortPickerProps, type FieldValues, FlowWaterfall, type FlowWaterfallProps, INTERACTION_SUBMIT_TIMEOUT_MESSAGE, INTERACTION_SUBMIT_TIMEOUT_MS, InteractionActionButton, type InteractionAnswerSubmission, type InteractionAnswerSubmitterOptions, InteractionBadge, type InteractionBadgeVariant, InteractionCancelData, InteractionPlanCard, type InteractionPlanCardProps, InteractionQuestionCard, type InteractionQuestionCardProps, InteractionRequestWire, type InteractionSubmitResult, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, QuestionOptionList, type QuestionOptionListProps, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type SubmitInteractionAnswer, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseChatInteractionsResult, type WaterfallRow, activityTone, buildAnswerData, cancelChatInteraction, consumeChatStream, createInteractionAnswerSubmitter, dispatchChatStreamLine, fieldAnswer, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, hasSecretField, interactionStatusLabels, interactionTerminalNotes, isLateAnswerableStatus, lateAnswerMessage, mergeActivityPages, nextRevealCount, pendingApprovalOf, resolveChatInteraction, responseErrorMessage, restoreChatInteractions, streamChatTurn, terminalizePendingChatInteractions, upsertChatInteraction, useChatInteractions, usePending, usePopover, useSmoothText, useThinkingSeconds, waterfallLayout };
@@ -7,54 +7,78 @@ import {
7
7
  DEFAULT_EFFORT_LEVELS,
8
8
  EffortPicker,
9
9
  FlowWaterfall,
10
- INTERACTION_CANCEL_EVENT,
11
- INTERACTION_EVENT,
12
- INTERACTION_RESOLVED_EVENT,
10
+ INTERACTION_SUBMIT_TIMEOUT_MESSAGE,
11
+ INTERACTION_SUBMIT_TIMEOUT_MS,
12
+ InteractionActionButton,
13
+ InteractionBadge,
14
+ InteractionPlanCard,
15
+ InteractionQuestionCard,
13
16
  MissionActivityLane,
14
17
  ModelPicker,
15
18
  ProviderLogo,
19
+ QuestionOptionList,
16
20
  RunDrillIn,
17
21
  SeatPaywall,
18
22
  activityTone,
19
- canTransitionInteractionStatus,
20
- cancelStatusFor,
21
- composerAnswerData,
22
- composerAnswerDeliveries,
23
+ buildAnswerData,
24
+ cancelChatInteraction,
23
25
  consumeChatStream,
24
- dedupeQuestionInteractionsByContent,
26
+ createInteractionAnswerSubmitter,
25
27
  dispatchChatStreamLine,
26
- fieldAcceptsFreeText,
28
+ fieldAnswer,
27
29
  formatActivityCost,
28
30
  formatActivityDuration,
29
31
  formatModelCost,
30
32
  formatTokensPerSecond,
31
- interactionFromWireRequest,
32
- interactionPartKey,
33
- interactionToPersistedPart,
34
- isRenderableInteractionKind,
35
- isSafeInteractionFieldKey,
36
- isTerminalInteractionStatus,
33
+ hasSecretField,
34
+ interactionStatusLabels,
35
+ interactionTerminalNotes,
36
+ isLateAnswerableStatus,
37
+ lateAnswerMessage,
37
38
  mergeActivityPages,
38
39
  nextRevealCount,
39
- noticePart,
40
- noticePartKey,
41
- parseInteractionCancel,
42
- parseInteractionRequest,
43
40
  pendingApprovalOf,
44
- persistedPartToInteraction,
45
- questionInteractionContentSignature,
41
+ resolveChatInteraction,
42
+ responseErrorMessage,
43
+ restoreChatInteractions,
46
44
  streamChatTurn,
45
+ terminalizePendingChatInteractions,
46
+ upsertChatInteraction,
47
+ useChatInteractions,
47
48
  usePending,
48
49
  usePopover,
49
50
  useSmoothText,
50
51
  useThinkingSeconds,
51
52
  waterfallLayout
52
- } from "../chunk-VMY4TKMN.js";
53
+ } from "../chunk-PEPXQTJ3.js";
53
54
  import {
54
55
  tabTerminalConnectionId,
55
56
  useSandboxTerminalConnection
56
57
  } from "../chunk-65P3HJY3.js";
57
58
  import "../chunk-2QI7XV2T.js";
59
+ import {
60
+ INTERACTION_CANCEL_EVENT,
61
+ INTERACTION_EVENT,
62
+ INTERACTION_RESOLVED_EVENT,
63
+ canTransitionInteractionStatus,
64
+ cancelStatusFor,
65
+ composerAnswerData,
66
+ composerAnswerDeliveries,
67
+ dedupeQuestionInteractionsByContent,
68
+ fieldAcceptsFreeText,
69
+ interactionFromWireRequest,
70
+ interactionPartKey,
71
+ interactionToPersistedPart,
72
+ isRenderableInteractionKind,
73
+ isSafeInteractionFieldKey,
74
+ isTerminalInteractionStatus,
75
+ noticePart,
76
+ noticePartKey,
77
+ parseInteractionCancel,
78
+ parseInteractionRequest,
79
+ persistedPartToInteraction,
80
+ questionInteractionContentSignature
81
+ } from "../chunk-4TXDD6P2.js";
58
82
  import "../chunk-E7QYOOON.js";
59
83
  export {
60
84
  AgentActivityPanel,
@@ -68,30 +92,46 @@ export {
68
92
  INTERACTION_CANCEL_EVENT,
69
93
  INTERACTION_EVENT,
70
94
  INTERACTION_RESOLVED_EVENT,
95
+ INTERACTION_SUBMIT_TIMEOUT_MESSAGE,
96
+ INTERACTION_SUBMIT_TIMEOUT_MS,
97
+ InteractionActionButton,
98
+ InteractionBadge,
99
+ InteractionPlanCard,
100
+ InteractionQuestionCard,
71
101
  MissionActivityLane,
72
102
  ModelPicker,
73
103
  ProviderLogo,
104
+ QuestionOptionList,
74
105
  RunDrillIn,
75
106
  SeatPaywall,
76
107
  activityTone,
108
+ buildAnswerData,
77
109
  canTransitionInteractionStatus,
110
+ cancelChatInteraction,
78
111
  cancelStatusFor,
79
112
  composerAnswerData,
80
113
  composerAnswerDeliveries,
81
114
  consumeChatStream,
115
+ createInteractionAnswerSubmitter,
82
116
  dedupeQuestionInteractionsByContent,
83
117
  dispatchChatStreamLine,
84
118
  fieldAcceptsFreeText,
119
+ fieldAnswer,
85
120
  formatActivityCost,
86
121
  formatActivityDuration,
87
122
  formatModelCost,
88
123
  formatTokensPerSecond,
124
+ hasSecretField,
89
125
  interactionFromWireRequest,
90
126
  interactionPartKey,
127
+ interactionStatusLabels,
128
+ interactionTerminalNotes,
91
129
  interactionToPersistedPart,
130
+ isLateAnswerableStatus,
92
131
  isRenderableInteractionKind,
93
132
  isSafeInteractionFieldKey,
94
133
  isTerminalInteractionStatus,
134
+ lateAnswerMessage,
95
135
  mergeActivityPages,
96
136
  nextRevealCount,
97
137
  noticePart,
@@ -101,8 +141,14 @@ export {
101
141
  pendingApprovalOf,
102
142
  persistedPartToInteraction,
103
143
  questionInteractionContentSignature,
144
+ resolveChatInteraction,
145
+ responseErrorMessage,
146
+ restoreChatInteractions,
104
147
  streamChatTurn,
105
148
  tabTerminalConnectionId,
149
+ terminalizePendingChatInteractions,
150
+ upsertChatInteraction,
151
+ useChatInteractions,
106
152
  usePending,
107
153
  usePopover,
108
154
  useSandboxTerminalConnection,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.43.23",
3
+ "version": "0.43.25",
4
4
  "packageManager": "pnpm@10.33.4",
5
5
  "description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
6
6
  "keywords": [
@@ -53,6 +53,11 @@
53
53
  "import": "./dist/platform/index.js",
54
54
  "default": "./dist/platform/index.js"
55
55
  },
56
+ "./app-auth": {
57
+ "types": "./dist/app-auth/index.d.ts",
58
+ "import": "./dist/app-auth/index.js",
59
+ "default": "./dist/app-auth/index.js"
60
+ },
56
61
  "./runtime": {
57
62
  "types": "./dist/runtime/index.d.ts",
58
63
  "import": "./dist/runtime/index.js",
@@ -133,6 +138,11 @@
133
138
  "import": "./dist/billing/index.js",
134
139
  "default": "./dist/billing/index.js"
135
140
  },
141
+ "./chat-store": {
142
+ "types": "./dist/chat-store/index.d.ts",
143
+ "import": "./dist/chat-store/index.js",
144
+ "default": "./dist/chat-store/index.js"
145
+ },
136
146
  "./crypto": {
137
147
  "types": "./dist/crypto/index.d.ts",
138
148
  "import": "./dist/crypto/index.js",
@@ -148,6 +158,11 @@
148
158
  "import": "./dist/integrations/index.js",
149
159
  "default": "./dist/integrations/index.js"
150
160
  },
161
+ "./interactions": {
162
+ "types": "./dist/interactions/index.d.ts",
163
+ "import": "./dist/interactions/index.js",
164
+ "default": "./dist/interactions/index.js"
165
+ },
151
166
  "./missions": {
152
167
  "types": "./dist/missions/index.d.ts",
153
168
  "import": "./dist/missions/index.js",
@@ -358,7 +373,7 @@
358
373
  "@tangle-network/agent-knowledge": "^1.7.0",
359
374
  "@tangle-network/agent-runtime": "^0.79.3",
360
375
  "@tangle-network/brand": "^1.0.0",
361
- "@tangle-network/sandbox": "^0.9.7",
376
+ "@tangle-network/sandbox": "^0.10.5",
362
377
  "@tangle-network/sandbox-ui": "^0.72.0",
363
378
  "@tangle-network/ui": "^11.0.0",
364
379
  "@testing-library/dom": "^10.4.1",
@@ -396,6 +411,7 @@
396
411
  "@tangle-network/sandbox": ">=0.9.7",
397
412
  "@tangle-network/sandbox-ui": ">=0.72.0",
398
413
  "@xyflow/react": ">=12.0.0",
414
+ "better-auth": ">=1.6.16",
399
415
  "drizzle-orm": ">=0.36",
400
416
  "konva": ">=9",
401
417
  "lucide-react": ">=1",
@@ -408,6 +424,9 @@
408
424
  "@huggingface/transformers": {
409
425
  "optional": true
410
426
  },
427
+ "better-auth": {
428
+ "optional": true
429
+ },
411
430
  "@tangle-network/agent-knowledge": {
412
431
  "optional": true
413
432
  },
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/preset-cloudflare/index.ts"],"sourcesContent":["/**\n * `@tangle-network/agent-app/preset-cloudflare` — the batteries-included default\n * stack.\n *\n * Every fleet agent runs the SAME backend: Cloudflare D1 (SQLite) through\n * Drizzle for state, a KV namespace as the artifact vault, AES-GCM field crypto\n * for PII, and per-workspace budget-capped model keys. The other agent-app\n * modules are pure SEAMS — `./tools` needs an `AppToolHandlers`, `./knowledge`\n * needs a `KnowledgeStateAccessor`, `./billing` needs a `WorkspaceKeyStore` +\n * `KeyCrypto`. This module is the ONE implementation of those seams against the\n * house stack, so a consumer that runs D1 + KV stands the whole shell up with\n * config + bindings and ZERO handler code.\n *\n * Layering:\n * - Drizzle is a PEER (the consumer installs `drizzle-orm`, never bundled). The\n * schema is therefore expressed two ways that need no import here: the plain\n * DDL ({@link PRESET_MIGRATION_SQL}) a consumer runs to create the tables, and\n * a {@link createPresetDrizzleSchema} factory that takes the consumer's\n * `drizzle-orm/sqlite-core` builder module and returns the typed tables. The\n * column names in {@link PRESET_TABLES} are the contract the handlers,\n * accessor, and DDL all agree on.\n * - D1 + KV are STRUCTURAL: {@link D1Like} (Cloudflare `D1Database` satisfies it)\n * and `KvLike` from `../web` (Cloudflare `KVNamespace` satisfies it). No\n * `@cloudflare/workers-types` dependency.\n * - Crypto/billing reuse `../crypto` + `../billing` exactly — this only wires\n * them to the D1 key table.\n */\n\nimport { createFieldCrypto } from '../crypto/index'\nimport {\n createWorkspaceKeyManager,\n type KeyCrypto,\n type KeyProvisioner,\n type WorkspaceKeyManager,\n type WorkspaceKeyRecord,\n type WorkspaceKeyStore,\n} from '../billing/index'\nimport type { KnowledgeStateAccessor } from '../knowledge/index'\nimport type {\n AddCitationArgs,\n AddCitationResult,\n AppToolContext,\n AppToolHandlers,\n RenderUiArgs,\n RenderUiResult,\n ScheduleFollowupArgs,\n ScheduleFollowupResult,\n SubmitProposalArgs,\n SubmitProposalResult,\n} from '../tools/index'\nimport type { KvLike } from '../web/index'\n\n// ---------------------------------------------------------------------------\n// D1 structural seam\n//\n// The minimal surface of Cloudflare's `D1Database` the handlers + accessor use.\n// `D1Database` satisfies it structurally, so the consumer passes `env.DB`\n// directly and tests pass an in-memory fake. We keep it to the\n// prepare/bind/first/run/all shape D1 already exposes — no Drizzle here, so the\n// default handlers run on a fresh Worker with only the D1 binding.\n// ---------------------------------------------------------------------------\n\n/** A prepared, bound D1 statement. */\nexport interface D1PreparedLike {\n bind(...values: unknown[]): D1PreparedLike\n first<T = Record<string, unknown>>(colName?: string): Promise<T | null>\n run(): Promise<unknown>\n all<T = Record<string, unknown>>(): Promise<{ results: T[] }>\n}\n\n/** The D1 surface the preset needs. Cloudflare `D1Database` satisfies it. */\nexport interface D1Like {\n prepare(query: string): D1PreparedLike\n}\n\n// ---------------------------------------------------------------------------\n// Default schema\n//\n// The four tables the default handlers + accessor read/write. Column names are\n// the single source of truth shared by the DDL, the Drizzle factory, the\n// handlers, and the accessor. Every table is workspace-scoped on `workspace_id`\n// (the accessor's default `where` column) so the knowledge `count` rule and the\n// tool writes agree without per-consumer wiring.\n// ---------------------------------------------------------------------------\n\n/** The preset table + column names — the contract the DDL, Drizzle schema,\n * handlers, and accessor share. Exposed so a consumer can reference a column\n * without a string literal. */\nexport const PRESET_TABLES = {\n proposals: {\n name: 'proposals',\n columns: {\n id: 'id',\n workspaceId: 'workspace_id',\n threadId: 'thread_id',\n type: 'type',\n title: 'title',\n description: 'description',\n status: 'status',\n createdBy: 'created_by',\n createdAt: 'created_at',\n },\n },\n threads: {\n name: 'threads',\n columns: {\n id: 'id',\n workspaceId: 'workspace_id',\n title: 'title',\n createdAt: 'created_at',\n },\n },\n knowledge: {\n name: 'knowledge',\n columns: {\n id: 'id',\n workspaceId: 'workspace_id',\n path: 'path',\n kind: 'kind',\n label: 'label',\n content: 'content',\n createdAt: 'created_at',\n },\n },\n deadlines: {\n name: 'deadlines',\n columns: {\n id: 'id',\n workspaceId: 'workspace_id',\n threadId: 'thread_id',\n title: 'title',\n dueDate: 'due_date',\n priority: 'priority',\n status: 'status',\n createdAt: 'created_at',\n },\n },\n workspaceKeys: {\n name: 'workspace_keys',\n columns: {\n id: 'id',\n workspaceId: 'workspace_id',\n keyId: 'key_id',\n keyEncrypted: 'key_encrypted',\n budgetUsd: 'budget_usd',\n expiresAt: 'expires_at',\n revokedAt: 'revoked_at',\n createdAt: 'created_at',\n },\n },\n} as const\n\n/**\n * Plain DDL for the preset schema — run by a consumer to create the tables with\n * ZERO drizzle (`for (const sql of PRESET_MIGRATION_SQL) await db.prepare(sql).run()`,\n * or paste into a `.sql` migration). One statement per table so D1's\n * single-statement `prepare` accepts each. Matches {@link PRESET_TABLES} exactly.\n */\nexport const PRESET_MIGRATION_SQL: readonly string[] = [\n `CREATE TABLE IF NOT EXISTS threads (\n id TEXT PRIMARY KEY,\n workspace_id TEXT NOT NULL,\n title TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS proposals (\n id TEXT PRIMARY KEY,\n workspace_id TEXT NOT NULL,\n thread_id TEXT,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n description TEXT,\n status TEXT NOT NULL DEFAULT 'pending',\n created_by TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS knowledge (\n id TEXT PRIMARY KEY,\n workspace_id TEXT NOT NULL,\n path TEXT NOT NULL,\n kind TEXT NOT NULL,\n label TEXT,\n content TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS deadlines (\n id TEXT PRIMARY KEY,\n workspace_id TEXT NOT NULL,\n thread_id TEXT,\n title TEXT NOT NULL,\n due_date TEXT NOT NULL,\n priority TEXT,\n status TEXT NOT NULL DEFAULT 'scheduled',\n created_at INTEGER NOT NULL\n )`,\n `CREATE TABLE IF NOT EXISTS workspace_keys (\n id TEXT PRIMARY KEY,\n workspace_id TEXT NOT NULL,\n key_id TEXT NOT NULL,\n key_encrypted TEXT NOT NULL,\n budget_usd REAL NOT NULL,\n expires_at INTEGER NOT NULL,\n revoked_at INTEGER,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS idx_proposals_ws ON proposals (workspace_id, status)`,\n `CREATE INDEX IF NOT EXISTS idx_deadlines_ws ON deadlines (workspace_id, status)`,\n `CREATE INDEX IF NOT EXISTS idx_knowledge_ws ON knowledge (workspace_id)`,\n `CREATE INDEX IF NOT EXISTS idx_workspace_keys_ws ON workspace_keys (workspace_id, revoked_at)`,\n]\n\n/** A chainable column builder — every modifier returns the builder so calls\n * like `.notNull().default('pending')` typecheck. The concrete drizzle builders\n * satisfy this structurally. */\nexport interface DrizzleColumnLike {\n primaryKey: () => DrizzleColumnLike\n notNull: () => DrizzleColumnLike\n default: (v: unknown) => DrizzleColumnLike\n}\n\n/** The shape of a `drizzle-orm/sqlite-core` module — the few builders the\n * preset schema uses. The consumer passes the real module; agent-app never\n * imports it (it stays a peer). */\nexport interface DrizzleSqliteCoreLike {\n sqliteTable: (name: string, columns: Record<string, DrizzleColumnLike>) => unknown\n text: (name?: string) => DrizzleColumnLike\n integer: (name?: string, config?: unknown) => DrizzleColumnLike\n real: (name?: string) => DrizzleColumnLike\n}\n\n/**\n * Build the typed Drizzle schema for the preset, given the consumer's\n * `drizzle-orm/sqlite-core` module. Returns one table object per\n * {@link PRESET_TABLES} entry — pass to `drizzle(db, { schema })` for typed\n * queries, or to drizzle-kit for migration generation. agent-app never imports\n * drizzle; the builder module is the seam.\n *\n * ```ts\n * import * as d from 'drizzle-orm/sqlite-core'\n * const schema = createPresetDrizzleSchema(d)\n * ```\n */\nexport function createPresetDrizzleSchema(d: DrizzleSqliteCoreLike) {\n const { sqliteTable, text, integer, real } = d\n const C = PRESET_TABLES\n return {\n threads: sqliteTable(C.threads.name, {\n id: text(C.threads.columns.id).primaryKey(),\n workspaceId: text(C.threads.columns.workspaceId).notNull(),\n title: text(C.threads.columns.title),\n createdAt: integer(C.threads.columns.createdAt).notNull(),\n }),\n proposals: sqliteTable(C.proposals.name, {\n id: text(C.proposals.columns.id).primaryKey(),\n workspaceId: text(C.proposals.columns.workspaceId).notNull(),\n threadId: text(C.proposals.columns.threadId),\n type: text(C.proposals.columns.type).notNull(),\n title: text(C.proposals.columns.title).notNull(),\n description: text(C.proposals.columns.description),\n status: text(C.proposals.columns.status).notNull().default('pending'),\n createdBy: text(C.proposals.columns.createdBy),\n createdAt: integer(C.proposals.columns.createdAt).notNull(),\n }),\n knowledge: sqliteTable(C.knowledge.name, {\n id: text(C.knowledge.columns.id).primaryKey(),\n workspaceId: text(C.knowledge.columns.workspaceId).notNull(),\n path: text(C.knowledge.columns.path).notNull(),\n kind: text(C.knowledge.columns.kind).notNull(),\n label: text(C.knowledge.columns.label),\n content: text(C.knowledge.columns.content),\n createdAt: integer(C.knowledge.columns.createdAt).notNull(),\n }),\n deadlines: sqliteTable(C.deadlines.name, {\n id: text(C.deadlines.columns.id).primaryKey(),\n workspaceId: text(C.deadlines.columns.workspaceId).notNull(),\n threadId: text(C.deadlines.columns.threadId),\n title: text(C.deadlines.columns.title).notNull(),\n dueDate: text(C.deadlines.columns.dueDate).notNull(),\n priority: text(C.deadlines.columns.priority),\n status: text(C.deadlines.columns.status).notNull().default('scheduled'),\n createdAt: integer(C.deadlines.columns.createdAt).notNull(),\n }),\n workspaceKeys: sqliteTable(C.workspaceKeys.name, {\n id: text(C.workspaceKeys.columns.id).primaryKey(),\n workspaceId: text(C.workspaceKeys.columns.workspaceId).notNull(),\n keyId: text(C.workspaceKeys.columns.keyId).notNull(),\n keyEncrypted: text(C.workspaceKeys.columns.keyEncrypted).notNull(),\n budgetUsd: real(C.workspaceKeys.columns.budgetUsd).notNull(),\n expiresAt: integer(C.workspaceKeys.columns.expiresAt).notNull(),\n revokedAt: integer(C.workspaceKeys.columns.revokedAt),\n createdAt: integer(C.workspaceKeys.columns.createdAt).notNull(),\n }),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Default AppToolHandlers over D1 + KV\n// ---------------------------------------------------------------------------\n\n/** The KV-backed vault. `KvLike` (from `../web`) is the structural KV contract;\n * Cloudflare `KVNamespace` satisfies it. Artifacts are stored under their path. */\nexport type VaultKv = KvLike\n\nexport interface PresetToolHandlerOptions {\n /** The D1 database (Cloudflare `D1Database` satisfies {@link D1Like}). */\n db: D1Like\n /** The KV namespace used as the artifact vault. */\n vault: VaultKv\n /** Id generator. Default `crypto.randomUUID`. Injectable for deterministic tests. */\n newId?: () => string\n /** Clock (epoch ms). Default `Date.now`. Injectable for deterministic tests. */\n now?: () => number\n /** Vault path prefix for `render_ui` artifacts. Default `'ui'`. */\n uiPathPrefix?: string\n /** Vault path prefix for `add_citation` artifacts. Default `'citations'`. */\n citationPathPrefix?: string\n}\n\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 64) || 'item'\n}\n\n/**\n * The default {@link AppToolHandlers} for the house stack:\n * - `submit_proposal` → insert a `proposals` row (`status='pending'`), deduped\n * on (workspace, title) so a retried turn doesn't double-queue.\n * - `schedule_followup` → insert a `deadlines` row, deduped on (workspace, title, due_date).\n * - `render_ui` → write the schema JSON as a `ui/<thread>/<slug>.json`\n * vault artifact AND a `knowledge` row pointing at it.\n * - `add_citation` → write the quote as a `citations/<slug>.json` artifact AND\n * a `knowledge` row.\n *\n * Returns the EXACT persisted content from `render_ui` (per the seam contract) so\n * a completion oracle sees real bytes. Pure seam wiring: a consumer that runs\n * D1 + KV gets all four tools with no handler code.\n */\nexport function createPresetToolHandlers(opts: PresetToolHandlerOptions): AppToolHandlers {\n const { db, vault } = opts\n const newId = opts.newId ?? (() => crypto.randomUUID())\n const now = opts.now ?? (() => Date.now())\n const uiPrefix = opts.uiPathPrefix ?? 'ui'\n const citationPrefix = opts.citationPathPrefix ?? 'citations'\n const P = PRESET_TABLES.proposals\n const D = PRESET_TABLES.deadlines\n const K = PRESET_TABLES.knowledge\n\n async function persistArtifact(path: string, body: string): Promise<void> {\n await vault.put(path, body)\n }\n\n async function insertKnowledge(workspaceId: string, path: string, kind: string, label: string | null, content: string): Promise<void> {\n await db\n .prepare(\n `INSERT INTO ${K.name} (${K.columns.id}, ${K.columns.workspaceId}, ${K.columns.path}, ${K.columns.kind}, ${K.columns.label}, ${K.columns.content}, ${K.columns.createdAt}) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .bind(newId(), workspaceId, path, kind, label, content, now())\n .run()\n }\n\n return {\n async submitProposal(args: SubmitProposalArgs, ctx: AppToolContext): Promise<SubmitProposalResult> {\n const existing = await db\n .prepare(`SELECT ${P.columns.id} AS id FROM ${P.name} WHERE ${P.columns.workspaceId} = ? AND ${P.columns.title} = ? LIMIT 1`)\n .bind(ctx.workspaceId, args.title)\n .first<{ id: string }>()\n if (existing) return { proposalId: existing.id, deduped: true }\n\n const id = newId()\n await db\n .prepare(\n `INSERT INTO ${P.name} (${P.columns.id}, ${P.columns.workspaceId}, ${P.columns.threadId}, ${P.columns.type}, ${P.columns.title}, ${P.columns.description}, ${P.columns.status}, ${P.columns.createdBy}, ${P.columns.createdAt}) VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?)`,\n )\n .bind(id, ctx.workspaceId, ctx.threadId, args.type, args.title, args.description ?? null, ctx.userId, now())\n .run()\n return { proposalId: id, deduped: false }\n },\n\n async scheduleFollowup(args: ScheduleFollowupArgs, ctx: AppToolContext): Promise<ScheduleFollowupResult> {\n const existing = await db\n .prepare(\n `SELECT ${D.columns.id} AS id, ${D.columns.dueDate} AS dueDate FROM ${D.name} WHERE ${D.columns.workspaceId} = ? AND ${D.columns.title} = ? AND ${D.columns.dueDate} = ? LIMIT 1`,\n )\n .bind(ctx.workspaceId, args.title, args.dueDate)\n .first<{ id: string; dueDate: string }>()\n if (existing) return { id: existing.id, dueDate: existing.dueDate, deduped: true }\n\n const id = newId()\n await db\n .prepare(\n `INSERT INTO ${D.name} (${D.columns.id}, ${D.columns.workspaceId}, ${D.columns.threadId}, ${D.columns.title}, ${D.columns.dueDate}, ${D.columns.priority}, ${D.columns.status}, ${D.columns.createdAt}) VALUES (?, ?, ?, ?, ?, ?, 'scheduled', ?)`,\n )\n .bind(id, ctx.workspaceId, ctx.threadId, args.title, args.dueDate, args.priority ?? null, now())\n .run()\n return { id, dueDate: args.dueDate, deduped: false }\n },\n\n async renderUi(args: RenderUiArgs, ctx: AppToolContext): Promise<RenderUiResult> {\n const content = JSON.stringify(args.schema)\n const path = `${uiPrefix}/${ctx.threadId ?? 'global'}/${slug(args.title)}.json`\n await persistArtifact(path, content)\n await insertKnowledge(ctx.workspaceId, path, 'ui', args.title, content)\n return { path, content }\n },\n\n async addCitation(args: AddCitationArgs, ctx: AppToolContext): Promise<AddCitationResult> {\n const citationId = newId()\n const path = `${citationPrefix}/${slug(args.label ?? args.path)}-${citationId.slice(0, 8)}.json`\n const body = JSON.stringify({ sourcePath: args.path, quote: args.quote, label: args.label ?? null })\n await persistArtifact(path, body)\n await insertKnowledge(ctx.workspaceId, path, 'citation', args.label ?? null, body)\n return { citationId, path }\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// D1-backed KnowledgeStateAccessor\n// ---------------------------------------------------------------------------\n\nexport interface PresetKnowledgeAccessorOptions {\n db: D1Like\n /** The active workspace — every `count` is scoped to it. */\n workspaceId: string\n /** Workspace config the `satisfiedBy: { config }` rules read. A resolved\n * object (dot-path lookup), or a function the accessor calls per path. */\n config: Record<string, unknown> | ((path: string) => unknown)\n /** The default workspace fk column a `count` rule scopes on when its rule\n * omits `where`. Default `'workspace_id'` (the preset schema convention). */\n defaultWhereColumn?: string\n}\n\nfunction readDotPath(obj: Record<string, unknown>, path: string): unknown {\n let cur: unknown = obj\n for (const part of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[part]\n }\n return cur\n}\n\n/**\n * The {@link KnowledgeStateAccessor} over the preset D1 schema — the seam that\n * lets the declarative `satisfiedBy` rules resolve with ZERO consumer code:\n * - `config(path)` reads the supplied workspace config by dot-path.\n * - `count({ table, where, statusIn })` runs `SELECT count(*)` scoped to the\n * active workspace (the rule's `where` column, default `workspace_id`),\n * optionally filtered to `statusIn` via a parameterized `IN (...)`.\n *\n * Identifiers (table/column) are validated against a safe pattern before\n * interpolation — they originate from the product's own config, never model\n * input, but we fail loud rather than build a malformed/injectable query.\n */\nexport function createD1KnowledgeStateAccessor(opts: PresetKnowledgeAccessorOptions): KnowledgeStateAccessor {\n const { db, workspaceId } = opts\n const defaultWhere = opts.defaultWhereColumn ?? 'workspace_id'\n const configFn = typeof opts.config === 'function' ? opts.config : (path: string) => readDotPath(opts.config as Record<string, unknown>, path)\n\n const isIdentifier = (s: string) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s)\n\n return {\n config: configFn,\n async count(query) {\n if (!isIdentifier(query.table)) throw new Error(`unsafe table identifier: ${query.table}`)\n const whereCol = query.where ?? defaultWhere\n if (!isIdentifier(whereCol)) throw new Error(`unsafe where identifier: ${whereCol}`)\n\n let sql = `SELECT count(*) AS n FROM ${query.table} WHERE ${whereCol} = ?`\n const binds: unknown[] = [workspaceId]\n if (query.statusIn && query.statusIn.length > 0) {\n sql += ` AND status IN (${query.statusIn.map(() => '?').join(', ')})`\n binds.push(...query.statusIn)\n }\n const row = await db.prepare(sql).bind(...binds).first<{ n: number }>()\n return row?.n ?? 0\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Crypto + per-workspace key wiring\n// ---------------------------------------------------------------------------\n\n/** Build the {@link KeyCrypto} the billing key store uses — AES-256-GCM field\n * crypto bound to the product's 64-char-hex `ENCRYPTION_KEY` (or a resolver).\n * This is the concrete impl behind the `../billing` `KeyCrypto` seam. */\nexport function createPresetFieldCrypto(key: string | (() => string)): KeyCrypto {\n return createFieldCrypto(key)\n}\n\n/**\n * The {@link WorkspaceKeyStore} over the preset `workspace_keys` table — the\n * persistence seam the per-workspace key manager needs. \"Active\" = a row with a\n * null `revoked_at`. Pure D1 wiring; no key minting (that's the provisioner).\n */\nexport function createPresetWorkspaceKeyStore(db: D1Like): WorkspaceKeyStore {\n const W = PRESET_TABLES.workspaceKeys\n return {\n async getActive(workspaceId: string): Promise<WorkspaceKeyRecord | null> {\n const row = await db\n .prepare(\n `SELECT ${W.columns.id} AS id, ${W.columns.keyId} AS keyId, ${W.columns.keyEncrypted} AS keyEncrypted, ${W.columns.budgetUsd} AS budgetUsd, ${W.columns.expiresAt} AS expiresAt FROM ${W.name} WHERE ${W.columns.workspaceId} = ? AND ${W.columns.revokedAt} IS NULL ORDER BY ${W.columns.createdAt} DESC LIMIT 1`,\n )\n .bind(workspaceId)\n .first<{ id: string; keyId: string; keyEncrypted: string; budgetUsd: number; expiresAt: number | null }>()\n if (!row) return null\n return {\n id: row.id,\n keyId: row.keyId,\n keyEncrypted: row.keyEncrypted,\n budgetUsd: row.budgetUsd,\n expiresAt: row.expiresAt == null ? null : new Date(row.expiresAt),\n }\n },\n async listActive(workspaceId: string): Promise<Array<{ id: string; keyId: string }>> {\n const res = await db\n .prepare(`SELECT ${W.columns.id} AS id, ${W.columns.keyId} AS keyId FROM ${W.name} WHERE ${W.columns.workspaceId} = ? AND ${W.columns.revokedAt} IS NULL`)\n .bind(workspaceId)\n .all<{ id: string; keyId: string }>()\n return res.results\n },\n async insert(record): Promise<void> {\n await db\n .prepare(\n `INSERT INTO ${W.name} (${W.columns.id}, ${W.columns.workspaceId}, ${W.columns.keyId}, ${W.columns.keyEncrypted}, ${W.columns.budgetUsd}, ${W.columns.expiresAt}, ${W.columns.revokedAt}, ${W.columns.createdAt}) VALUES (?, ?, ?, ?, ?, ?, NULL, ?)`,\n )\n .bind(crypto.randomUUID(), record.workspaceId, record.keyId, record.keyEncrypted, record.budgetUsd, record.expiresAt.getTime(), Date.now())\n .run()\n },\n async markRevoked(id: string, now: Date): Promise<void> {\n await db\n .prepare(`UPDATE ${W.name} SET ${W.columns.revokedAt} = ? WHERE ${W.columns.id} = ?`)\n .bind(now.getTime(), id)\n .run()\n },\n }\n}\n\nexport interface PresetBillingOptions {\n db: D1Like\n /** The key provisioner (`@tangle-network/tcloud`'s client satisfies it structurally). */\n provisioner: KeyProvisioner\n /** Field-crypto key (64-char hex) or resolver — encrypts the minted key at rest. */\n encryptionKey: string | (() => string)\n /** Default monthly USD allowance when a call doesn't specify one. */\n defaultBudgetUsd: number\n /** Injectable clock. */\n now?: () => Date\n /** tcloud product the key is scoped to. Default `'router'`. */\n product?: string\n}\n\n/**\n * Stand up the per-workspace budget-capped {@link WorkspaceKeyManager} on the\n * house stack: the preset `workspace_keys` D1 store + AES-GCM field crypto +\n * the consumer's tcloud provisioner. The mint/rotate/rollover/usage LOGIC lives\n * in `../billing`; this only binds it to the preset table + crypto.\n */\nexport function createPresetWorkspaceKeyManager(opts: PresetBillingOptions): WorkspaceKeyManager {\n return createWorkspaceKeyManager({\n provisioner: opts.provisioner,\n store: createPresetWorkspaceKeyStore(opts.db),\n crypto: createPresetFieldCrypto(opts.encryptionKey),\n defaultBudgetUsd: opts.defaultBudgetUsd,\n now: opts.now,\n product: opts.product,\n })\n}\n"],"mappings":"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","names":[]}