@tangle-network/agent-app 0.43.63 → 0.43.65
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/assistant/index.d.ts +4 -4
- package/dist/assistant/index.js +5 -5
- package/dist/{attachment-validation-tPRp-PP1.d.ts → attachment-validation-B2FFna9E.d.ts} +1 -1
- package/dist/chat-routes/index.d.ts +5 -5
- package/dist/chat-routes/index.js +5 -5
- package/dist/chat-store/index.d.ts +4 -4
- package/dist/chat-store/index.js +3 -3
- package/dist/{chunk-7YW6EBDX.js → chunk-3JUTOVUH.js} +2 -2
- package/dist/{chunk-YKOM4ZLQ.js → chunk-3ZK5IJSW.js} +1 -1
- package/dist/chunk-3ZK5IJSW.js.map +1 -0
- package/dist/{chunk-BG52UKNN.js → chunk-5EPIPT4V.js} +2 -2
- package/dist/{chunk-K3LIPKFV.js → chunk-6GQ5DKFK.js} +2 -2
- package/dist/{chunk-BPSV5AA2.js → chunk-FMDMI25K.js} +2 -2
- package/dist/{chunk-DTSPS2HV.js → chunk-X3N2H6JE.js} +2 -2
- package/dist/{chunk-C3NSB66C.js → chunk-YTSEDJWA.js} +59 -10
- package/dist/chunk-YTSEDJWA.js.map +1 -0
- package/dist/{contract-TjB68uqA.d.ts → contract-B3h7peV3.d.ts} +30 -5
- package/dist/durable-chat/index.d.ts +1 -1
- package/dist/durable-chat/index.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/interactions/index.d.ts +2 -2
- package/dist/interactions/index.js +2 -2
- package/dist/{parts-n9XUon0a.d.ts → parts-Bg8qcDvB.d.ts} +1 -1
- package/dist/stream/index.d.ts +3 -3
- package/dist/stream/index.js +2 -2
- package/dist/{stream-normalizer-BlCP_Cdd.d.ts → stream-normalizer-QYUl4vnl.d.ts} +1 -1
- package/dist/web-react/index.d.ts +53 -8
- package/dist/web-react/index.js +7 -5
- package/package.json +1 -1
- package/dist/chunk-C3NSB66C.js.map +0 -1
- package/dist/chunk-YKOM4ZLQ.js.map +0 -1
- /package/dist/{chunk-7YW6EBDX.js.map → chunk-3JUTOVUH.js.map} +0 -0
- /package/dist/{chunk-BG52UKNN.js.map → chunk-5EPIPT4V.js.map} +0 -0
- /package/dist/{chunk-K3LIPKFV.js.map → chunk-6GQ5DKFK.js.map} +0 -0
- /package/dist/{chunk-BPSV5AA2.js.map → chunk-FMDMI25K.js.map} +0 -0
- /package/dist/{chunk-DTSPS2HV.js.map → chunk-X3N2H6JE.js.map} +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { ToolDetailRenderers, ChatUiMessage } from '../web-react/index.js';
|
|
4
|
-
import '../contract-
|
|
4
|
+
import '../contract-B3h7peV3.js';
|
|
5
5
|
import '@tangle-network/agent-interface';
|
|
6
6
|
import '../plans/index.js';
|
|
7
|
-
import '../parts-
|
|
7
|
+
import '../parts-Bg8qcDvB.js';
|
|
8
8
|
import '../agent-activity-C8ZG0F0M.js';
|
|
9
9
|
import '../flow-types-CqomVAUN.js';
|
|
10
10
|
import '../sandbox-terminal-ChNEdHF8.js';
|
|
11
11
|
import '../catalog/index.js';
|
|
12
12
|
import '../harness/index.js';
|
|
13
|
-
import '../attachment-validation-
|
|
14
|
-
import '../stream-normalizer-
|
|
13
|
+
import '../attachment-validation-B2FFna9E.js';
|
|
14
|
+
import '../stream-normalizer-QYUl4vnl.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Wire + UI types for the in-app assistant panel. The wire shapes mirror the
|
package/dist/assistant/index.js
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
ChatMessages,
|
|
4
4
|
ModelPicker,
|
|
5
5
|
ProviderLogo
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-YTSEDJWA.js";
|
|
7
7
|
import "../chunk-HCOROIRT.js";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-FMDMI25K.js";
|
|
9
9
|
import "../chunk-FBVLEGEG.js";
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-X3N2H6JE.js";
|
|
11
|
+
import "../chunk-5EPIPT4V.js";
|
|
12
|
+
import "../chunk-3ZK5IJSW.js";
|
|
13
13
|
import "../chunk-YJMCRXQQ.js";
|
|
14
14
|
import "../chunk-CQZSAR77.js";
|
|
15
15
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { g as ChatMessagePart, L as ChatTurnRequestPayload, M as ChatTurnPartInput, N as ChatTurnFilePartInput, a as ChatAttachmentPart, C as ChatAttachmentKind, f as ChatMentionPart } from '../parts-
|
|
2
|
-
export { O as ChatAttachmentInput, e as ChatMentionKind, P as ChatTurnInputError, Q as ChatTurnTextPartInput, R as DISPATCH_MAX_MEDIA_PARTS, T as DISPATCH_MAX_PARTS, U as DISPATCH_REQUEST_MAX_BYTES, V as DISPATCH_STRUCTURAL_RESERVE_BYTES, K as FileMention, W as FileMentionsToPartsOptions, X as INLINE_PARTS_MAX_BYTES, Y as MENTION_MAX_COUNT, Z as ProducerErrorEvent, _ as ProducerNoticeEvent, $ as ProducerPassthroughEvent, a0 as ProducerPassthroughEventType, a1 as ProducerReasoningEvent, a2 as ProducerTextEvent, a3 as ProducerToolCallEvent, a4 as ProducerToolResultEvent, a5 as ProducerUsageEvent, a6 as ProducerWireEvent, a7 as SandboxMentionPathCheck, a8 as assertPromptPartsWithinCap, a9 as base64WireLen, aa as buildMentionPromptBlock, ab as chatTurnRequestInit, ac as fileMentionsToParts, ad as formatBytes, ae as mediaTypeForMentionPath, af as mentionKindForPath, ag as parseChatTurnParts, ah as parseFileMentions, ai as promptPartsByteSize, aj as validateSandboxMentionPath } from '../parts-
|
|
3
|
-
export { A as ALLOWED_ATTACHMENT_SNIFFED_MIMES, a as ATTACHMENT_ACCEPT, b as ATTACHMENT_MAX_COUNT, c as AttachmentTypeCheckResult, C as CreateSandboxFileIndexRouteOptions, F as FileIndexAuthorization, d as FileIndexCache, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse, M as MAX_ATTACHMENT_TOTAL_BYTES, h as MAX_BINARY_ATTACHMENT_BYTES, i as MAX_TEXT_ATTACHMENT_BYTES, S as SandboxFileTreeSource, j as SandboxTreeFile, k as SandboxTreeResult, l as SniffResult, m as attachmentSizeErrorMessage, n as attachmentTotalSizeErrorMessage, o as checkAttachmentType, p as createSandboxFileIndexRoute, s as sanitizeAttachmentFileName, q as sniffBinary } from '../attachment-validation-
|
|
1
|
+
import { g as ChatMessagePart, L as ChatTurnRequestPayload, M as ChatTurnPartInput, N as ChatTurnFilePartInput, a as ChatAttachmentPart, C as ChatAttachmentKind, f as ChatMentionPart } from '../parts-Bg8qcDvB.js';
|
|
2
|
+
export { O as ChatAttachmentInput, e as ChatMentionKind, P as ChatTurnInputError, Q as ChatTurnTextPartInput, R as DISPATCH_MAX_MEDIA_PARTS, T as DISPATCH_MAX_PARTS, U as DISPATCH_REQUEST_MAX_BYTES, V as DISPATCH_STRUCTURAL_RESERVE_BYTES, K as FileMention, W as FileMentionsToPartsOptions, X as INLINE_PARTS_MAX_BYTES, Y as MENTION_MAX_COUNT, Z as ProducerErrorEvent, _ as ProducerNoticeEvent, $ as ProducerPassthroughEvent, a0 as ProducerPassthroughEventType, a1 as ProducerReasoningEvent, a2 as ProducerTextEvent, a3 as ProducerToolCallEvent, a4 as ProducerToolResultEvent, a5 as ProducerUsageEvent, a6 as ProducerWireEvent, a7 as SandboxMentionPathCheck, a8 as assertPromptPartsWithinCap, a9 as base64WireLen, aa as buildMentionPromptBlock, ab as chatTurnRequestInit, ac as fileMentionsToParts, ad as formatBytes, ae as mediaTypeForMentionPath, af as mentionKindForPath, ag as parseChatTurnParts, ah as parseFileMentions, ai as promptPartsByteSize, aj as validateSandboxMentionPath } from '../parts-Bg8qcDvB.js';
|
|
3
|
+
export { A as ALLOWED_ATTACHMENT_SNIFFED_MIMES, a as ATTACHMENT_ACCEPT, b as ATTACHMENT_MAX_COUNT, c as AttachmentTypeCheckResult, C as CreateSandboxFileIndexRouteOptions, F as FileIndexAuthorization, d as FileIndexCache, e as FileIndexReadyResponse, f as FileIndexResponse, g as FileIndexWarmingResponse, M as MAX_ATTACHMENT_TOTAL_BYTES, h as MAX_BINARY_ATTACHMENT_BYTES, i as MAX_TEXT_ATTACHMENT_BYTES, S as SandboxFileTreeSource, j as SandboxTreeFile, k as SandboxTreeResult, l as SniffResult, m as attachmentSizeErrorMessage, n as attachmentTotalSizeErrorMessage, o as checkAttachmentType, p as createSandboxFileIndexRoute, s as sanitizeAttachmentFileName, q as sniffBinary } from '../attachment-validation-B2FFna9E.js';
|
|
4
4
|
import { ChatTurnIdentity, ChatTurnProducer } from '@tangle-network/agent-runtime';
|
|
5
5
|
import { InteractionAnswerRoute, InteractionAnswerRouteOptions } from '../interactions/index.js';
|
|
6
6
|
import { PersistedChatMessageForTurn } from '../stream/index.js';
|
|
7
7
|
import { d as TurnEventStore } from '../turn-buffer-DGnAPKwa.js';
|
|
8
8
|
export { D as DEFAULT_STALE_TURN_LOCK_GRACE_MS, a as DEFAULT_TERMINAL_TURN_LOCK_GRACE_MS, R as ReconcileStaleTurnLockOptions, b as ReconcileStaleTurnLockResult, S as StaleTurnLockSandboxProbeResult, c as StaleTurnLockSessionProbeResult, r as reconcileStaleTurnLock } from '../stale-turn-lock-DucQzvXu.js';
|
|
9
|
-
import { J as JsonRecord } from '../stream-normalizer-
|
|
9
|
+
import { J as JsonRecord } from '../stream-normalizer-QYUl4vnl.js';
|
|
10
10
|
import { SandboxExecChannel, PromptInputPart } from '../sandbox/index.js';
|
|
11
11
|
import '@tangle-network/agent-interface';
|
|
12
|
-
import '../contract-
|
|
12
|
+
import '../contract-B3h7peV3.js';
|
|
13
13
|
import '../plans/index.js';
|
|
14
14
|
import '@tangle-network/sandbox';
|
|
15
15
|
import '../auth-_FU8w01b.js';
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
createSandboxFileIndexRoute,
|
|
12
12
|
sanitizeAttachmentFileName,
|
|
13
13
|
sniffBinary
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-FMDMI25K.js";
|
|
15
15
|
import {
|
|
16
16
|
DEFAULT_STALE_TURN_LOCK_GRACE_MS,
|
|
17
17
|
DEFAULT_TERMINAL_TURN_LOCK_GRACE_MS,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from "../chunk-YN7QR7MJ.js";
|
|
30
30
|
import {
|
|
31
31
|
createInteractionAnswerRoute
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-3JUTOVUH.js";
|
|
33
33
|
import {
|
|
34
34
|
ChatTurnInputError,
|
|
35
35
|
DISPATCH_MAX_MEDIA_PARTS,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
promptPartsByteSize,
|
|
55
55
|
toChatMessageParts,
|
|
56
56
|
validateSandboxMentionPath
|
|
57
|
-
} from "../chunk-
|
|
57
|
+
} from "../chunk-X3N2H6JE.js";
|
|
58
58
|
import {
|
|
59
59
|
asRecord,
|
|
60
60
|
asString,
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
normalizePersistedPart,
|
|
67
67
|
normalizeToolEvent,
|
|
68
68
|
terminalizeDanglingAssistantToolUpdates
|
|
69
|
-
} from "../chunk-
|
|
69
|
+
} from "../chunk-5EPIPT4V.js";
|
|
70
70
|
import {
|
|
71
71
|
cancelStatusFor,
|
|
72
72
|
interactionPartKey,
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
noticePartKey,
|
|
77
77
|
parseInteractionCancel,
|
|
78
78
|
parseInteractionRequest
|
|
79
|
-
} from "../chunk-
|
|
79
|
+
} from "../chunk-3ZK5IJSW.js";
|
|
80
80
|
import {
|
|
81
81
|
parsePlanSubmittedEvent,
|
|
82
82
|
planToPersistedPart
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export { B as BULK_DELETE_MAX_THREADS, C as ChatStoreInputError, t as threadTitleFromMessage } from '../core-7qIM7svy.js';
|
|
2
|
-
import { g as ChatMessagePart } from '../parts-
|
|
3
|
-
export { C as ChatAttachmentKind, a as ChatAttachmentPart, b as ChatFilePart, c as ChatImagePart, d as ChatInteractionPart, e as ChatMentionKind, f as ChatMentionPart, h as ChatNoticePart, i as ChatPartTime, j as ChatPlanPart, k as ChatReasoningPart, l as ChatStepFinishPart, m as ChatStepStartPart, n as ChatSubtaskPart, o as ChatTextPart, p as ChatToolPart, q as ChatToolState, r as ChatToolStatus, s as ChatUsageTokens, D as DEFAULT_ATTACHMENT_PROMPT_HEADER, S as StorableHarnessPartKind, t as attachmentInputToPart, u as attachmentKindForMime, v as attachmentPartsFromMessageParts, w as buildAttachmentPromptBlock, x as historyContentWithAttachments, y as isChatAttachmentPart, z as isChatInteractionPart, A as isChatMentionPart, B as isChatPlanPart, E as isChatStepFinishPart, F as isChatTextPart, G as isChatToolPart, H as mentionInputToPart, I as mentionPartsFromMessageParts, J as toChatMessageParts } from '../parts-
|
|
2
|
+
import { g as ChatMessagePart } from '../parts-Bg8qcDvB.js';
|
|
3
|
+
export { C as ChatAttachmentKind, a as ChatAttachmentPart, b as ChatFilePart, c as ChatImagePart, d as ChatInteractionPart, e as ChatMentionKind, f as ChatMentionPart, h as ChatNoticePart, i as ChatPartTime, j as ChatPlanPart, k as ChatReasoningPart, l as ChatStepFinishPart, m as ChatStepStartPart, n as ChatSubtaskPart, o as ChatTextPart, p as ChatToolPart, q as ChatToolState, r as ChatToolStatus, s as ChatUsageTokens, D as DEFAULT_ATTACHMENT_PROMPT_HEADER, S as StorableHarnessPartKind, t as attachmentInputToPart, u as attachmentKindForMime, v as attachmentPartsFromMessageParts, w as buildAttachmentPromptBlock, x as historyContentWithAttachments, y as isChatAttachmentPart, z as isChatInteractionPart, A as isChatMentionPart, B as isChatPlanPart, E as isChatStepFinishPart, F as isChatTextPart, G as isChatToolPart, H as mentionInputToPart, I as mentionPartsFromMessageParts, J as toChatMessageParts } from '../parts-Bg8qcDvB.js';
|
|
4
4
|
import * as drizzle_orm from 'drizzle-orm';
|
|
5
5
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
6
6
|
import { SQLiteColumnBuilderBase, AnySQLiteTable, AnySQLiteColumn, BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
|
|
7
|
-
export { d as attachmentPartKey } from '../stream-normalizer-
|
|
7
|
+
export { d as attachmentPartKey } from '../stream-normalizer-QYUl4vnl.js';
|
|
8
8
|
import '@tangle-network/agent-interface';
|
|
9
|
-
import '../contract-
|
|
9
|
+
import '../contract-B3h7peV3.js';
|
|
10
10
|
import '../plans/index.js';
|
|
11
11
|
|
|
12
12
|
/** A product table referenced by FK — only the `id` column is touched. */
|
package/dist/chat-store/index.js
CHANGED
|
@@ -20,11 +20,11 @@ import {
|
|
|
20
20
|
mentionInputToPart,
|
|
21
21
|
mentionPartsFromMessageParts,
|
|
22
22
|
toChatMessageParts
|
|
23
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-X3N2H6JE.js";
|
|
24
24
|
import {
|
|
25
25
|
attachmentPartKey
|
|
26
|
-
} from "../chunk-
|
|
27
|
-
import "../chunk-
|
|
26
|
+
} from "../chunk-5EPIPT4V.js";
|
|
27
|
+
import "../chunk-3ZK5IJSW.js";
|
|
28
28
|
import "../chunk-YJMCRXQQ.js";
|
|
29
29
|
|
|
30
30
|
// src/chat-store/schema.ts
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
interactionFromWireRequest,
|
|
3
3
|
isSafeInteractionFieldKey,
|
|
4
4
|
questionInteractionContentSignature
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3ZK5IJSW.js";
|
|
6
6
|
|
|
7
7
|
// src/interactions/sidecar.ts
|
|
8
8
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
@@ -304,4 +304,4 @@ export {
|
|
|
304
304
|
mapInteractionRespondFailure,
|
|
305
305
|
createInteractionAnswerRoute
|
|
306
306
|
};
|
|
307
|
-
//# sourceMappingURL=chunk-
|
|
307
|
+
//# sourceMappingURL=chunk-3JUTOVUH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/interactions/contract.ts"],"sourcesContent":["// Shared contract for agent interaction events (kind: \"question\" et al) — the\n// generalized human-in-the-loop primitive on the chat stream. Framework-agnostic\n// (no server- or React-only imports) so a producer (chat route) and a consumer\n// (stream parser, transcript, question card) agree on one wire shape and one\n// persisted-part shape.\n//\n// An `interaction` event means the run is BLOCKED inside the sidecar's\n// InteractionBroker until the user answers, the agent withdraws the ask\n// (`interaction.cancel`), or the broker times out. A pending interaction is\n// \"waiting on the user\", not \"model working\".\n\nimport {\n InteractionRequestSchema,\n type InteractionData,\n type InteractionField,\n type InteractionOutcome,\n type InteractionRequest,\n} from '@tangle-network/agent-interface'\n\nexport type { InteractionData, InteractionOutcome, InteractionRequest }\n\n// ---------------------------------------------------------------------------\n// Event names\n\n/** Sidecar → client: the agent raised an ask; data = `{ request }`. */\nexport const INTERACTION_EVENT = 'interaction' as const\n/** Sidecar → client: the ask was withdrawn; data = `{ id, reason? }`. */\nexport const INTERACTION_CANCEL_EVENT = 'interaction.cancel' as const\n/** An ask was answered; data = `{ id, status }`. In the wire contract so a\n * server broadcast and a client-local mark share one event name. */\nexport const INTERACTION_RESOLVED_EVENT = 'interaction.resolved' as const\n\n/** Interaction kinds a product typically renders a card for. Anything else is\n * auto-declined by the chat producer's safety net and never reaches a client.\n * A pure default; a product may substitute its own renderable set. */\nconst RENDERABLE_INTERACTION_KINDS: ReadonlySet<string> = new Set(['question', 'plan'])\n\n/** Resolve if the given interaction kind is renderable within the application context */\nexport function isRenderableInteractionKind(kind: string): boolean {\n return RENDERABLE_INTERACTION_KINDS.has(kind)\n}\n\n/** Answer/field keys the sidecar will accept: identifier-safe and never a\n * prototype-pollution vector. */\nexport function isSafeInteractionFieldKey(key: string): boolean {\n return /^[A-Za-z0-9_-]+$/.test(key) && key !== '__proto__' && key !== 'constructor' && key !== 'prototype'\n}\n\n// ---------------------------------------------------------------------------\n// Field types\n//\n// `allowCustom` (a select that also accepts a write-in value) is defined by\n// newer agent-interface schemas; older pinned schemas strip unknown keys on\n// parse. The wire/persisted field types below carry the flag so a card can gate\n// its write-in input, and `parseInteractionRequest` returns the RAW payload\n// (schema-validated, not schema-parsed) so the flag survives.\n\n/** Extract select-type interaction fields and optionally allow custom values */\nexport type ChatSelectField = Extract<InteractionField, { type: 'select' }> & {\n allowCustom?: boolean\n}\n\n/**\n * A field the user types free text into, which may declare the longest answer\n * its answer route will accept — so a card can stop the typing rather than let\n * the route reject it.\n *\n * Both `text` and `secret`, which is why this is not `ChatTextField`: unlike\n * `ChatSelectField`, it does not name a single `type` literal. They render\n * differently (a textarea vs a password input) and are grouped only by the one\n * property that matters here — an answer whose length can run past what the\n * route takes.\n *\n * Carried the same way as `allowCustom`: the schema may not define it, so it\n * rides on the wire/persisted type and survives because `parseInteractionRequest`\n * returns the raw payload. A product that SYNTHESISES an interaction (rather than\n * parsing one off the wire) sets it directly from whatever bound its own route\n * validates against.\n */\nexport type ChatFreeTextField = Extract<InteractionField, { type: 'text' | 'secret' }> & {\n maxLength?: number\n}\n\n/** An `InteractionField` widened where a card needs a flag the pinned schema may\n * not define: `allowCustom` on a select, `maxLength` on a free-text field. Every\n * other kind passes through unchanged. */\nexport type ChatInteractionField =\n | Exclude<InteractionField, { type: 'select' | 'text' | 'secret' }>\n | ChatSelectField\n | ChatFreeTextField\n\n/** `InteractionRequest` whose fields carry those widenings — a select that may\n * grant `allowCustom`, a free-text field that may declare `maxLength`. */\nexport type InteractionRequestWire = Omit<InteractionRequest, 'answerSpec'> & {\n answerSpec: { fields: ChatInteractionField[] }\n}\n\n// ---------------------------------------------------------------------------\n// Interaction lifecycle\n\n/** Define possible statuses representing the state of a chat interaction */\nexport type ChatInteractionStatus = 'pending' | 'answered' | 'declined' | 'cancelled' | 'expired'\n\n/** Accepted field selections keyed by answer-spec field name. */\n/** Accepted answer values. Select fields historically used `string[]`; the\n * wider scalar union is additive and lets durable stores preserve text,\n * numeric, and boolean answer fields without coercion. */\nexport type InteractionAnswerValue = string | number | boolean | string[]\n/** Map interaction identifiers to their corresponding answer values */\nexport type InteractionAnswers = Record<string, InteractionAnswerValue>\n\n/** Resolve the result of parsing interaction answers with success status and corresponding data or error message */\nexport type ParseInteractionAnswersResult =\n | { succeeded: true; value: InteractionAnswers }\n | { succeeded: false; error: string }\n\n/** Strictly validates and copies persisted answer selections. */\nexport function parseInteractionAnswers(value: unknown): ParseInteractionAnswersResult {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return { succeeded: false, error: 'interaction answers must be an object' }\n }\n const answers: InteractionAnswers = {}\n for (const [key, selection] of Object.entries(value as Record<string, unknown>)) {\n if (!isSafeInteractionFieldKey(key)) {\n return { succeeded: false, error: `interaction answers contain an unsafe field key: ${key}` }\n }\n const valid = typeof selection === 'string' || typeof selection === 'number' || typeof selection === 'boolean' ||\n (Array.isArray(selection) && selection.every((item) => typeof item === 'string'))\n if (!valid) {\n return { succeeded: false, error: `interaction answer ${key} must be a string, number, boolean, or string array` }\n }\n answers[key] = Array.isArray(selection) ? [...selection] : selection\n }\n return { succeeded: true, value: answers }\n}\n\n/** The client/persisted view of one ask. `fields` come verbatim off the wire. */\nexport interface ChatInteraction {\n id: string\n kind: string\n title: string\n body?: string\n fields: ChatInteractionField[]\n status: ChatInteractionStatus\n /** Accepted selections, restored with the transcript after reload. */\n answers?: InteractionAnswers\n /** Set when status came from an `interaction.cancel` (e.g. \"timeout\"). */\n cancelReason?: string\n}\n\n/** Resolve if the interaction status is a terminal state excluding pending */\nexport function isTerminalInteractionStatus(status: ChatInteractionStatus): boolean {\n return status !== 'pending'\n}\n\n/** Statuses only move forward (pending → terminal); a replayed/stale `pending`\n * must never resurrect a resolved card. */\nexport function canTransitionInteractionStatus(\n from: ChatInteractionStatus,\n to: ChatInteractionStatus,\n): boolean {\n return from === 'pending' && to !== from\n}\n\n/** Maps an `interaction.cancel` reason to the card's terminal status. */\nexport function cancelStatusFor(reason: string | undefined): ChatInteractionStatus {\n return reason === 'timeout' ? 'expired' : 'cancelled'\n}\n\nfunction stableValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(stableValue)\n if (!value || typeof value !== 'object') return value\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, stableValue(nested)]),\n )\n}\n\nfunction normalizedInteractionText(value: string | undefined): string {\n return (value ?? '').replace(/\\s+/g, ' ').trim()\n}\n\n/** Content identity for duplicate safety nets. Excludes volatile ids/statuses. */\nexport function questionInteractionContentSignature(interaction: ChatInteraction): string | null {\n if (interaction.kind !== 'question') return null\n return JSON.stringify(stableValue({\n kind: interaction.kind,\n title: normalizedInteractionText(interaction.title),\n body: normalizedInteractionText(interaction.body),\n fields: interaction.fields,\n }))\n}\n\n/** Remove duplicate question interactions based on their content signature to ensure uniqueness */\nexport function dedupeQuestionInteractionsByContent(interactions: ChatInteraction[]): ChatInteraction[] {\n const seen = new Set<string>()\n return interactions.filter((interaction) => {\n const signature = questionInteractionContentSignature(interaction)\n if (!signature) return true\n if (seen.has(signature)) return false\n seen.add(signature)\n return true\n })\n}\n\n// ---------------------------------------------------------------------------\n// Wire parsing — typed outcomes, fail loud at the caller (log + skip; never a\n// half-rendered card).\n\n/** Resolve interaction parsing outcome as success with value or failure with error message */\nexport type ParseInteractionResult =\n | { succeeded: true; value: InteractionRequestWire }\n | { succeeded: false; error: string }\n\n/** Parses an `interaction` event's data (`{ request }`). Validates the shape\n * with the agent-interface schema but returns the raw request so a field a\n * pinned schema predates (`allowCustom`) survives. */\nexport function parseInteractionRequest(data: Record<string, unknown> | undefined): ParseInteractionResult {\n const request = data?.request\n if (!request || typeof request !== 'object') {\n return { succeeded: false, error: 'interaction event carried no request object' }\n }\n const validation = InteractionRequestSchema.safeParse(request)\n if (!validation.success) {\n return { succeeded: false, error: `malformed interaction request: ${validation.error.message}` }\n }\n return { succeeded: true, value: request as InteractionRequestWire }\n}\n\n/** Describe data required to cancel an interaction including its identifier and optional reason */\nexport interface InteractionCancelData {\n id: string\n reason?: string\n}\n\n/** Parse interaction cancel data and return success status with parsed value or error message */\nexport function parseInteractionCancel(\n data: Record<string, unknown> | undefined,\n): { succeeded: true; value: InteractionCancelData } | { succeeded: false; error: string } {\n const id = typeof data?.id === 'string' && data.id ? data.id : null\n if (!id) return { succeeded: false, error: 'interaction.cancel event carried no id' }\n const reason = typeof data?.reason === 'string' && data.reason ? data.reason : undefined\n return { succeeded: true, value: { id, ...(reason ? { reason } : {}) } }\n}\n\n// ---------------------------------------------------------------------------\n// Composer-as-answer delivery: while asks are pending the composer never\n// blocks — typed text is delivered verbatim to every open ask and the agent\n// decides what it means. No interpretation here; the sidecar validates answers\n// fail-closed (invalid free text on an option-only ask → 400).\n\n/** Determine if a chat interaction field allows free text input */\nexport function fieldAcceptsFreeText(field: ChatInteractionField): boolean {\n if (field.type === 'text') return true\n if (field.type === 'select') return (field as ChatSelectField).allowCustom === true\n return false\n}\n\n/** Define the structure for delivering answers linked to a specific chat interaction and field */\nexport interface ComposerAnswerDelivery {\n interactionId: string\n field: ChatInteractionField\n}\n\n/** One delivery per pending ask: the first free-text-capable field, else the\n * first field. Zero-field asks are skipped (nothing to carry the text). */\nexport function composerAnswerDeliveries(pending: ChatInteraction[]): ComposerAnswerDelivery[] {\n const deliveries: ComposerAnswerDelivery[] = []\n for (const interaction of pending) {\n // Only questions take a composer-routed answer. A non-question ask (a plan)\n // is POSTed as outcome:\"accepted\" when answered — routing composer text to\n // it would silently APPROVE it. Approval is an explicit card click, so the\n // composer skips it and the plan card stays the only path.\n if (interaction.kind !== 'question') continue\n const field = interaction.fields.find(fieldAcceptsFreeText) ?? interaction.fields[0]\n if (!field) continue\n deliveries.push({ interactionId: interaction.id, field })\n }\n return deliveries\n}\n\n/** Shapes composer text into the respond payload for the routed field\n * (select answers are string arrays on the wire; text answers are strings). */\nexport function composerAnswerData(field: ChatInteractionField, text: string): InteractionData {\n return { [field.name]: field.type === 'select' ? [text] : text }\n}\n\n// ---------------------------------------------------------------------------\n// Part keys + codecs (persisted `messages.parts` entries and live stream parts\n// share these shapes).\n\n/** Generate a unique key string for an interaction using the given identifier */\nexport function interactionPartKey(id: string): string {\n return `interaction:${id}`\n}\n\n/** Generate a unique key string for a notice using the given identifier */\nexport function noticePartKey(id: string): string {\n return `notice:${id}`\n}\n\n/** Define specific string literals representing different kinds of notices */\nexport type NoticeKind = 'warning' | 'auto-declined'\n\n/**\n * Persisted-part shapes the codecs below produce — the SAME rows\n * `/chat-store`'s `ChatInteractionPart`/`ChatNoticePart` store, typed at the\n * source so a product pushing them into a `ChatMessagePart[]` transcript needs\n * no cast. Type aliases (not interfaces) on purpose: the implicit index\n * signature keeps them assignable to the `Record<string, unknown>` these\n * codecs previously returned, so existing consumers stay source-compatible.\n */\nexport type InteractionPersistedPart = {\n type: 'interaction'\n id: string\n kind: string\n title: string\n body?: string\n answerSpec: { fields: ChatInteractionField[] }\n status: ChatInteractionStatus\n answers?: InteractionAnswers\n cancelReason?: string\n}\n\n/** Define a persisted notice part with type, id, kind, and text properties */\nexport type NoticePersistedPart = {\n type: 'notice'\n id: string\n noticeKind: NoticeKind\n text: string\n}\n\n/** Builds the persisted/streamed `notice` part — a one-line transcript notice\n * explaining an out-of-band event (warning, auto-declined interaction). */\nexport function noticePart(noticeKind: NoticeKind, id: string, text: string): NoticePersistedPart {\n return { type: 'notice', id, noticeKind, text }\n}\n\n/** Reads a wire request into the client's pending `ChatInteraction`. */\nexport function interactionFromWireRequest(request: InteractionRequestWire): ChatInteraction {\n return {\n id: request.id,\n kind: request.kind,\n title: request.title,\n ...(request.body ? { body: request.body } : {}),\n fields: request.answerSpec.fields,\n status: 'pending',\n }\n}\n\n/** Builds the persisted/streamed `interaction` part from a wire request. */\nexport function interactionToPersistedPart(\n request: InteractionRequestWire,\n status: ChatInteractionStatus,\n cancelReason?: string,\n answers?: InteractionAnswers,\n): InteractionPersistedPart {\n const parsedAnswers = answers === undefined ? undefined : parseInteractionAnswers(answers)\n if (parsedAnswers && !parsedAnswers.succeeded) throw new TypeError(parsedAnswers.error)\n return {\n type: 'interaction',\n id: request.id,\n kind: request.kind,\n title: request.title,\n ...(request.body ? { body: request.body } : {}),\n answerSpec: { fields: request.answerSpec.fields },\n status,\n ...(parsedAnswers?.succeeded ? { answers: parsedAnswers.value } : {}),\n ...(cancelReason ? { cancelReason } : {}),\n }\n}\n\n/** Stamps accepted values onto matching persisted interaction parts without\n * mutating the caller's transcript or answer maps. */\nexport function stampInteractionAnswers(\n parts: Array<Record<string, unknown>>,\n answersByInteractionId: Readonly<Record<string, InteractionAnswers>>,\n): Array<Record<string, unknown>> {\n return parts.map((part) => {\n if (String(part.type ?? '') !== 'interaction' || typeof part.id !== 'string') return part\n if (!Object.prototype.hasOwnProperty.call(answersByInteractionId, part.id)) return part\n const rawAnswers = answersByInteractionId[part.id]\n if (rawAnswers === undefined) return part\n const parsed = parseInteractionAnswers(rawAnswers)\n if (!parsed.succeeded) throw new TypeError(parsed.error)\n return { ...part, answers: parsed.value }\n })\n}\n\n/** Reads a persisted/streamed `interaction` part back into a `ChatInteraction`.\n * Returns null (caller logs) when the part is not one of ours. */\nexport function persistedPartToInteraction(part: Record<string, unknown>): ChatInteraction | null {\n if (String(part.type ?? '') !== 'interaction') return null\n const id = typeof part.id === 'string' && part.id ? part.id : null\n const kind = typeof part.kind === 'string' && part.kind ? part.kind : null\n const title = typeof part.title === 'string' ? part.title : ''\n const answerSpec = part.answerSpec as { fields?: unknown } | undefined\n const fields = Array.isArray(answerSpec?.fields) ? (answerSpec.fields as ChatInteractionField[]) : null\n const status = part.status as ChatInteractionStatus | undefined\n const validStatus = status && ['pending', 'answered', 'declined', 'cancelled', 'expired'].includes(status)\n const parsedAnswers = part.answers === undefined ? undefined : parseInteractionAnswers(part.answers)\n if (!id || !kind || !fields || !validStatus || (parsedAnswers && !parsedAnswers.succeeded)) return null\n return {\n id,\n kind,\n title,\n ...(typeof part.body === 'string' && part.body ? { body: part.body } : {}),\n fields,\n status,\n ...(parsedAnswers?.succeeded ? { answers: parsedAnswers.value } : {}),\n ...(typeof part.cancelReason === 'string' && part.cancelReason ? { cancelReason: part.cancelReason } : {}),\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canTransitionInteractionStatus,
|
|
3
3
|
persistedPartToInteraction
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3ZK5IJSW.js";
|
|
5
5
|
import {
|
|
6
6
|
canTransitionPlanStatus,
|
|
7
7
|
persistedPartToPlan,
|
|
@@ -380,4 +380,4 @@ export {
|
|
|
380
380
|
terminalizeDanglingAssistantToolUpdates,
|
|
381
381
|
encodeEvent
|
|
382
382
|
};
|
|
383
|
-
//# sourceMappingURL=chunk-
|
|
383
|
+
//# sourceMappingURL=chunk-5EPIPT4V.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
parseInteractionCancel,
|
|
8
8
|
parseInteractionRequest,
|
|
9
9
|
questionInteractionContentSignature
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3ZK5IJSW.js";
|
|
11
11
|
import {
|
|
12
12
|
canTransitionPlanStatus,
|
|
13
13
|
parsePlanSubmittedEvent,
|
|
@@ -917,4 +917,4 @@ export {
|
|
|
917
917
|
createDurableInteractionRoutePersistence,
|
|
918
918
|
createDurablePlanRoutes
|
|
919
919
|
};
|
|
920
|
-
//# sourceMappingURL=chunk-
|
|
920
|
+
//# sourceMappingURL=chunk-6GQ5DKFK.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatBytes
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-X3N2H6JE.js";
|
|
4
4
|
|
|
5
5
|
// src/chat-routes/binary-sniff.ts
|
|
6
6
|
function bytesStartWith(bytes, offset, signature) {
|
|
@@ -236,4 +236,4 @@ export {
|
|
|
236
236
|
attachmentTotalSizeErrorMessage,
|
|
237
237
|
createSandboxFileIndexRoute
|
|
238
238
|
};
|
|
239
|
-
//# sourceMappingURL=chunk-
|
|
239
|
+
//# sourceMappingURL=chunk-FMDMI25K.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
persistedPartToInteraction
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3ZK5IJSW.js";
|
|
4
4
|
import {
|
|
5
5
|
persistedPartToPlan,
|
|
6
6
|
planToPersistedPart
|
|
@@ -358,4 +358,4 @@ export {
|
|
|
358
358
|
buildAttachmentPromptBlock,
|
|
359
359
|
historyContentWithAttachments
|
|
360
360
|
};
|
|
361
|
-
//# sourceMappingURL=chunk-
|
|
361
|
+
//# sourceMappingURL=chunk-X3N2H6JE.js.map
|
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
checkAttachmentType,
|
|
10
10
|
sanitizeAttachmentFileName,
|
|
11
11
|
sniffBinary
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FMDMI25K.js";
|
|
13
13
|
import {
|
|
14
14
|
stepActivityFlowTrace
|
|
15
15
|
} from "./chunk-FBVLEGEG.js";
|
|
16
16
|
import {
|
|
17
17
|
attachmentPartsFromMessageParts,
|
|
18
18
|
formatBytes
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-X3N2H6JE.js";
|
|
20
20
|
import {
|
|
21
21
|
cancelStatusFor,
|
|
22
22
|
fieldAcceptsFreeText,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
parseInteractionRequest,
|
|
27
27
|
persistedPartToInteraction,
|
|
28
28
|
questionInteractionContentSignature
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3ZK5IJSW.js";
|
|
30
30
|
import {
|
|
31
31
|
parsePlanSubmittedEvent,
|
|
32
32
|
persistedPartToPlan
|
|
@@ -502,6 +502,26 @@ async function responseErrorMessage(res) {
|
|
|
502
502
|
}
|
|
503
503
|
return { message: `Answer failed (${res.status})` };
|
|
504
504
|
}
|
|
505
|
+
function settleInteractionSubmit(run, timeoutMs = INTERACTION_SUBMIT_TIMEOUT_MS) {
|
|
506
|
+
return new Promise((resolve) => {
|
|
507
|
+
const timer = setTimeout(
|
|
508
|
+
() => resolve({ ok: false, expired: false, message: INTERACTION_SUBMIT_TIMEOUT_MESSAGE }),
|
|
509
|
+
timeoutMs
|
|
510
|
+
);
|
|
511
|
+
const settle = (result) => {
|
|
512
|
+
clearTimeout(timer);
|
|
513
|
+
resolve(result);
|
|
514
|
+
};
|
|
515
|
+
Promise.resolve().then(run).then(
|
|
516
|
+
settle,
|
|
517
|
+
(err) => settle({
|
|
518
|
+
ok: false,
|
|
519
|
+
expired: false,
|
|
520
|
+
message: err instanceof Error ? err.message : "Failed to submit the answer"
|
|
521
|
+
})
|
|
522
|
+
);
|
|
523
|
+
});
|
|
524
|
+
}
|
|
505
525
|
function createInteractionAnswerSubmitter(options) {
|
|
506
526
|
const timeoutMs = options.timeoutMs ?? INTERACTION_SUBMIT_TIMEOUT_MS;
|
|
507
527
|
return async (submission) => {
|
|
@@ -606,6 +626,13 @@ function QuestionOptionList({
|
|
|
606
626
|
function selectField(field) {
|
|
607
627
|
return field.type === "select" ? field : null;
|
|
608
628
|
}
|
|
629
|
+
function freeTextField(field) {
|
|
630
|
+
return field.type === "text" || field.type === "secret" ? field : null;
|
|
631
|
+
}
|
|
632
|
+
function textFieldMaxLength(field) {
|
|
633
|
+
const max = field.maxLength;
|
|
634
|
+
return typeof max === "number" && Number.isInteger(max) && max > 0 ? max : void 0;
|
|
635
|
+
}
|
|
609
636
|
function valuesWithSelected(values, field, optionValue) {
|
|
610
637
|
const current = values[field.name]?.selected ?? [];
|
|
611
638
|
let selected = [optionValue];
|
|
@@ -629,6 +656,10 @@ function InteractionQuestionCard({
|
|
|
629
656
|
submitAnswer,
|
|
630
657
|
onResolved,
|
|
631
658
|
onLateAnswer,
|
|
659
|
+
kindLabel,
|
|
660
|
+
sourceNote,
|
|
661
|
+
timeoutNote,
|
|
662
|
+
renderMarkdown,
|
|
632
663
|
className
|
|
633
664
|
}) {
|
|
634
665
|
const [values, setValues] = useState3(() => fieldValuesFromAnswers(interaction.fields, interaction.answers));
|
|
@@ -637,6 +668,14 @@ function InteractionQuestionCard({
|
|
|
637
668
|
const [lateAnswerSent, setLateAnswerSent] = useState3(false);
|
|
638
669
|
const [error, setError] = useState3(null);
|
|
639
670
|
const submitInFlightRef = useRef3(false);
|
|
671
|
+
const [askId, setAskId] = useState3(interaction.id);
|
|
672
|
+
if (askId !== interaction.id) {
|
|
673
|
+
setAskId(interaction.id);
|
|
674
|
+
setValues(fieldValuesFromAnswers(interaction.fields, interaction.answers));
|
|
675
|
+
setLocalStatus(null);
|
|
676
|
+
setLateAnswerSent(false);
|
|
677
|
+
setError(null);
|
|
678
|
+
}
|
|
640
679
|
useEffect3(() => {
|
|
641
680
|
if (!interaction.answers) return;
|
|
642
681
|
setValues(fieldValuesFromAnswers(interaction.fields, interaction.answers));
|
|
@@ -686,7 +725,9 @@ function InteractionQuestionCard({
|
|
|
686
725
|
setSubmitting(true);
|
|
687
726
|
setError(null);
|
|
688
727
|
try {
|
|
689
|
-
const result = await
|
|
728
|
+
const result = await settleInteractionSubmit(
|
|
729
|
+
() => submitAnswer({ id: interaction.id, outcome: "accepted", data: answerData })
|
|
730
|
+
);
|
|
690
731
|
if (result.ok) {
|
|
691
732
|
setLocalStatus("answered");
|
|
692
733
|
onResolved?.(interaction.id, "answered", answerData);
|
|
@@ -705,6 +746,7 @@ function InteractionQuestionCard({
|
|
|
705
746
|
}
|
|
706
747
|
const terminalNote = secretLateAnswerBlocked ? "This question asked for a secret, so it cannot be sent as a new chat message. Ask the agent to request it again." : TERMINAL_NOTES[status];
|
|
707
748
|
const showSubmitButton = status === "pending" || canWrite && lateAnswerable && !lateAnswerSent;
|
|
749
|
+
const showTimeoutNote = timeoutNote != null && status === "pending";
|
|
708
750
|
let submitLabel = "Submit answer";
|
|
709
751
|
if (lateAnswerable) {
|
|
710
752
|
submitLabel = submitting ? "Sending\u2026" : "Send as new message";
|
|
@@ -714,16 +756,17 @@ function InteractionQuestionCard({
|
|
|
714
756
|
return /* @__PURE__ */ jsxs3("div", { className: `rounded-xl border border-border bg-card p-4 shadow-sm ${className ?? ""}`, children: [
|
|
715
757
|
/* @__PURE__ */ jsxs3("div", { className: "mb-3 flex flex-wrap items-center justify-between gap-2", children: [
|
|
716
758
|
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
717
|
-
/* @__PURE__ */ jsx4(InteractionBadge, { variant: "outline", children: "Question" }),
|
|
759
|
+
/* @__PURE__ */ jsx4(InteractionBadge, { variant: "outline", children: kindLabel ?? "Question" }),
|
|
718
760
|
/* @__PURE__ */ jsx4(InteractionBadge, { variant: answered ? "default" : status === "expired" || status === "declined" ? "destructive" : "outline", children: STATUS_LABELS[status] })
|
|
719
761
|
] }),
|
|
720
|
-
/* @__PURE__ */ jsx4("span", { className: "text-xs text-muted-foreground", children: "The agent asked for input" })
|
|
762
|
+
/* @__PURE__ */ jsx4("span", { className: "text-xs text-muted-foreground", children: sourceNote ?? "The agent asked for input" })
|
|
721
763
|
] }),
|
|
722
764
|
interaction.title.trim() && interaction.fields.every((field) => field.label !== interaction.title) && /* @__PURE__ */ jsx4("p", { className: "mb-3 text-sm font-medium leading-5 text-foreground", children: interaction.title }),
|
|
723
|
-
interaction.body && /* @__PURE__ */ jsx4("p", { className: "mb-3 text-sm leading-5 text-muted-foreground", children: interaction.body }),
|
|
765
|
+
interaction.body && (renderMarkdown ? /* @__PURE__ */ jsx4("div", { className: "mb-3 text-sm leading-5 text-muted-foreground", children: renderMarkdown(interaction.body) }) : /* @__PURE__ */ jsx4("p", { className: "mb-3 text-sm leading-5 text-muted-foreground", children: interaction.body })),
|
|
724
766
|
/* @__PURE__ */ jsx4("div", { className: "space-y-4", children: interaction.fields.map((field) => {
|
|
725
767
|
const value = values[field.name] ?? {};
|
|
726
768
|
const select = selectField(field);
|
|
769
|
+
const freeText = freeTextField(field);
|
|
727
770
|
return /* @__PURE__ */ jsxs3("fieldset", { className: "space-y-2", children: [
|
|
728
771
|
/* @__PURE__ */ jsx4("p", { className: "text-sm font-medium leading-5 text-foreground", children: field.label }),
|
|
729
772
|
select ? /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
|
|
@@ -784,6 +827,7 @@ function InteractionQuestionCard({
|
|
|
784
827
|
"aria-label": field.label,
|
|
785
828
|
onChange: (event) => setFieldValue(field.name, { text: event.target.value }),
|
|
786
829
|
placeholder: field.placeholder,
|
|
830
|
+
maxLength: freeText ? textFieldMaxLength(freeText) : void 0,
|
|
787
831
|
className: FIELD_INPUT_CLASSES
|
|
788
832
|
}
|
|
789
833
|
) : /* @__PURE__ */ jsx4(
|
|
@@ -794,15 +838,19 @@ function InteractionQuestionCard({
|
|
|
794
838
|
"aria-label": field.label,
|
|
795
839
|
onChange: (event) => setFieldValue(field.name, { text: event.target.value }),
|
|
796
840
|
rows: 3,
|
|
841
|
+
maxLength: freeText ? textFieldMaxLength(freeText) : void 0,
|
|
797
842
|
placeholder: field.type === "text" ? field.placeholder : void 0,
|
|
798
843
|
className: FIELD_INPUT_CLASSES
|
|
799
844
|
}
|
|
800
845
|
)
|
|
801
846
|
] }, field.name);
|
|
802
847
|
}) }),
|
|
803
|
-
error && /* @__PURE__ */ jsx4("p", { className: "mt-3 text-xs text-destructive", children: error }),
|
|
848
|
+
error && /* @__PURE__ */ jsx4("p", { role: "alert", className: "mt-3 text-xs text-destructive", children: error }),
|
|
804
849
|
terminalNote && /* @__PURE__ */ jsx4("p", { className: "mt-3 text-xs text-muted-foreground", children: terminalNote }),
|
|
805
|
-
showSubmitButton && /* @__PURE__ */
|
|
850
|
+
(showSubmitButton || showTimeoutNote) && /* @__PURE__ */ jsxs3("div", { className: "mt-4 flex flex-wrap items-center justify-end gap-2", children: [
|
|
851
|
+
showTimeoutNote && /* @__PURE__ */ jsx4("div", { className: "mr-auto text-xs text-muted-foreground", children: timeoutNote }),
|
|
852
|
+
showSubmitButton && /* @__PURE__ */ jsx4(InteractionActionButton, { onClick: () => void submit(), disabled: disabled || !answerData, children: submitLabel })
|
|
853
|
+
] }),
|
|
806
854
|
answered && /* @__PURE__ */ jsx4("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
807
855
|
/* @__PURE__ */ jsx4(CheckGlyph, { className: "h-3 w-3" }),
|
|
808
856
|
"Answered"
|
|
@@ -3835,6 +3883,7 @@ export {
|
|
|
3835
3883
|
INTERACTION_SUBMIT_TIMEOUT_MS,
|
|
3836
3884
|
INTERACTION_SUBMIT_TIMEOUT_MESSAGE,
|
|
3837
3885
|
responseErrorMessage,
|
|
3886
|
+
settleInteractionSubmit,
|
|
3838
3887
|
createInteractionAnswerSubmitter,
|
|
3839
3888
|
InteractionBadge,
|
|
3840
3889
|
InteractionActionButton,
|
|
@@ -3891,4 +3940,4 @@ export {
|
|
|
3891
3940
|
useThinkingSeconds,
|
|
3892
3941
|
ChatMessages
|
|
3893
3942
|
};
|
|
3894
|
-
//# sourceMappingURL=chunk-
|
|
3943
|
+
//# sourceMappingURL=chunk-YTSEDJWA.js.map
|