@assistant-ui/eve 0.0.0 → 0.0.1
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 +2 -1
- package/dist/convertEveMessages.d.ts.map +1 -1
- package/dist/convertEveMessages.js.map +1 -1
- package/dist/useEveAgentRuntime.d.ts.map +1 -1
- package/dist/useEveAgentRuntime.js +36 -2
- package/dist/useEveAgentRuntime.js.map +1 -1
- package/package.json +11 -11
- package/src/convertEveMessages.test.ts +3 -1
- package/src/convertEveMessages.ts +4 -5
- package/src/useEveAgentRuntime.ts +67 -1
- package/LICENSE +0 -21
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AppendMessage, RespondToToolApprovalOptions, ThreadMessage } from "@assistant-ui/core";
|
|
2
|
-
import { EveMessage, EveMessageData
|
|
2
|
+
import { EveMessage, EveMessageData } from "eve/react";
|
|
3
|
+
import { InputResponse, SendTurnPayload } from "eve/client";
|
|
3
4
|
|
|
4
5
|
//#region src/convertEveMessages.d.ts
|
|
5
6
|
type ConvertEveMessagesOptions = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertEveMessages.d.ts","names":[],"sources":["../src/convertEveMessages.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"convertEveMessages.d.ts","names":[],"sources":["../src/convertEveMessages.ts"],"mappings":";;;;;KAkCY,yBAAA;;AAAZ;;;WAKW,SAAA;EAAA,SACA,YAAA,KAAiB,OAAA,EAAS,UAAA,KAAe,IAAI;AAAA;;;;cA0K3C,iBAAA,GACX,OAAA,EAAS,UAAA,EACT,KAAA,UACA,QAAA,WAAmB,UAAA,IACnB,OAAA,GAAS,yBAAA,KACR,aAAA;AA/KqD;AA0KxD;;AA1KwD,cAsO3C,kBAAA,GACX,IAAA,EAAM,cAAA,EACN,OAAA,GAAS,yBAAA,KACR,aAAA;;;;;cASU,oBAAA,GACX,OAAA,EAAS,aAAA,KACR,WAAA,CAAY,eAAA;;;;cAqDF,kBAAA,GACX,QAAA,EAAU,4BAAA,KACT,aAID"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertEveMessages.js","names":["_exhaustiveCheck"],"sources":["../src/convertEveMessages.ts"],"sourcesContent":["import type {\n AppendMessage,\n MessageStatus,\n RespondToToolApprovalOptions,\n TextMessagePart,\n ThreadAssistantMessagePart,\n ThreadMessage,\n ThreadUserMessagePart,\n ToolApprovalOption,\n ToolCallMessagePart,\n} from \"@assistant-ui/core\";\nimport type {\n EveDynamicToolPart,\n EveMessage,\n EveMessageData,\n EveMessageInputRequest,\n EveMessagePart,\n InputResponse,\n SendTurnPayload,\n} from \"eve/react\";\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 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.\n */\n readonly isRunning?: boolean | undefined;\n readonly getCreatedAt?: ((message: EveMessage) => Date) | 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): Record<string, unknown> => {\n if (isRecord(value)) return value;\n if (value === undefined) return {};\n return { value };\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): MessageStatus => {\n if (message.role !== \"assistant\") return USER_FALLBACK_STATUS;\n\n const hasPendingApproval = message.parts.some(\n (part) =>\n part.type === \"dynamic-tool\" && part.state === \"approval-requested\",\n );\n\n if (hasPendingApproval) {\n return { type: \"requires-action\", reason: \"tool-calls\" };\n }\n\n if (message.metadata?.status === \"failed\") {\n return { type: \"incomplete\", reason: \"error\" };\n }\n\n if (\n message.metadata?.status === \"streaming\" ||\n (options.isRunning === true && index === messages.length - 1)\n ) {\n return ASSISTANT_RUNNING_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 === \"deny\"\n ? \"reject-once\"\n : `_${option.id}`,\n ...(option.label && { label: option.label }),\n ...(option.description && { description: option.description }),\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 options = toolApprovalOptionsFromInputRequest(\n part.toolMetadata?.eve?.inputRequest,\n );\n\n return {\n id: approval.id,\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 convertDynamicToolPart = (\n part: EveDynamicToolPart,\n): ToolCallMessagePart => {\n const approval = toApproval(part);\n const toolCall: ToolCallMessagePart = {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n args: toJsonObject(part.input),\n argsText: stringifyArgs(part.input),\n ...(approval && { approval }),\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\nconst convertAssistantPart = (\n part: EveMessagePart,\n): ThreadAssistantMessagePart | null => {\n switch (part.type) {\n case \"text\":\n case \"reasoning\":\n return { type: part.type, text: part.text };\n\n case \"step-start\":\n return null;\n\n case \"dynamic-tool\":\n return convertDynamicToolPart(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\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 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 content =\n message.role === \"assistant\"\n ? message.parts.map(convertAssistantPart).filter((part) => part !== null)\n : message.parts.map(convertUserPart).filter((part) => part !== null);\n\n const fallbackTextPart: TextMessagePart = {\n type: \"text\",\n text: \"\",\n };\n\n if (message.role === \"user\") {\n return {\n id: message.id,\n createdAt,\n role: \"user\",\n content:\n content.length > 0\n ? (content as readonly ThreadUserMessagePart[])\n : [fallbackTextPart],\n attachments: [],\n metadata,\n };\n }\n\n return {\n id: message.id,\n createdAt,\n role: \"assistant\",\n content:\n content.length > 0\n ? (content as readonly ThreadAssistantMessagePart[])\n : [],\n status: toMessageStatus(message, index, messages, options),\n metadata: {\n unstable_state: null,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n ...metadata,\n },\n };\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 data.messages.map((message, index, messages) =>\n convertEveMessage(message, index, messages, options),\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): NonNullable<SendTurnPayload[\"message\"]> => {\n const content = [\n ...message.content,\n ...(message.attachments?.flatMap((attachment) => attachment.content) ?? []),\n ];\n\n const parts = content.map((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 return {\n type: \"file\" as const,\n data: part.data,\n mediaType: part.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n\n case \"image\":\n return {\n type: \"file\" as const,\n data: part.image,\n mediaType: \"image/*\",\n ...(part.filename && { filename: part.filename }),\n };\n\n default: {\n const _exhaustiveCheck:\n | \"audio\"\n | \"data\"\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 * Converts an assistant-ui tool approval response into an Eve input response.\n */\nexport const toEveInputResponse = (\n response: RespondToToolApprovalOptions,\n): InputResponse => ({\n requestId: response.approvalId,\n optionId: response.optionId ?? (response.approved ? \"approve\" : \"deny\"),\n ...(response.reason && { text: response.reason }),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"convertEveMessages.js","names":["_exhaustiveCheck"],"sources":["../src/convertEveMessages.ts"],"sourcesContent":["import type {\n AppendMessage,\n MessageStatus,\n RespondToToolApprovalOptions,\n TextMessagePart,\n ThreadAssistantMessagePart,\n ThreadMessage,\n ThreadUserMessagePart,\n ToolApprovalOption,\n ToolCallMessagePart,\n} from \"@assistant-ui/core\";\nimport type {\n EveDynamicToolPart,\n EveMessage,\n EveMessageData,\n EveMessageInputRequest,\n EveMessagePart,\n} from \"eve/react\";\nimport type { InputResponse, SendTurnPayload } 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 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.\n */\n readonly isRunning?: boolean | undefined;\n readonly getCreatedAt?: ((message: EveMessage) => Date) | 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): MessageStatus => {\n if (message.role !== \"assistant\") return USER_FALLBACK_STATUS;\n\n const hasPendingApproval = message.parts.some(\n (part) =>\n part.type === \"dynamic-tool\" && part.state === \"approval-requested\",\n );\n\n if (hasPendingApproval) {\n return { type: \"requires-action\", reason: \"tool-calls\" };\n }\n\n if (message.metadata?.status === \"failed\") {\n return { type: \"incomplete\", reason: \"error\" };\n }\n\n if (\n message.metadata?.status === \"streaming\" ||\n (options.isRunning === true && index === messages.length - 1)\n ) {\n return ASSISTANT_RUNNING_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 === \"deny\"\n ? \"reject-once\"\n : `_${option.id}`,\n ...(option.label && { label: option.label }),\n ...(option.description && { description: option.description }),\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 options = toolApprovalOptionsFromInputRequest(\n part.toolMetadata?.eve?.inputRequest,\n );\n\n return {\n id: approval.id,\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 convertDynamicToolPart = (\n part: EveDynamicToolPart,\n): ToolCallMessagePart => {\n const approval = toApproval(part);\n const toolCall: ToolCallMessagePart = {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n args: toJsonObject(part.input),\n argsText: stringifyArgs(part.input),\n ...(approval && { approval }),\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\nconst convertAssistantPart = (\n part: EveMessagePart,\n): ThreadAssistantMessagePart | null => {\n switch (part.type) {\n case \"text\":\n case \"reasoning\":\n return { type: part.type, text: part.text };\n\n case \"step-start\":\n return null;\n\n case \"dynamic-tool\":\n return convertDynamicToolPart(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\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 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 content =\n message.role === \"assistant\"\n ? message.parts.map(convertAssistantPart).filter((part) => part !== null)\n : message.parts.map(convertUserPart).filter((part) => part !== null);\n\n const fallbackTextPart: TextMessagePart = {\n type: \"text\",\n text: \"\",\n };\n\n if (message.role === \"user\") {\n return {\n id: message.id,\n createdAt,\n role: \"user\",\n content:\n content.length > 0\n ? (content as readonly ThreadUserMessagePart[])\n : [fallbackTextPart],\n attachments: [],\n metadata,\n };\n }\n\n return {\n id: message.id,\n createdAt,\n role: \"assistant\",\n content:\n content.length > 0\n ? (content as readonly ThreadAssistantMessagePart[])\n : [],\n status: toMessageStatus(message, index, messages, options),\n metadata: {\n unstable_state: null,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n ...metadata,\n },\n };\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 data.messages.map((message, index, messages) =>\n convertEveMessage(message, index, messages, options),\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): NonNullable<SendTurnPayload[\"message\"]> => {\n const content = [\n ...message.content,\n ...(message.attachments?.flatMap((attachment) => attachment.content) ?? []),\n ];\n\n const parts = content.map((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 return {\n type: \"file\" as const,\n data: part.data,\n mediaType: part.mimeType,\n ...(part.filename && { filename: part.filename }),\n };\n\n case \"image\":\n return {\n type: \"file\" as const,\n data: part.image,\n mediaType: \"image/*\",\n ...(part.filename && { filename: part.filename }),\n };\n\n default: {\n const _exhaustiveCheck:\n | \"audio\"\n | \"data\"\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 * Converts an assistant-ui tool approval response into an Eve input response.\n */\nexport const toEveInputResponse = (\n response: RespondToToolApprovalOptions,\n): InputResponse => ({\n requestId: response.approvalId,\n optionId: response.optionId ?? (response.approved ? \"approve\" : \"deny\"),\n ...(response.reason && { text: response.reason }),\n});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEveAgentRuntime.d.ts","names":[],"sources":["../src/useEveAgentRuntime.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"useEveAgentRuntime.d.ts","names":[],"sources":["../src/useEveAgentRuntime.ts"],"mappings":";;;;KA+CY,yBAAA,GAA4B,IAAA,CACtC,kBAAA,CAAmB,cAAA,gBAGnB,0BAAA;EAAA,SACW,QAAA;IAAA,SAEM,WAAA,GAAc,iBAAA;IAAA,SACd,MAAA,GAAS,sBAAA;IAAA,SACT,SAAA,GAAY,gBAAA;IAAA,SACZ,KAAA,GAAQ,oBAAA;IAAA,SACR,QAAA,GAAW,eAAA;EAAA;AAAA;;;;;;;;cAYjB,kBAAA,GAAsB,OAAA,GAAS,yBAA8B,kCAAA,gBAAA"}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { convertEveMessages, getEveMessageContent, toEveInputResponse } from "./convertEveMessages.js";
|
|
3
3
|
import { useMemo, useRef, useState } from "react";
|
|
4
|
-
import { pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
4
|
+
import { fromThreadMessageLike, generateId, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
5
5
|
import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/react";
|
|
6
6
|
import { useEveAgent } from "eve/react";
|
|
7
7
|
//#region src/useEveAgentRuntime.ts
|
|
8
|
+
const USER_STAGED_STATUS = {
|
|
9
|
+
type: "complete",
|
|
10
|
+
reason: "unknown"
|
|
11
|
+
};
|
|
12
|
+
const truncateThreadMessages = (messages, parentId) => {
|
|
13
|
+
if (parentId === null) return [];
|
|
14
|
+
const parentIndex = messages.findIndex((message) => message.id === parentId);
|
|
15
|
+
if (parentIndex === -1) return [];
|
|
16
|
+
return messages.slice(0, parentIndex + 1);
|
|
17
|
+
};
|
|
8
18
|
/**
|
|
9
19
|
* Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
|
|
10
20
|
*
|
|
@@ -17,10 +27,12 @@ const useEveAgentRuntime = (options = {}) => {
|
|
|
17
27
|
const agent = useEveAgent(agentOptions);
|
|
18
28
|
const runtimeAdapters = useRuntimeAdapters();
|
|
19
29
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
30
|
+
const [stagedMessages, setStagedMessages] = useState(null);
|
|
20
31
|
const createdAtByMessageIdRef = useRef(/* @__PURE__ */ new Map());
|
|
32
|
+
const stagedInputsRef = useRef(/* @__PURE__ */ new Map());
|
|
21
33
|
const hasExecutingTools = Object.values(toolStatuses).some((status) => status?.type === "executing");
|
|
22
34
|
const isRunning = agent.status === "submitted" || agent.status === "streaming" || hasExecutingTools;
|
|
23
|
-
const
|
|
35
|
+
const convertedMessages = useMemo(() => {
|
|
24
36
|
const createdAtByMessageId = createdAtByMessageIdRef.current;
|
|
25
37
|
const messageIds = new Set(agent.data.messages.map((message) => message.id));
|
|
26
38
|
for (const messageId of createdAtByMessageId.keys()) if (!messageIds.has(messageId)) createdAtByMessageId.delete(messageId);
|
|
@@ -35,6 +47,17 @@ const useEveAgentRuntime = (options = {}) => {
|
|
|
35
47
|
}
|
|
36
48
|
});
|
|
37
49
|
}, [agent.data, isRunning]);
|
|
50
|
+
const messages = stagedMessages ?? convertedMessages;
|
|
51
|
+
const messagesRef = useRef(messages);
|
|
52
|
+
messagesRef.current = messages;
|
|
53
|
+
const stageUserMessage = (message) => {
|
|
54
|
+
const threadMessage = fromThreadMessageLike(message, generateId(), USER_STAGED_STATUS);
|
|
55
|
+
stagedInputsRef.current.set(threadMessage.id, {
|
|
56
|
+
message,
|
|
57
|
+
runConfig: message.runConfig
|
|
58
|
+
});
|
|
59
|
+
setStagedMessages([...truncateThreadMessages(messagesRef.current, message.parentId), threadMessage]);
|
|
60
|
+
};
|
|
38
61
|
return useExternalStoreRuntime({
|
|
39
62
|
...pickExternalStoreSharedOptions(options),
|
|
40
63
|
messages,
|
|
@@ -49,8 +72,19 @@ const useEveAgentRuntime = (options = {}) => {
|
|
|
49
72
|
feedback: adapters?.feedback
|
|
50
73
|
},
|
|
51
74
|
onNew: async (message) => {
|
|
75
|
+
if (!(message.startRun ?? message.role === "user")) {
|
|
76
|
+
stageUserMessage(message);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
52
79
|
await agent.send({ message: getEveMessageContent(message) });
|
|
53
80
|
},
|
|
81
|
+
...stagedMessages ? { onReload: async (parentId) => {
|
|
82
|
+
const staged = parentId ? stagedInputsRef.current.get(parentId) : null;
|
|
83
|
+
if (!staged) throw new Error("Runtime does not support reloading messages.");
|
|
84
|
+
stagedInputsRef.current.delete(parentId);
|
|
85
|
+
setStagedMessages(null);
|
|
86
|
+
await agent.send({ message: getEveMessageContent(staged.message) });
|
|
87
|
+
} } : {},
|
|
54
88
|
onCancel: () => {
|
|
55
89
|
agent.stop();
|
|
56
90
|
return Promise.resolve();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEveAgentRuntime.js","names":[],"sources":["../src/useEveAgentRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useRef, useState } from \"react\";\nimport {\n pickExternalStoreSharedOptions,\n type AttachmentAdapter,\n type DictationAdapter,\n type ExternalStoreSharedOptions,\n type FeedbackAdapter,\n type RealtimeVoiceAdapter,\n type SpeechSynthesisAdapter,\n type ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport {\n useEveAgent,\n type EveMessageData,\n type UseEveAgentOptions,\n} from \"eve/react\";\nimport {\n convertEveMessages,\n getEveMessageContent,\n toEveInputResponse,\n} from \"./convertEveMessages\";\n\nexport type UseEveAgentRuntimeOptions = Omit<\n UseEveAgentOptions<EveMessageData>,\n \"reducer\"\n> &\n ExternalStoreSharedOptions & {\n readonly adapters?:\n | {\n readonly attachments?: AttachmentAdapter | undefined;\n readonly speech?: SpeechSynthesisAdapter | undefined;\n readonly dictation?: DictationAdapter | undefined;\n readonly voice?: RealtimeVoiceAdapter | undefined;\n readonly feedback?: FeedbackAdapter | undefined;\n }\n | undefined;\n };\n\n/**\n * Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.\n *\n * The runtime renders Eve messages, forwards new user messages to the Eve\n * session, supports cancellation, and maps Eve input requests to assistant-ui\n * tool approval UI.\n */\nexport const useEveAgentRuntime = (options: UseEveAgentRuntimeOptions = {}) => {\n const {\n adapters,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n suggestions: _suggestions,\n unstable_capabilities: _unstable_capabilities,\n ...agentOptions\n } = options;\n true satisfies keyof typeof agentOptions &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n\n const agent = useEveAgent(agentOptions);\n const runtimeAdapters = useRuntimeAdapters();\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const createdAtByMessageIdRef = useRef(new Map<string, Date>());\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (status) => status?.type === \"executing\",\n );\n const isRunning =\n agent.status === \"submitted\" ||\n agent.status === \"streaming\" ||\n hasExecutingTools;\n\n const
|
|
1
|
+
{"version":3,"file":"useEveAgentRuntime.js","names":[],"sources":["../src/useEveAgentRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useMemo, useRef, useState } from \"react\";\nimport {\n fromThreadMessageLike,\n generateId,\n pickExternalStoreSharedOptions,\n type AppendMessage,\n type AttachmentAdapter,\n type DictationAdapter,\n type ExternalStoreSharedOptions,\n type FeedbackAdapter,\n type RealtimeVoiceAdapter,\n type SpeechSynthesisAdapter,\n type ThreadMessage,\n type ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport {\n useEveAgent,\n type EveMessageData,\n type UseEveAgentOptions,\n} from \"eve/react\";\nimport {\n convertEveMessages,\n getEveMessageContent,\n toEveInputResponse,\n} from \"./convertEveMessages\";\n\nconst USER_STAGED_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} as const;\n\nconst truncateThreadMessages = (\n messages: readonly ThreadMessage[],\n parentId: string | null,\n) => {\n if (parentId === null) return [];\n const parentIndex = messages.findIndex((message) => message.id === parentId);\n if (parentIndex === -1) return [];\n return messages.slice(0, parentIndex + 1);\n};\n\nexport type UseEveAgentRuntimeOptions = Omit<\n UseEveAgentOptions<EveMessageData>,\n \"reducer\"\n> &\n ExternalStoreSharedOptions & {\n readonly adapters?:\n | {\n readonly attachments?: AttachmentAdapter | undefined;\n readonly speech?: SpeechSynthesisAdapter | undefined;\n readonly dictation?: DictationAdapter | undefined;\n readonly voice?: RealtimeVoiceAdapter | undefined;\n readonly feedback?: FeedbackAdapter | undefined;\n }\n | undefined;\n };\n\n/**\n * Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.\n *\n * The runtime renders Eve messages, forwards new user messages to the Eve\n * session, supports cancellation, and maps Eve input requests to assistant-ui\n * tool approval UI.\n */\nexport const useEveAgentRuntime = (options: UseEveAgentRuntimeOptions = {}) => {\n const {\n adapters,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n suggestions: _suggestions,\n unstable_capabilities: _unstable_capabilities,\n ...agentOptions\n } = options;\n true satisfies keyof typeof agentOptions &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n\n const agent = useEveAgent(agentOptions);\n const runtimeAdapters = useRuntimeAdapters();\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const [stagedMessages, setStagedMessages] = useState<ThreadMessage[] | null>(\n null,\n );\n const createdAtByMessageIdRef = useRef(new Map<string, Date>());\n const stagedInputsRef = useRef(\n new Map<\n string,\n { message: AppendMessage; runConfig: AppendMessage[\"runConfig\"] }\n >(),\n );\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (status) => status?.type === \"executing\",\n );\n const isRunning =\n agent.status === \"submitted\" ||\n agent.status === \"streaming\" ||\n hasExecutingTools;\n\n const convertedMessages = useMemo(() => {\n const createdAtByMessageId = createdAtByMessageIdRef.current;\n const messageIds = new Set(\n agent.data.messages.map((message) => message.id),\n );\n for (const messageId of createdAtByMessageId.keys()) {\n if (!messageIds.has(messageId)) createdAtByMessageId.delete(messageId);\n }\n\n return convertEveMessages(agent.data, {\n isRunning,\n getCreatedAt: (message) => {\n const existing = createdAtByMessageId.get(message.id);\n if (existing) return existing;\n\n const createdAt = new Date();\n createdAtByMessageId.set(message.id, createdAt);\n return createdAt;\n },\n });\n }, [agent.data, isRunning]);\n\n const messages = stagedMessages ?? convertedMessages;\n const messagesRef = useRef(messages);\n messagesRef.current = messages;\n\n const stageUserMessage = (message: AppendMessage) => {\n const threadMessage = fromThreadMessageLike(\n message,\n generateId(),\n USER_STAGED_STATUS,\n );\n stagedInputsRef.current.set(threadMessage.id, {\n message,\n runConfig: message.runConfig,\n });\n setStagedMessages([\n ...truncateThreadMessages(messagesRef.current, message.parentId),\n threadMessage,\n ]);\n };\n\n return useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n messages,\n isRunning,\n unstable_enableToolInvocations: true,\n setToolStatuses,\n adapters: {\n attachments: adapters?.attachments ?? runtimeAdapters?.attachments,\n speech: adapters?.speech,\n dictation: adapters?.dictation,\n voice: adapters?.voice,\n feedback: adapters?.feedback,\n },\n onNew: async (message) => {\n if (!(message.startRun ?? message.role === \"user\")) {\n stageUserMessage(message);\n return;\n }\n await agent.send({ message: getEveMessageContent(message) });\n },\n ...(stagedMessages\n ? {\n onReload: async (parentId: string | null) => {\n const staged = parentId\n ? stagedInputsRef.current.get(parentId)\n : null;\n if (!staged)\n throw new Error(\"Runtime does not support reloading messages.\");\n stagedInputsRef.current.delete(parentId!);\n setStagedMessages(null);\n await agent.send({ message: getEveMessageContent(staged.message) });\n },\n }\n : {}),\n onCancel: () => {\n agent.stop();\n return Promise.resolve();\n },\n onRespondToToolApproval: async (response) => {\n await agent.send({ inputResponses: [toEveInputResponse(response)] });\n },\n });\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/eve",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"description": "Eve runtime adapter for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eve",
|
|
@@ -27,12 +27,17 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"sideEffects": false,
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "aui-build",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest"
|
|
34
|
+
},
|
|
30
35
|
"dependencies": {
|
|
31
36
|
"@assistant-ui/core": "^0.2.18"
|
|
32
37
|
},
|
|
33
38
|
"peerDependencies": {
|
|
34
39
|
"@types/react": "*",
|
|
35
|
-
"eve": "^0.
|
|
40
|
+
"eve": "^0.12.0",
|
|
36
41
|
"react": "^18 || ^19"
|
|
37
42
|
},
|
|
38
43
|
"peerDependenciesMeta": {
|
|
@@ -41,11 +46,11 @@
|
|
|
41
46
|
}
|
|
42
47
|
},
|
|
43
48
|
"devDependencies": {
|
|
49
|
+
"@assistant-ui/x-buildutils": "workspace:*",
|
|
44
50
|
"@types/react": "^19.2.17",
|
|
45
|
-
"eve": "^0.
|
|
51
|
+
"eve": "^0.12.0",
|
|
46
52
|
"react": "^19.2.7",
|
|
47
|
-
"vitest": "^4.1.
|
|
48
|
-
"@assistant-ui/x-buildutils": "0.0.15"
|
|
53
|
+
"vitest": "^4.1.9"
|
|
49
54
|
},
|
|
50
55
|
"publishConfig": {
|
|
51
56
|
"access": "public",
|
|
@@ -59,10 +64,5 @@
|
|
|
59
64
|
},
|
|
60
65
|
"bugs": {
|
|
61
66
|
"url": "https://github.com/assistant-ui/assistant-ui/issues"
|
|
62
|
-
},
|
|
63
|
-
"scripts": {
|
|
64
|
-
"build": "aui-build",
|
|
65
|
-
"test": "vitest run",
|
|
66
|
-
"test:watch": "vitest"
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|
|
@@ -106,7 +106,7 @@ describe("convertEveMessages", () => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
it("handles denied tool parts without approval
|
|
109
|
+
it("handles denied tool parts without an approval reason", () => {
|
|
110
110
|
const data = {
|
|
111
111
|
messages: [
|
|
112
112
|
{
|
|
@@ -119,6 +119,7 @@ describe("convertEveMessages", () => {
|
|
|
119
119
|
toolCallId: "call_1",
|
|
120
120
|
toolName: "send_email",
|
|
121
121
|
input: { to: "dev@example.com" },
|
|
122
|
+
approval: { id: "req_1", approved: false },
|
|
122
123
|
},
|
|
123
124
|
],
|
|
124
125
|
},
|
|
@@ -164,6 +165,7 @@ describe("getEveMessageContent", () => {
|
|
|
164
165
|
it("returns plain text for text-only messages", () => {
|
|
165
166
|
const message = {
|
|
166
167
|
role: "user",
|
|
168
|
+
createdAt: new Date(),
|
|
167
169
|
parentId: null,
|
|
168
170
|
sourceId: null,
|
|
169
171
|
runConfig: undefined,
|
|
@@ -15,9 +15,8 @@ import type {
|
|
|
15
15
|
EveMessageData,
|
|
16
16
|
EveMessageInputRequest,
|
|
17
17
|
EveMessagePart,
|
|
18
|
-
InputResponse,
|
|
19
|
-
SendTurnPayload,
|
|
20
18
|
} from "eve/react";
|
|
19
|
+
import type { InputResponse, SendTurnPayload } from "eve/client";
|
|
21
20
|
|
|
22
21
|
const ASSISTANT_COMPLETE_STATUS = {
|
|
23
22
|
type: "complete",
|
|
@@ -45,10 +44,10 @@ export type ConvertEveMessagesOptions = {
|
|
|
45
44
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
46
45
|
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47
46
|
|
|
48
|
-
const toJsonObject = (value: unknown):
|
|
49
|
-
if (isRecord(value)) return value;
|
|
47
|
+
const toJsonObject = (value: unknown): ToolCallMessagePart["args"] => {
|
|
48
|
+
if (isRecord(value)) return value as ToolCallMessagePart["args"];
|
|
50
49
|
if (value === undefined) return {};
|
|
51
|
-
return { value };
|
|
50
|
+
return { value } as ToolCallMessagePart["args"];
|
|
52
51
|
};
|
|
53
52
|
|
|
54
53
|
const stringifyArgs = (value: unknown): string => {
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import { useMemo, useRef, useState } from "react";
|
|
4
4
|
import {
|
|
5
|
+
fromThreadMessageLike,
|
|
6
|
+
generateId,
|
|
5
7
|
pickExternalStoreSharedOptions,
|
|
8
|
+
type AppendMessage,
|
|
6
9
|
type AttachmentAdapter,
|
|
7
10
|
type DictationAdapter,
|
|
8
11
|
type ExternalStoreSharedOptions,
|
|
9
12
|
type FeedbackAdapter,
|
|
10
13
|
type RealtimeVoiceAdapter,
|
|
11
14
|
type SpeechSynthesisAdapter,
|
|
15
|
+
type ThreadMessage,
|
|
12
16
|
type ToolExecutionStatus,
|
|
13
17
|
} from "@assistant-ui/core";
|
|
14
18
|
import {
|
|
@@ -26,6 +30,21 @@ import {
|
|
|
26
30
|
toEveInputResponse,
|
|
27
31
|
} from "./convertEveMessages";
|
|
28
32
|
|
|
33
|
+
const USER_STAGED_STATUS = {
|
|
34
|
+
type: "complete",
|
|
35
|
+
reason: "unknown",
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
const truncateThreadMessages = (
|
|
39
|
+
messages: readonly ThreadMessage[],
|
|
40
|
+
parentId: string | null,
|
|
41
|
+
) => {
|
|
42
|
+
if (parentId === null) return [];
|
|
43
|
+
const parentIndex = messages.findIndex((message) => message.id === parentId);
|
|
44
|
+
if (parentIndex === -1) return [];
|
|
45
|
+
return messages.slice(0, parentIndex + 1);
|
|
46
|
+
};
|
|
47
|
+
|
|
29
48
|
export type UseEveAgentRuntimeOptions = Omit<
|
|
30
49
|
UseEveAgentOptions<EveMessageData>,
|
|
31
50
|
"reducer"
|
|
@@ -68,7 +87,16 @@ export const useEveAgentRuntime = (options: UseEveAgentRuntimeOptions = {}) => {
|
|
|
68
87
|
const [toolStatuses, setToolStatuses] = useState<
|
|
69
88
|
Record<string, ToolExecutionStatus>
|
|
70
89
|
>({});
|
|
90
|
+
const [stagedMessages, setStagedMessages] = useState<ThreadMessage[] | null>(
|
|
91
|
+
null,
|
|
92
|
+
);
|
|
71
93
|
const createdAtByMessageIdRef = useRef(new Map<string, Date>());
|
|
94
|
+
const stagedInputsRef = useRef(
|
|
95
|
+
new Map<
|
|
96
|
+
string,
|
|
97
|
+
{ message: AppendMessage; runConfig: AppendMessage["runConfig"] }
|
|
98
|
+
>(),
|
|
99
|
+
);
|
|
72
100
|
|
|
73
101
|
const hasExecutingTools = Object.values(toolStatuses).some(
|
|
74
102
|
(status) => status?.type === "executing",
|
|
@@ -78,7 +106,7 @@ export const useEveAgentRuntime = (options: UseEveAgentRuntimeOptions = {}) => {
|
|
|
78
106
|
agent.status === "streaming" ||
|
|
79
107
|
hasExecutingTools;
|
|
80
108
|
|
|
81
|
-
const
|
|
109
|
+
const convertedMessages = useMemo(() => {
|
|
82
110
|
const createdAtByMessageId = createdAtByMessageIdRef.current;
|
|
83
111
|
const messageIds = new Set(
|
|
84
112
|
agent.data.messages.map((message) => message.id),
|
|
@@ -100,6 +128,26 @@ export const useEveAgentRuntime = (options: UseEveAgentRuntimeOptions = {}) => {
|
|
|
100
128
|
});
|
|
101
129
|
}, [agent.data, isRunning]);
|
|
102
130
|
|
|
131
|
+
const messages = stagedMessages ?? convertedMessages;
|
|
132
|
+
const messagesRef = useRef(messages);
|
|
133
|
+
messagesRef.current = messages;
|
|
134
|
+
|
|
135
|
+
const stageUserMessage = (message: AppendMessage) => {
|
|
136
|
+
const threadMessage = fromThreadMessageLike(
|
|
137
|
+
message,
|
|
138
|
+
generateId(),
|
|
139
|
+
USER_STAGED_STATUS,
|
|
140
|
+
);
|
|
141
|
+
stagedInputsRef.current.set(threadMessage.id, {
|
|
142
|
+
message,
|
|
143
|
+
runConfig: message.runConfig,
|
|
144
|
+
});
|
|
145
|
+
setStagedMessages([
|
|
146
|
+
...truncateThreadMessages(messagesRef.current, message.parentId),
|
|
147
|
+
threadMessage,
|
|
148
|
+
]);
|
|
149
|
+
};
|
|
150
|
+
|
|
103
151
|
return useExternalStoreRuntime({
|
|
104
152
|
...pickExternalStoreSharedOptions(options),
|
|
105
153
|
messages,
|
|
@@ -114,8 +162,26 @@ export const useEveAgentRuntime = (options: UseEveAgentRuntimeOptions = {}) => {
|
|
|
114
162
|
feedback: adapters?.feedback,
|
|
115
163
|
},
|
|
116
164
|
onNew: async (message) => {
|
|
165
|
+
if (!(message.startRun ?? message.role === "user")) {
|
|
166
|
+
stageUserMessage(message);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
117
169
|
await agent.send({ message: getEveMessageContent(message) });
|
|
118
170
|
},
|
|
171
|
+
...(stagedMessages
|
|
172
|
+
? {
|
|
173
|
+
onReload: async (parentId: string | null) => {
|
|
174
|
+
const staged = parentId
|
|
175
|
+
? stagedInputsRef.current.get(parentId)
|
|
176
|
+
: null;
|
|
177
|
+
if (!staged)
|
|
178
|
+
throw new Error("Runtime does not support reloading messages.");
|
|
179
|
+
stagedInputsRef.current.delete(parentId!);
|
|
180
|
+
setStagedMessages(null);
|
|
181
|
+
await agent.send({ message: getEveMessageContent(staged.message) });
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
: {}),
|
|
119
185
|
onCancel: () => {
|
|
120
186
|
agent.stop();
|
|
121
187
|
return Promise.resolve();
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 AgentbaseAI Inc.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|