@assistant-ui/eve 0.0.24 → 0.0.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.
- package/dist/convertEveMessages.d.ts +40 -51
- package/dist/convertEveMessages.d.ts.map +1 -1
- package/dist/convertEveMessages.js +146 -117
- package/dist/convertEveMessages.js.map +1 -1
- package/dist/deriveCreatedAt.d.ts +9 -9
- package/dist/deriveCreatedAt.d.ts.map +1 -1
- package/dist/deriveCreatedAt.js +25 -34
- package/dist/deriveCreatedAt.js.map +1 -1
- package/dist/eveCloudSessions.js +1 -2
- package/dist/eveExtras.d.ts +4 -2
- package/dist/eveExtras.d.ts.map +1 -1
- package/dist/eveExtras.js +1 -2
- package/dist/eveExtras.js.map +1 -1
- package/dist/hooks.d.ts +4 -3
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +5 -5
- package/dist/hooks.js.map +1 -1
- package/dist/sdkIdentity.js +2 -3
- package/dist/useEveAgentRuntime.d.ts +3 -5
- package/dist/useEveAgentRuntime.d.ts.map +1 -1
- package/dist/useEveAgentRuntime.js +34 -23
- package/dist/useEveAgentRuntime.js.map +1 -1
- package/package.json +10 -10
- package/src/convertEveMessages.test.ts +925 -729
- package/src/convertEveMessages.ts +282 -227
- package/src/deriveCreatedAt.test.ts +90 -88
- package/src/deriveCreatedAt.ts +32 -36
- package/src/eveExtras.ts +4 -4
- package/src/hooks.ts +4 -3
- package/src/testUtils.ts +189 -8
- package/src/useEveAgentRuntime.cloud.test.tsx +105 -136
- package/src/useEveAgentRuntime.eveResume.test.tsx +22 -104
- package/src/useEveAgentRuntime.fast-refresh.test.tsx +195 -37
- package/src/useEveAgentRuntime.interruptedTurn.test.tsx +86 -40
- package/src/useEveAgentRuntime.refetch.test.tsx +19 -58
- package/src/useEveAgentRuntime.test.tsx +372 -291
- package/src/useEveAgentRuntime.ts +100 -113
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertEveMessages.js","names":["_exhaustiveCheck"],"sources":["../src/convertEveMessages.ts"],"sourcesContent":["import {\n fromThreadMessageLike,\n toAssistantError,\n type AppendMessage,\n type CompleteAttachment,\n type DataMessagePart,\n type FileMessagePart,\n type MessagePartStreamStatus,\n type MessageStatus,\n type PartProviderMetadata,\n type RespondToToolApprovalOptions,\n type ThreadAssistantMessagePart,\n type ThreadMessage,\n type ThreadMessageLike,\n type ThreadUserMessagePart,\n type ToolApprovalDisplay,\n type ToolApprovalOption,\n type ToolCallMessagePart,\n} from \"@assistant-ui/core\";\nimport {\n httpUrlPattern,\n resolveFileMediaType,\n resolveFilePartSource,\n resolveImageMediaType,\n toMediaWireUrl,\n} from \"@assistant-ui/core/internal\";\nimport type {\n EveAuthorizationOutcome,\n EveAuthorizationPart,\n EveDynamicToolPart,\n EveMessage,\n EveMessageData,\n EveMessageInputRequest,\n EveMessagePart,\n} from \"eve/react\";\nimport type { InputResponse } from \"eve/client\";\nimport type { MessageStreamEvent } from \"eve/client\";\n\nconst ASSISTANT_COMPLETE_STATUS = {\n type: \"complete\",\n reason: \"stop\",\n} satisfies MessageStatus;\n\nconst ASSISTANT_RUNNING_STATUS = {\n type: \"running\",\n} satisfies MessageStatus;\n\nconst ASSISTANT_CANCELLED_STATUS = {\n type: \"incomplete\",\n reason: \"cancelled\",\n} satisfies MessageStatus;\n\nconst USER_FALLBACK_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} satisfies MessageStatus;\n\nexport type ConvertEveMessagesOptions = {\n /**\n * Marks the last assistant message as running while Eve is submitting or\n * streaming. When omitted, a message carrying Eve's `\"streaming\"` marker is\n * treated as running; pass `false` to settle interrupted messages to a\n * terminal status.\n */\n readonly isRunning?: boolean | undefined;\n /**\n * The Eve session error, mapped onto the assistant message it interrupted.\n */\n readonly error?: unknown;\n readonly getCreatedAt?: ((message: EveMessage) => Date) | undefined;\n /**\n * The session's stream events. A `turn.failed` or `turn.cancelled` event\n * marks its turn's assistant message as incomplete, with a failure's code\n * and message as its error.\n */\n readonly events?: readonly MessageStreamEvent[] | undefined;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst toJsonObject = (value: unknown): ToolCallMessagePart[\"args\"] => {\n if (isRecord(value)) return value as ToolCallMessagePart[\"args\"];\n if (value === undefined) return {};\n return { value } as ToolCallMessagePart[\"args\"];\n};\n\nconst stringifyArgs = (value: unknown): string => {\n try {\n return JSON.stringify(value ?? {});\n } catch {\n return \"\";\n }\n};\n\nconst toMessageStatus = (\n message: EveMessage,\n index: number,\n messages: readonly EveMessage[],\n options: ConvertEveMessagesOptions,\n interruptedTurns: ReadonlyMap<string, MessageStatus>,\n): MessageStatus => {\n if (message.role !== \"assistant\") return USER_FALLBACK_STATUS;\n\n const interrupted =\n message.metadata?.turnId === undefined\n ? undefined\n : interruptedTurns.get(message.metadata.turnId);\n if (interrupted) return interrupted;\n\n const isLast = index === messages.length - 1;\n const hasPendingApproval = message.parts.some(\n (part) =>\n part.type === \"dynamic-tool\" && part.state === \"approval-requested\",\n );\n // Scoped to the stale-marker case so a terminalized or errored turn keeps its\n // own status; the hold only claims the fall-through that reads as cancelled.\n const hasPendingAuthorization =\n message.metadata?.status === \"streaming\" &&\n (!isLast || options.error === undefined) &&\n message.parts.some(\n (part) => part.type === \"authorization\" && part.state === \"required\",\n );\n\n if (hasPendingApproval) {\n return { type: \"requires-action\", reason: \"tool-calls\" };\n }\n\n // A connector authorization is answered outside the thread, so the turn is\n // held on external input rather than on a tool call awaiting a result.\n if (hasPendingAuthorization) {\n return { type: \"requires-action\", reason: \"interrupt\" };\n }\n\n if (message.metadata?.status === \"failed\") {\n return { type: \"incomplete\", reason: \"error\" };\n }\n\n if (isLast && options.isRunning === true) {\n return ASSISTANT_RUNNING_STATUS;\n }\n\n // Some eve versions leave the streaming marker after cancellation or failure.\n if (message.metadata?.status === \"streaming\") {\n if (options.isRunning === undefined) {\n return ASSISTANT_RUNNING_STATUS;\n }\n if (isLast && options.error !== undefined) {\n return {\n type: \"incomplete\",\n reason: \"error\",\n error: toAssistantError(options.error),\n };\n }\n return ASSISTANT_CANCELLED_STATUS;\n }\n\n return ASSISTANT_COMPLETE_STATUS;\n};\n\nconst toolApprovalOptionsFromInputRequest = (\n inputRequest: EveMessageInputRequest | undefined,\n): readonly ToolApprovalOption[] | undefined => {\n const options = inputRequest?.options;\n if (!options || options.length === 0) return undefined;\n\n return options.map((option) => ({\n id: option.id,\n kind:\n option.id === \"approve\"\n ? \"allow-once\"\n : option.id === \"cancel\"\n ? \"reject-once\"\n : `_${option.id}`,\n ...(option.label && { label: option.label }),\n ...(option.description && { description: option.description }),\n }));\n};\n\n/**\n * Eve resolves a request the moment any response for it arrives, so the answer\n * shapes it accepts decide both what the renderer may offer and what\n * {@link toEveInputResponse} may submit. A request with no options and no\n * `display` takes a typed answer, which is why the absence of both is not the\n * same as a confirmation.\n */\nconst isDroppedOptionApproval = (inputRequest: EveMessageInputRequest) =>\n inputRequest.kind === \"tool-approval\" && !inputRequest.options?.length;\n\nconst acceptsFreeformAnswer = (inputRequest: EveMessageInputRequest): boolean =>\n inputRequest.display !== \"confirmation\" &&\n !isDroppedOptionApproval(inputRequest) &&\n (inputRequest.display === \"text\" ||\n inputRequest.allowFreeform === true ||\n !inputRequest.options?.length);\n\nconst toolApprovalDisplay = (\n inputRequest: EveMessageInputRequest,\n): ToolApprovalDisplay => {\n // The mapper answers this shape through its approve/cancel branch whatever\n // the request declares, so the projection has to agree: presenting it as a\n // question would offer an answer the mapper turns into a decision.\n if (isDroppedOptionApproval(inputRequest)) return \"decision\";\n\n switch (inputRequest.display) {\n case \"confirmation\":\n return \"decision\";\n case \"select\":\n return \"select\";\n case \"text\":\n return \"text\";\n default:\n if (inputRequest.kind === \"tool-approval\") return \"decision\";\n return inputRequest.options?.length ? \"select\" : \"text\";\n }\n};\n\nconst toApproval = (\n part: EveDynamicToolPart,\n): ToolCallMessagePart[\"approval\"] | undefined => {\n if (\n part.state !== \"approval-requested\" &&\n part.state !== \"approval-responded\" &&\n part.state !== \"output-available\" &&\n part.state !== \"output-error\" &&\n part.state !== \"output-denied\"\n ) {\n return undefined;\n }\n\n const approval = part.approval;\n if (!approval) return undefined;\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n const options = toolApprovalOptionsFromInputRequest(inputRequest);\n\n return {\n id: approval.id,\n ...(inputRequest && {\n prompt: inputRequest.prompt,\n display: toolApprovalDisplay(inputRequest),\n ...(acceptsFreeformAnswer(inputRequest) && { allowFreeform: true }),\n }),\n ...(approval.approved !== undefined && { approved: approval.approved }),\n ...(approval.reason && { reason: approval.reason }),\n ...(approval.isAutomatic !== undefined && {\n isAutomatic: approval.isAutomatic,\n }),\n ...(options && { options }),\n };\n};\n\nconst toJsonSafeInputRequest = (\n inputRequest: EveMessageInputRequest,\n): PartProviderMetadata[string] => ({\n requestId: inputRequest.requestId,\n prompt: inputRequest.prompt,\n kind: inputRequest.kind,\n ...(inputRequest.display !== undefined && { display: inputRequest.display }),\n ...(inputRequest.allowFreeform !== undefined && {\n allowFreeform: inputRequest.allowFreeform,\n }),\n ...(inputRequest.options && {\n options: inputRequest.options.map((option) => ({\n id: option.id,\n label: option.label,\n ...(option.description !== undefined && {\n description: option.description,\n }),\n ...(option.style !== undefined && { style: option.style }),\n })),\n }),\n});\n\nconst toToolProviderMetadata = (\n part: EveDynamicToolPart,\n): PartProviderMetadata | undefined => {\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n if (!inputRequest) return undefined;\n return { eve: { inputRequest: toJsonSafeInputRequest(inputRequest) } };\n};\n\nconst convertDynamicToolPart = (\n part: EveDynamicToolPart,\n): ToolCallMessagePart => {\n const approval = toApproval(part);\n const providerMetadata = toToolProviderMetadata(part);\n const toolCall: ToolCallMessagePart = {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n args: toJsonObject(part.input),\n argsText: part.state === \"input-streaming\" ? \"\" : stringifyArgs(part.input),\n ...(approval && { approval }),\n ...(providerMetadata && { providerMetadata }),\n };\n\n switch (part.state) {\n case \"output-available\":\n return { ...toolCall, result: part.output };\n\n case \"output-error\":\n return {\n ...toolCall,\n result: { error: part.errorText },\n isError: true,\n };\n\n case \"output-denied\":\n return {\n ...toolCall,\n result: { error: part.approval?.reason ?? \"Tool approval denied\" },\n isError: true,\n };\n\n default:\n return toolCall;\n }\n};\n\n/**\n * Payload of the `authorization` data part the Eve runtime emits for a\n * connector authorization challenge. `state` discriminates a pending challenge\n * from a settled one; every other field is present only when Eve projected it.\n * This converter drops a `url` whose scheme is not `http(s)`, so a renderer can\n * link to it without checking the scheme itself; Eve itself passes through\n * whatever the connector supplied. Eve's\n * `turnId` and `stepIndex` part identity is omitted: a renderer receives the\n * one part it renders, in Eve's own step order, so display never has to\n * re-identify a challenge among several.\n */\nexport type EveAuthorizationData = {\n readonly state: EveAuthorizationPart[\"state\"];\n readonly name: string;\n readonly displayName?: string;\n readonly description?: string;\n readonly url?: string;\n readonly userCode?: string;\n readonly instructions?: string;\n readonly expiresAt?: string;\n readonly outcome?: EveAuthorizationOutcome;\n readonly reason?: string;\n};\n\nconst convertAuthorizationPart = (\n part: EveAuthorizationPart,\n): DataMessagePart<EveAuthorizationData> => ({\n type: \"data\",\n name: \"authorization\",\n data: {\n state: part.state,\n name: part.name,\n ...(part.displayName !== undefined && { displayName: part.displayName }),\n ...(part.description !== undefined && { description: part.description }),\n ...(part.authorization?.url !== undefined &&\n httpUrlPattern.test(part.authorization.url) && {\n url: part.authorization.url,\n }),\n ...(part.authorization?.userCode !== undefined && {\n userCode: part.authorization.userCode,\n }),\n ...(part.authorization?.instructions !== undefined && {\n instructions: part.authorization.instructions,\n }),\n ...(part.authorization?.expiresAt !== undefined && {\n expiresAt: part.authorization.expiresAt,\n }),\n ...(part.outcome !== undefined && { outcome: part.outcome }),\n ...(part.reason !== undefined && { reason: part.reason }),\n },\n});\n\nconst convertFilePart = (\n part: Extract<EveMessagePart, { type: \"file\" }>,\n): FileMessagePart | null => {\n if (part.url === undefined) return null;\n return {\n type: \"file\",\n data: part.url,\n mimeType: resolveFileMediaType(part.url, part.mediaType),\n ...(part.filename && { filename: part.filename }),\n ...(httpUrlPattern.test(part.url) && { sourceType: \"url\" as const }),\n };\n};\n\n// Eve's `state` is a run marker: the reducer settles a part to \"done\" only on\n// `reasoning.completed`, `message.completed`, or `turn.cancelled`.\n// `emitStreamContent` does not flush leftover reasoning on a tool-call, so a\n// non-last reasoning part stays `streaming` until the model stream ends and the\n// leftover flush runs. Mapping `streaming` to running would pin that block\n// open. Only `done` is trustworthy; an unsettled part falls back to core's\n// last-part rule.\nconst partStateToStatus = (\n state: \"done\" | \"streaming\" | undefined,\n): MessagePartStreamStatus | undefined =>\n state === \"done\" ? { type: \"complete\" } : undefined;\n\nconst convertAssistantPart = (\n part: EveMessagePart,\n): ThreadAssistantMessagePart | null => {\n switch (part.type) {\n case \"text\":\n case \"reasoning\": {\n const status = partStateToStatus(part.state);\n return {\n type: part.type,\n text: part.text,\n ...(status && { status }),\n };\n }\n\n case \"step-start\":\n return null;\n\n case \"dynamic-tool\":\n return convertDynamicToolPart(part);\n\n case \"authorization\":\n return convertAuthorizationPart(part);\n\n case \"file\":\n return convertFilePart(part);\n\n default:\n return null;\n }\n};\n\nconst convertUserPart = (\n part: EveMessagePart,\n): ThreadUserMessagePart | null => {\n switch (part.type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n default:\n return null;\n }\n};\n\nconst toUserContent = (\n parts: readonly EveMessagePart[],\n attachments: readonly CompleteAttachment[],\n): readonly ThreadUserMessagePart[] => {\n const content = parts.map(convertUserPart).filter((part) => part !== null);\n return content.length > 0 || attachments.length > 0\n ? content\n : [{ type: \"text\", text: \"\" }];\n};\n\nconst toUserAttachments = (\n parts: readonly EveMessagePart[],\n): CompleteAttachment[] => {\n const attachments: CompleteAttachment[] = [];\n for (const part of parts) {\n if (part.type !== \"file\") continue;\n const file = convertFilePart(part);\n if (file === null) continue;\n const isImage = file.mimeType.startsWith(\"image/\");\n attachments.push({\n id: String(attachments.length),\n type: isImage ? \"image\" : \"file\",\n name: part.filename ?? \"file\",\n content: [\n isImage\n ? {\n type: \"image\",\n image: file.data,\n ...(part.filename && { filename: part.filename }),\n }\n : file,\n ],\n contentType: file.mimeType,\n status: { type: \"complete\" },\n });\n }\n return attachments;\n};\n\n/**\n * Converts a single Eve message into an assistant-ui thread message.\n */\nexport const convertEveMessage = (\n message: EveMessage,\n index: number,\n messages: readonly EveMessage[],\n options: ConvertEveMessagesOptions = {},\n): ThreadMessage =>\n convertEveMessageWithInterruptions(\n message,\n index,\n messages,\n options,\n getInterruptedTurns(options.events),\n );\n\nconst convertEveMessageWithInterruptions = (\n message: EveMessage,\n index: number,\n messages: readonly EveMessage[],\n options: ConvertEveMessagesOptions,\n interruptedTurns: ReadonlyMap<string, MessageStatus>,\n): ThreadMessage => {\n const createdAt = options.getCreatedAt?.(message) ?? new Date();\n const metadata = {\n ...(message.metadata?.optimistic && { isOptimistic: true }),\n custom: {\n ...(message.metadata ?? {}),\n },\n };\n\n const attachments =\n message.role === \"user\" ? toUserAttachments(message.parts) : [];\n const like: ThreadMessageLike =\n message.role === \"user\"\n ? {\n role: \"user\",\n id: message.id,\n createdAt,\n content: toUserContent(message.parts, attachments),\n attachments,\n metadata,\n }\n : {\n role: \"assistant\",\n id: message.id,\n createdAt,\n content: message.parts\n .map(convertAssistantPart)\n .filter((part) => part !== null),\n metadata,\n };\n\n return fromThreadMessageLike(\n like,\n message.id,\n toMessageStatus(message, index, messages, options, interruptedTurns),\n );\n};\n\nexport type InterruptedTurnEventCache = {\n lastEvents: readonly MessageStreamEvent[];\n interruptions: readonly MessageStreamEvent[];\n};\n\nconst isTurnInterruption = (event: MessageStreamEvent) =>\n event.type === \"turn.failed\" || event.type === \"turn.cancelled\";\n\n/**\n * Collects the `turn.failed` and `turn.cancelled` events of an append-only\n * event log, scanning only the events appended since the cached call. The\n * returned array keeps its identity until a new interruption arrives.\n */\nexport const collectInterruptedTurnEvents = (\n events: readonly MessageStreamEvent[],\n cache: InterruptedTurnEventCache,\n): readonly MessageStreamEvent[] => {\n if (events === cache.lastEvents) return cache.interruptions;\n\n const scanned = cache.lastEvents;\n const resumesScan =\n scanned.length === 0 ||\n events[scanned.length - 1] === scanned[scanned.length - 1];\n\n let interruptions = resumesScan ? cache.interruptions : [];\n for (let i = resumesScan ? scanned.length : 0; i < events.length; i++) {\n const event = events[i]!;\n if (isTurnInterruption(event)) interruptions = [...interruptions, event];\n }\n\n cache.lastEvents = events;\n cache.interruptions = interruptions;\n return interruptions;\n};\n\nconst getInterruptedTurns = (\n events: readonly MessageStreamEvent[] | undefined,\n) => {\n const interrupted = new Map<string, MessageStatus>();\n for (const event of events ?? []) {\n if (event.type === \"turn.failed\") {\n interrupted.set(event.data.turnId, {\n type: \"incomplete\",\n reason: \"error\",\n error: { code: event.data.code, message: event.data.message },\n });\n } else if (event.type === \"turn.cancelled\") {\n interrupted.set(event.data.turnId, ASSISTANT_CANCELLED_STATUS);\n }\n }\n return interrupted;\n};\n\n/**\n * Converts the full Eve message data object into assistant-ui thread messages.\n */\nexport const convertEveMessages = (\n data: EveMessageData,\n options: ConvertEveMessagesOptions = {},\n): ThreadMessage[] => {\n const interruptedTurns = getInterruptedTurns(options.events);\n return data.messages.map((message, index, messages) =>\n convertEveMessageWithInterruptions(\n message,\n index,\n messages,\n options,\n interruptedTurns,\n ),\n );\n};\n\n/**\n * Structural subset of the `string | UserContent` message content Eve's `send`\n * API accepts. The helpers declare the shapes they produce and leave\n * assignability to the send call site, checked against the installed version.\n */\nexport type EveMessageContent =\n | string\n | (\n | { readonly type: \"text\"; readonly text: string }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mediaType: string;\n readonly filename?: string;\n }\n )[];\n\ntype OutboundPart = AppendMessage[\"content\"][number] & {\n readonly contentType?: string | undefined;\n};\n\n/**\n * Converts an assistant-ui append message into the message payload accepted by\n * Eve's `send` API.\n */\nexport const getEveMessageContent = (\n message: AppendMessage,\n): EveMessageContent => {\n const content: OutboundPart[] = [\n ...message.content,\n ...(message.attachments?.flatMap((attachment) =>\n attachment.content.map((part) => ({\n ...part,\n contentType: attachment.contentType,\n })),\n ) ?? []),\n ];\n\n const parts = content.flatMap((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n\n case \"file\": {\n const mediaType = resolveFileMediaType(\n part.data,\n part.mimeType || part.contentType,\n );\n return {\n type: \"file\" as const,\n data:\n part.sourceType === \"id\"\n ? part.data\n : toMediaWireUrl(part.data, mediaType),\n mediaType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n\n case \"image\": {\n const mediaType = resolveImageMediaType(part.image, part.contentType);\n return {\n type: \"file\" as const,\n data: toMediaWireUrl(part.image, mediaType),\n mediaType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n\n case \"audio\": {\n // A data URL's own media type wins over `mediaType` downstream, so the\n // envelope is rebuilt from the typed format rather than forwarded.\n const mediaType = `audio/${part.audio.format}`;\n const data = part.audio.data;\n const source = resolveFilePartSource({ data, mimeType: mediaType });\n return {\n type: \"file\" as const,\n data:\n source.kind === \"url\"\n ? source.url\n : `data:${mediaType};base64,${source.data}`,\n mediaType,\n };\n }\n\n case \"data\":\n return [];\n\n default: {\n const _exhaustiveCheck:\n | \"generative-ui\"\n | \"reasoning\"\n | \"source\"\n | \"tool-call\" = type;\n throw new Error(\n `Unsupported eve append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (parts.length === 1 && parts[0]?.type === \"text\") {\n return parts[0].text;\n }\n\n return parts;\n};\n\n/**\n * Finds the pending input request answered by the given approval id, so the\n * response mapping can honor the request's display mode.\n */\nexport const findEveInputRequest = (\n data: EveMessageData,\n approvalId: string,\n): EveMessageInputRequest | undefined => {\n for (const message of data.messages) {\n for (const part of message.parts) {\n if (part.type === \"dynamic-tool\" && part.approval?.id === approvalId) {\n return part.toolMetadata?.eve?.inputRequest;\n }\n }\n }\n return undefined;\n};\n\n/**\n * Converts an assistant-ui tool approval response into an Eve input response.\n *\n * When `inputRequest` is known, every returned response carries either an\n * option the request declares or a free-form answer. A literal option match\n * wins, then the `\"approve\"` / `\"cancel\"` option the response's boolean decision\n * names, then the response's `text` (or its `reason`, for a caller that\n * predates the first-class answer field) when the request takes a free-form\n * answer (`display: \"text\"`, `allowFreeform`, or no options at all, and never\n * `display: \"confirmation\"`) and the response is not a refusal.\n * A one-argument call, or a part with no request, still forwards a caller\n * `optionId` as it always has, including ids the request never declared.\n *\n * A response the known request cannot record as the answer it asked for throws\n * instead of being submitted, because eve resolves a request the moment any\n * response for it arrives, and an empty one is recorded as an answer with no\n * content. Not sending leaves the request pending, so the caller can retry or\n * the user can answer it as an ordinary message.\n *\n * With no request to map against — a one-argument call, or a part carrying no\n * `toolMetadata.eve.inputRequest` — the response maps as it always has, to the\n * literal `\"approve\"` / `\"cancel\"` option every eve approval declares. Guessing\n * a display mode is what this mapper stopped doing; an unknown request is not\n * a guess about one.\n */\nexport const toEveInputResponse = (\n response: RespondToToolApprovalOptions,\n inputRequest?: EveMessageInputRequest,\n): InputResponse => {\n const requestId = response.approvalId;\n const options = inputRequest?.options;\n const text = response.text ?? response.reason;\n\n if (response.optionId !== undefined) {\n if (\n !inputRequest ||\n options?.some((option) => option.id === response.optionId)\n ) {\n return {\n requestId,\n optionId: response.optionId,\n ...(text && { text }),\n };\n }\n throw new Error(\n `Eve input request \"${requestId}\" has no option with id \"${response.optionId}\"; respond with one of: ${\n options?.length\n ? options.map((option) => option.id).join(\", \")\n : \"(the request carries no options)\"\n }`,\n );\n }\n\n const decisionOptionId = response.approved ? \"approve\" : \"cancel\";\n // Eve's harness always declares `approve`/`cancel` on a `tool-approval`\n // request, so honoring the kind when the options were dropped keeps a\n // non-spec approval payload answerable rather than stuck. A tool-approval\n // that declares its own options still requires one of them.\n if (\n !inputRequest ||\n (inputRequest.kind === \"tool-approval\" && !options?.length) ||\n options?.some((option) => option.id === decisionOptionId)\n ) {\n return { requestId, optionId: decisionOptionId, ...(text && { text }) };\n }\n\n // Eve recognises an approval by its literal two-option `approve`/`cancel`\n // shape, so past this point the request is a question and the boolean\n // carries no decision eve would act on.\n const acceptsText = acceptsFreeformAnswer(inputRequest);\n if (acceptsText && text && response.approved !== false) {\n return { requestId, text };\n }\n\n throw new Error(\n `Eve input request \"${requestId}\" (${inputRequest.prompt}) was not answered by this response; ${\n options?.length\n ? `respond with one of: ${options.map((option) => option.id).join(\", \")}`\n : !acceptsText\n ? \"the request declares no options to respond with\"\n : response.approved === false\n ? \"a refusal carries no answer for a free-form request; resend with `approved` unset or true and the answer in the response text\"\n : \"pass the answer as the response text, because the request takes a free-form answer\"\n }`,\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"convertEveMessages.js","names":["_exhaustiveCheck"],"sources":["../src/convertEveMessages.ts"],"sourcesContent":["import {\n fromThreadMessageLike,\n toAssistantError,\n type AppendMessage,\n type CompleteAttachment,\n type DataMessagePart,\n type FileMessagePart,\n type MessagePartStreamStatus,\n type MessageStatus,\n type PartProviderMetadata,\n type RespondToToolApprovalOptions,\n type ThreadAssistantMessagePart,\n type ThreadMessage,\n type ThreadMessageLike,\n type ThreadUserMessagePart,\n type ToolApprovalDisplay,\n type ToolApprovalOption,\n type ToolCallMessagePart,\n} from \"@assistant-ui/core\";\nimport {\n httpUrlPattern,\n resolveFileMediaType,\n resolveFilePartSource,\n resolveImageMediaType,\n toMediaWireUrl,\n} from \"@assistant-ui/core/internal\";\nimport type {\n EveMessage,\n EveMessagePart,\n EveToolPart,\n Interaction,\n} from \"eve/react\";\nimport type { ConversationState, SessionStreamEvent } from \"eve/client\";\nimport {\n APPROVE_OPTION_ID,\n DENY_OPTION_ID,\n type Answer,\n type InteractionOutcome,\n} from \"eve/events\";\n\nconst ASSISTANT_COMPLETE_STATUS = {\n type: \"complete\",\n reason: \"stop\",\n} satisfies MessageStatus;\n\nconst ASSISTANT_RUNNING_STATUS = {\n type: \"running\",\n} satisfies MessageStatus;\n\nconst ASSISTANT_CANCELLED_STATUS = {\n type: \"incomplete\",\n reason: \"cancelled\",\n} satisfies MessageStatus;\n\nconst USER_FALLBACK_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} satisfies MessageStatus;\n\nexport type ConvertEveMessagesOptions = {\n /**\n * Marks the last assistant message as running while Eve has a turn in\n * flight. When omitted, a message carrying Eve's `\"streaming\"` marker is\n * treated as running; pass `false` to settle interrupted messages to a\n * terminal status.\n */\n readonly isRunning?: boolean | undefined;\n /**\n * The Eve session error, mapped onto the assistant message it interrupted.\n */\n readonly error?: unknown;\n readonly getCreatedAt?: ((message: EveMessage) => Date) | undefined;\n /**\n * The session's stream events. A failed or cancelled turn marks its\n * assistant message as incomplete, with a failure's code and message as its\n * error.\n */\n readonly events?: readonly SessionStreamEvent[] | undefined;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst toJsonObject = (value: unknown): ToolCallMessagePart[\"args\"] => {\n if (isRecord(value)) return value as ToolCallMessagePart[\"args\"];\n if (value === undefined) return {};\n return { value } as ToolCallMessagePart[\"args\"];\n};\n\nconst stringifyArgs = (value: unknown): string => {\n try {\n return JSON.stringify(value ?? {});\n } catch {\n return \"\";\n }\n};\n\nconst toMessageStatus = (\n message: EveMessage,\n index: number,\n messages: readonly EveMessage[],\n options: ConvertEveMessagesOptions,\n interruptedTurns: ReadonlyMap<string, MessageStatus>,\n): MessageStatus => {\n if (message.role !== \"assistant\") return USER_FALLBACK_STATUS;\n\n const interrupted =\n message.metadata?.turnId === undefined\n ? undefined\n : interruptedTurns.get(message.metadata.turnId);\n if (interrupted) return interrupted;\n\n const isLast = index === messages.length - 1;\n const interactions = message.parts.flatMap((part) =>\n part.type === \"interaction\"\n ? [part]\n : part.type === \"tool\" && part.interaction\n ? [part.interaction]\n : [],\n );\n const hasPendingApproval = interactions.some(\n (interaction) =>\n interaction.status === \"open\" && interaction.request.kind !== \"sign-in\",\n );\n // Scoped to the stale-marker case so a terminalized or errored turn keeps its\n // own status; the hold only claims the fall-through that reads as cancelled.\n const hasPendingAuthorization =\n message.metadata?.status === \"streaming\" &&\n (!isLast || options.error === undefined) &&\n interactions.some(\n (interaction) =>\n interaction.status === \"open\" && interaction.request.kind === \"sign-in\",\n );\n\n if (hasPendingApproval) {\n return { type: \"requires-action\", reason: \"tool-calls\" };\n }\n\n // A sign-in is answered outside the thread, so the turn is held on external\n // input rather than on a tool call awaiting a result.\n if (hasPendingAuthorization) {\n return { type: \"requires-action\", reason: \"interrupt\" };\n }\n\n if (message.metadata?.status === \"failed\") {\n return { type: \"incomplete\", reason: \"error\" };\n }\n\n if (isLast && options.isRunning === true) {\n return ASSISTANT_RUNNING_STATUS;\n }\n if (message.metadata?.status === \"streaming\") {\n if (options.isRunning === undefined) {\n return ASSISTANT_RUNNING_STATUS;\n }\n if (isLast && options.error !== undefined) {\n return {\n type: \"incomplete\",\n reason: \"error\",\n error: toAssistantError(options.error),\n };\n }\n return ASSISTANT_CANCELLED_STATUS;\n }\n\n return ASSISTANT_COMPLETE_STATUS;\n};\n\nconst toolApprovalOptionsFromInputRequest = (\n inputRequest: Interaction[\"request\"] | undefined,\n): readonly ToolApprovalOption[] | undefined => {\n const options = inputRequest?.options;\n if (!options || options.length === 0) return undefined;\n\n return options.map((option) => ({\n id: option.id,\n kind:\n option.id === APPROVE_OPTION_ID\n ? \"allow-once\"\n : option.id === DENY_OPTION_ID\n ? \"reject-once\"\n : `_${option.id}`,\n ...(option.label && { label: option.label }),\n ...(option.description && { description: option.description }),\n }));\n};\n\n/**\n * Eve resolves an interaction the moment any answer for it arrives, so the\n * answer shapes it accepts decide both what the renderer may offer and what\n * {@link toEveInputResponse} may submit. A request with no options and no\n * `display` takes a typed answer, which is why the absence of both is not the\n * same as a confirmation.\n */\nconst isDroppedOptionApproval = (inputRequest: Interaction[\"request\"]) =>\n inputRequest.kind === \"approval\" && !inputRequest.options?.length;\n\nconst acceptsFreeformAnswer = (inputRequest: Interaction[\"request\"]): boolean =>\n inputRequest.display !== \"confirmation\" &&\n !isDroppedOptionApproval(inputRequest) &&\n (inputRequest.display === \"text\" ||\n inputRequest.allowFreeform === true ||\n !inputRequest.options?.length);\n\nconst toolApprovalDisplay = (\n inputRequest: Interaction[\"request\"],\n): ToolApprovalDisplay => {\n // The mapper answers this shape through its approve/cancel branch whatever\n // the request declares, so the projection has to agree: presenting it as a\n // question would offer an answer the mapper turns into a decision.\n if (isDroppedOptionApproval(inputRequest)) return \"decision\";\n\n switch (inputRequest.display) {\n case \"confirmation\":\n return \"decision\";\n case \"select\":\n return \"select\";\n case \"text\":\n return \"text\";\n default:\n if (inputRequest.kind === \"approval\") return \"decision\";\n return inputRequest.options?.length ? \"select\" : \"text\";\n }\n};\n\nconst toApproval = (\n interaction: Interaction,\n): NonNullable<ToolCallMessagePart[\"approval\"]> => {\n const request = interaction.request;\n const options = toolApprovalOptionsFromInputRequest(request);\n const settled = interaction.status === \"settled\";\n const approved =\n interaction.outcome === \"accepted\"\n ? true\n : interaction.outcome === \"declined\"\n ? false\n : undefined;\n\n return {\n id: interaction.interactionId,\n prompt: request.prompt,\n display: toolApprovalDisplay(request),\n ...(acceptsFreeformAnswer(request) && { allowFreeform: true }),\n ...(settled && approved !== undefined && { approved }),\n ...(settled &&\n approved === undefined && {\n resolution:\n interaction.outcome === \"expired\"\n ? (\"expired\" as const)\n : (\"cancelled\" as const),\n }),\n ...(interaction.reason && { reason: interaction.reason }),\n ...(settled &&\n interaction.answer?.optionId !== undefined && {\n optionId: interaction.answer.optionId,\n }),\n ...(settled &&\n interaction.answer?.text !== undefined && {\n text: interaction.answer.text,\n }),\n ...(options && { options }),\n };\n};\n\nconst toToolProviderMetadata = (\n interaction: Interaction,\n): PartProviderMetadata => {\n const request = interaction.request;\n return {\n eve: {\n interaction: {\n interactionId: interaction.interactionId,\n prompt: request.prompt,\n kind: request.kind,\n ...(request.display !== undefined && { display: request.display }),\n ...(request.allowFreeform !== undefined && {\n allowFreeform: request.allowFreeform,\n }),\n ...(request.options && {\n options: request.options.map((option) => ({ ...option })),\n }),\n },\n },\n };\n};\n\nconst convertToolPart = (\n part: EveToolPart,\n): Omit<ToolCallMessagePart, \"args\"> &\n Partial<Pick<ToolCallMessagePart, \"args\">> => {\n const toolCall: ReturnType<typeof convertToolPart> = {\n type: \"tool-call\",\n toolCallId: part.callId,\n toolName: part.name,\n ...(part.state !== \"streaming\" && { args: toJsonObject(part.input) }),\n argsText:\n part.state === \"streaming\" ? part.inputText : stringifyArgs(part.input),\n ...(part.interaction && {\n approval: toApproval(part.interaction),\n providerMetadata: toToolProviderMetadata(part.interaction),\n }),\n };\n\n switch (part.state) {\n case \"completed\":\n return { ...toolCall, result: part.output };\n case \"failed\":\n case \"rejected\":\n case \"cancelled\":\n return {\n ...toolCall,\n result: {\n error:\n part.error?.message ??\n part.interaction?.reason ??\n (part.state === \"rejected\"\n ? \"Tool approval denied\"\n : part.state === \"cancelled\"\n ? \"Tool call cancelled\"\n : \"Tool call failed\"),\n },\n isError: true,\n };\n default:\n return part.output === undefined\n ? toolCall\n : { ...toolCall, result: part.output, isPreliminary: true };\n }\n};\n\n/**\n * Payload of the `authorization` data part the Eve runtime emits for a sign-in\n * interaction. `state` discriminates a pending sign-in from a settled one;\n * every other field is present only when Eve projected it. This converter\n * drops a `url` whose scheme is not `http(s)`, so a renderer can link to it\n * without checking the scheme itself; Eve itself passes through whatever the\n * connector supplied.\n */\nexport type EveAuthorizationData = {\n readonly state: \"required\" | \"completed\";\n readonly name: string;\n readonly displayName?: string;\n readonly description?: string;\n readonly url?: string;\n readonly userCode?: string;\n readonly instructions?: string;\n readonly expiresAt?: string;\n readonly outcome?:\n | \"authorized\"\n | \"declined\"\n | \"failed\"\n | \"timed-out\"\n | \"cancelled\";\n readonly reason?: string;\n};\n\nconst toAuthorizationOutcome = (\n outcome: InteractionOutcome,\n): NonNullable<EveAuthorizationData[\"outcome\"]> => {\n switch (outcome) {\n case \"accepted\":\n return \"authorized\";\n case \"declined\":\n case \"invalid\":\n return \"declined\";\n case \"expired\":\n return \"timed-out\";\n case \"failed\":\n return \"failed\";\n default:\n return \"cancelled\";\n }\n};\n\nconst convertAuthorizationPart = (\n interaction: Interaction,\n): DataMessagePart<EveAuthorizationData> => {\n const signIn = interaction.request.signIn;\n return {\n type: \"data\",\n name: \"authorization\",\n data: {\n state: interaction.status === \"open\" ? \"required\" : \"completed\",\n name: signIn?.name ?? interaction.request.title ?? \"sign-in\",\n ...(signIn?.displayName !== undefined && {\n displayName: signIn.displayName,\n }),\n description: interaction.request.prompt,\n ...(signIn?.url !== undefined &&\n httpUrlPattern.test(signIn.url) && { url: signIn.url }),\n ...(signIn?.userCode !== undefined && { userCode: signIn.userCode }),\n ...(signIn?.instructions !== undefined && {\n instructions: signIn.instructions,\n }),\n ...(signIn?.expiresAt !== undefined && { expiresAt: signIn.expiresAt }),\n ...(interaction.outcome !== undefined && {\n outcome: toAuthorizationOutcome(interaction.outcome),\n }),\n ...(interaction.reason !== undefined && { reason: interaction.reason }),\n },\n };\n};\n\nconst convertInteractionPart = (\n interaction: Interaction,\n): ThreadAssistantMessagePart => {\n if (interaction.request.kind === \"sign-in\")\n return convertAuthorizationPart(interaction);\n const approval = toApproval(interaction);\n return {\n type: \"tool-call\",\n toolCallId: interaction.interactionId,\n toolName: interaction.call?.name ?? interaction.request.kind,\n args: toJsonObject(interaction.call?.input),\n argsText: stringifyArgs(interaction.call?.input),\n approval,\n providerMetadata: toToolProviderMetadata(interaction),\n ...(interaction.status === \"settled\" && {\n result: interaction.answer ?? {\n outcome: interaction.outcome,\n reason: interaction.reason,\n },\n ...(interaction.outcome !== \"accepted\" && { isError: true }),\n }),\n };\n};\n\nconst convertFilePart = (\n part: Extract<EveMessagePart, { type: \"file\" }>,\n): FileMessagePart | null => {\n if (part.url === undefined) return null;\n return {\n type: \"file\",\n data: part.url,\n mimeType: resolveFileMediaType(part.url, part.mediaType),\n ...(part.filename && { filename: part.filename }),\n ...(httpUrlPattern.test(part.url) && { sourceType: \"url\" as const }),\n };\n};\nconst partStateToStatus = (\n state: \"done\" | \"streaming\" | undefined,\n): MessagePartStreamStatus | undefined =>\n state === \"done\" ? { type: \"complete\" } : undefined;\n\nconst convertAssistantPart = (\n part: EveMessagePart,\n): ThreadAssistantMessagePart | ReturnType<typeof convertToolPart> | null => {\n switch (part.type) {\n case \"text\":\n case \"reasoning\": {\n const status = partStateToStatus(part.state);\n return {\n type: part.type,\n text: part.text,\n ...(status && { status }),\n };\n }\n\n case \"tool\":\n return convertToolPart(part);\n\n case \"interaction\":\n return convertInteractionPart(part);\n\n case \"file\":\n return convertFilePart(part);\n\n default:\n return null;\n }\n};\n\nconst convertUserPart = (\n part: EveMessagePart,\n): ThreadUserMessagePart | null => {\n switch (part.type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n default:\n return null;\n }\n};\n\nconst toUserContent = (\n parts: readonly EveMessagePart[],\n attachments: readonly CompleteAttachment[],\n): readonly ThreadUserMessagePart[] => {\n const content = parts.map(convertUserPart).filter((part) => part !== null);\n return content.length > 0 || attachments.length > 0\n ? content\n : [{ type: \"text\", text: \"\" }];\n};\n\nconst toUserAttachments = (\n parts: readonly EveMessagePart[],\n): CompleteAttachment[] => {\n const attachments: CompleteAttachment[] = [];\n for (const part of parts) {\n if (part.type !== \"file\") continue;\n const file = convertFilePart(part);\n if (file === null) continue;\n const isImage = file.mimeType.startsWith(\"image/\");\n attachments.push({\n id: String(attachments.length),\n type: isImage ? \"image\" : \"file\",\n name: part.filename ?? \"file\",\n content: [\n isImage\n ? {\n type: \"image\",\n image: file.data,\n ...(part.filename && { filename: part.filename }),\n }\n : file,\n ],\n contentType: file.mimeType,\n status: { type: \"complete\" },\n });\n }\n return attachments;\n};\n\n/**\n * Converts a single Eve message into an assistant-ui thread message.\n */\nexport const convertEveMessage = (\n message: EveMessage,\n index: number,\n messages: readonly EveMessage[],\n options: ConvertEveMessagesOptions = {},\n): ThreadMessage =>\n convertEveMessageWithInterruptions(\n message,\n index,\n messages,\n options,\n getInterruptedTurns(options.events),\n );\n\nconst convertEveMessageWithInterruptions = (\n message: EveMessage,\n index: number,\n messages: readonly EveMessage[],\n options: ConvertEveMessagesOptions,\n interruptedTurns: ReadonlyMap<string, MessageStatus>,\n): ThreadMessage => {\n const createdAt = options.getCreatedAt?.(message) ?? new Date();\n const metadata = {\n ...(message.metadata?.optimistic && { isOptimistic: true }),\n custom: {\n ...(message.metadata ?? {}),\n },\n };\n\n const attachments =\n message.role === \"user\" ? toUserAttachments(message.parts) : [];\n const like: ThreadMessageLike =\n message.role === \"user\"\n ? {\n role: \"user\",\n id: message.id,\n createdAt,\n content: toUserContent(message.parts, attachments),\n attachments,\n metadata,\n }\n : {\n role: \"assistant\",\n id: message.id,\n createdAt,\n content: message.parts\n .map(convertAssistantPart)\n .filter((part) => part !== null),\n metadata,\n };\n\n return fromThreadMessageLike(\n like,\n message.id,\n toMessageStatus(message, index, messages, options, interruptedTurns),\n );\n};\n\nexport type InterruptedTurnEventCache = {\n lastEvents: readonly SessionStreamEvent[];\n interruptions: readonly SessionStreamEvent[];\n};\n\nconst isTurnInterruption = (event: SessionStreamEvent) =>\n (event.type === \"turn.settled\" && event.data.outcome !== \"completed\") ||\n (event.type === \"session.ended\" && event.data.outcome === \"failed\");\n\nexport const collectInterruptedTurnEvents = (\n events: readonly SessionStreamEvent[],\n cache: InterruptedTurnEventCache,\n): readonly SessionStreamEvent[] => {\n if (events === cache.lastEvents) return cache.interruptions;\n\n const scanned = cache.lastEvents;\n const resumesScan =\n scanned.length === 0 ||\n events[scanned.length - 1] === scanned[scanned.length - 1];\n\n const interruptions = resumesScan ? cache.interruptions : [];\n let nextInterruptions: SessionStreamEvent[] | undefined;\n for (let i = resumesScan ? scanned.length : 0; i < events.length; i++) {\n const event = events[i]!;\n if (isTurnInterruption(event)) {\n nextInterruptions ??= [...interruptions];\n nextInterruptions.push(event);\n }\n }\n\n cache.lastEvents = events;\n cache.interruptions = nextInterruptions ?? interruptions;\n return cache.interruptions;\n};\n\nconst getInterruptedTurns = (\n events: readonly SessionStreamEvent[] | undefined,\n) => {\n const interrupted = new Map<string, MessageStatus>();\n const sessionFailures = new Map<string, MessageStatus>();\n for (const event of events ?? []) {\n if (event.type === \"turn.settled\" && event.data.outcome === \"failed\") {\n interrupted.set(event.data.turnId, {\n type: \"incomplete\",\n reason: \"error\",\n ...(event.data.error && { error: toAssistantError(event.data.error) }),\n });\n } else if (\n event.type === \"turn.settled\" &&\n event.data.outcome === \"cancelled\"\n ) {\n interrupted.set(event.data.turnId, ASSISTANT_CANCELLED_STATUS);\n } else if (\n event.type === \"session.ended\" &&\n event.data.outcome === \"failed\" &&\n event.data.cause &&\n \"turnId\" in event.data.cause\n ) {\n sessionFailures.set(event.data.cause.turnId, {\n type: \"incomplete\",\n reason: \"error\",\n ...(event.data.error && { error: toAssistantError(event.data.error) }),\n });\n }\n }\n for (const [turnId, status] of sessionFailures)\n interrupted.set(turnId, status);\n return interrupted;\n};\n\n/**\n * Converts Eve's conversation messages into assistant-ui thread messages.\n */\nexport const convertEveMessages = (\n data: Pick<ConversationState, \"messages\">,\n options: ConvertEveMessagesOptions = {},\n): ThreadMessage[] => {\n const interruptedTurns = getInterruptedTurns(options.events);\n return data.messages.map((message, index, messages) =>\n convertEveMessageWithInterruptions(\n message,\n index,\n messages,\n options,\n interruptedTurns,\n ),\n );\n};\n\n/**\n * Structural subset of the message content Eve's `send` API accepts. The\n * helpers declare the shapes they produce and leave assignability to the send\n * call site, checked against the installed version.\n */\nexport type EveMessageContent =\n | string\n | (\n | { readonly type: \"text\"; readonly text: string }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mediaType: string;\n readonly filename?: string;\n }\n )[];\n\ntype OutboundPart = AppendMessage[\"content\"][number] & {\n readonly contentType?: string | undefined;\n};\n\n/**\n * Converts an assistant-ui append message into the message payload accepted by\n * Eve's `send` API.\n */\nexport const getEveMessageContent = (\n message: AppendMessage,\n): EveMessageContent => {\n const content: OutboundPart[] = [\n ...message.content,\n ...(message.attachments?.flatMap((attachment) =>\n attachment.content.map((part) => ({\n ...part,\n contentType: attachment.contentType,\n })),\n ) ?? []),\n ];\n\n const parts = content.flatMap((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n\n case \"file\": {\n const mediaType = resolveFileMediaType(\n part.data,\n part.mimeType || part.contentType,\n );\n return {\n type: \"file\" as const,\n data:\n part.sourceType === \"id\"\n ? part.data\n : toMediaWireUrl(part.data, mediaType),\n mediaType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n\n case \"image\": {\n const mediaType = resolveImageMediaType(part.image, part.contentType);\n return {\n type: \"file\" as const,\n data: toMediaWireUrl(part.image, mediaType),\n mediaType,\n ...(part.filename && { filename: part.filename }),\n };\n }\n\n case \"audio\": {\n const mediaType = `audio/${part.audio.format}`;\n const data = part.audio.data;\n const source = resolveFilePartSource({ data, mimeType: mediaType });\n return {\n type: \"file\" as const,\n data:\n source.kind === \"url\"\n ? source.url\n : `data:${mediaType};base64,${source.data}`,\n mediaType,\n };\n }\n\n case \"data\":\n return [];\n\n default: {\n const _exhaustiveCheck:\n | \"generative-ui\"\n | \"reasoning\"\n | \"source\"\n | \"tool-call\" = type;\n throw new Error(\n `Unsupported eve append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (parts.length === 1 && parts[0]?.type === \"text\") {\n return parts[0].text;\n }\n\n return parts;\n};\n\n/**\n * Finds the request of the interaction answered by the given approval id, so\n * the answer mapping can honor the request's display mode.\n */\nexport const findEveInputRequest = (\n data: Pick<ConversationState, \"messages\">,\n approvalId: string,\n): Interaction[\"request\"] | undefined => {\n for (const message of data.messages) {\n for (const part of message.parts) {\n const interaction =\n part.type === \"interaction\"\n ? part\n : part.type === \"tool\"\n ? part.interaction\n : undefined;\n if (interaction?.interactionId === approvalId) return interaction.request;\n }\n }\n return undefined;\n};\n\n/**\n * Converts an assistant-ui tool approval response into an Eve `Answer`.\n *\n * When `inputRequest` is known, every returned answer carries an option the\n * request declares, the literal `\"approve\"` / `\"deny\"` for an approval that\n * declares no options, or a free-form answer. A literal option match wins,\n * then the `\"approve\"` / `\"deny\"` option the response's boolean decision\n * names, then the response's `text` (or its `reason`, for a caller that\n * predates the first-class answer field) when the request takes a free-form\n * answer (`display: \"text\"`, `allowFreeform`, or no options at all, and never\n * `display: \"confirmation\"`) and the response is not a refusal.\n *\n * A response the known request cannot record as the answer it asked for throws\n * instead of being submitted, because Eve resolves an interaction the moment\n * any answer for it arrives, and an empty one is recorded as an answer with no\n * content. Not sending leaves the interaction open, so the caller can retry or\n * the user can answer it as an ordinary message.\n *\n * With no request to map against, a one-argument call forwards a caller\n * `optionId` as is and otherwise maps the decision to the literal `\"approve\"` /\n * `\"deny\"` option every Eve approval declares.\n */\nexport const toEveInputResponse = (\n response: RespondToToolApprovalOptions,\n inputRequest?: Interaction[\"request\"],\n): Answer => {\n const interactionId = response.approvalId;\n const options = inputRequest?.options;\n const text = response.text ?? response.reason;\n\n if (response.optionId !== undefined) {\n if (\n !inputRequest ||\n options?.some((option) => option.id === response.optionId)\n ) {\n return {\n interactionId,\n optionId: response.optionId,\n ...(text && { text }),\n };\n }\n throw new Error(\n `Eve interaction \"${interactionId}\" has no option with id \"${response.optionId}\"; respond with one of: ${\n options?.length\n ? options.map((option) => option.id).join(\", \")\n : \"(the request carries no options)\"\n }`,\n );\n }\n\n const decisionOptionId = response.approved\n ? APPROVE_OPTION_ID\n : DENY_OPTION_ID;\n if (\n !inputRequest ||\n (inputRequest.kind === \"approval\" && !options?.length) ||\n options?.some((option) => option.id === decisionOptionId)\n ) {\n return { interactionId, optionId: decisionOptionId, ...(text && { text }) };\n }\n const acceptsText = acceptsFreeformAnswer(inputRequest);\n if (acceptsText && text && response.approved !== false) {\n return { interactionId, text };\n }\n\n throw new Error(\n `Eve interaction \"${interactionId}\" (${inputRequest.prompt}) was not answered by this response; ${\n options?.length\n ? `respond with one of: ${options.map((option) => option.id).join(\", \")}`\n : !acceptsText\n ? \"the request declares no options to respond with\"\n : response.approved === false\n ? \"a refusal carries no answer for a free-form request; resend with `approved` unset or true and the answer in the response text\"\n : \"pass the answer as the response text, because the request takes a free-form answer\"\n }`,\n );\n};\n"],"mappings":";;;;AAwCA,MAAM,4BAA4B;CAChC,MAAM;CACN,QAAQ;AACV;AAEA,MAAM,2BAA2B,EAC/B,MAAM,UACR;AAEA,MAAM,6BAA6B;CACjC,MAAM;CACN,QAAQ;AACV;AAEA,MAAM,uBAAuB;CAC3B,MAAM;CACN,QAAQ;AACV;AAuBA,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,MAAM,gBAAgB,UAAgD;CACpE,IAAI,SAAS,KAAK,GAAG,OAAO;CAC5B,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC;CACjC,OAAO,EAAE,MAAM;AACjB;AAEA,MAAM,iBAAiB,UAA2B;CAChD,IAAI;EACF,OAAO,KAAK,UAAU,SAAS,CAAC,CAAC;CACnC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,mBACJ,SACA,OACA,UACA,SACA,qBACkB;CAClB,IAAI,QAAQ,SAAS,aAAa,OAAO;CAEzC,MAAM,cACJ,QAAQ,UAAU,WAAW,KAAA,IACzB,KAAA,IACA,iBAAiB,IAAI,QAAQ,SAAS,MAAM;CAClD,IAAI,aAAa,OAAO;CAExB,MAAM,SAAS,UAAU,SAAS,SAAS;CAC3C,MAAM,eAAe,QAAQ,MAAM,SAAS,SAC1C,KAAK,SAAS,gBACV,CAAC,IAAI,IACL,KAAK,SAAS,UAAU,KAAK,cAC3B,CAAC,KAAK,WAAW,IACjB,CAAC,CACT;CACA,MAAM,qBAAqB,aAAa,MACrC,gBACC,YAAY,WAAW,UAAU,YAAY,QAAQ,SAAS,SAClE;CAGA,MAAM,0BACJ,QAAQ,UAAU,WAAW,gBAC5B,CAAC,UAAU,QAAQ,UAAU,KAAA,MAC9B,aAAa,MACV,gBACC,YAAY,WAAW,UAAU,YAAY,QAAQ,SAAS,SAClE;CAEF,IAAI,oBACF,OAAO;EAAE,MAAM;EAAmB,QAAQ;CAAa;CAKzD,IAAI,yBACF,OAAO;EAAE,MAAM;EAAmB,QAAQ;CAAY;CAGxD,IAAI,QAAQ,UAAU,WAAW,UAC/B,OAAO;EAAE,MAAM;EAAc,QAAQ;CAAQ;CAG/C,IAAI,UAAU,QAAQ,cAAc,MAClC,OAAO;CAET,IAAI,QAAQ,UAAU,WAAW,aAAa;EAC5C,IAAI,QAAQ,cAAc,KAAA,GACxB,OAAO;EAET,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;GACL,MAAM;GACN,QAAQ;GACR,OAAO,iBAAiB,QAAQ,KAAK;EACvC;EAEF,OAAO;CACT;CAEA,OAAO;AACT;AAEA,MAAM,uCACJ,iBAC8C;CAC9C,MAAM,UAAU,cAAc;CAC9B,IAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,OAAO,KAAA;CAE7C,OAAO,QAAQ,KAAK,YAAY;EAC9B,IAAI,OAAO;EACX,MACE,OAAO,OAAO,oBACV,eACA,OAAO,OAAO,iBACZ,gBACA,IAAI,OAAO;EACnB,GAAI,OAAO,SAAS,EAAE,OAAO,OAAO,MAAM;EAC1C,GAAI,OAAO,eAAe,EAAE,aAAa,OAAO,YAAY;CAC9D,EAAE;AACJ;;;;;;;;AASA,MAAM,2BAA2B,iBAC/B,aAAa,SAAS,cAAc,CAAC,aAAa,SAAS;AAE7D,MAAM,yBAAyB,iBAC7B,aAAa,YAAY,kBACzB,CAAC,wBAAwB,YAAY,MACpC,aAAa,YAAY,UACxB,aAAa,kBAAkB,QAC/B,CAAC,aAAa,SAAS;AAE3B,MAAM,uBACJ,iBACwB;CAIxB,IAAI,wBAAwB,YAAY,GAAG,OAAO;CAElD,QAAQ,aAAa,SAArB;EACE,KAAK,gBACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT;GACE,IAAI,aAAa,SAAS,YAAY,OAAO;GAC7C,OAAO,aAAa,SAAS,SAAS,WAAW;CACrD;AACF;AAEA,MAAM,cACJ,gBACiD;CACjD,MAAM,UAAU,YAAY;CAC5B,MAAM,UAAU,oCAAoC,OAAO;CAC3D,MAAM,UAAU,YAAY,WAAW;CACvC,MAAM,WACJ,YAAY,YAAY,aACpB,OACA,YAAY,YAAY,aACtB,QACA,KAAA;CAER,OAAO;EACL,IAAI,YAAY;EAChB,QAAQ,QAAQ;EAChB,SAAS,oBAAoB,OAAO;EACpC,GAAI,sBAAsB,OAAO,KAAK,EAAE,eAAe,KAAK;EAC5D,GAAI,WAAW,aAAa,KAAA,KAAa,EAAE,SAAS;EACpD,GAAI,WACF,aAAa,KAAA,KAAa,EACxB,YACE,YAAY,YAAY,YACnB,YACA,YACT;EACF,GAAI,YAAY,UAAU,EAAE,QAAQ,YAAY,OAAO;EACvD,GAAI,WACF,YAAY,QAAQ,aAAa,KAAA,KAAa,EAC5C,UAAU,YAAY,OAAO,SAC/B;EACF,GAAI,WACF,YAAY,QAAQ,SAAS,KAAA,KAAa,EACxC,MAAM,YAAY,OAAO,KAC3B;EACF,GAAI,WAAW,EAAE,QAAQ;CAC3B;AACF;AAEA,MAAM,0BACJ,gBACyB;CACzB,MAAM,UAAU,YAAY;CAC5B,OAAO,EACL,KAAK,EACH,aAAa;EACX,eAAe,YAAY;EAC3B,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,SAAS,QAAQ,QAAQ;EAChE,GAAI,QAAQ,kBAAkB,KAAA,KAAa,EACzC,eAAe,QAAQ,cACzB;EACA,GAAI,QAAQ,WAAW,EACrB,SAAS,QAAQ,QAAQ,KAAK,YAAY,EAAE,GAAG,OAAO,EAAE,EAC1D;CACF,EACF,EACF;AACF;AAEA,MAAM,mBACJ,SAE8C;CAC9C,MAAM,WAA+C;EACnD,MAAM;EACN,YAAY,KAAK;EACjB,UAAU,KAAK;EACf,GAAI,KAAK,UAAU,eAAe,EAAE,MAAM,aAAa,KAAK,KAAK,EAAE;EACnE,UACE,KAAK,UAAU,cAAc,KAAK,YAAY,cAAc,KAAK,KAAK;EACxE,GAAI,KAAK,eAAe;GACtB,UAAU,WAAW,KAAK,WAAW;GACrC,kBAAkB,uBAAuB,KAAK,WAAW;EAC3D;CACF;CAEA,QAAQ,KAAK,OAAb;EACE,KAAK,aACH,OAAO;GAAE,GAAG;GAAU,QAAQ,KAAK;EAAO;EAC5C,KAAK;EACL,KAAK;EACL,KAAK,aACH,OAAO;GACL,GAAG;GACH,QAAQ,EACN,OACE,KAAK,OAAO,WACZ,KAAK,aAAa,WACjB,KAAK,UAAU,aACZ,yBACA,KAAK,UAAU,cACb,wBACA,oBACV;GACA,SAAS;EACX;EACF,SACE,OAAO,KAAK,WAAW,KAAA,IACnB,WACA;GAAE,GAAG;GAAU,QAAQ,KAAK;GAAQ,eAAe;EAAK;CAChE;AACF;AA4BA,MAAM,0BACJ,YACiD;CACjD,QAAQ,SAAR;EACE,KAAK,YACH,OAAO;EACT,KAAK;EACL,KAAK,WACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,MAAM,4BACJ,gBAC0C;CAC1C,MAAM,SAAS,YAAY,QAAQ;CACnC,OAAO;EACL,MAAM;EACN,MAAM;EACN,MAAM;GACJ,OAAO,YAAY,WAAW,SAAS,aAAa;GACpD,MAAM,QAAQ,QAAQ,YAAY,QAAQ,SAAS;GACnD,GAAI,QAAQ,gBAAgB,KAAA,KAAa,EACvC,aAAa,OAAO,YACtB;GACA,aAAa,YAAY,QAAQ;GACjC,GAAI,QAAQ,QAAQ,KAAA,KAClB,eAAe,KAAK,OAAO,GAAG,KAAK,EAAE,KAAK,OAAO,IAAI;GACvD,GAAI,QAAQ,aAAa,KAAA,KAAa,EAAE,UAAU,OAAO,SAAS;GAClE,GAAI,QAAQ,iBAAiB,KAAA,KAAa,EACxC,cAAc,OAAO,aACvB;GACA,GAAI,QAAQ,cAAc,KAAA,KAAa,EAAE,WAAW,OAAO,UAAU;GACrE,GAAI,YAAY,YAAY,KAAA,KAAa,EACvC,SAAS,uBAAuB,YAAY,OAAO,EACrD;GACA,GAAI,YAAY,WAAW,KAAA,KAAa,EAAE,QAAQ,YAAY,OAAO;EACvE;CACF;AACF;AAEA,MAAM,0BACJ,gBAC+B;CAC/B,IAAI,YAAY,QAAQ,SAAS,WAC/B,OAAO,yBAAyB,WAAW;CAC7C,MAAM,WAAW,WAAW,WAAW;CACvC,OAAO;EACL,MAAM;EACN,YAAY,YAAY;EACxB,UAAU,YAAY,MAAM,QAAQ,YAAY,QAAQ;EACxD,MAAM,aAAa,YAAY,MAAM,KAAK;EAC1C,UAAU,cAAc,YAAY,MAAM,KAAK;EAC/C;EACA,kBAAkB,uBAAuB,WAAW;EACpD,GAAI,YAAY,WAAW,aAAa;GACtC,QAAQ,YAAY,UAAU;IAC5B,SAAS,YAAY;IACrB,QAAQ,YAAY;GACtB;GACA,GAAI,YAAY,YAAY,cAAc,EAAE,SAAS,KAAK;EAC5D;CACF;AACF;AAEA,MAAM,mBACJ,SAC2B;CAC3B,IAAI,KAAK,QAAQ,KAAA,GAAW,OAAO;CACnC,OAAO;EACL,MAAM;EACN,MAAM,KAAK;EACX,UAAU,qBAAqB,KAAK,KAAK,KAAK,SAAS;EACvD,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;EAC/C,GAAI,eAAe,KAAK,KAAK,GAAG,KAAK,EAAE,YAAY,MAAe;CACpE;AACF;AACA,MAAM,qBACJ,UAEA,UAAU,SAAS,EAAE,MAAM,WAAW,IAAI,KAAA;AAE5C,MAAM,wBACJ,SAC2E;CAC3E,QAAQ,KAAK,MAAb;EACE,KAAK;EACL,KAAK,aAAa;GAChB,MAAM,SAAS,kBAAkB,KAAK,KAAK;GAC3C,OAAO;IACL,MAAM,KAAK;IACX,MAAM,KAAK;IACX,GAAI,UAAU,EAAE,OAAO;GACzB;EACF;EAEA,KAAK,QACH,OAAO,gBAAgB,IAAI;EAE7B,KAAK,eACH,OAAO,uBAAuB,IAAI;EAEpC,KAAK,QACH,OAAO,gBAAgB,IAAI;EAE7B,SACE,OAAO;CACX;AACF;AAEA,MAAM,mBACJ,SACiC;CACjC,QAAQ,KAAK,MAAb;EACE,KAAK,QACH,OAAO;GAAE,MAAM;GAAQ,MAAM,KAAK;EAAK;EAEzC,SACE,OAAO;CACX;AACF;AAEA,MAAM,iBACJ,OACA,gBACqC;CACrC,MAAM,UAAU,MAAM,IAAI,eAAe,CAAC,CAAC,QAAQ,SAAS,SAAS,IAAI;CACzE,OAAO,QAAQ,SAAS,KAAK,YAAY,SAAS,IAC9C,UACA,CAAC;EAAE,MAAM;EAAQ,MAAM;CAAG,CAAC;AACjC;AAEA,MAAM,qBACJ,UACyB;CACzB,MAAM,cAAoC,CAAC;CAC3C,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,SAAS,QAAQ;EAC1B,MAAM,OAAO,gBAAgB,IAAI;EACjC,IAAI,SAAS,MAAM;EACnB,MAAM,UAAU,KAAK,SAAS,WAAW,QAAQ;EACjD,YAAY,KAAK;GACf,IAAI,OAAO,YAAY,MAAM;GAC7B,MAAM,UAAU,UAAU;GAC1B,MAAM,KAAK,YAAY;GACvB,SAAS,CACP,UACI;IACE,MAAM;IACN,OAAO,KAAK;IACZ,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;GACjD,IACA,IACN;GACA,aAAa,KAAK;GAClB,QAAQ,EAAE,MAAM,WAAW;EAC7B,CAAC;CACH;CACA,OAAO;AACT;;;;AAKA,MAAa,qBACX,SACA,OACA,UACA,UAAqC,CAAC,MAEtC,mCACE,SACA,OACA,UACA,SACA,oBAAoB,QAAQ,MAAM,CACpC;AAEF,MAAM,sCACJ,SACA,OACA,UACA,SACA,qBACkB;CAClB,MAAM,YAAY,QAAQ,eAAe,OAAO,qBAAK,IAAI,KAAK;CAC9D,MAAM,WAAW;EACf,GAAI,QAAQ,UAAU,cAAc,EAAE,cAAc,KAAK;EACzD,QAAQ,EACN,GAAI,QAAQ,YAAY,CAAC,EAC3B;CACF;CAEA,MAAM,cACJ,QAAQ,SAAS,SAAS,kBAAkB,QAAQ,KAAK,IAAI,CAAC;CAChE,MAAM,OACJ,QAAQ,SAAS,SACb;EACE,MAAM;EACN,IAAI,QAAQ;EACZ;EACA,SAAS,cAAc,QAAQ,OAAO,WAAW;EACjD;EACA;CACF,IACA;EACE,MAAM;EACN,IAAI,QAAQ;EACZ;EACA,SAAS,QAAQ,MACd,IAAI,oBAAoB,CAAC,CACzB,QAAQ,SAAS,SAAS,IAAI;EACjC;CACF;CAEN,OAAO,sBACL,MACA,QAAQ,IACR,gBAAgB,SAAS,OAAO,UAAU,SAAS,gBAAgB,CACrE;AACF;AAOA,MAAM,sBAAsB,UACzB,MAAM,SAAS,kBAAkB,MAAM,KAAK,YAAY,eACxD,MAAM,SAAS,mBAAmB,MAAM,KAAK,YAAY;AAE5D,MAAa,gCACX,QACA,UACkC;CAClC,IAAI,WAAW,MAAM,YAAY,OAAO,MAAM;CAE9C,MAAM,UAAU,MAAM;CACtB,MAAM,cACJ,QAAQ,WAAW,KACnB,OAAO,QAAQ,SAAS,OAAO,QAAQ,QAAQ,SAAS;CAE1D,MAAM,gBAAgB,cAAc,MAAM,gBAAgB,CAAC;CAC3D,IAAI;CACJ,KAAK,IAAI,IAAI,cAAc,QAAQ,SAAS,GAAG,IAAI,OAAO,QAAQ,KAAK;EACrE,MAAM,QAAQ,OAAO;EACrB,IAAI,mBAAmB,KAAK,GAAG;GAC7B,sBAAsB,CAAC,GAAG,aAAa;GACvC,kBAAkB,KAAK,KAAK;EAC9B;CACF;CAEA,MAAM,aAAa;CACnB,MAAM,gBAAgB,qBAAqB;CAC3C,OAAO,MAAM;AACf;AAEA,MAAM,uBACJ,WACG;CACH,MAAM,8BAAc,IAAI,IAA2B;CACnD,MAAM,kCAAkB,IAAI,IAA2B;CACvD,KAAK,MAAM,SAAS,UAAU,CAAC,GAC7B,IAAI,MAAM,SAAS,kBAAkB,MAAM,KAAK,YAAY,UAC1D,YAAY,IAAI,MAAM,KAAK,QAAQ;EACjC,MAAM;EACN,QAAQ;EACR,GAAI,MAAM,KAAK,SAAS,EAAE,OAAO,iBAAiB,MAAM,KAAK,KAAK,EAAE;CACtE,CAAC;MACI,IACL,MAAM,SAAS,kBACf,MAAM,KAAK,YAAY,aAEvB,YAAY,IAAI,MAAM,KAAK,QAAQ,0BAA0B;MACxD,IACL,MAAM,SAAS,mBACf,MAAM,KAAK,YAAY,YACvB,MAAM,KAAK,SACX,YAAY,MAAM,KAAK,OAEvB,gBAAgB,IAAI,MAAM,KAAK,MAAM,QAAQ;EAC3C,MAAM;EACN,QAAQ;EACR,GAAI,MAAM,KAAK,SAAS,EAAE,OAAO,iBAAiB,MAAM,KAAK,KAAK,EAAE;CACtE,CAAC;CAGL,KAAK,MAAM,CAAC,QAAQ,WAAW,iBAC7B,YAAY,IAAI,QAAQ,MAAM;CAChC,OAAO;AACT;;;;AAKA,MAAa,sBACX,MACA,UAAqC,CAAC,MAClB;CACpB,MAAM,mBAAmB,oBAAoB,QAAQ,MAAM;CAC3D,OAAO,KAAK,SAAS,KAAK,SAAS,OAAO,aACxC,mCACE,SACA,OACA,UACA,SACA,gBACF,CACF;AACF;;;;;AA2BA,MAAa,wBACX,YACsB;CAWtB,MAAM,QAAQ,CATZ,GAAG,QAAQ,SACX,GAAI,QAAQ,aAAa,SAAS,eAChC,WAAW,QAAQ,KAAK,UAAU;EAChC,GAAG;EACH,aAAa,WAAW;CAC1B,EAAE,CACJ,KAAK,CAAC,CAGY,CAAC,CAAC,SAAS,SAAS;EACtC,MAAM,OAAO,KAAK;EAClB,QAAQ,MAAR;GACE,KAAK,QACH,OAAO;IAAE,MAAM;IAAiB,MAAM,KAAK;GAAK;GAElD,KAAK,QAAQ;IACX,MAAM,YAAY,qBAChB,KAAK,MACL,KAAK,YAAY,KAAK,WACxB;IACA,OAAO;KACL,MAAM;KACN,MACE,KAAK,eAAe,OAChB,KAAK,OACL,eAAe,KAAK,MAAM,SAAS;KACzC;KACA,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;IACjD;GACF;GAEA,KAAK,SAAS;IACZ,MAAM,YAAY,sBAAsB,KAAK,OAAO,KAAK,WAAW;IACpE,OAAO;KACL,MAAM;KACN,MAAM,eAAe,KAAK,OAAO,SAAS;KAC1C;KACA,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;IACjD;GACF;GAEA,KAAK,SAAS;IACZ,MAAM,YAAY,SAAS,KAAK,MAAM;IACtC,MAAM,OAAO,KAAK,MAAM;IACxB,MAAM,SAAS,sBAAsB;KAAE;KAAM,UAAU;IAAU,CAAC;IAClE,OAAO;KACL,MAAM;KACN,MACE,OAAO,SAAS,QACZ,OAAO,MACP,QAAQ,UAAU,UAAU,OAAO;KACzC;IACF;GACF;GAEA,KAAK,QACH,OAAO,CAAC;GAEV,SAME,MAAM,IAAI,MACR,6CAA6CA,MAC/C;EAEJ;CACF,CAAC;CAED,IAAI,MAAM,WAAW,KAAK,MAAM,EAAE,EAAE,SAAS,QAC3C,OAAO,MAAM,EAAE,CAAC;CAGlB,OAAO;AACT;;;;;AAMA,MAAa,uBACX,MACA,eACuC;CACvC,KAAK,MAAM,WAAW,KAAK,UACzB,KAAK,MAAM,QAAQ,QAAQ,OAAO;EAChC,MAAM,cACJ,KAAK,SAAS,gBACV,OACA,KAAK,SAAS,SACZ,KAAK,cACL,KAAA;EACR,IAAI,aAAa,kBAAkB,YAAY,OAAO,YAAY;CACpE;AAGJ;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,sBACX,UACA,iBACW;CACX,MAAM,gBAAgB,SAAS;CAC/B,MAAM,UAAU,cAAc;CAC9B,MAAM,OAAO,SAAS,QAAQ,SAAS;CAEvC,IAAI,SAAS,aAAa,KAAA,GAAW;EACnC,IACE,CAAC,gBACD,SAAS,MAAM,WAAW,OAAO,OAAO,SAAS,QAAQ,GAEzD,OAAO;GACL;GACA,UAAU,SAAS;GACnB,GAAI,QAAQ,EAAE,KAAK;EACrB;EAEF,MAAM,IAAI,MACR,oBAAoB,cAAc,2BAA2B,SAAS,SAAS,0BAC7E,SAAS,SACL,QAAQ,KAAK,WAAW,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI,IAC5C,oCAER;CACF;CAEA,MAAM,mBAAmB,SAAS,WAC9B,oBACA;CACJ,IACE,CAAC,gBACA,aAAa,SAAS,cAAc,CAAC,SAAS,UAC/C,SAAS,MAAM,WAAW,OAAO,OAAO,gBAAgB,GAExD,OAAO;EAAE;EAAe,UAAU;EAAkB,GAAI,QAAQ,EAAE,KAAK;CAAG;CAE5E,MAAM,cAAc,sBAAsB,YAAY;CACtD,IAAI,eAAe,QAAQ,SAAS,aAAa,OAC/C,OAAO;EAAE;EAAe;CAAK;CAG/B,MAAM,IAAI,MACR,oBAAoB,cAAc,KAAK,aAAa,OAAO,uCACzD,SAAS,SACL,wBAAwB,QAAQ,KAAK,WAAW,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI,MACpE,CAAC,cACC,oDACA,SAAS,aAAa,QACpB,kIACA,sFAEZ;AACF"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SessionStreamEvent } from "eve/client";
|
|
2
2
|
export type TurnTimestamps = {
|
|
3
3
|
readonly user?: Date;
|
|
4
4
|
readonly assistant?: Date;
|
|
5
5
|
};
|
|
6
6
|
export type TurnTimestampCache = {
|
|
7
|
-
lastEvents: readonly
|
|
7
|
+
lastEvents: readonly SessionStreamEvent[];
|
|
8
8
|
timestamps: ReadonlyMap<string, TurnTimestamps>;
|
|
9
9
|
};
|
|
10
10
|
export declare const createTurnTimestampCache: () => TurnTimestampCache;
|
|
11
11
|
/**
|
|
12
|
-
* Eve appends to its log
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* Eve appends to its log, so a snapshot that keeps the previous scan's last
|
|
13
|
+
* element by identity shares the whole prefix and the scan resumes there. Any
|
|
14
|
+
* other snapshot is re-derived into a fresh map: turn ids are per-session
|
|
15
|
+
* sequence numbers that recur after `newSession()`, so entries must not
|
|
16
|
+
* outlive the log that produced them. Re-derivation is also what makes the
|
|
17
|
+
* render-phase cache writes safe when React discards a render.
|
|
18
18
|
*/
|
|
19
|
-
export declare const collectTurnTimestamps: (events: readonly
|
|
19
|
+
export declare const collectTurnTimestamps: (events: readonly SessionStreamEvent[], cache: TurnTimestampCache) => ReadonlyMap<string, TurnTimestamps>;
|
|
20
20
|
//# sourceMappingURL=deriveCreatedAt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deriveCreatedAt.d.ts","sourceRoot":"","sources":["../src/deriveCreatedAt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC1C,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACjD,CAAC;
|
|
1
|
+
{"version":3,"file":"deriveCreatedAt.d.ts","sourceRoot":"","sources":["../src/deriveCreatedAt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC1C,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACjD,CAAC;AAyBF,eAAO,MAAM,wBAAwB,QAAO,kBAG1C,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,SAAS,kBAAkB,EAAE,EACrC,OAAO,kBAAkB,KACxB,WAAW,CAAC,MAAM,EAAE,cAAc,CA6CpC,CAAC"}
|
package/dist/deriveCreatedAt.js
CHANGED
|
@@ -1,42 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
// src/deriveCreatedAt.ts
|
|
2
2
|
/**
|
|
3
|
-
* The
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* before the model runs. An event eve adds to the creating set later is absent
|
|
9
|
-
* here and falls back to the wall clock instead of stamping a wrong time.
|
|
3
|
+
* The facts eve projects into a message: a `delivery.consumed` carrying parts
|
|
4
|
+
* opens the turn's user message, and the model, content, call, and interaction
|
|
5
|
+
* facts open its assistant message. A fact eve adds to the creating set later
|
|
6
|
+
* is absent here and falls back to the wall clock instead of stamping a wrong
|
|
7
|
+
* time.
|
|
10
8
|
*/
|
|
11
9
|
const ROLE_BY_EVENT_TYPE = {
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"message.appended": "assistant",
|
|
24
|
-
"message.completed": "assistant",
|
|
25
|
-
"result.completed": "assistant",
|
|
26
|
-
"turn.completed": "assistant",
|
|
27
|
-
"turn.cancelled": "assistant"
|
|
10
|
+
"delivery.consumed": "user",
|
|
11
|
+
"model.requested": "assistant",
|
|
12
|
+
"model.started": "assistant",
|
|
13
|
+
"content.delta": "assistant",
|
|
14
|
+
"content.completed": "assistant",
|
|
15
|
+
"call.input": "assistant",
|
|
16
|
+
"call.requested": "assistant",
|
|
17
|
+
"call.started": "assistant",
|
|
18
|
+
"call.settled": "assistant",
|
|
19
|
+
"call.progress": "assistant",
|
|
20
|
+
"interaction.opened": "assistant"
|
|
28
21
|
};
|
|
29
22
|
const createTurnTimestampCache = () => ({
|
|
30
23
|
lastEvents: [],
|
|
31
24
|
timestamps: /* @__PURE__ */ new Map()
|
|
32
25
|
});
|
|
33
26
|
/**
|
|
34
|
-
* Eve appends to its log
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
27
|
+
* Eve appends to its log, so a snapshot that keeps the previous scan's last
|
|
28
|
+
* element by identity shares the whole prefix and the scan resumes there. Any
|
|
29
|
+
* other snapshot is re-derived into a fresh map: turn ids are per-session
|
|
30
|
+
* sequence numbers that recur after `newSession()`, so entries must not
|
|
31
|
+
* outlive the log that produced them. Re-derivation is also what makes the
|
|
32
|
+
* render-phase cache writes safe when React discards a render.
|
|
40
33
|
*/
|
|
41
34
|
const collectTurnTimestamps = (events, cache) => {
|
|
42
35
|
if (events === cache.lastEvents) return cache.timestamps;
|
|
@@ -53,9 +46,8 @@ const collectTurnTimestamps = (events, cache) => {
|
|
|
53
46
|
if (!Object.prototype.hasOwnProperty.call(ROLE_BY_EVENT_TYPE, event.type)) continue;
|
|
54
47
|
const role = ROLE_BY_EVENT_TYPE[event.type];
|
|
55
48
|
if (role === void 0) continue;
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
58
|
-
const turnId = data.turnId;
|
|
49
|
+
const turnId = event.type === "delivery.consumed" ? event.data.turnId : event.scope?.turnId;
|
|
50
|
+
if (event.type === "delivery.consumed" && event.data.parts.length === 0) continue;
|
|
59
51
|
if (typeof turnId !== "string") continue;
|
|
60
52
|
const known = timestamps.get(turnId);
|
|
61
53
|
if (known?.[role] !== void 0) continue;
|
|
@@ -74,7 +66,6 @@ const collectTurnTimestamps = (events, cache) => {
|
|
|
74
66
|
cache.timestamps = timestamps;
|
|
75
67
|
return timestamps;
|
|
76
68
|
};
|
|
77
|
-
//#endregion
|
|
78
69
|
export { collectTurnTimestamps, createTurnTimestampCache };
|
|
79
70
|
|
|
80
71
|
//# sourceMappingURL=deriveCreatedAt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deriveCreatedAt.js","names":[],"sources":["../src/deriveCreatedAt.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"deriveCreatedAt.js","names":[],"sources":["../src/deriveCreatedAt.ts"],"sourcesContent":["import type { SessionStreamEvent } from \"eve/client\";\n\nexport type TurnTimestamps = {\n readonly user?: Date;\n readonly assistant?: Date;\n};\n\nexport type TurnTimestampCache = {\n lastEvents: readonly SessionStreamEvent[];\n timestamps: ReadonlyMap<string, TurnTimestamps>;\n};\n\n/**\n * The facts eve projects into a message: a `delivery.consumed` carrying parts\n * opens the turn's user message, and the model, content, call, and interaction\n * facts open its assistant message. A fact eve adds to the creating set later\n * is absent here and falls back to the wall clock instead of stamping a wrong\n * time.\n */\nconst ROLE_BY_EVENT_TYPE: Partial<\n Record<SessionStreamEvent[\"type\"], keyof TurnTimestamps>\n> = {\n \"delivery.consumed\": \"user\",\n \"model.requested\": \"assistant\",\n \"model.started\": \"assistant\",\n \"content.delta\": \"assistant\",\n \"content.completed\": \"assistant\",\n \"call.input\": \"assistant\",\n \"call.requested\": \"assistant\",\n \"call.started\": \"assistant\",\n \"call.settled\": \"assistant\",\n \"call.progress\": \"assistant\",\n \"interaction.opened\": \"assistant\",\n};\n\nexport const createTurnTimestampCache = (): TurnTimestampCache => ({\n lastEvents: [],\n timestamps: new Map(),\n});\n\n/**\n * Eve appends to its log, so a snapshot that keeps the previous scan's last\n * element by identity shares the whole prefix and the scan resumes there. Any\n * other snapshot is re-derived into a fresh map: turn ids are per-session\n * sequence numbers that recur after `newSession()`, so entries must not\n * outlive the log that produced them. Re-derivation is also what makes the\n * render-phase cache writes safe when React discards a render.\n */\nexport const collectTurnTimestamps = (\n events: readonly SessionStreamEvent[],\n cache: TurnTimestampCache,\n): ReadonlyMap<string, TurnTimestamps> => {\n if (events === cache.lastEvents) return cache.timestamps;\n\n const scanned = cache.lastEvents;\n const resumesScan =\n scanned.length === 0 ||\n events[scanned.length - 1] === scanned[scanned.length - 1];\n\n let timestamps = cache.timestamps;\n let draft: Map<string, TurnTimestamps> | undefined;\n if (!resumesScan) {\n draft = new Map();\n timestamps = draft;\n }\n for (let i = resumesScan ? scanned.length : 0; i < events.length; i++) {\n const event = events[i]!;\n // `type` arrives off the wire, so an inherited member such as\n // `__proto__` would resolve here instead of missing, and be used as a\n // timestamp key. Only the table's own entries count.\n if (!Object.prototype.hasOwnProperty.call(ROLE_BY_EVENT_TYPE, event.type))\n continue;\n const role = ROLE_BY_EVENT_TYPE[event.type];\n if (role === undefined) continue;\n const turnId =\n event.type === \"delivery.consumed\"\n ? event.data.turnId\n : event.scope?.turnId;\n if (event.type === \"delivery.consumed\" && event.data.parts.length === 0)\n continue;\n if (typeof turnId !== \"string\") continue;\n const known = timestamps.get(turnId);\n if (known?.[role] !== undefined) continue;\n const at: unknown = (event as { readonly meta?: { readonly at?: unknown } })\n .meta?.at;\n if (typeof at !== \"string\") continue;\n const date = new Date(at);\n if (Number.isNaN(date.getTime())) continue;\n draft ??= new Map(timestamps);\n draft.set(turnId, { ...known, [role]: date });\n timestamps = draft;\n }\n\n cache.lastEvents = events;\n cache.timestamps = timestamps;\n return timestamps;\n};\n"],"mappings":";;;;;;;;AAmBA,MAAM,qBAEF;CACF,qBAAqB;CACrB,mBAAmB;CACnB,iBAAiB;CACjB,iBAAiB;CACjB,qBAAqB;CACrB,cAAc;CACd,kBAAkB;CAClB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,sBAAsB;AACxB;AAEA,MAAa,kCAAsD;CACjE,YAAY,CAAC;CACb,4BAAY,IAAI,IAAI;AACtB;;;;;;;;;AAUA,MAAa,yBACX,QACA,UACwC;CACxC,IAAI,WAAW,MAAM,YAAY,OAAO,MAAM;CAE9C,MAAM,UAAU,MAAM;CACtB,MAAM,cACJ,QAAQ,WAAW,KACnB,OAAO,QAAQ,SAAS,OAAO,QAAQ,QAAQ,SAAS;CAE1D,IAAI,aAAa,MAAM;CACvB,IAAI;CACJ,IAAI,CAAC,aAAa;EAChB,wBAAQ,IAAI,IAAI;EAChB,aAAa;CACf;CACA,KAAK,IAAI,IAAI,cAAc,QAAQ,SAAS,GAAG,IAAI,OAAO,QAAQ,KAAK;EACrE,MAAM,QAAQ,OAAO;EAIrB,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,oBAAoB,MAAM,IAAI,GACtE;EACF,MAAM,OAAO,mBAAmB,MAAM;EACtC,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,SACJ,MAAM,SAAS,sBACX,MAAM,KAAK,SACX,MAAM,OAAO;EACnB,IAAI,MAAM,SAAS,uBAAuB,MAAM,KAAK,MAAM,WAAW,GACpE;EACF,IAAI,OAAO,WAAW,UAAU;EAChC,MAAM,QAAQ,WAAW,IAAI,MAAM;EACnC,IAAI,QAAQ,UAAU,KAAA,GAAW;EACjC,MAAM,KAAe,MAClB,MAAM;EACT,IAAI,OAAO,OAAO,UAAU;EAC5B,MAAM,OAAO,IAAI,KAAK,EAAE;EACxB,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;EAClC,UAAU,IAAI,IAAI,UAAU;EAC5B,MAAM,IAAI,QAAQ;GAAE,GAAG;IAAQ,OAAO;EAAK,CAAC;EAC5C,aAAa;CACf;CAEA,MAAM,aAAa;CACnB,MAAM,aAAa;CACnB,OAAO;AACT"}
|
package/dist/eveCloudSessions.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/eveCloudSessions.ts
|
|
2
2
|
const createPendingSession = () => {
|
|
3
3
|
let resolve;
|
|
4
4
|
let reject;
|
|
@@ -45,7 +45,6 @@ const createEveCloudSessions = () => {
|
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
|
-
//#endregion
|
|
49
48
|
export { createEveCloudSessions };
|
|
50
49
|
|
|
51
50
|
//# sourceMappingURL=eveCloudSessions.js.map
|
package/dist/eveExtras.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type EveRuntimeExtras = Pick<
|
|
1
|
+
import type { UseEveAgentReturn } from "eve/react";
|
|
2
|
+
export type EveRuntimeExtras = Pick<UseEveAgentReturn, "error" | "events" | "session"> & {
|
|
3
|
+
readonly reset: UseEveAgentReturn["newSession"];
|
|
4
|
+
};
|
|
3
5
|
export declare const eveExtras: import("@assistant-ui/core/react").RuntimeExtras<EveRuntimeExtras>;
|
|
4
6
|
//# sourceMappingURL=eveExtras.d.ts.map
|
package/dist/eveExtras.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eveExtras.d.ts","sourceRoot":"","sources":["../src/eveExtras.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"eveExtras.d.ts","sourceRoot":"","sources":["../src/eveExtras.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,iBAAiB,EACjB,OAAO,GAAG,QAAQ,GAAG,SAAS,CAC/B,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAA;CAAE,CAAC;AAExD,eAAO,MAAM,SAAS,oEACuC,CAAC"}
|
package/dist/eveExtras.js
CHANGED
package/dist/eveExtras.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eveExtras.js","names":[],"sources":["../src/eveExtras.ts"],"sourcesContent":["import { createRuntimeExtras } from \"@assistant-ui/core/react\";\nimport type {
|
|
1
|
+
{"version":3,"file":"eveExtras.js","names":[],"sources":["../src/eveExtras.ts"],"sourcesContent":["import { createRuntimeExtras } from \"@assistant-ui/core/react\";\nimport type { UseEveAgentReturn } from \"eve/react\";\n\nexport type EveRuntimeExtras = Pick<\n UseEveAgentReturn,\n \"error\" | \"events\" | \"session\"\n> & { readonly reset: UseEveAgentReturn[\"newSession\"] };\n\nexport const eveExtras =\n createRuntimeExtras<EveRuntimeExtras>(\"useEveAgentRuntime\");\n"],"mappings":";;AAQA,MAAa,YACX,oBAAsC,oBAAoB"}
|
package/dist/hooks.d.ts
CHANGED
|
@@ -15,9 +15,10 @@ export declare const useEveSession: () => EveRuntimeExtras["session"] | undefine
|
|
|
15
15
|
*/
|
|
16
16
|
export declare const useEveEvents: () => EveRuntimeExtras["events"];
|
|
17
17
|
/**
|
|
18
|
-
* Returns a function that
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Returns a function that starts a new Eve session: it stops reading the
|
|
19
|
+
* current session and clears its events and messages, without cancelling a
|
|
20
|
+
* turn still running on the server. Pending staged messages and tool execution
|
|
21
|
+
* state are discarded. Safe to render
|
|
21
22
|
* outside an Eve runtime; invoking the returned function there throws.
|
|
22
23
|
*
|
|
23
24
|
* With `cloud`, it starts a new thread instead, leaving the current thread and its session in the list.
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAoB;AAIpD,+DAA+D;AAC/D,eAAO,MAAM,WAAW,yBAAiD,CAAC;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,QAAO,gBAAgB,CAAC,SAAS,CAAC,GAAG,SACnB,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAO,gBAAgB,CAAC,QAAQ,CACX,CAAC;AAE/C
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAoB;AAIpD,+DAA+D;AAC/D,eAAO,MAAM,WAAW,yBAAiD,CAAC;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,QAAO,gBAAgB,CAAC,SAAS,CAAC,GAAG,SACnB,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAO,gBAAgB,CAAC,QAAQ,CACX,CAAC;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,kBAGvB,CAAC"}
|
package/dist/hooks.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { eveExtras } from "./eveExtras.js";
|
|
3
3
|
import { useAui } from "@assistant-ui/store";
|
|
4
|
-
|
|
4
|
+
// src/hooks.ts
|
|
5
5
|
const EMPTY_EVENTS = Object.freeze([]);
|
|
6
6
|
/** Read the last Eve session error from the runtime extras. */
|
|
7
7
|
const useEveError = () => eveExtras.use((e) => e.error, void 0);
|
|
@@ -19,9 +19,10 @@ const useEveSession = () => eveExtras.use((e) => e.session, void 0);
|
|
|
19
19
|
*/
|
|
20
20
|
const useEveEvents = () => eveExtras.use((e) => e.events, EMPTY_EVENTS);
|
|
21
21
|
/**
|
|
22
|
-
* Returns a function that
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Returns a function that starts a new Eve session: it stops reading the
|
|
23
|
+
* current session and clears its events and messages, without cancelling a
|
|
24
|
+
* turn still running on the server. Pending staged messages and tool execution
|
|
25
|
+
* state are discarded. Safe to render
|
|
25
26
|
* outside an Eve runtime; invoking the returned function there throws.
|
|
26
27
|
*
|
|
27
28
|
* With `cloud`, it starts a new thread instead, leaving the current thread and its session in the list.
|
|
@@ -30,7 +31,6 @@ const useEveReset = () => {
|
|
|
30
31
|
const aui = useAui();
|
|
31
32
|
return () => eveExtras.get(aui).reset();
|
|
32
33
|
};
|
|
33
|
-
//#endregion
|
|
34
34
|
export { useEveError, useEveEvents, useEveReset, useEveSession };
|
|
35
35
|
|
|
36
36
|
//# sourceMappingURL=hooks.js.map
|
package/dist/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport { useAui } from \"@assistant-ui/store\";\nimport { eveExtras } from \"./eveExtras\";\nimport type { EveRuntimeExtras } from \"./eveExtras\";\n\nconst EMPTY_EVENTS: EveRuntimeExtras[\"events\"] = Object.freeze([]);\n\n/** Read the last Eve session error from the runtime extras. */\nexport const useEveError = () => eveExtras.use((e) => e.error, undefined);\n\n/**\n * Read the current Eve session cursor from the runtime extras. Persist it to\n * resume the session later via `initialSession`. `undefined` when no session\n * exists yet or outside an Eve runtime.\n *\n * With `cloud`, each cloud thread already keeps its session, so there is nothing to persist.\n */\nexport const useEveSession = (): EveRuntimeExtras[\"session\"] | undefined =>\n eveExtras.use((e) => e.session, undefined);\n\n/**\n * Read the authoritative Eve server event stream from the runtime extras.\n * Defaults to an empty array outside an Eve runtime.\n */\nexport const useEveEvents = (): EveRuntimeExtras[\"events\"] =>\n eveExtras.use((e) => e.events, EMPTY_EVENTS);\n\n/**\n * Returns a function that
|
|
1
|
+
{"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport { useAui } from \"@assistant-ui/store\";\nimport { eveExtras } from \"./eveExtras\";\nimport type { EveRuntimeExtras } from \"./eveExtras\";\n\nconst EMPTY_EVENTS: EveRuntimeExtras[\"events\"] = Object.freeze([]);\n\n/** Read the last Eve session error from the runtime extras. */\nexport const useEveError = () => eveExtras.use((e) => e.error, undefined);\n\n/**\n * Read the current Eve session cursor from the runtime extras. Persist it to\n * resume the session later via `initialSession`. `undefined` when no session\n * exists yet or outside an Eve runtime.\n *\n * With `cloud`, each cloud thread already keeps its session, so there is nothing to persist.\n */\nexport const useEveSession = (): EveRuntimeExtras[\"session\"] | undefined =>\n eveExtras.use((e) => e.session, undefined);\n\n/**\n * Read the authoritative Eve server event stream from the runtime extras.\n * Defaults to an empty array outside an Eve runtime.\n */\nexport const useEveEvents = (): EveRuntimeExtras[\"events\"] =>\n eveExtras.use((e) => e.events, EMPTY_EVENTS);\n\n/**\n * Returns a function that starts a new Eve session: it stops reading the\n * current session and clears its events and messages, without cancelling a\n * turn still running on the server. Pending staged messages and tool execution\n * state are discarded. Safe to render\n * outside an Eve runtime; invoking the returned function there throws.\n *\n * With `cloud`, it starts a new thread instead, leaving the current thread and its session in the list.\n */\nexport const useEveReset = () => {\n const aui = useAui();\n return () => eveExtras.get(aui).reset();\n};\n"],"mappings":";;;;AAMA,MAAM,eAA2C,OAAO,OAAO,CAAC,CAAC;;AAGjE,MAAa,oBAAoB,UAAU,KAAK,MAAM,EAAE,OAAO,KAAA,CAAS;;;;;;;;AASxE,MAAa,sBACX,UAAU,KAAK,MAAM,EAAE,SAAS,KAAA,CAAS;;;;;AAM3C,MAAa,qBACX,UAAU,KAAK,MAAM,EAAE,QAAQ,YAAY;;;;;;;;;;AAW7C,MAAa,oBAAoB;CAC/B,MAAM,MAAM,OAAO;CACnB,aAAa,UAAU,IAAI,GAAG,CAAC,CAAC,MAAM;AACxC"}
|
package/dist/sdkIdentity.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type AttachmentAdapter, type DictationAdapter, type ExternalStoreSharedOptions, type FeedbackAdapter, type RealtimeVoiceAdapter, type SpeechSynthesisAdapter } from "@assistant-ui/core";
|
|
2
2
|
import type { AssistantCloud } from "assistant-cloud";
|
|
3
|
-
import { type
|
|
4
|
-
type
|
|
5
|
-
export type UseEveAgentRuntimeOptions = EveAgentOptions & ExternalStoreSharedOptions & {
|
|
3
|
+
import { type UseEveAgentOptions } from "eve/react";
|
|
4
|
+
export type UseEveAgentRuntimeOptions = UseEveAgentOptions & ExternalStoreSharedOptions & {
|
|
6
5
|
readonly adapters?: {
|
|
7
6
|
readonly attachments?: AttachmentAdapter | undefined;
|
|
8
7
|
readonly speech?: SpeechSynthesisAdapter | undefined;
|
|
@@ -19,9 +18,8 @@ export type UseEveAgentRuntimeOptions = EveAgentOptions & ExternalStoreSharedOpt
|
|
|
19
18
|
* Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
|
|
20
19
|
*
|
|
21
20
|
* The runtime renders Eve messages, forwards new user messages to the Eve
|
|
22
|
-
* session, supports cancellation, and maps Eve
|
|
21
|
+
* session, supports cancellation, and maps Eve interactions to assistant-ui
|
|
23
22
|
* tool approval UI.
|
|
24
23
|
*/
|
|
25
24
|
export declare const useEveAgentRuntime: (options?: UseEveAgentRuntimeOptions) => import("@assistant-ui/core").AssistantRuntime;
|
|
26
|
-
export {};
|
|
27
25
|
//# sourceMappingURL=useEveAgentRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEveAgentRuntime.d.ts","sourceRoot":"","sources":["../src/useEveAgentRuntime.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAG5B,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,
|
|
1
|
+
{"version":3,"file":"useEveAgentRuntime.d.ts","sourceRoot":"","sources":["../src/useEveAgentRuntime.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAG5B,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAwDjE,MAAM,MAAM,yBAAyB,GAAG,kBAAkB,GACxD,0BAA0B,GAAG;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EACd;QACE,QAAQ,CAAC,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;QACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;QACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;QAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;QAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;KACjD,GACD,SAAS,CAAC;IACd;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CAC7C,CAAC;AAshBJ;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAS,yBAA8B,kDAazE,CAAC"}
|