@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 +1 -1
- package/dist/eveCloudSessions.d.ts +9 -0
- package/dist/eveCloudSessions.d.ts.map +1 -0
- package/dist/eveCloudSessions.js +51 -0
- package/dist/eveCloudSessions.js.map +1 -0
- package/dist/hooks.d.ts +4 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +4 -0
- package/dist/hooks.js.map +1 -1
- package/dist/sdkIdentity.d.ts +3 -0
- package/dist/sdkIdentity.d.ts.map +1 -0
- package/dist/sdkIdentity.js +9 -0
- package/dist/sdkIdentity.js.map +1 -0
- package/dist/useEveAgentRuntime.d.ts +8 -1
- package/dist/useEveAgentRuntime.d.ts.map +1 -1
- package/dist/useEveAgentRuntime.js +104 -21
- package/dist/useEveAgentRuntime.js.map +1 -1
- package/package.json +10 -6
- package/src/eveCloudSessions.test.ts +78 -0
- package/src/eveCloudSessions.ts +59 -0
- package/src/hooks.ts +4 -0
- package/src/sdkIdentity.ts +9 -0
- package/src/useEveAgentRuntime.cloud.test.tsx +558 -0
- package/src/useEveAgentRuntime.eveResume.test.tsx +102 -2
- package/src/useEveAgentRuntime.fast-refresh.test.tsx +342 -0
- package/src/useEveAgentRuntime.ts +203 -45
package/LICENSE
CHANGED
|
@@ -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
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAoB;AAIpD,+DAA+D;AAC/D,eAAO,MAAM,WAAW,yBAAiD,CAAC;AAE1E
|
|
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
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
-
|
|
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;
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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) =>
|
|
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
|
-
}, [
|
|
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: () =>
|
|
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":";;;;;;;;;;;;;AAyDA,MAAM,qBAAqB;CACzB,MAAM;CACN,QAAQ;AACV;AAEA,MAAM,qBAAqB,IAAI,oBAC7B,qDACF;AAEA,MAAM,qCAAqB,IAAI,MAC7B,qDACF;AAEA,MAAM,iBAAiB,UACrB,UAAU,sBAAsB,UAAU;AAQ5C,MAAM,mCACJ,MACA,UACG;CACH,QAAQ,MAAM,sBAAsB,KAAK,2BAA2B,KAAK;AAC3E;AAEA,MAAM,8BACJ,MACA,UACA,UACG;CACH,IAAI,CAAC,UAAU;CAEf,IAAI;EACF,QAAa,QAAQ,SAAS,KAAK,CAAC,CAAC,CAAC,OAAO,UAAU;GACrD,gCAAgC,MAAM,KAAK;EAC7C,CAAC;CACH,SAAS,OAAO;EACd,gCAAgC,MAAM,KAAK;CAC7C;AACF;AAEA,MAAM,gBACJ,cAEA,WAAW,WAAW,KAAA,KAAa,OAAO,KAAK,UAAU,MAAM,CAAC,CAAC,SAAS;;;;;;;AAyB5E,MAAM,oBACJ,cAEA,aAAa,SAAS,IAClB,EAAE,eAAe,UAAU,OAA2B,IACtD,KAAA;AA4BN,MAAM,0BACJ,EACE,eAAe,gBACf,gBAAgB,iBAChB,QAAQ,SACR,SAAS,UACT,GAAG,WAEL,cAEA,cAAc,KAAA,IACV,UACA;CACE,GAAG;CACH,gBAAgB;EAAE;EAAW,aAAa;CAAE;CAC5C,QAAQ;AACV;AAEN,MAAM,uBACJ,SACA,kBACG;CACH,MAAM,EACJ,UACA,OAAO,QACP,YAAY,aACZ,gBAAgB,iBAChB,aAAa,cACb,uBAAuB,wBACvB,GAAG,iBACD;CAMJ,MAAM,MAAM,OAAO;CACnB,MAAM,CAAC,eAAe,eAA2C;EAC/D,IAAI,CAAC,eAAe,OAAO,KAAA;EAC3B,MAAM,EAAE,IAAI,QAAQ,eAAe,IAAI,eAAe,SAAS;EAC/D,OAAO;GACL,UAAU;GACV;GACA,OAAO,WAAW;GAClB,WAAW;EACb;CACF,CAAC;CACD,MAAM,CAAC,kBAAkB,eACvB,cACI,YAAY,cAAc,KAAA,IAC1B,aAAa,WAAW,IAC9B;CACA,MAAM,gBACJ,gBAAgB,KAAA,KAChB,CAAC,YAAY,SACb,YAAY,cAAc,KAAA;CAE5B,MAAM,EAAE,SAAS,SAAS,UAAU,oBAAoB;CACxD,MAAM,sBAAsB,OAAiC,IAAI;CACjE,MAAM,QAAQ,YAAY;EACxB,GAAI,cACA,uBAAuB,cAAc,YAAY,SAAS,IAC1D;EACJ,GAAI,UACA,EACE,UAAU,UACR,2BAA2B,WAAW,SAAS,KAAK,EACxD,IACA,CAAC;EACL,GAAI,UACA,EACE,UAAU,UACR,2BAA2B,WAAW,SAAS,KAAK,EACxD,IACA,CAAC;EACL,WAAW,aAAa;GACtB,oBAAoB,UAAU,SAAS;GACvC,2BAA2B,YAAY,UAAU,QAAQ;EAC3D;EACA,GAAI,mBAAmB,aAAa,QAChC,EACE,kBAAkB,YAAY;GAC5B,IAAI,aAAa,SAAS,YAAY,KAAA,GACpC,YAAY,SAAS,OACnB,YAAY,oBACZ,IAAI,MAAM,iDAAiD,CAC7D;QACK,IAAI,aAAa,SAAS,YAAY,KAAA,GAAW;IACtD,YAAY,SAAS,QAAQ,YAAY,IAAI,QAAQ,SAAS;IAE9D,IAAI,IAAI,eAAe,SAAS,CAAC,CAAC,WAAW,OAC3C,IAAI,eAAe,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC;GAClD;GACA,2BACE,mBACA,iBACA,OACF;EACF,EACF,IACA,CAAC;CACP,CAAC;CACD,IAAI,eAAe,EAAE,YAAY,QAC/B,MAAM,IAAI,MACR,+GACF;CAEF,MAAM,kBAAkB,mBAAmB;CAC3C,MAAM,CAAC,cAAc,mBAAmB,SAEtC,CAAC,CAAC;CACJ,MAAM,CAAC,gBAAgB,qBAAqB,SAC1C,IACF;CACA,MAAM,0BAA0B,uBAAO,IAAI,IAAkB,CAAC;CAC9D,MAAM,kBAAkB,uBACtB,IAAI,IAGF,CACJ;CAEA,MAAM,oBAAoB,OAAO,OAAO,YAAY,CAAC,CAAC,MACnD,WAAW,QAAQ,SAAS,WAC/B;CACA,MAAM,oBACJ,MAAM,WAAW,eAAe,MAAM,WAAW;CACnD,MAAM,YAAY,qBAAqB;CAIvC,MAAM,wBAAwB,OAAO,yBAAyB,CAAC;CAC/D,MAAM,iBAAiB,cACf,sBAAsB,MAAM,QAAQ,sBAAsB,OAAO,GACvE,CAAC,MAAM,MAAM,CACf;CAEA,MAAM,oBAAoB,cAAc;EACtC,MAAM,uBAAuB,wBAAwB;EACrD,MAAM,aAAa,IAAI,IACrB,MAAM,KAAK,SAAS,KAAK,YAAY,QAAQ,EAAE,CACjD;EACA,KAAK,MAAM,aAAa,qBAAqB,KAAK,GAChD,IAAI,CAAC,WAAW,IAAI,SAAS,GAAG,qBAAqB,OAAO,SAAS;EAGvE,OAAO,mBAAmB,MAAM,MAAM;GACpC;GACA,OAAO,MAAM;GACb,eAAe,YAAY;IACzB,MAAM,SAAS,QAAQ,UAAU;IACjC,MAAM,UACJ,WAAW,KAAA,IACP,KAAA,IACA,eAAe,IAAI,MAAM,CAAC,GAAG,QAAQ;IAC3C,IAAI,YAAY,KAAA,GAAW,OAAO;IAElC,MAAM,WAAW,qBAAqB,IAAI,QAAQ,EAAE;IACpD,IAAI,UAAU,OAAO;IAErB,MAAM,4BAAY,IAAI,KAAK;IAC3B,qBAAqB,IAAI,QAAQ,IAAI,SAAS;IAC9C,OAAO;GACT;EACF,CAAC;CACH,GAAG;EAAC,MAAM;EAAM,MAAM;EAAO;EAAW;CAAc,CAAC;CAEvD,MAAM,WAAW,kBAAkB;CACnC,MAAM,cAAc,OAAO,QAAQ;CACnC,MAAM,WAAW,OAAO,KAAK;CAG7B,yBAAyB;EACvB,YAAY,UAAU;EACtB,SAAS,UAAU;CACrB,GAAG,CAAC,OAAO,QAAQ,CAAC;CAMpB,MAAM,eAAe,OAAsB,QAAQ,QAAQ,CAAC;CAC5D,MAAM,eAAe,OAAO,CAAC;CAK7B,MAAM,gBAAgB,OAAO,CAAC;CAC9B,MAAM,eAAe,OAAO,IAAI;CAChC,MAAM,aAAa,OACjB,IACF;CAEA,MAAM,cAAc,aAEhB,UACA,WAAgC,iBAC7B;EACH,MAAM,QAAQ,SAAS;EACvB,MAAM,OAAO,aAAa,QAAQ,WAAW;GAC3C,IAAI,CAAC,aAAa,SAAS,MAAM;GACjC,IAAI,UAAU,SAAS,SAAS,MAAM;GACtC,OAAO,SAAS;EAClB,CAAC;EACD,aAAa,UAAU,KAAK,YAAY,CAAC,CAAC;EAC1C,OAAO;CACT,GACA,CAAC,CACH;CAMA,gBAAgB;EACd,aAAa,UAAU;EACvB,aAAa;GACX,aAAa,UAAU;EACzB;CACF,GAAG,CAAC,CAAC;CAGL,gCACc;EACV,aAAa,WAAW;CAC1B,GACA,CAAC,CACH;CAGA,MAAM,gBAAgB,kBAElB,YAAY,YAAY;EACtB,MAAM,OAAO,SAAS;EACtB,IAAI,KAAK,YAAY,KAAA,KAAa,EAAE,YAAY,OAAO;EACvD,MAAM,KAAK,OAAO;CACpB,GAAG,aAAa,GAClB,CAAC,WAAW,CACd;CAEA,gBAAgB;EACd,IAAI,CAAC,gBAAgB;EAErB,IAAI,SAAS;EACb,qBAAqB;GACnB,IAAI,QAAQ,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC;EAC5C,CAAC;EACD,aAAa;GACX,SAAS;EACX;CACF,GAAG,CAAC,eAAe,cAAc,CAAC;CAElC,0BAA0B;EACxB,IAAI,CAAC,aAAa,OAAO;EACzB,aAAa,YAAY,SAAS,QAAQ,YAAY,EAAE;CAC1D,GAAG,CAAC,WAAW,CAAC;CAEhB,gBAAgB;EACd,IAAI,gBAAgB,QAAQ,SAAS,GAAG;EACxC,MAAM,UAAU,IAAI,IAAI,kBAAkB,KAAK,YAAY,QAAQ,EAAE,CAAC;EACtE,MAAM,YAAY,YAAY,QAAQ,QACnC,YACC,gBAAgB,QAAQ,IAAI,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,QAAQ,EAAE,CACtE;EACA,kBACE,UAAU,SAAS,IAAI,CAAC,GAAG,mBAAmB,GAAG,SAAS,IAAI,IAChE;CACF,GAAG,CAAC,iBAAiB,CAAC;CAEtB,MAAM,gBAAgB,aAA4B;EAChD,IAAI,CAAC,YAAY,CAAC,gBAAgB,QAAQ,IAAI,QAAQ,GAAG,OAAO;EAChE,MAAM,SAGA,CAAC;EACP,KAAK,MAAM,WAAW,YAAY,SAAS;GACzC,MAAM,QAAQ,gBAAgB,QAAQ,IAAI,QAAQ,EAAE;GACpD,IAAI,OAAO,OAAO,KAAK;IAAE;IAAS;GAAM,CAAC;GACzC,IAAI,QAAQ,OAAO,UAAU;EAC/B;EACA,OAAO;CACT;CAEA,MAAM,oBAAoB,YAA2B;EACnD,MAAM,gBAAgB,sBACpB,SACA,WAAW,GACX,kBACF;EACA,gBAAgB,QAAQ,IAAI,cAAc,IAAI;GAC5C;GACA,WAAW,QAAQ;EACrB,CAAC;EACD,MAAM,eAAe,CAAC,GAAG,YAAY,SAAS,aAAa;EAC3D,YAAY,UAAU;EACtB,kBAAkB,YAAY;CAChC;CAEA,MAAM,QAAQ,kBAAkB;EAE9B,IAAI,aAAa;GACf,IAAI,QAAQ,kBAAkB;GAC9B;EACF;EACA,WAAW,SAAS,OAAO,4BAA4B;EAKvD,aAAa,WAAW;EACxB,cAAc,WAAW;EACzB,oBAAoB,UAAU;EAC9B,kBAAkB,IAAI;EACtB,gBAAgB,QAAQ,MAAM;EAC9B,gBAAgB,CAAC,CAAC;EAClB,MAAM,MAAM;CACd,GAAG;EAAC;EAAO;EAAK;CAAW,CAAC;CAE5B,MAAM,SAAS,cAEX,UAAU,QAAQ;EAChB,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,SAAS,MAAM;EACf;CACF,CAAC,GACH;EAAC,MAAM;EAAO,MAAM;EAAQ,MAAM;EAAS;CAAK,CAClD;CAEA,MAAM,UAAU,wBAAwB;EACtC,GAAG,+BAA+B,OAAO;EACzC;EACA,WAAW;EACX,WAAW,MAAM,WAAW;EAC5B;EACA,gCAAgC;EAChC;EACA,UAAU;GACR,aAAa,UAAU,eAAe,iBAAiB;GACvD,QAAQ,UAAU;GAClB,WAAW,UAAU;GACrB,OAAO,UAAU;GACjB,UAAU,UAAU;EACtB;EACA,OAAO,OAAO,YAAY;GACxB,IAAI,eACF,MAAM,IAAI,oBACR,4CACF;GACF,IAAI,EAAE,QAAQ,YAAY,QAAQ,SAAS,SAAS;IAElD,IAAI,aAAa,OACf,YAAY,SAAS,OACnB,YAAY,oBACZ,IAAI,MAAM,sDAAsD,CAClE;IACF,iBAAiB,OAAO;IACxB;GACF;GACA,IAAI;IACF,MAAM,kBACJ,MAAM,KACJ,qBAAqB,OAAO,GAC5B,iBAAiB,QAAQ,SAAS,CACpC,CACF;GACF,SAAS,OAAO;IAId,IAAI,UAAU,oBAAoB;IAClC,MAAM;GACR;EACF;EACA,GAAI,iBACA,EACE,UAAU,OAAO,UAAyB,WAAW;GACnD,MAAM,YAAY,aAAa,QAAQ;GACvC,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,8CAA8C;GAChE,MAAM,QAAQ,aAAa;GAC3B,MAAM,aAAa,cAAc;GACjC,KAAK,MAAM,EAAE,SAAS,eAAe,WAAW,WAAW;IACzD,IAAI,UAAU,aAAa,SAAS;IACpC,MAAM,mBAAmB,YAAY;IACrC,gBAAgB,QAAQ,OAAO,cAAc,EAAE;IAC/C,MAAM,eAAe,iBAAiB,QACnC,YAAY,QAAQ,OAAO,cAAc,EAC5C;IACA,YAAY,UAAU;IACtB,kBACE,gBAAgB,QAAQ,OAAO,IAAI,eAAe,IACpD;IAIA,MAAM,YACJ,cAAc,OAAO,YAAY,aAAa,OAAO,SAAS,IAC1D,OAAO,YACP,MAAM;IACZ,IAAI;KACF,MAAM,kBACJ,MAAM,KACJ,qBAAqB,MAAM,OAAO,GAClC,iBAAiB,SAAS,CAC5B,CACF;IACF,SAAS,OAAO;KAId,IAAI,eAAe,cAAc,SAAS;KAC1C,gBAAgB,QAAQ,IAAI,cAAc,IAAI,KAAK;KACnD,YAAY,UAAU;KACtB,kBAAkB,gBAAgB;KAClC,IAAI,cAAc,KAAK,GAAG;KAC1B,MAAM;IACR;IACA,IAAI,oBAAoB,YAAY,SAAS;GAC/C;EACF,EACF,IACA,CAAC;EACL,UAAU,YAAY;GACpB,aAAa,WAAW;GAIxB,MAAM,WAAW;GAGjB,IAAI,YAAY,UACd,MAAM,SAAS,OAAO;QAEtB,SAAS,KAAK;EAElB;EAGA,GAAI,YAAY,QACZ,EACE,uBACE,cAAc,CAAC,CAAC,OAAO,UAAU;GAC/B,IAAI,cAAc,KAAK,GAAG;GAC1B,MAAM;EACR,CAAC,EACL,IACA,CAAC;EACL,0BAA0B,aAAa;GAMrC,MAAM,gBAAgB,mBACpB,UACA,oBAAoB,MAAM,MAAM,SAAS,UAAU,CACrD;GACA,OAAO,kBAAkB,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OACtD,UAAU;IACT,IAAI,CAAC,cAAc,KAAK,GAAG,MAAM;GACnC,CACF;EACF;CACF,CAAC;CACD,WAAW,UAAU;CAErB,OAAO;AACT;AAEA,MAAM,sBACJ,OACA,YACG;CACH,MAAM,CAAC,YAAY,SAAS,sBAAsB;CAClD,MAAM,UAAU,0BAA0B;EACxC;EACA,KAAK;EACL,QAAQ;EACR,QAAQ,OAAO,cAAc,EAAE,YAAY,MAAM,SAAS,KAAK,QAAQ,EAAE;CAC3E,CAAC;CACD,OAAO,2BAA2B;EAChC;EACA,cAAc;EACd,aAAa,SAAS,cAAc;GAClC,OAAO,oBAAoB,SAAS,QAAQ;EAC9C;CACF,CAAC;AACH;;;;;;;;AASA,MAAa,sBAAsB,UAAqC,CAAC,MAAM;CAC7E,MAAM,CAAC,YAAY,SAAS,QAAQ,UAAU,KAAA,CAAS;CACvD,IAAK,QAAQ,UAAU,KAAA,MAAe,UACpC,MAAM,IAAI,MACR,mHACF;CAEF,IAAI,CAAC,QAAQ,OAEX,OAAO,oBAAoB,SAAS,KAAA,CAAS;CAG/C,OAAO,mBAAmB,QAAQ,OAAO,OAAO;AAClD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/eve",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
32
|
-
"@assistant-ui/store": "^0.3.
|
|
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.
|
|
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.
|
|
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:
|
|
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
|
}
|