@assistant-ui/eve 0.0.19 → 0.0.21

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 AgentbaseAI Inc.
3
+ Copyright (c) 2026 AgentbaseAI Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,9 @@
1
+ /** Lets the cloud thread list wait for the eve session a new thread's first turn creates, because eve assigns a session id only once that turn is accepted while a cloud thread takes its external id when it is created. */
2
+ export declare const createEveCloudSessions: () => {
3
+ wait: (threadId: string) => Promise<string>;
4
+ resolve: (threadId: string, sessionId: string) => void;
5
+ reject: (threadId: string, error: Error) => void;
6
+ release: (threadId: string) => void;
7
+ };
8
+ export type EveCloudSessions = ReturnType<typeof createEveCloudSessions>;
9
+ //# sourceMappingURL=eveCloudSessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eveCloudSessions.d.ts","sourceRoot":"","sources":["../src/eveCloudSessions.ts"],"names":[],"mappings":"AAmBA,6NAA6N;AAC7N,eAAO,MAAM,sBAAsB;qBAad,MAAM;wBACH,MAAM,aAAa,MAAM;uBAM1B,MAAM,SAAS,KAAK;wBAMnB,MAAM;CAU7B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -0,0 +1,51 @@
1
+ //#region src/eveCloudSessions.ts
2
+ const createPendingSession = () => {
3
+ let resolve;
4
+ let reject;
5
+ const promise = new Promise((onResolve, onReject) => {
6
+ resolve = onResolve;
7
+ reject = onReject;
8
+ });
9
+ promise.catch(() => {});
10
+ return {
11
+ promise,
12
+ resolve,
13
+ reject
14
+ };
15
+ };
16
+ /** Lets the cloud thread list wait for the eve session a new thread's first turn creates, because eve assigns a session id only once that turn is accepted while a cloud thread takes its external id when it is created. */
17
+ const createEveCloudSessions = () => {
18
+ const pending = /* @__PURE__ */ new Map();
19
+ const get = (threadId) => {
20
+ let session = pending.get(threadId);
21
+ if (!session) {
22
+ session = createPendingSession();
23
+ pending.set(threadId, session);
24
+ }
25
+ return session;
26
+ };
27
+ return {
28
+ wait: (threadId) => get(threadId).promise,
29
+ resolve: (threadId, sessionId) => {
30
+ const session = get(threadId);
31
+ if (session.sessionId !== void 0) return;
32
+ session.sessionId = sessionId;
33
+ session.resolve(sessionId);
34
+ },
35
+ reject: (threadId, error) => {
36
+ const session = pending.get(threadId);
37
+ if (!session || session.sessionId !== void 0) return;
38
+ pending.delete(threadId);
39
+ session.reject(error);
40
+ },
41
+ release: (threadId) => {
42
+ const session = pending.get(threadId);
43
+ pending.delete(threadId);
44
+ session?.reject(/* @__PURE__ */ new Error("The thread's eve runtime unmounted before its first turn created a session."));
45
+ }
46
+ };
47
+ };
48
+ //#endregion
49
+ export { createEveCloudSessions };
50
+
51
+ //# sourceMappingURL=eveCloudSessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eveCloudSessions.js","names":[],"sources":["../src/eveCloudSessions.ts"],"sourcesContent":["type PendingSession = {\n readonly promise: Promise<string>;\n readonly resolve: (sessionId: string) => void;\n readonly reject: (error: unknown) => void;\n sessionId?: string;\n};\n\nconst createPendingSession = (): PendingSession => {\n let resolve!: (sessionId: string) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<string>((onResolve, onReject) => {\n resolve = onResolve;\n reject = onReject;\n });\n // A thread can fail its first turn before the thread list asks for its session.\n promise.catch(() => {});\n return { promise, resolve, reject };\n};\n\n/** Lets the cloud thread list wait for the eve session a new thread's first turn creates, because eve assigns a session id only once that turn is accepted while a cloud thread takes its external id when it is created. */\nexport const createEveCloudSessions = () => {\n const pending = new Map<string, PendingSession>();\n\n const get = (threadId: string) => {\n let session = pending.get(threadId);\n if (!session) {\n session = createPendingSession();\n pending.set(threadId, session);\n }\n return session;\n };\n\n return {\n wait: (threadId: string) => get(threadId).promise,\n resolve: (threadId: string, sessionId: string) => {\n const session = get(threadId);\n if (session.sessionId !== undefined) return;\n session.sessionId = sessionId;\n session.resolve(sessionId);\n },\n reject: (threadId: string, error: Error) => {\n const session = pending.get(threadId);\n if (!session || session.sessionId !== undefined) return;\n pending.delete(threadId);\n session.reject(error);\n },\n release: (threadId: string) => {\n const session = pending.get(threadId);\n pending.delete(threadId);\n session?.reject(\n new Error(\n \"The thread's eve runtime unmounted before its first turn created a session.\",\n ),\n );\n },\n };\n};\n\nexport type EveCloudSessions = ReturnType<typeof createEveCloudSessions>;\n"],"mappings":";AAOA,MAAM,6BAA6C;CACjD,IAAI;CACJ,IAAI;CACJ,MAAM,UAAU,IAAI,SAAiB,WAAW,aAAa;EAC3D,UAAU;EACV,SAAS;CACX,CAAC;CAED,QAAQ,YAAY,CAAC,CAAC;CACtB,OAAO;EAAE;EAAS;EAAS;CAAO;AACpC;;AAGA,MAAa,+BAA+B;CAC1C,MAAM,0BAAU,IAAI,IAA4B;CAEhD,MAAM,OAAO,aAAqB;EAChC,IAAI,UAAU,QAAQ,IAAI,QAAQ;EAClC,IAAI,CAAC,SAAS;GACZ,UAAU,qBAAqB;GAC/B,QAAQ,IAAI,UAAU,OAAO;EAC/B;EACA,OAAO;CACT;CAEA,OAAO;EACL,OAAO,aAAqB,IAAI,QAAQ,CAAC,CAAC;EAC1C,UAAU,UAAkB,cAAsB;GAChD,MAAM,UAAU,IAAI,QAAQ;GAC5B,IAAI,QAAQ,cAAc,KAAA,GAAW;GACrC,QAAQ,YAAY;GACpB,QAAQ,QAAQ,SAAS;EAC3B;EACA,SAAS,UAAkB,UAAiB;GAC1C,MAAM,UAAU,QAAQ,IAAI,QAAQ;GACpC,IAAI,CAAC,WAAW,QAAQ,cAAc,KAAA,GAAW;GACjD,QAAQ,OAAO,QAAQ;GACvB,QAAQ,OAAO,KAAK;EACtB;EACA,UAAU,aAAqB;GAC7B,MAAM,UAAU,QAAQ,IAAI,QAAQ;GACpC,QAAQ,OAAO,QAAQ;GACvB,SAAS,uBACP,IAAI,MACF,6EACF,CACF;EACF;CACF;AACF"}
package/dist/hooks.d.ts CHANGED
@@ -5,6 +5,8 @@ export declare const useEveError: () => Error | undefined;
5
5
  * Read the current Eve session cursor from the runtime extras. Persist it to
6
6
  * resume the session later via `initialSession`. `undefined` when no session
7
7
  * exists yet or outside an Eve runtime.
8
+ *
9
+ * With `cloud`, each cloud thread already keeps its session, so there is nothing to persist.
8
10
  */
9
11
  export declare const useEveSession: () => EveRuntimeExtras["session"] | undefined;
10
12
  /**
@@ -17,6 +19,8 @@ export declare const useEveEvents: () => EveRuntimeExtras["events"];
17
19
  * recreates the owned session, and clears events and projected data. Pending
18
20
  * staged messages and tool execution state are discarded. Safe to render
19
21
  * outside an Eve runtime; invoking the returned function there throws.
22
+ *
23
+ * With `cloud`, it starts a new thread instead, leaving the current thread and its session in the list.
20
24
  */
21
25
  export declare const useEveReset: () => () => void;
22
26
  //# sourceMappingURL=hooks.d.ts.map
@@ -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;;;;GAIG;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;;;;;GAKG;AACH,eAAO,MAAM,WAAW,kBAGvB,CAAC"}
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;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,kBAGvB,CAAC"}
package/dist/hooks.js CHANGED
@@ -9,6 +9,8 @@ const useEveError = () => eveExtras.use((e) => e.error, void 0);
9
9
  * Read the current Eve session cursor from the runtime extras. Persist it to
10
10
  * resume the session later via `initialSession`. `undefined` when no session
11
11
  * exists yet or outside an Eve runtime.
12
+ *
13
+ * With `cloud`, each cloud thread already keeps its session, so there is nothing to persist.
12
14
  */
13
15
  const useEveSession = () => eveExtras.use((e) => e.session, void 0);
14
16
  /**
@@ -21,6 +23,8 @@ const useEveEvents = () => eveExtras.use((e) => e.events, EMPTY_EVENTS);
21
23
  * recreates the owned session, and clears events and projected data. Pending
22
24
  * staged messages and tool execution state are discarded. Safe to render
23
25
  * outside an Eve runtime; invoking the returned function there throws.
26
+ *
27
+ * With `cloud`, it starts a new thread instead, leaving the current thread and its session in the list.
24
28
  */
25
29
  const useEveReset = () => {
26
30
  const aui = useAui();
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 */\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 resets the Eve session: aborts any in-flight turn,\n * recreates the owned session, and clears events and projected data. Pending\n * staged messages and tool execution state are discarded. Safe to render\n * outside an Eve runtime; invoking the returned function there throws.\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;;;;;;AAOxE,MAAa,sBACX,UAAU,KAAK,MAAM,EAAE,SAAS,KAAA,CAAS;;;;;AAM3C,MAAa,qBACX,UAAU,KAAK,MAAM,EAAE,QAAQ,YAAY;;;;;;;AAQ7C,MAAa,oBAAoB;CAC/B,MAAM,MAAM,OAAO;CACnB,aAAa,UAAU,IAAI,GAAG,CAAC,CAAC,MAAM;AACxC"}
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 resets the Eve session: aborts any in-flight turn,\n * recreates the owned session, and clears events and projected data. Pending\n * staged messages and tool execution 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;;;;;;;;;AAU7C,MAAa,oBAAoB;CAC/B,MAAM,MAAM,OAAO;CACnB,aAAa,UAAU,IAAI,GAAG,CAAC,CAAC,MAAM;AACxC"}
@@ -0,0 +1,3 @@
1
+ import type { SdkIdentity } from "assistant-cloud";
2
+ export declare const EVE_SDK: SdkIdentity;
3
+ //# sourceMappingURL=sdkIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkIdentity.d.ts","sourceRoot":"","sources":["../src/sdkIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,eAAO,MAAM,OAAO,EAAE,WAMrB,CAAC"}
@@ -0,0 +1,9 @@
1
+ //#region src/sdkIdentity.ts
2
+ const EVE_SDK = {
3
+ name: "@assistant-ui/eve",
4
+ version: "0.0.21"
5
+ };
6
+ //#endregion
7
+ export { EVE_SDK };
8
+
9
+ //# sourceMappingURL=sdkIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkIdentity.js","names":[],"sources":["../src/sdkIdentity.ts"],"sourcesContent":["import type { SdkIdentity } from \"assistant-cloud\";\n\nexport const EVE_SDK: SdkIdentity = {\n name: \"@assistant-ui/eve\",\n version:\n typeof __AUI_PACKAGE_VERSION__ === \"string\"\n ? __AUI_PACKAGE_VERSION__\n : \"0.0.0\",\n};\n"],"mappings":";AAEA,MAAa,UAAuB;CAClC,MAAM;CACN,SAAA;AAIF"}
@@ -1,6 +1,8 @@
1
1
  import { type AttachmentAdapter, type DictationAdapter, type ExternalStoreSharedOptions, type FeedbackAdapter, type RealtimeVoiceAdapter, type SpeechSynthesisAdapter } from "@assistant-ui/core";
2
+ import type { AssistantCloud } from "assistant-cloud";
2
3
  import { type EveMessageData, type UseEveAgentOptions } from "eve/react";
3
- export type UseEveAgentRuntimeOptions = Omit<UseEveAgentOptions<EveMessageData>, "reducer"> & ExternalStoreSharedOptions & {
4
+ type EveAgentOptions = Omit<UseEveAgentOptions<EveMessageData>, "reducer">;
5
+ export type UseEveAgentRuntimeOptions = EveAgentOptions & ExternalStoreSharedOptions & {
4
6
  readonly adapters?: {
5
7
  readonly attachments?: AttachmentAdapter | undefined;
6
8
  readonly speech?: SpeechSynthesisAdapter | undefined;
@@ -8,6 +10,10 @@ export type UseEveAgentRuntimeOptions = Omit<UseEveAgentOptions<EveMessageData>,
8
10
  readonly voice?: RealtimeVoiceAdapter | undefined;
9
11
  readonly feedback?: FeedbackAdapter | undefined;
10
12
  } | undefined;
13
+ /**
14
+ * Backs the thread list with Assistant Cloud. Each cloud thread keeps one Eve session as its external id, saved once the thread's first turn creates the session, and opening a thread resumes it, so `session`, `initialSession`, `initialEvents`, and `resume` are not used. Pass it from the first render: adding or removing it later throws, so remount the runtime, for example with a `key`, to switch.
15
+ */
16
+ readonly cloud?: AssistantCloud | undefined;
11
17
  };
12
18
  /**
13
19
  * Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
@@ -17,4 +23,5 @@ export type UseEveAgentRuntimeOptions = Omit<UseEveAgentOptions<EveMessageData>,
17
23
  * tool approval UI.
18
24
  */
19
25
  export declare const useEveAgentRuntime: (options?: UseEveAgentRuntimeOptions) => import("@assistant-ui/core").AssistantRuntime;
26
+ export {};
20
27
  //# 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;AAK5B,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAExB,MAAM,WAAW,CAAC;AA6FnB,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,kBAAkB,CAAC,cAAc,CAAC,EAClC,SAAS,CACV,GACC,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;CACf,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAS,yBAA8B,kDA6WzE,CAAC"}
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;AAS5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAExB,MAAM,WAAW,CAAC;AAkGnB,KAAK,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC,CAAC;AAE3E,MAAM,MAAM,yBAAyB,GAAG,eAAe,GACrD,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;AAmfJ;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAS,yBAA8B,kDAazE,CAAC"}
@@ -1,10 +1,14 @@
1
1
  "use client";
2
2
  import { convertEveMessages, findEveInputRequest, getEveMessageContent, toEveInputResponse } from "./convertEveMessages.js";
3
3
  import { collectTurnTimestamps, createTurnTimestampCache } from "./deriveCreatedAt.js";
4
+ import { createEveCloudSessions } from "./eveCloudSessions.js";
4
5
  import { eveExtras } from "./eveExtras.js";
6
+ import { EVE_SDK } from "./sdkIdentity.js";
5
7
  import { MessageNotSentError, fromThreadMessageLike, generateId, pickExternalStoreSharedOptions } from "@assistant-ui/core";
6
- import { useExternalStoreRuntime, useRuntimeAdapters } from "@assistant-ui/core/react";
8
+ import { useCloudThreadListAdapter, useExternalStoreRuntime, useRemoteThreadListRuntime, useRuntimeAdapters } from "@assistant-ui/core/react";
9
+ import { useAui } from "@assistant-ui/store";
7
10
  import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState } from "react";
11
+ import { useReplaySafeEffect } from "@assistant-ui/store/internal";
8
12
  import { useEveAgent } from "eve/react";
9
13
  //#region src/useEveAgentRuntime.ts
10
14
  const USER_STAGED_STATUS = {
@@ -35,27 +39,49 @@ const hasRunConfig = (runConfig) => runConfig?.custom !== void 0 && Object.keys(
35
39
  * prompt and to every eve-side handler.
36
40
  */
37
41
  const toEveSendOptions = (runConfig) => hasRunConfig(runConfig) ? { clientContext: runConfig.custom } : void 0;
38
- /**
39
- * Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
40
- *
41
- * The runtime renders Eve messages, forwards new user messages to the Eve
42
- * session, supports cancellation, and maps Eve input requests to assistant-ui
43
- * tool approval UI.
44
- */
45
- const useEveAgentRuntime = (options = {}) => {
46
- const { adapters, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, suggestions: _suggestions, unstable_capabilities: _unstable_capabilities, ...agentOptions } = options;
42
+ const withCloudThreadSession = ({ initialEvents: _initialEvents, initialSession: _initialSession, resume: _resume, session: _session, ...options }, sessionId) => sessionId === void 0 ? options : {
43
+ ...options,
44
+ initialSession: {
45
+ sessionId,
46
+ streamIndex: 0
47
+ },
48
+ resume: true
49
+ };
50
+ const useEveThreadRuntime = (options, cloudSessions) => {
51
+ const { adapters, cloud: _cloud, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, suggestions: _suggestions, unstable_capabilities: _unstable_capabilities, ...agentOptions } = options;
52
+ const aui = useAui();
53
+ const [cloudThread] = useState(() => {
54
+ if (!cloudSessions) return void 0;
55
+ const { id, status, externalId } = aui.threadListItem.getState();
56
+ return {
57
+ sessions: cloudSessions,
58
+ id,
59
+ isNew: status === "new",
60
+ sessionId: externalId
61
+ };
62
+ });
63
+ const [resumesOnMount] = useState(() => cloudThread ? cloudThread.sessionId !== void 0 : agentOptions.resume === true);
64
+ const isSessionless = cloudThread !== void 0 && !cloudThread.isNew && cloudThread.sessionId === void 0;
47
65
  const { onError, onEvent, onFinish, onSessionChange } = agentOptions;
48
66
  const lastFinishStatusRef = useRef(null);
49
67
  const agent = useEveAgent({
50
- ...agentOptions,
68
+ ...cloudThread ? withCloudThreadSession(agentOptions, cloudThread.sessionId) : agentOptions,
51
69
  ...onError ? { onError: (error) => invokeEveLifecycleCallback("onError", onError, error) } : {},
52
70
  ...onEvent ? { onEvent: (event) => invokeEveLifecycleCallback("onEvent", onEvent, event) } : {},
53
71
  onFinish: (snapshot) => {
54
72
  lastFinishStatusRef.current = snapshot.status;
55
73
  invokeEveLifecycleCallback("onFinish", onFinish, snapshot);
56
74
  },
57
- ...onSessionChange ? { onSessionChange: (session) => invokeEveLifecycleCallback("onSessionChange", onSessionChange, session) } : {}
75
+ ...onSessionChange || cloudThread?.isNew ? { onSessionChange: (session) => {
76
+ if (cloudThread?.isNew && session === void 0) cloudThread.sessions.reject(cloudThread.id, /* @__PURE__ */ new Error("The eve turn ended before it created a session."));
77
+ else if (cloudThread?.isNew && session !== void 0) {
78
+ cloudThread.sessions.resolve(cloudThread.id, session.sessionId);
79
+ if (aui.threadListItem.getState().status === "new") aui.threadListItem.initialize().catch(() => {});
80
+ }
81
+ invokeEveLifecycleCallback("onSessionChange", onSessionChange, session);
82
+ } } : {}
58
83
  });
84
+ if (cloudThread && !("resume" in agent)) throw new Error("useEveAgentRuntime needs eve 0.44.1 or later for `cloud`, because opening a cloud thread resumes its session.");
59
85
  const runtimeAdapters = useRuntimeAdapters();
60
86
  const [toolStatuses, setToolStatuses] = useState({});
61
87
  const [stagedMessages, setStagedMessages] = useState(null);
@@ -102,7 +128,7 @@ const useEveAgentRuntime = (options = {}) => {
102
128
  const resetEpochRef = useRef(0);
103
129
  const isMountedRef = useRef(true);
104
130
  const runtimeRef = useRef(null);
105
- const enqueueSend = (dispatch, epochRef = sendEpochRef) => {
131
+ const enqueueSend = useCallback((dispatch, epochRef = sendEpochRef) => {
106
132
  const epoch = epochRef.current;
107
133
  const next = sendChainRef.current.then(() => {
108
134
  if (!isMountedRef.current) throw sendAbandonedError;
@@ -111,14 +137,35 @@ const useEveAgentRuntime = (options = {}) => {
111
137
  });
112
138
  sendChainRef.current = next.catch(() => {});
113
139
  return next;
114
- };
140
+ }, []);
115
141
  useEffect(() => {
116
142
  isMountedRef.current = true;
117
143
  return () => {
118
144
  isMountedRef.current = false;
119
- sendEpochRef.current += 1;
120
145
  };
121
146
  }, []);
147
+ useReplaySafeEffect(() => () => {
148
+ sendEpochRef.current += 1;
149
+ }, []);
150
+ const enqueueResume = useCallback(() => enqueueSend(async () => {
151
+ const live = agentRef.current;
152
+ if (live.session === void 0 || !("resume" in live)) return;
153
+ await live.resume();
154
+ }, resetEpochRef), [enqueueSend]);
155
+ useEffect(() => {
156
+ if (!resumesOnMount) return;
157
+ let active = true;
158
+ queueMicrotask(() => {
159
+ if (active) enqueueResume().catch(() => {});
160
+ });
161
+ return () => {
162
+ active = false;
163
+ };
164
+ }, [enqueueResume, resumesOnMount]);
165
+ useReplaySafeEffect(() => {
166
+ if (!cloudThread?.isNew) return;
167
+ return () => cloudThread.sessions.release(cloudThread.id);
168
+ }, [cloudThread]);
122
169
  useEffect(() => {
123
170
  if (stagedInputsRef.current.size === 0) return;
124
171
  const baseIds = new Set(convertedMessages.map((message) => message.id));
@@ -149,6 +196,10 @@ const useEveAgentRuntime = (options = {}) => {
149
196
  setStagedMessages(nextMessages);
150
197
  };
151
198
  const reset = useCallback(() => {
199
+ if (cloudThread) {
200
+ aui.threads.switchToNewThread();
201
+ return;
202
+ }
152
203
  runtimeRef.current?.thread.unstable_notifySessionReset();
153
204
  sendEpochRef.current += 1;
154
205
  resetEpochRef.current += 1;
@@ -157,7 +208,11 @@ const useEveAgentRuntime = (options = {}) => {
157
208
  stagedInputsRef.current.clear();
158
209
  setToolStatuses({});
159
210
  agent.reset();
160
- }, [agent]);
211
+ }, [
212
+ agent,
213
+ aui,
214
+ cloudThread
215
+ ]);
161
216
  const extras = useMemo(() => eveExtras.provide({
162
217
  error: agent.error,
163
218
  events: agent.events,
@@ -173,6 +228,7 @@ const useEveAgentRuntime = (options = {}) => {
173
228
  ...pickExternalStoreSharedOptions(options),
174
229
  messages,
175
230
  isRunning: providerIsRunning,
231
+ isLoading: agent.status === "resuming",
176
232
  extras,
177
233
  unstable_enableToolInvocations: true,
178
234
  setToolStatuses,
@@ -184,7 +240,9 @@ const useEveAgentRuntime = (options = {}) => {
184
240
  feedback: adapters?.feedback
185
241
  },
186
242
  onNew: async (message) => {
243
+ if (isSessionless) throw new MessageNotSentError("This thread has no eve session to send to.");
187
244
  if (!(message.startRun ?? message.role === "user")) {
245
+ if (cloudThread?.isNew) cloudThread.sessions.reject(cloudThread.id, /* @__PURE__ */ new Error("The thread's first message was staged without a run."));
188
246
  stageUserMessage(message);
189
247
  return;
190
248
  }
@@ -227,11 +285,7 @@ const useEveAgentRuntime = (options = {}) => {
227
285
  if ("cancel" in controls) await controls.cancel();
228
286
  else controls.stop();
229
287
  },
230
- ..."resume" in agent ? { onRefetchThread: () => enqueueSend(async () => {
231
- const live = agentRef.current;
232
- if (live.session === void 0) return;
233
- await live.resume();
234
- }, resetEpochRef).catch((error) => {
288
+ ..."resume" in agent ? { onRefetchThread: () => enqueueResume().catch((error) => {
235
289
  if (isDroppedSend(error)) return;
236
290
  throw error;
237
291
  }) } : {},
@@ -245,6 +299,35 @@ const useEveAgentRuntime = (options = {}) => {
245
299
  runtimeRef.current = runtime;
246
300
  return runtime;
247
301
  };
302
+ const useEveCloudRuntime = (cloud, options) => {
303
+ const [sessions] = useState(createEveCloudSessions);
304
+ const adapter = useCloudThreadListAdapter({
305
+ cloud,
306
+ sdk: EVE_SDK,
307
+ upsert: true,
308
+ create: async (threadId) => ({ externalId: await sessions.wait(threadId) })
309
+ });
310
+ return useRemoteThreadListRuntime({
311
+ adapter,
312
+ allowNesting: true,
313
+ runtimeHook: function RuntimeHook() {
314
+ return useEveThreadRuntime(options, sessions);
315
+ }
316
+ });
317
+ };
318
+ /**
319
+ * Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
320
+ *
321
+ * The runtime renders Eve messages, forwards new user messages to the Eve
322
+ * session, supports cancellation, and maps Eve input requests to assistant-ui
323
+ * tool approval UI.
324
+ */
325
+ const useEveAgentRuntime = (options = {}) => {
326
+ const [hasCloud] = useState(options.cloud !== void 0);
327
+ if (options.cloud !== void 0 !== hasCloud) throw new Error("useEveAgentRuntime cannot add or remove `cloud` after it mounts; remount it, for example with a `key`, to switch.");
328
+ if (!options.cloud) return useEveThreadRuntime(options, void 0);
329
+ return useEveCloudRuntime(options.cloud, options);
330
+ };
248
331
  //#endregion
249
332
  export { useEveAgentRuntime };
250
333
 
@@ -1 +1 @@
1
- {"version":3,"file":"useEveAgentRuntime.js","names":[],"sources":["../src/useEveAgentRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n fromThreadMessageLike,\n generateId,\n MessageNotSentError,\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 type UseEveAgentStatus,\n} from \"eve/react\";\nimport {\n convertEveMessages,\n findEveInputRequest,\n getEveMessageContent,\n toEveInputResponse,\n} from \"./convertEveMessages\";\nimport {\n collectTurnTimestamps,\n createTurnTimestampCache,\n} from \"./deriveCreatedAt\";\nimport { eveExtras } from \"./eveExtras\";\n\nconst USER_STAGED_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} as const;\n\nconst sendCancelledError = new MessageNotSentError(\n \"eve send was dropped because the run was cancelled.\",\n);\n\nconst sendAbandonedError = new Error(\n \"eve send was dropped because the runtime unmounted.\",\n);\n\nconst isDroppedSend = (error: unknown) =>\n error === sendCancelledError || error === sendAbandonedError;\n\ntype EveLifecycleCallbackName =\n | \"onError\"\n | \"onEvent\"\n | \"onFinish\"\n | \"onSessionChange\";\n\nconst reportEveLifecycleCallbackError = (\n name: EveLifecycleCallbackName,\n error: unknown,\n) => {\n console.error(`[assistant-ui/eve] ${name} callback threw an error`, error);\n};\n\nconst invokeEveLifecycleCallback = <T>(\n name: EveLifecycleCallbackName,\n callback: ((value: T) => unknown) | undefined,\n value: T,\n) => {\n if (!callback) return;\n\n try {\n void Promise.resolve(callback(value)).catch((error) => {\n reportEveLifecycleCallbackError(name, error);\n });\n } catch (error) {\n reportEveLifecycleCallbackError(name, error);\n }\n};\n\nconst hasRunConfig = (\n runConfig: AppendMessage[\"runConfig\"],\n): runConfig is NonNullable<AppendMessage[\"runConfig\"]> =>\n runConfig?.custom !== undefined && Object.keys(runConfig.custom).length > 0;\n\ntype EveJsonValue =\n | string\n | number\n | boolean\n | null\n | readonly EveJsonValue[]\n | { readonly [key: string]: EveJsonValue };\n\n/**\n * Structural equivalent of eve's `JsonObject`. Eve demoted its public send\n * payload type once already (`SendTurnPayload`, public through 0.30, internal\n * from 0.31), so the helpers declare the shapes they forward instead of\n * re-exporting eve's option types, and assignability is checked at the send\n * call sites against the installed version.\n */\ntype EveClientContext = { readonly [key: string]: EveJsonValue };\n\n/**\n * Only the `custom` bag crosses the wire. Eve reads `clientContext` as its own\n * namespace and serializes it into a model-visible context message, so sending\n * the assistant-ui envelope would surface a literal `\"custom\"` key in the\n * prompt and to every eve-side handler.\n */\nconst toEveSendOptions = (\n runConfig: AppendMessage[\"runConfig\"],\n): { readonly clientContext: EveClientContext } | undefined =>\n hasRunConfig(runConfig)\n ? { clientContext: runConfig.custom as EveClientContext }\n : undefined;\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 { onError, onEvent, onFinish, onSessionChange } = agentOptions;\n const lastFinishStatusRef = useRef<UseEveAgentStatus | null>(null);\n const agent = useEveAgent({\n ...agentOptions,\n ...(onError\n ? {\n onError: (error) =>\n invokeEveLifecycleCallback(\"onError\", onError, error),\n }\n : {}),\n ...(onEvent\n ? {\n onEvent: (event) =>\n invokeEveLifecycleCallback(\"onEvent\", onEvent, event),\n }\n : {}),\n onFinish: (snapshot) => {\n lastFinishStatusRef.current = snapshot.status;\n invokeEveLifecycleCallback(\"onFinish\", onFinish, snapshot);\n },\n ...(onSessionChange\n ? {\n onSessionChange: (session) =>\n invokeEveLifecycleCallback(\n \"onSessionChange\",\n onSessionChange,\n session,\n ),\n }\n : {}),\n });\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 providerIsRunning =\n agent.status === \"submitted\" || agent.status === \"streaming\";\n const isRunning = providerIsRunning || hasExecutingTools;\n\n // Kept apart from the message memo so events that teach no timestamp keep\n // the map identity and skip rebuilding every ThreadMessage.\n const turnTimestampCacheRef = useRef(createTurnTimestampCache());\n const turnTimestamps = useMemo(\n () => collectTurnTimestamps(agent.events, turnTimestampCacheRef.current),\n [agent.events],\n );\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 error: agent.error,\n getCreatedAt: (message) => {\n const turnId = message.metadata?.turnId;\n const durable =\n turnId === undefined\n ? undefined\n : turnTimestamps.get(turnId)?.[message.role];\n if (durable !== undefined) return durable;\n\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, agent.error, isRunning, turnTimestamps]);\n\n const messages = stagedMessages ?? convertedMessages;\n const messagesRef = useRef(messages);\n const agentRef = useRef(agent);\n // Descendant layout effects can dispatch against these refs synchronously;\n // this matches useA2ARuntime's commit-scoped ref publication.\n useInsertionEffect(() => {\n messagesRef.current = messages;\n agentRef.current = agent;\n }, [agent, messages]);\n\n // Upstream `EveAgentStore` `send` and `respond` reject while a turn is in\n // flight and only resolve once the turn's stream parks, so a pending chain\n // link is exactly an active turn; chaining every dispatch serializes them\n // without watching status.\n const sendChainRef = useRef<Promise<void>>(Promise.resolve());\n const sendEpochRef = useRef(0);\n // A cancel drops the queued send but keeps its draft for a later promotion;\n // only a reset discards the draft with the session, so the two need separate\n // counters. A queued read has no draft and outlives a cancel, so it waits on\n // the reset counter instead.\n const resetEpochRef = useRef(0);\n const isMountedRef = useRef(true);\n const runtimeRef = useRef<ReturnType<typeof useExternalStoreRuntime> | null>(\n null,\n );\n\n const enqueueSend = (\n dispatch: () => Promise<void>,\n epochRef: { current: number } = sendEpochRef,\n ) => {\n const epoch = epochRef.current;\n const next = sendChainRef.current.then(() => {\n if (!isMountedRef.current) throw sendAbandonedError;\n if (epoch !== epochRef.current) throw sendCancelledError;\n return dispatch();\n });\n sendChainRef.current = next.catch(() => {});\n return next;\n };\n\n // The store outlives the component (useEveAgent holds it in a ref with no\n // cleanup), so queued sends must not fire server turns after unmount. The\n // flag separates that teardown from a user cancel, and is re-armed in setup\n // for a remounted tree.\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n sendEpochRef.current += 1;\n };\n }, []);\n\n useEffect(() => {\n if (stagedInputsRef.current.size === 0) return;\n const baseIds = new Set(convertedMessages.map((message) => message.id));\n const remaining = messagesRef.current.filter(\n (message) =>\n stagedInputsRef.current.has(message.id) && !baseIds.has(message.id),\n );\n setStagedMessages(\n remaining.length > 0 ? [...convertedMessages, ...remaining] : null,\n );\n }, [convertedMessages]);\n\n const getStagedRun = (parentId: string | null) => {\n if (!parentId || !stagedInputsRef.current.has(parentId)) return null;\n const staged: {\n message: ThreadMessage;\n input: { message: AppendMessage; runConfig: AppendMessage[\"runConfig\"] };\n }[] = [];\n for (const message of messagesRef.current) {\n const input = stagedInputsRef.current.get(message.id);\n if (input) staged.push({ message, input });\n if (message.id === parentId) break;\n }\n return staged;\n };\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 const nextMessages = [...messagesRef.current, threadMessage];\n messagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n };\n\n const reset = useCallback(() => {\n runtimeRef.current?.thread.unstable_notifySessionReset();\n // Sends parked behind an active turn captured the pre-reset epoch, so the\n // epoch has to advance before the session is torn down or they dispatch\n // into the new one; `lastFinishStatusRef` is run-scoped for the same\n // reason.\n sendEpochRef.current += 1;\n resetEpochRef.current += 1;\n lastFinishStatusRef.current = null;\n setStagedMessages(null);\n stagedInputsRef.current.clear();\n setToolStatuses({});\n agent.reset();\n }, [agent]);\n\n const extras = useMemo(\n () =>\n eveExtras.provide({\n error: agent.error,\n events: agent.events,\n session: agent.session,\n reset,\n }),\n [agent.error, agent.events, agent.session, reset],\n );\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n messages,\n isRunning: providerIsRunning,\n extras,\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 try {\n await enqueueSend(() =>\n agent.send(\n getEveMessageContent(message),\n toEveSendOptions(message.runConfig),\n ),\n );\n } catch (error) {\n // A cancelled send never reached the session, so it rethrows for the\n // composer to take the draft back; an unmounted one has no composer\n // left to restore.\n if (error === sendAbandonedError) return;\n throw error;\n }\n },\n ...(stagedMessages\n ? {\n onReload: async (parentId: string | null, config) => {\n const stagedRun = getStagedRun(parentId);\n if (!stagedRun)\n throw new Error(\"Runtime does not support reloading messages.\");\n const epoch = sendEpochRef.current;\n const resetEpoch = resetEpochRef.current;\n for (const { message: stagedMessage, input } of stagedRun) {\n if (epoch !== sendEpochRef.current) return;\n const previousMessages = messagesRef.current;\n stagedInputsRef.current.delete(stagedMessage.id);\n const nextMessages = previousMessages.filter(\n (message) => message.id !== stagedMessage.id,\n );\n messagesRef.current = nextMessages;\n setStagedMessages(\n stagedInputsRef.current.size > 0 ? nextMessages : null,\n );\n // The reload config belongs to the message being reloaded; the\n // drafts promoted ahead of it keep the config they were staged\n // with, or reloading the tail would rewrite their context too.\n const runConfig =\n stagedMessage.id === parentId && hasRunConfig(config.runConfig)\n ? config.runConfig\n : input.runConfig;\n try {\n await enqueueSend(() =>\n agent.send(\n getEveMessageContent(input.message),\n toEveSendOptions(runConfig),\n ),\n );\n } catch (error) {\n // A reset discarded the draft along with the session, so\n // restoring it here would refloat a message the thread no\n // longer has. A cancel still restores.\n if (resetEpoch !== resetEpochRef.current) return;\n stagedInputsRef.current.set(stagedMessage.id, input);\n messagesRef.current = previousMessages;\n setStagedMessages(previousMessages);\n if (isDroppedSend(error)) return;\n throw error;\n }\n if (lastFinishStatusRef.current === \"error\") return;\n }\n },\n }\n : {}),\n onCancel: async () => {\n sendEpochRef.current += 1;\n // Eve 0.38 replaced the binding's local-abort `stop()` with the durable\n // `cancel()`, so the adapter detects which side of that break the host's\n // eve provides instead of pinning the peer range to one of them.\n const controls = agent as\n | { readonly cancel: () => Promise<unknown> }\n | { readonly stop: () => void };\n if (\"cancel\" in controls) {\n await controls.cancel();\n } else {\n controls.stop();\n }\n },\n // Hosts below eve 0.44.1 expose no `resume`; leaving the capability absent\n // keeps `threads.reloadMainThread()` on core's no-capability no-op.\n ...(\"resume\" in agent\n ? {\n onRefetchThread: () =>\n // `resume()` rejects during a turn, so the replay rides the send\n // chain like every other dispatch and runs once the turn parks; a\n // cancel of that turn does not drop it, or the caller would be told\n // the thread was refetched when it was not. Upstream shares one\n // replay across concurrent `resume()` calls, so a refetch\n // dispatched while `resume: true` is replaying on mount joins that\n // read instead of taking a fresh one. The session is read at\n // dispatch time because nothing durable exists before the first\n // send lands.\n enqueueSend(async () => {\n const live = agentRef.current;\n if (live.session === undefined) return;\n await live.resume();\n }, resetEpochRef).catch((error) => {\n if (isDroppedSend(error)) return;\n throw error;\n }),\n }\n : {}),\n onRespondToToolApproval: (response) => {\n // Eve resolves a request the moment any response for it arrives, and an\n // empty one is recorded as an answer with no content. Mapping before the\n // send is enqueued keeps an unmappable response unsent, so the request\n // stays answerable; the mapper's error reaches the caller as the seam's\n // rejection.\n const inputResponse = toEveInputResponse(\n response,\n findEveInputRequest(agent.data, response.approvalId),\n );\n return enqueueSend(() => agent.respond([inputResponse])).catch(\n (error) => {\n if (!isDroppedSend(error)) throw error;\n },\n );\n },\n });\n runtimeRef.current = runtime;\n\n return runtime;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useEveAgentRuntime.js","names":[],"sources":["../src/useEveAgentRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n fromThreadMessageLike,\n generateId,\n MessageNotSentError,\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 useCloudThreadListAdapter,\n useExternalStoreRuntime,\n useRemoteThreadListRuntime,\n useRuntimeAdapters,\n} from \"@assistant-ui/core/react\";\nimport { useReplaySafeEffect } from \"@assistant-ui/store/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n useEveAgent,\n type EveMessageData,\n type UseEveAgentOptions,\n type UseEveAgentStatus,\n} from \"eve/react\";\nimport {\n convertEveMessages,\n findEveInputRequest,\n getEveMessageContent,\n toEveInputResponse,\n} from \"./convertEveMessages\";\nimport {\n collectTurnTimestamps,\n createTurnTimestampCache,\n} from \"./deriveCreatedAt\";\nimport {\n createEveCloudSessions,\n type EveCloudSessions,\n} from \"./eveCloudSessions\";\nimport { eveExtras } from \"./eveExtras\";\nimport { EVE_SDK } from \"./sdkIdentity\";\n\nconst USER_STAGED_STATUS = {\n type: \"complete\",\n reason: \"unknown\",\n} as const;\n\nconst sendCancelledError = new MessageNotSentError(\n \"eve send was dropped because the run was cancelled.\",\n);\n\nconst sendAbandonedError = new Error(\n \"eve send was dropped because the runtime unmounted.\",\n);\n\nconst isDroppedSend = (error: unknown) =>\n error === sendCancelledError || error === sendAbandonedError;\n\ntype EveLifecycleCallbackName =\n | \"onError\"\n | \"onEvent\"\n | \"onFinish\"\n | \"onSessionChange\";\n\nconst reportEveLifecycleCallbackError = (\n name: EveLifecycleCallbackName,\n error: unknown,\n) => {\n console.error(`[assistant-ui/eve] ${name} callback threw an error`, error);\n};\n\nconst invokeEveLifecycleCallback = <T>(\n name: EveLifecycleCallbackName,\n callback: ((value: T) => unknown) | undefined,\n value: T,\n) => {\n if (!callback) return;\n\n try {\n void Promise.resolve(callback(value)).catch((error) => {\n reportEveLifecycleCallbackError(name, error);\n });\n } catch (error) {\n reportEveLifecycleCallbackError(name, error);\n }\n};\n\nconst hasRunConfig = (\n runConfig: AppendMessage[\"runConfig\"],\n): runConfig is NonNullable<AppendMessage[\"runConfig\"]> =>\n runConfig?.custom !== undefined && Object.keys(runConfig.custom).length > 0;\n\ntype EveJsonValue =\n | string\n | number\n | boolean\n | null\n | readonly EveJsonValue[]\n | { readonly [key: string]: EveJsonValue };\n\n/**\n * Structural equivalent of eve's `JsonObject`. Eve demoted its public send\n * payload type once already (`SendTurnPayload`, public through 0.30, internal\n * from 0.31), so the helpers declare the shapes they forward instead of\n * re-exporting eve's option types, and assignability is checked at the send\n * call sites against the installed version.\n */\ntype EveClientContext = { readonly [key: string]: EveJsonValue };\n\n/**\n * Only the `custom` bag crosses the wire. Eve reads `clientContext` as its own\n * namespace and serializes it into a model-visible context message, so sending\n * the assistant-ui envelope would surface a literal `\"custom\"` key in the\n * prompt and to every eve-side handler.\n */\nconst toEveSendOptions = (\n runConfig: AppendMessage[\"runConfig\"],\n): { readonly clientContext: EveClientContext } | undefined =>\n hasRunConfig(runConfig)\n ? { clientContext: runConfig.custom as EveClientContext }\n : undefined;\n\ntype EveAgentOptions = Omit<UseEveAgentOptions<EveMessageData>, \"reducer\">;\n\nexport type UseEveAgentRuntimeOptions = EveAgentOptions &\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 * Backs the thread list with Assistant Cloud. Each cloud thread keeps one Eve session as its external id, saved once the thread's first turn creates the session, and opening a thread resumes it, so `session`, `initialSession`, `initialEvents`, and `resume` are not used. Pass it from the first render: adding or removing it later throws, so remount the runtime, for example with a `key`, to switch.\n */\n readonly cloud?: AssistantCloud | undefined;\n };\n\ntype EveCloudThread = {\n readonly sessions: EveCloudSessions;\n readonly id: string;\n readonly isNew: boolean;\n readonly sessionId: string | undefined;\n};\n\nconst withCloudThreadSession = (\n {\n initialEvents: _initialEvents,\n initialSession: _initialSession,\n resume: _resume,\n session: _session,\n ...options\n }: EveAgentOptions,\n sessionId: string | undefined,\n): EveAgentOptions =>\n sessionId === undefined\n ? options\n : {\n ...options,\n initialSession: { sessionId, streamIndex: 0 },\n resume: true,\n };\n\nconst useEveThreadRuntime = (\n options: UseEveAgentRuntimeOptions,\n cloudSessions: EveCloudSessions | undefined,\n) => {\n const {\n adapters,\n cloud: _cloud,\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 aui = useAui();\n const [cloudThread] = useState((): EveCloudThread | undefined => {\n if (!cloudSessions) return undefined;\n const { id, status, externalId } = aui.threadListItem.getState();\n return {\n sessions: cloudSessions,\n id,\n isNew: status === \"new\",\n sessionId: externalId,\n };\n });\n const [resumesOnMount] = useState(() =>\n cloudThread\n ? cloudThread.sessionId !== undefined\n : agentOptions.resume === true,\n );\n const isSessionless =\n cloudThread !== undefined &&\n !cloudThread.isNew &&\n cloudThread.sessionId === undefined;\n\n const { onError, onEvent, onFinish, onSessionChange } = agentOptions;\n const lastFinishStatusRef = useRef<UseEveAgentStatus | null>(null);\n const agent = useEveAgent({\n ...(cloudThread\n ? withCloudThreadSession(agentOptions, cloudThread.sessionId)\n : agentOptions),\n ...(onError\n ? {\n onError: (error) =>\n invokeEveLifecycleCallback(\"onError\", onError, error),\n }\n : {}),\n ...(onEvent\n ? {\n onEvent: (event) =>\n invokeEveLifecycleCallback(\"onEvent\", onEvent, event),\n }\n : {}),\n onFinish: (snapshot) => {\n lastFinishStatusRef.current = snapshot.status;\n invokeEveLifecycleCallback(\"onFinish\", onFinish, snapshot);\n },\n ...(onSessionChange || cloudThread?.isNew\n ? {\n onSessionChange: (session) => {\n if (cloudThread?.isNew && session === undefined) {\n cloudThread.sessions.reject(\n cloudThread.id,\n new Error(\"The eve turn ended before it created a session.\"),\n );\n } else if (cloudThread?.isNew && session !== undefined) {\n cloudThread.sessions.resolve(cloudThread.id, session.sessionId);\n // A first message staged without a run leaves the thread unsaved, so the run that creates the session saves it.\n if (aui.threadListItem.getState().status === \"new\")\n aui.threadListItem.initialize().catch(() => {});\n }\n invokeEveLifecycleCallback(\n \"onSessionChange\",\n onSessionChange,\n session,\n );\n },\n }\n : {}),\n });\n if (cloudThread && !(\"resume\" in agent)) {\n throw new Error(\n \"useEveAgentRuntime needs eve 0.44.1 or later for `cloud`, because opening a cloud thread resumes its session.\",\n );\n }\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 providerIsRunning =\n agent.status === \"submitted\" || agent.status === \"streaming\";\n const isRunning = providerIsRunning || hasExecutingTools;\n\n // Kept apart from the message memo so events that teach no timestamp keep\n // the map identity and skip rebuilding every ThreadMessage.\n const turnTimestampCacheRef = useRef(createTurnTimestampCache());\n const turnTimestamps = useMemo(\n () => collectTurnTimestamps(agent.events, turnTimestampCacheRef.current),\n [agent.events],\n );\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 error: agent.error,\n getCreatedAt: (message) => {\n const turnId = message.metadata?.turnId;\n const durable =\n turnId === undefined\n ? undefined\n : turnTimestamps.get(turnId)?.[message.role];\n if (durable !== undefined) return durable;\n\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, agent.error, isRunning, turnTimestamps]);\n\n const messages = stagedMessages ?? convertedMessages;\n const messagesRef = useRef(messages);\n const agentRef = useRef(agent);\n // Descendant layout effects can dispatch against these refs synchronously;\n // this matches useA2ARuntime's commit-scoped ref publication.\n useInsertionEffect(() => {\n messagesRef.current = messages;\n agentRef.current = agent;\n }, [agent, messages]);\n\n // Upstream `EveAgentStore` `send` and `respond` reject while a turn is in\n // flight and only resolve once the turn's stream parks, so a pending chain\n // link is exactly an active turn; chaining every dispatch serializes them\n // without watching status.\n const sendChainRef = useRef<Promise<void>>(Promise.resolve());\n const sendEpochRef = useRef(0);\n // A cancel drops the queued send but keeps its draft for a later promotion;\n // only a reset discards the draft with the session, so the two need separate\n // counters. A queued read has no draft and outlives a cancel, so it waits on\n // the reset counter instead.\n const resetEpochRef = useRef(0);\n const isMountedRef = useRef(true);\n const runtimeRef = useRef<ReturnType<typeof useExternalStoreRuntime> | null>(\n null,\n );\n\n const enqueueSend = useCallback(\n (\n dispatch: () => Promise<void>,\n epochRef: { current: number } = sendEpochRef,\n ) => {\n const epoch = epochRef.current;\n const next = sendChainRef.current.then(() => {\n if (!isMountedRef.current) throw sendAbandonedError;\n if (epoch !== epochRef.current) throw sendCancelledError;\n return dispatch();\n });\n sendChainRef.current = next.catch(() => {});\n return next;\n },\n [],\n );\n\n // The store outlives the component (useEveAgent holds it in a ref with no\n // cleanup), so queued sends must not fire server turns after unmount. The\n // flag separates that teardown from a user cancel, and is re-armed in setup\n // for a remounted tree.\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n // A replay (Fast Refresh, StrictMode) must not cancel the sends queued behind the active turn.\n useReplaySafeEffect(\n () => () => {\n sendEpochRef.current += 1;\n },\n [],\n );\n\n // A replay rides the send chain because `resume()` rejects during a turn and upstream refuses sends while it runs; the reset counter keeps a cancel from dropping a refetch, and the hook's own replay on mount joins this one since upstream shares concurrent `resume()` calls.\n const enqueueResume = useCallback(\n () =>\n enqueueSend(async () => {\n const live = agentRef.current;\n if (live.session === undefined || !(\"resume\" in live)) return;\n await live.resume();\n }, resetEpochRef),\n [enqueueSend],\n );\n\n useEffect(() => {\n if (!resumesOnMount) return;\n // StrictMode's second setup queues the replay again, so only the setup that survives queues it.\n let active = true;\n queueMicrotask(() => {\n if (active) enqueueResume().catch(() => {});\n });\n return () => {\n active = false;\n };\n }, [enqueueResume, resumesOnMount]);\n\n useReplaySafeEffect(() => {\n if (!cloudThread?.isNew) return;\n return () => cloudThread.sessions.release(cloudThread.id);\n }, [cloudThread]);\n\n useEffect(() => {\n if (stagedInputsRef.current.size === 0) return;\n const baseIds = new Set(convertedMessages.map((message) => message.id));\n const remaining = messagesRef.current.filter(\n (message) =>\n stagedInputsRef.current.has(message.id) && !baseIds.has(message.id),\n );\n setStagedMessages(\n remaining.length > 0 ? [...convertedMessages, ...remaining] : null,\n );\n }, [convertedMessages]);\n\n const getStagedRun = (parentId: string | null) => {\n if (!parentId || !stagedInputsRef.current.has(parentId)) return null;\n const staged: {\n message: ThreadMessage;\n input: { message: AppendMessage; runConfig: AppendMessage[\"runConfig\"] };\n }[] = [];\n for (const message of messagesRef.current) {\n const input = stagedInputsRef.current.get(message.id);\n if (input) staged.push({ message, input });\n if (message.id === parentId) break;\n }\n return staged;\n };\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 const nextMessages = [...messagesRef.current, threadMessage];\n messagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n };\n\n const reset = useCallback(() => {\n // A cloud thread keeps the session its external id names, so a fresh session starts a new thread and leaves this one in the list.\n if (cloudThread) {\n aui.threads.switchToNewThread();\n return;\n }\n runtimeRef.current?.thread.unstable_notifySessionReset();\n // Sends parked behind an active turn captured the pre-reset epoch, so the\n // epoch has to advance before the session is torn down or they dispatch\n // into the new one; `lastFinishStatusRef` is run-scoped for the same\n // reason.\n sendEpochRef.current += 1;\n resetEpochRef.current += 1;\n lastFinishStatusRef.current = null;\n setStagedMessages(null);\n stagedInputsRef.current.clear();\n setToolStatuses({});\n agent.reset();\n }, [agent, aui, cloudThread]);\n\n const extras = useMemo(\n () =>\n eveExtras.provide({\n error: agent.error,\n events: agent.events,\n session: agent.session,\n reset,\n }),\n [agent.error, agent.events, agent.session, reset],\n );\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n messages,\n isRunning: providerIsRunning,\n isLoading: agent.status === \"resuming\",\n extras,\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 (isSessionless)\n throw new MessageNotSentError(\n \"This thread has no eve session to send to.\",\n );\n if (!(message.startRun ?? message.role === \"user\")) {\n // Saving a new cloud thread waits for its first session, which a staged message never creates.\n if (cloudThread?.isNew)\n cloudThread.sessions.reject(\n cloudThread.id,\n new Error(\"The thread's first message was staged without a run.\"),\n );\n stageUserMessage(message);\n return;\n }\n try {\n await enqueueSend(() =>\n agent.send(\n getEveMessageContent(message),\n toEveSendOptions(message.runConfig),\n ),\n );\n } catch (error) {\n // A cancelled send never reached the session, so it rethrows for the\n // composer to take the draft back; an unmounted one has no composer\n // left to restore.\n if (error === sendAbandonedError) return;\n throw error;\n }\n },\n ...(stagedMessages\n ? {\n onReload: async (parentId: string | null, config) => {\n const stagedRun = getStagedRun(parentId);\n if (!stagedRun)\n throw new Error(\"Runtime does not support reloading messages.\");\n const epoch = sendEpochRef.current;\n const resetEpoch = resetEpochRef.current;\n for (const { message: stagedMessage, input } of stagedRun) {\n if (epoch !== sendEpochRef.current) return;\n const previousMessages = messagesRef.current;\n stagedInputsRef.current.delete(stagedMessage.id);\n const nextMessages = previousMessages.filter(\n (message) => message.id !== stagedMessage.id,\n );\n messagesRef.current = nextMessages;\n setStagedMessages(\n stagedInputsRef.current.size > 0 ? nextMessages : null,\n );\n // The reload config belongs to the message being reloaded; the\n // drafts promoted ahead of it keep the config they were staged\n // with, or reloading the tail would rewrite their context too.\n const runConfig =\n stagedMessage.id === parentId && hasRunConfig(config.runConfig)\n ? config.runConfig\n : input.runConfig;\n try {\n await enqueueSend(() =>\n agent.send(\n getEveMessageContent(input.message),\n toEveSendOptions(runConfig),\n ),\n );\n } catch (error) {\n // A reset discarded the draft along with the session, so\n // restoring it here would refloat a message the thread no\n // longer has. A cancel still restores.\n if (resetEpoch !== resetEpochRef.current) return;\n stagedInputsRef.current.set(stagedMessage.id, input);\n messagesRef.current = previousMessages;\n setStagedMessages(previousMessages);\n if (isDroppedSend(error)) return;\n throw error;\n }\n if (lastFinishStatusRef.current === \"error\") return;\n }\n },\n }\n : {}),\n onCancel: async () => {\n sendEpochRef.current += 1;\n // Eve 0.38 replaced the binding's local-abort `stop()` with the durable\n // `cancel()`, so the adapter detects which side of that break the host's\n // eve provides instead of pinning the peer range to one of them.\n const controls = agent as\n | { readonly cancel: () => Promise<unknown> }\n | { readonly stop: () => void };\n if (\"cancel\" in controls) {\n await controls.cancel();\n } else {\n controls.stop();\n }\n },\n // Hosts below eve 0.44.1 expose no `resume`; leaving the capability absent\n // keeps `threads.reloadMainThread()` on core's no-capability no-op.\n ...(\"resume\" in agent\n ? {\n onRefetchThread: () =>\n enqueueResume().catch((error) => {\n if (isDroppedSend(error)) return;\n throw error;\n }),\n }\n : {}),\n onRespondToToolApproval: (response) => {\n // Eve resolves a request the moment any response for it arrives, and an\n // empty one is recorded as an answer with no content. Mapping before the\n // send is enqueued keeps an unmappable response unsent, so the request\n // stays answerable; the mapper's error reaches the caller as the seam's\n // rejection.\n const inputResponse = toEveInputResponse(\n response,\n findEveInputRequest(agent.data, response.approvalId),\n );\n return enqueueSend(() => agent.respond([inputResponse])).catch(\n (error) => {\n if (!isDroppedSend(error)) throw error;\n },\n );\n },\n });\n runtimeRef.current = runtime;\n\n return runtime;\n};\n\nconst useEveCloudRuntime = (\n cloud: AssistantCloud,\n options: UseEveAgentRuntimeOptions,\n) => {\n const [sessions] = useState(createEveCloudSessions);\n const adapter = useCloudThreadListAdapter({\n cloud,\n sdk: EVE_SDK,\n upsert: true,\n create: async (threadId) => ({ externalId: await sessions.wait(threadId) }),\n });\n return useRemoteThreadListRuntime({\n adapter,\n allowNesting: true,\n runtimeHook: function RuntimeHook() {\n return useEveThreadRuntime(options, sessions);\n },\n });\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 [hasCloud] = useState(options.cloud !== undefined);\n if ((options.cloud !== undefined) !== hasCloud) {\n throw new Error(\n \"useEveAgentRuntime cannot add or remove `cloud` after it mounts; remount it, for example with a `key`, to switch.\",\n );\n }\n if (!options.cloud) {\n // oxlint-disable-next-line react-hooks/rules-of-hooks -- `cloud` stays set or unset for the runtime's lifetime, so every render takes the same branch\n return useEveThreadRuntime(options, undefined);\n }\n // oxlint-disable-next-line react-hooks/rules-of-hooks -- `cloud` stays set or unset for the runtime's lifetime, so every render takes the same branch\n return useEveCloudRuntime(options.cloud, options);\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.19",
3
+ "version": "0.0.21",
4
4
  "description": "Eve runtime adapter for assistant-ui",
5
5
  "keywords": [
6
6
  "eve",
@@ -28,8 +28,9 @@
28
28
  ],
29
29
  "sideEffects": false,
30
30
  "dependencies": {
31
- "@assistant-ui/core": "^0.3.21",
32
- "@assistant-ui/store": "^0.3.15"
31
+ "@assistant-ui/core": "^0.3.23",
32
+ "@assistant-ui/store": "^0.3.17",
33
+ "assistant-cloud": "*"
33
34
  },
34
35
  "peerDependencies": {
35
36
  "@types/react": "*",
@@ -42,7 +43,8 @@
42
43
  }
43
44
  },
44
45
  "devDependencies": {
45
- "@assistant-ui/x-buildutils": "0.0.29",
46
+ "@assistant-ui/x-buildutils": "0.0.30",
47
+ "@assistant-ui/x-react18": "0.0.0",
46
48
  "@testing-library/dom": "^10.4.2",
47
49
  "@testing-library/react": "^16.3.3",
48
50
  "@types/react": "^19.3.0",
@@ -50,7 +52,7 @@
50
52
  "jsdom": "^30.0.1",
51
53
  "react": "^19.3.0",
52
54
  "react-dom": "^19.3.0",
53
- "vitest": "^5.0.1"
55
+ "vitest": "^5.0.3"
54
56
  },
55
57
  "publishConfig": {
56
58
  "access": "public",
@@ -69,6 +71,8 @@
69
71
  "build": "aui-build",
70
72
  "test": "vitest run",
71
73
  "typecheck": "tsc --noEmit",
72
- "test:watch": "vitest"
74
+ "test:peer-react18": "vitest run --config vitest.peer-react18.config.ts",
75
+ "test:watch": "vitest",
76
+ "test:types:peer-react18": "aui-react18-types"
73
77
  }
74
78
  }