@assistant-ui/eve 0.0.18 → 0.0.20

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.
Files changed (39) hide show
  1. package/LICENSE +1 -1
  2. package/dist/convertEveMessages.d.ts +31 -33
  3. package/dist/convertEveMessages.d.ts.map +1 -1
  4. package/dist/deriveCreatedAt.d.ts +5 -7
  5. package/dist/deriveCreatedAt.d.ts.map +1 -1
  6. package/dist/deriveCreatedAt.js +1 -0
  7. package/dist/deriveCreatedAt.js.map +1 -1
  8. package/dist/eveCloudSessions.d.ts +9 -0
  9. package/dist/eveCloudSessions.d.ts.map +1 -0
  10. package/dist/eveCloudSessions.js +51 -0
  11. package/dist/eveCloudSessions.js.map +1 -0
  12. package/dist/eveExtras.d.ts +1 -3
  13. package/dist/eveExtras.d.ts.map +1 -1
  14. package/dist/hooks.d.ts +5 -3
  15. package/dist/hooks.d.ts.map +1 -1
  16. package/dist/hooks.js +4 -0
  17. package/dist/hooks.js.map +1 -1
  18. package/dist/index.d.ts +8 -6
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/sdkIdentity.d.ts +3 -0
  21. package/dist/sdkIdentity.d.ts.map +1 -0
  22. package/dist/sdkIdentity.js +9 -0
  23. package/dist/sdkIdentity.js.map +1 -0
  24. package/dist/useEveAgentRuntime.d.ts +17 -12
  25. package/dist/useEveAgentRuntime.d.ts.map +1 -1
  26. package/dist/useEveAgentRuntime.js +104 -21
  27. package/dist/useEveAgentRuntime.js.map +1 -1
  28. package/package.json +9 -5
  29. package/src/deriveCreatedAt.test.ts +22 -0
  30. package/src/deriveCreatedAt.ts +5 -0
  31. package/src/eveCloudSessions.test.ts +78 -0
  32. package/src/eveCloudSessions.ts +59 -0
  33. package/src/hooks.ts +4 -0
  34. package/src/index.ts +1 -1
  35. package/src/sdkIdentity.ts +9 -0
  36. package/src/useEveAgentRuntime.cloud.test.tsx +558 -0
  37. package/src/useEveAgentRuntime.eveResume.test.tsx +102 -2
  38. package/src/useEveAgentRuntime.fast-refresh.test.tsx +342 -0
  39. package/src/useEveAgentRuntime.ts +203 -45
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
@@ -1,20 +1,19 @@
1
- import { AppendMessage, RespondToToolApprovalOptions, ThreadMessage } from "@assistant-ui/core";
2
- import { EveAuthorizationOutcome, EveAuthorizationPart, EveMessage, EveMessageData, EveMessageInputRequest } from "eve/react";
3
- import { InputResponse } from "eve/client";
4
- //#region src/convertEveMessages.d.ts
1
+ import { type AppendMessage, type RespondToToolApprovalOptions, type ThreadMessage } from "@assistant-ui/core";
2
+ import type { EveAuthorizationOutcome, EveAuthorizationPart, EveMessage, EveMessageData, EveMessageInputRequest } from "eve/react";
3
+ import type { InputResponse } from "eve/client";
5
4
  export type ConvertEveMessagesOptions = {
6
- /**
7
- * Marks the last assistant message as running while Eve is submitting or
8
- * streaming. When omitted, a message carrying Eve's `"streaming"` marker is
9
- * treated as running; pass `false` to settle interrupted messages to a
10
- * terminal status.
11
- */
12
- readonly isRunning?: boolean | undefined;
13
- /**
14
- * The Eve session error, mapped onto the assistant message it interrupted.
15
- */
16
- readonly error?: unknown;
17
- readonly getCreatedAt?: ((message: EveMessage) => Date) | undefined;
5
+ /**
6
+ * Marks the last assistant message as running while Eve is submitting or
7
+ * streaming. When omitted, a message carrying Eve's `"streaming"` marker is
8
+ * treated as running; pass `false` to settle interrupted messages to a
9
+ * terminal status.
10
+ */
11
+ readonly isRunning?: boolean | undefined;
12
+ /**
13
+ * The Eve session error, mapped onto the assistant message it interrupted.
14
+ */
15
+ readonly error?: unknown;
16
+ readonly getCreatedAt?: ((message: EveMessage) => Date) | undefined;
18
17
  };
19
18
  /**
20
19
  * Payload of the `authorization` data part the Eve runtime emits for a
@@ -28,16 +27,16 @@ export type ConvertEveMessagesOptions = {
28
27
  * re-identify a challenge among several.
29
28
  */
30
29
  export type EveAuthorizationData = {
31
- readonly state: EveAuthorizationPart["state"];
32
- readonly name: string;
33
- readonly displayName?: string;
34
- readonly description?: string;
35
- readonly url?: string;
36
- readonly userCode?: string;
37
- readonly instructions?: string;
38
- readonly expiresAt?: string;
39
- readonly outcome?: EveAuthorizationOutcome;
40
- readonly reason?: string;
30
+ readonly state: EveAuthorizationPart["state"];
31
+ readonly name: string;
32
+ readonly displayName?: string;
33
+ readonly description?: string;
34
+ readonly url?: string;
35
+ readonly userCode?: string;
36
+ readonly instructions?: string;
37
+ readonly expiresAt?: string;
38
+ readonly outcome?: EveAuthorizationOutcome;
39
+ readonly reason?: string;
41
40
  };
42
41
  /**
43
42
  * Converts a single Eve message into an assistant-ui thread message.
@@ -53,13 +52,13 @@ export declare const convertEveMessages: (data: EveMessageData, options?: Conver
53
52
  * assignability to the send call site, checked against the installed version.
54
53
  */
55
54
  export type EveMessageContent = string | ({
56
- readonly type: "text";
57
- readonly text: string;
55
+ readonly type: "text";
56
+ readonly text: string;
58
57
  } | {
59
- readonly type: "file";
60
- readonly data: string;
61
- readonly mediaType: string;
62
- readonly filename?: string;
58
+ readonly type: "file";
59
+ readonly data: string;
60
+ readonly mediaType: string;
61
+ readonly filename?: string;
63
62
  })[];
64
63
  /**
65
64
  * Converts an assistant-ui append message into the message payload accepted by
@@ -97,5 +96,4 @@ export declare const findEveInputRequest: (data: EveMessageData, approvalId: str
97
96
  * a guess about one.
98
97
  */
99
98
  export declare const toEveInputResponse: (response: RespondToToolApprovalOptions, inputRequest?: EveMessageInputRequest) => InputResponse;
100
- //#endregion
101
99
  //# sourceMappingURL=convertEveMessages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convertEveMessages.d.ts","names":[],"sources":["../src/convertEveMessages.ts"],"mappings":";;;;YAqDY;;;;;;;WAOD;;;;WAIA;WACA,iBAAiB,SAAS,eAAe;;;;;;;;;;;;;YA0PxC;WACD,OAAO;WACP;WACA;WACA;WACA;WACA;WACA;WACA;WACA,UAAU;WACV;;;;;qBA6IE,oBACX,SAAS,YACT,eACA,mBAAmB,cACnB,UAAS,8BACR;;;;qBAuCU,qBACX,MAAM,gBACN,UAAS,8BACR;;;;;;YAUS;WAGO;WAAuB;;WAEvB;WACA;WACA;WACA;;;;;;qBAQN,uBACX,SAAS,kBACR;;;;;qBAuEU,sBACX,MAAM,gBACN,uBACC;;;;;;;;;;;;;;;;;;;;;;;;;;qBAoCU,qBACX,UAAU,8BACV,eAAe,2BACd"}
1
+ {"version":3,"file":"convertEveMessages.d.ts","sourceRoot":"","sources":["../src/convertEveMessages.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAOlB,KAAK,4BAA4B,EAEjC,KAAK,aAAa,EAMnB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EAEpB,UAAU,EACV,cAAc,EACd,sBAAsB,EAEvB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAqBhD,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrE,CAAC;AA8OF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAyIF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,UAAU,EACnB,OAAO,MAAM,EACb,UAAU,SAAS,UAAU,EAAE,EAC/B,UAAS,yBAA8B,KACtC,aAkCF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,cAAc,EACpB,UAAS,yBAA8B,KACtC,aAAa,EAGb,CAAC;AAEJ;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,CACI;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CACJ,EAAE,CAAC;AAER;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,aAAa,KACrB,iBAiEF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,MAAM,cAAc,EACpB,YAAY,MAAM,KACjB,sBAAsB,GAAG,SAS3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,4BAA4B,EACtC,eAAe,sBAAsB,KACpC,aAyDF,CAAC"}
@@ -1,12 +1,11 @@
1
- import { MessageStreamEvent } from "eve/client";
2
- //#region src/deriveCreatedAt.d.ts
1
+ import type { MessageStreamEvent } from "eve/client";
3
2
  export type TurnTimestamps = {
4
- readonly user?: Date;
5
- readonly assistant?: Date;
3
+ readonly user?: Date;
4
+ readonly assistant?: Date;
6
5
  };
7
6
  export type TurnTimestampCache = {
8
- lastEvents: readonly MessageStreamEvent[];
9
- timestamps: ReadonlyMap<string, TurnTimestamps>;
7
+ lastEvents: readonly MessageStreamEvent[];
8
+ timestamps: ReadonlyMap<string, TurnTimestamps>;
10
9
  };
11
10
  export declare const createTurnTimestampCache: () => TurnTimestampCache;
12
11
  /**
@@ -18,5 +17,4 @@ export declare const createTurnTimestampCache: () => TurnTimestampCache;
18
17
  * makes the render-phase cache writes safe when React discards a render.
19
18
  */
20
19
  export declare const collectTurnTimestamps: (events: readonly MessageStreamEvent[], cache: TurnTimestampCache) => ReadonlyMap<string, TurnTimestamps>;
21
- //#endregion
22
20
  //# sourceMappingURL=deriveCreatedAt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deriveCreatedAt.d.ts","names":[],"sources":["../src/deriveCreatedAt.ts"],"mappings":";;YAEY;WACD,OAAO;WACP,YAAY;;YAGX;EACV,qBAAqB;EACrB,YAAY,oBAAoB;;qBAiCrB,gCAA+B;;;;;;;;;qBAa/B,wBACX,iBAAiB,sBACjB,OAAO,uBACN,oBAAoB"}
1
+ {"version":3,"file":"deriveCreatedAt.d.ts","sourceRoot":"","sources":["../src/deriveCreatedAt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC1C,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACjD,CAAC;AAgCF,eAAO,MAAM,wBAAwB,QAAO,kBAG1C,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,SAAS,kBAAkB,EAAE,EACrC,OAAO,kBAAkB,KACxB,WAAW,CAAC,MAAM,EAAE,cAAc,CA0CpC,CAAC"}
@@ -50,6 +50,7 @@ const collectTurnTimestamps = (events, cache) => {
50
50
  }
51
51
  for (let i = resumesScan ? scanned.length : 0; i < events.length; i++) {
52
52
  const event = events[i];
53
+ if (!Object.prototype.hasOwnProperty.call(ROLE_BY_EVENT_TYPE, event.type)) continue;
53
54
  const role = ROLE_BY_EVENT_TYPE[event.type];
54
55
  if (role === void 0) continue;
55
56
  const data = event.data;
@@ -1 +1 @@
1
- {"version":3,"file":"deriveCreatedAt.js","names":[],"sources":["../src/deriveCreatedAt.ts"],"sourcesContent":["import type { MessageStreamEvent } from \"eve/client\";\n\nexport type TurnTimestamps = {\n readonly user?: Date;\n readonly assistant?: Date;\n};\n\nexport type TurnTimestampCache = {\n lastEvents: readonly MessageStreamEvent[];\n timestamps: ReadonlyMap<string, TurnTimestamps>;\n};\n\n/**\n * The reducer cases eve projects into a message: `message.received` creates\n * `${turnId}:user`, and every assistant entry reaches `updateAssistantMessage`,\n * which creates `${turnId}:assistant` for a turn that has none. It enumerates\n * that reducer across the `>=0.32.0` peer range rather than stating a rule\n * about turn ids, because `turn.started` and the compaction events carry one\n * before the model runs. An event eve adds to the creating set later is absent\n * here and falls back to the wall clock instead of stamping a wrong time.\n */\nconst ROLE_BY_EVENT_TYPE: Partial<\n Record<MessageStreamEvent[\"type\"], keyof TurnTimestamps>\n> = {\n \"message.received\": \"user\",\n \"step.started\": \"assistant\",\n \"reasoning.appended\": \"assistant\",\n \"reasoning.completed\": \"assistant\",\n \"action.input.appended\": \"assistant\",\n \"actions.requested\": \"assistant\",\n \"input.requested\": \"assistant\",\n \"action.result\": \"assistant\",\n \"action.partial\": \"assistant\",\n \"authorization.required\": \"assistant\",\n \"authorization.completed\": \"assistant\",\n \"message.appended\": \"assistant\",\n \"message.completed\": \"assistant\",\n \"result.completed\": \"assistant\",\n \"turn.completed\": \"assistant\",\n \"turn.cancelled\": \"assistant\",\n};\n\nexport const createTurnTimestampCache = (): TurnTimestampCache => ({\n lastEvents: [],\n timestamps: new Map(),\n});\n\n/**\n * Eve appends to its log (`[...events, event]`), so a snapshot that keeps the\n * previous scan's last element by identity shares the whole prefix and the\n * scan resumes there. Any other snapshot is re-derived into a fresh map: turn\n * ids are per-session sequence numbers that recur after `reset()`, so entries\n * must not outlive the log that produced them. Re-derivation is also what\n * makes the render-phase cache writes safe when React discards a render.\n */\nexport const collectTurnTimestamps = (\n events: readonly MessageStreamEvent[],\n cache: TurnTimestampCache,\n): ReadonlyMap<string, TurnTimestamps> => {\n if (events === cache.lastEvents) return cache.timestamps;\n\n const scanned = cache.lastEvents;\n const resumesScan =\n scanned.length === 0 ||\n events[scanned.length - 1] === scanned[scanned.length - 1];\n\n let timestamps = cache.timestamps;\n let draft: Map<string, TurnTimestamps> | undefined;\n if (!resumesScan) {\n draft = new Map();\n timestamps = draft;\n }\n for (let i = resumesScan ? scanned.length : 0; i < events.length; i++) {\n const event = events[i]!;\n const role = ROLE_BY_EVENT_TYPE[event.type];\n if (role === undefined) continue;\n const data: unknown = (event as { readonly data?: unknown }).data;\n if (typeof data !== \"object\" || data === null) continue;\n const turnId = (data as { readonly turnId?: unknown }).turnId;\n if (typeof turnId !== \"string\") continue;\n const known = timestamps.get(turnId);\n if (known?.[role] !== undefined) continue;\n const at: unknown = (event as { readonly meta?: { readonly at?: unknown } })\n .meta?.at;\n if (typeof at !== \"string\") continue;\n const date = new Date(at);\n if (Number.isNaN(date.getTime())) continue;\n draft ??= new Map(timestamps);\n draft.set(turnId, { ...known, [role]: date });\n timestamps = draft;\n }\n\n cache.lastEvents = events;\n cache.timestamps = timestamps;\n return timestamps;\n};\n"],"mappings":";;;;;;;;;;AAqBA,MAAM,qBAEF;CACF,oBAAoB;CACpB,gBAAgB;CAChB,sBAAsB;CACtB,uBAAuB;CACvB,yBAAyB;CACzB,qBAAqB;CACrB,mBAAmB;CACnB,iBAAiB;CACjB,kBAAkB;CAClB,0BAA0B;CAC1B,2BAA2B;CAC3B,oBAAoB;CACpB,qBAAqB;CACrB,oBAAoB;CACpB,kBAAkB;CAClB,kBAAkB;AACpB;AAEA,MAAa,kCAAsD;CACjE,YAAY,CAAC;CACb,4BAAY,IAAI,IAAI;AACtB;;;;;;;;;AAUA,MAAa,yBACX,QACA,UACwC;CACxC,IAAI,WAAW,MAAM,YAAY,OAAO,MAAM;CAE9C,MAAM,UAAU,MAAM;CACtB,MAAM,cACJ,QAAQ,WAAW,KACnB,OAAO,QAAQ,SAAS,OAAO,QAAQ,QAAQ,SAAS;CAE1D,IAAI,aAAa,MAAM;CACvB,IAAI;CACJ,IAAI,CAAC,aAAa;EAChB,wBAAQ,IAAI,IAAI;EAChB,aAAa;CACf;CACA,KAAK,IAAI,IAAI,cAAc,QAAQ,SAAS,GAAG,IAAI,OAAO,QAAQ,KAAK;EACrE,MAAM,QAAQ,OAAO;EACrB,MAAM,OAAO,mBAAmB,MAAM;EACtC,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,OAAiB,MAAsC;EAC7D,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAC/C,MAAM,SAAU,KAAuC;EACvD,IAAI,OAAO,WAAW,UAAU;EAChC,MAAM,QAAQ,WAAW,IAAI,MAAM;EACnC,IAAI,QAAQ,UAAU,KAAA,GAAW;EACjC,MAAM,KAAe,MAClB,MAAM;EACT,IAAI,OAAO,OAAO,UAAU;EAC5B,MAAM,OAAO,IAAI,KAAK,EAAE;EACxB,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;EAClC,UAAU,IAAI,IAAI,UAAU;EAC5B,MAAM,IAAI,QAAQ;GAAE,GAAG;IAAQ,OAAO;EAAK,CAAC;EAC5C,aAAa;CACf;CAEA,MAAM,aAAa;CACnB,MAAM,aAAa;CACnB,OAAO;AACT"}
1
+ {"version":3,"file":"deriveCreatedAt.js","names":[],"sources":["../src/deriveCreatedAt.ts"],"sourcesContent":["import type { MessageStreamEvent } from \"eve/client\";\n\nexport type TurnTimestamps = {\n readonly user?: Date;\n readonly assistant?: Date;\n};\n\nexport type TurnTimestampCache = {\n lastEvents: readonly MessageStreamEvent[];\n timestamps: ReadonlyMap<string, TurnTimestamps>;\n};\n\n/**\n * The reducer cases eve projects into a message: `message.received` creates\n * `${turnId}:user`, and every assistant entry reaches `updateAssistantMessage`,\n * which creates `${turnId}:assistant` for a turn that has none. It enumerates\n * that reducer across the `>=0.32.0` peer range rather than stating a rule\n * about turn ids, because `turn.started` and the compaction events carry one\n * before the model runs. An event eve adds to the creating set later is absent\n * here and falls back to the wall clock instead of stamping a wrong time.\n */\nconst ROLE_BY_EVENT_TYPE: Partial<\n Record<MessageStreamEvent[\"type\"], keyof TurnTimestamps>\n> = {\n \"message.received\": \"user\",\n \"step.started\": \"assistant\",\n \"reasoning.appended\": \"assistant\",\n \"reasoning.completed\": \"assistant\",\n \"action.input.appended\": \"assistant\",\n \"actions.requested\": \"assistant\",\n \"input.requested\": \"assistant\",\n \"action.result\": \"assistant\",\n \"action.partial\": \"assistant\",\n \"authorization.required\": \"assistant\",\n \"authorization.completed\": \"assistant\",\n \"message.appended\": \"assistant\",\n \"message.completed\": \"assistant\",\n \"result.completed\": \"assistant\",\n \"turn.completed\": \"assistant\",\n \"turn.cancelled\": \"assistant\",\n};\n\nexport const createTurnTimestampCache = (): TurnTimestampCache => ({\n lastEvents: [],\n timestamps: new Map(),\n});\n\n/**\n * Eve appends to its log (`[...events, event]`), so a snapshot that keeps the\n * previous scan's last element by identity shares the whole prefix and the\n * scan resumes there. Any other snapshot is re-derived into a fresh map: turn\n * ids are per-session sequence numbers that recur after `reset()`, so entries\n * must not outlive the log that produced them. Re-derivation is also what\n * makes the render-phase cache writes safe when React discards a render.\n */\nexport const collectTurnTimestamps = (\n events: readonly MessageStreamEvent[],\n cache: TurnTimestampCache,\n): ReadonlyMap<string, TurnTimestamps> => {\n if (events === cache.lastEvents) return cache.timestamps;\n\n const scanned = cache.lastEvents;\n const resumesScan =\n scanned.length === 0 ||\n events[scanned.length - 1] === scanned[scanned.length - 1];\n\n let timestamps = cache.timestamps;\n let draft: Map<string, TurnTimestamps> | undefined;\n if (!resumesScan) {\n draft = new Map();\n timestamps = draft;\n }\n for (let i = resumesScan ? scanned.length : 0; i < events.length; i++) {\n const event = events[i]!;\n // `type` arrives off the wire, so an inherited member such as\n // `__proto__` would resolve here instead of missing, and be used as a\n // timestamp key. Only the table's own entries count.\n if (!Object.prototype.hasOwnProperty.call(ROLE_BY_EVENT_TYPE, event.type))\n continue;\n const role = ROLE_BY_EVENT_TYPE[event.type];\n if (role === undefined) continue;\n const data: unknown = (event as { readonly data?: unknown }).data;\n if (typeof data !== \"object\" || data === null) continue;\n const turnId = (data as { readonly turnId?: unknown }).turnId;\n if (typeof turnId !== \"string\") continue;\n const known = timestamps.get(turnId);\n if (known?.[role] !== undefined) continue;\n const at: unknown = (event as { readonly meta?: { readonly at?: unknown } })\n .meta?.at;\n if (typeof at !== \"string\") continue;\n const date = new Date(at);\n if (Number.isNaN(date.getTime())) continue;\n draft ??= new Map(timestamps);\n draft.set(turnId, { ...known, [role]: date });\n timestamps = draft;\n }\n\n cache.lastEvents = events;\n cache.timestamps = timestamps;\n return timestamps;\n};\n"],"mappings":";;;;;;;;;;AAqBA,MAAM,qBAEF;CACF,oBAAoB;CACpB,gBAAgB;CAChB,sBAAsB;CACtB,uBAAuB;CACvB,yBAAyB;CACzB,qBAAqB;CACrB,mBAAmB;CACnB,iBAAiB;CACjB,kBAAkB;CAClB,0BAA0B;CAC1B,2BAA2B;CAC3B,oBAAoB;CACpB,qBAAqB;CACrB,oBAAoB;CACpB,kBAAkB;CAClB,kBAAkB;AACpB;AAEA,MAAa,kCAAsD;CACjE,YAAY,CAAC;CACb,4BAAY,IAAI,IAAI;AACtB;;;;;;;;;AAUA,MAAa,yBACX,QACA,UACwC;CACxC,IAAI,WAAW,MAAM,YAAY,OAAO,MAAM;CAE9C,MAAM,UAAU,MAAM;CACtB,MAAM,cACJ,QAAQ,WAAW,KACnB,OAAO,QAAQ,SAAS,OAAO,QAAQ,QAAQ,SAAS;CAE1D,IAAI,aAAa,MAAM;CACvB,IAAI;CACJ,IAAI,CAAC,aAAa;EAChB,wBAAQ,IAAI,IAAI;EAChB,aAAa;CACf;CACA,KAAK,IAAI,IAAI,cAAc,QAAQ,SAAS,GAAG,IAAI,OAAO,QAAQ,KAAK;EACrE,MAAM,QAAQ,OAAO;EAIrB,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,oBAAoB,MAAM,IAAI,GACtE;EACF,MAAM,OAAO,mBAAmB,MAAM;EACtC,IAAI,SAAS,KAAA,GAAW;EACxB,MAAM,OAAiB,MAAsC;EAC7D,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAC/C,MAAM,SAAU,KAAuC;EACvD,IAAI,OAAO,WAAW,UAAU;EAChC,MAAM,QAAQ,WAAW,IAAI,MAAM;EACnC,IAAI,QAAQ,UAAU,KAAA,GAAW;EACjC,MAAM,KAAe,MAClB,MAAM;EACT,IAAI,OAAO,OAAO,UAAU;EAC5B,MAAM,OAAO,IAAI,KAAK,EAAE;EACxB,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;EAClC,UAAU,IAAI,IAAI,UAAU;EAC5B,MAAM,IAAI,QAAQ;GAAE,GAAG;IAAQ,OAAO;EAAK,CAAC;EAC5C,aAAa;CACf;CAEA,MAAM,aAAa;CACnB,MAAM,aAAa;CACnB,OAAO;AACT"}
@@ -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"}
@@ -1,6 +1,4 @@
1
- import { EveMessageData, UseEveAgentHelpers } from "eve/react";
2
- //#region src/eveExtras.d.ts
1
+ import type { EveMessageData, UseEveAgentHelpers } from "eve/react";
3
2
  export type EveRuntimeExtras = Pick<UseEveAgentHelpers<EveMessageData>, "error" | "events" | "session" | "reset">;
4
3
  export declare const eveExtras: import("@assistant-ui/core/react").RuntimeExtras<EveRuntimeExtras>;
5
- //#endregion
6
4
  //# sourceMappingURL=eveExtras.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eveExtras.d.ts","names":[],"sources":["../src/eveExtras.ts"],"mappings":";;YAGY,mBAAmB,KAC7B,mBAAmB;qBAIR,8CAAS,cAAA"}
1
+ {"version":3,"file":"eveExtras.d.ts","sourceRoot":"","sources":["../src/eveExtras.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEpE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,kBAAkB,CAAC,cAAc,CAAC,EAClC,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CACzC,CAAC;AAEF,eAAO,MAAM,SAAS,oEACuC,CAAC"}
package/dist/hooks.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- import { EveRuntimeExtras } from "./eveExtras.js";
2
- //#region src/hooks.d.ts
1
+ import type { EveRuntimeExtras } from "./eveExtras.js";
3
2
  /** Read the last Eve session error from the runtime extras. */
4
3
  export declare const useEveError: () => Error | undefined;
5
4
  /**
6
5
  * Read the current Eve session cursor from the runtime extras. Persist it to
7
6
  * resume the session later via `initialSession`. `undefined` when no session
8
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.
9
10
  */
10
11
  export declare const useEveSession: () => EveRuntimeExtras["session"] | undefined;
11
12
  /**
@@ -18,7 +19,8 @@ export declare const useEveEvents: () => EveRuntimeExtras["events"];
18
19
  * recreates the owned session, and clears events and projected data. Pending
19
20
  * staged messages and tool execution state are discarded. Safe to render
20
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.
21
24
  */
22
25
  export declare const useEveReset: () => () => void;
23
- //#endregion
24
26
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;qBASa,mBAAW;;;;;;qBAOX,qBAAoB;;;;;qBAOpB,oBAAmB;;;;;;;qBASnB"}
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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- /// <reference types="@assistant-ui/core/react" />
2
- import { ConvertEveMessagesOptions, EveAuthorizationData, EveMessageContent, convertEveMessage, convertEveMessages, getEveMessageContent, toEveInputResponse } from "./convertEveMessages.js";
3
- import { EveRuntimeExtras } from "./eveExtras.js";
4
- import { useEveError, useEveEvents, useEveReset, useEveSession } from "./hooks.js";
5
- import { UseEveAgentRuntimeOptions, useEveAgentRuntime } from "./useEveAgentRuntime.js";
6
- export { type ConvertEveMessagesOptions, type EveAuthorizationData, type EveMessageContent, type EveRuntimeExtras, type UseEveAgentRuntimeOptions, convertEveMessage, convertEveMessages, getEveMessageContent, toEveInputResponse, useEveAgentRuntime, useEveError, useEveEvents, useEveReset, useEveSession };
1
+ /// <reference types="@assistant-ui/core/react" preserve="true" />
2
+ export { convertEveMessage, convertEveMessages, getEveMessageContent, toEveInputResponse, } from "./convertEveMessages.js";
3
+ export type { ConvertEveMessagesOptions, EveAuthorizationData, EveMessageContent, } from "./convertEveMessages.js";
4
+ export { useEveAgentRuntime } from "./useEveAgentRuntime.js";
5
+ export type { UseEveAgentRuntimeOptions } from "./useEveAgentRuntime.js";
6
+ export { useEveError, useEveEvents, useEveReset, useEveSession } from "./hooks.js";
7
+ export type { EveRuntimeExtras } from "./eveExtras.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,GACnB,gCAA6B;AAC9B,YAAY,EACV,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,GAClB,gCAA6B;AAC9B,OAAO,EAAE,kBAAkB,EAAE,gCAA6B;AAC1D,YAAY,EAAE,yBAAyB,EAAE,gCAA6B;AACtE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAgB;AAChF,YAAY,EAAE,gBAAgB,EAAE,uBAAoB"}
@@ -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.20"
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,14 +1,19 @@
1
- import { AttachmentAdapter, DictationAdapter, ExternalStoreSharedOptions, FeedbackAdapter, RealtimeVoiceAdapter, SpeechSynthesisAdapter } from "@assistant-ui/core";
2
- import { EveMessageData, UseEveAgentOptions } from "eve/react";
3
- //#region src/useEveAgentRuntime.d.ts
4
- export type UseEveAgentRuntimeOptions = Omit<UseEveAgentOptions<EveMessageData>, "reducer"> & ExternalStoreSharedOptions & {
5
- readonly adapters?: {
6
- readonly attachments?: AttachmentAdapter | undefined;
7
- readonly speech?: SpeechSynthesisAdapter | undefined;
8
- readonly dictation?: DictationAdapter | undefined;
9
- readonly voice?: RealtimeVoiceAdapter | undefined;
10
- readonly feedback?: FeedbackAdapter | undefined;
11
- } | undefined;
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";
3
+ import { type EveMessageData, type UseEveAgentOptions } from "eve/react";
4
+ type EveAgentOptions = Omit<UseEveAgentOptions<EveMessageData>, "reducer">;
5
+ export type UseEveAgentRuntimeOptions = EveAgentOptions & ExternalStoreSharedOptions & {
6
+ readonly adapters?: {
7
+ readonly attachments?: AttachmentAdapter | undefined;
8
+ readonly speech?: SpeechSynthesisAdapter | undefined;
9
+ readonly dictation?: DictationAdapter | undefined;
10
+ readonly voice?: RealtimeVoiceAdapter | undefined;
11
+ readonly feedback?: FeedbackAdapter | undefined;
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;
12
17
  };
13
18
  /**
14
19
  * Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
@@ -18,5 +23,5 @@ export type UseEveAgentRuntimeOptions = Omit<UseEveAgentOptions<EveMessageData>,
18
23
  * tool approval UI.
19
24
  */
20
25
  export declare const useEveAgentRuntime: (options?: UseEveAgentRuntimeOptions) => import("@assistant-ui/core").AssistantRuntime;
21
- //#endregion
26
+ export {};
22
27
  //# sourceMappingURL=useEveAgentRuntime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEveAgentRuntime.d.ts","names":[],"sources":["../src/useEveAgentRuntime.ts"],"mappings":";;;YA+HY,4BAA4B,KACtC,mBAAmB,8BAGnB;WACW;aAEM,cAAc;aACd,SAAS;aACT,YAAY;aACZ,QAAQ;aACR,WAAW;;;;;;;;;;qBAYjB,qBAAsB,UAAS,2DAA8B"}
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