@ekairos/events 1.22.34-beta.development.0 → 1.22.35

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 (74) hide show
  1. package/README.md +58 -83
  2. package/dist/codex.d.ts +11 -2
  3. package/dist/codex.js +16 -8
  4. package/dist/context.action-calls.d.ts +48 -0
  5. package/dist/context.action-calls.js +123 -0
  6. package/dist/context.action.d.ts +55 -0
  7. package/dist/context.action.js +25 -0
  8. package/dist/context.builder.d.ts +71 -43
  9. package/dist/context.builder.js +123 -28
  10. package/dist/context.config.d.ts +2 -1
  11. package/dist/context.config.js +8 -3
  12. package/dist/context.contract.d.ts +2 -4
  13. package/dist/context.contract.js +3 -9
  14. package/dist/context.d.ts +3 -2
  15. package/dist/context.engine.d.ts +75 -46
  16. package/dist/context.engine.js +538 -302
  17. package/dist/context.events.js +28 -87
  18. package/dist/context.js +1 -0
  19. package/dist/context.part-identity.d.ts +40 -0
  20. package/dist/context.part-identity.js +270 -0
  21. package/dist/context.parts.d.ts +389 -164
  22. package/dist/context.parts.js +343 -218
  23. package/dist/context.registry.d.ts +1 -1
  24. package/dist/context.runtime.d.ts +21 -0
  25. package/dist/context.runtime.js +39 -0
  26. package/dist/context.step-stream.d.ts +16 -2
  27. package/dist/context.step-stream.js +58 -16
  28. package/dist/context.store.d.ts +63 -10
  29. package/dist/context.stream.d.ts +14 -4
  30. package/dist/context.stream.js +31 -3
  31. package/dist/domain.d.ts +1 -0
  32. package/dist/domain.js +1 -0
  33. package/dist/index.d.ts +13 -10
  34. package/dist/index.js +7 -6
  35. package/dist/react.context-event-parts.d.ts +18 -0
  36. package/dist/react.context-event-parts.js +509 -0
  37. package/dist/react.d.ts +7 -42
  38. package/dist/react.js +4 -87
  39. package/dist/react.step-stream.d.ts +39 -0
  40. package/dist/react.step-stream.js +625 -0
  41. package/dist/react.types.d.ts +121 -0
  42. package/dist/react.types.js +2 -0
  43. package/dist/react.use-context.d.ts +7 -0
  44. package/dist/react.use-context.js +867 -0
  45. package/dist/reactors/ai-sdk.chunk-map.d.ts +1 -0
  46. package/dist/reactors/ai-sdk.chunk-map.js +56 -5
  47. package/dist/reactors/ai-sdk.reactor.d.ts +8 -5
  48. package/dist/reactors/ai-sdk.reactor.js +10 -9
  49. package/dist/reactors/ai-sdk.step.d.ts +6 -6
  50. package/dist/reactors/ai-sdk.step.js +32 -24
  51. package/dist/reactors/scripted.reactor.d.ts +7 -4
  52. package/dist/reactors/types.d.ts +23 -8
  53. package/dist/runtime.d.ts +6 -0
  54. package/dist/runtime.js +9 -0
  55. package/dist/runtime.step.js +2 -2
  56. package/dist/schema.d.ts +268 -2
  57. package/dist/schema.js +5 -9
  58. package/dist/steps/do-context-stream-step.d.ts +2 -2
  59. package/dist/steps/do-context-stream-step.js +6 -8
  60. package/dist/steps/durable.steps.d.ts +28 -0
  61. package/dist/steps/durable.steps.js +34 -0
  62. package/dist/steps/store.steps.d.ts +121 -39
  63. package/dist/steps/store.steps.js +266 -111
  64. package/dist/steps/stream.steps.d.ts +36 -3
  65. package/dist/steps/stream.steps.js +137 -14
  66. package/dist/steps/trace.steps.d.ts +4 -2
  67. package/dist/steps/trace.steps.js +26 -8
  68. package/dist/stores/instant.store.d.ts +15 -11
  69. package/dist/stores/instant.store.js +155 -6
  70. package/dist/tools-to-model-tools.d.ts +39 -3
  71. package/dist/tools-to-model-tools.js +63 -6
  72. package/package.json +20 -6
  73. package/dist/context.toolcalls.d.ts +0 -60
  74. package/dist/context.toolcalls.js +0 -117
@@ -1,4 +1,6 @@
1
- import { contextStreamByteLength, parseContextStepStreamChunk, } from "../context.step-stream.js";
1
+ import { getContextRuntimeServices } from "../context.runtime.js";
2
+ import { createContextStepStreamChunk, contextStreamByteLength, encodeContextStepStreamChunk, parseContextStepStreamChunk, } from "../context.step-stream.js";
3
+ import { resolveContextPartChunkIdentity } from "../context.part-identity.js";
2
4
  export async function writeContextEvents(params) {
3
5
  "use step";
4
6
  const writable = params.writable;
@@ -14,7 +16,9 @@ export async function writeContextEvents(params) {
14
16
  }
15
17
  }
16
18
  finally {
17
- writer.releaseLock();
19
+ if (typeof writer?.releaseLock === "function") {
20
+ writer.releaseLock();
21
+ }
18
22
  }
19
23
  }
20
24
  export async function closeContextStream(params) {
@@ -30,7 +34,9 @@ export async function closeContextStream(params) {
30
34
  await writer.write({ type: "finish" });
31
35
  }
32
36
  finally {
33
- writer.releaseLock();
37
+ if (typeof writer?.releaseLock === "function") {
38
+ writer.releaseLock();
39
+ }
34
40
  }
35
41
  }
36
42
  if (!preventClose) {
@@ -43,6 +49,19 @@ function asRecord(value) {
43
49
  function asString(value) {
44
50
  return typeof value === "string" ? value.trim() : "";
45
51
  }
52
+ function toJsonSafeRecord(value) {
53
+ if (typeof value === "undefined")
54
+ return undefined;
55
+ try {
56
+ const json = JSON.parse(JSON.stringify(value));
57
+ return json && typeof json === "object"
58
+ ? json
59
+ : { value: json };
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ }
46
65
  function createUnsetStreamLinkTx(db, executionId, label, streamId) {
47
66
  try {
48
67
  return db.tx.event_executions[executionId].unlink({ [label]: streamId });
@@ -58,10 +77,7 @@ export function createContextStepStreamClientId(stepId) {
58
77
  }
59
78
  return `event-step:${normalized}`;
60
79
  }
61
- export async function createPersistedContextStepStream(params) {
62
- "use step";
63
- const { getContextRuntime } = await import("../runtime.js");
64
- const runtime = await getContextRuntime(params.env);
80
+ export async function createPersistedContextStepStreamForRuntime(runtime, params) {
65
81
  const db = runtime?.db;
66
82
  if (!db?.streams?.createWriteStream) {
67
83
  throw new Error("InstantDB streams are not available on the configured runtime. Upgrade @instantdb/admin to a streams-capable version.");
@@ -101,11 +117,13 @@ export async function createPersistedContextStepStream(params) {
101
117
  stepId: params.stepId,
102
118
  };
103
119
  }
104
- async function finalizePersistedContextStepStream(params) {
120
+ export async function createPersistedContextStepStream(params) {
105
121
  "use step";
106
- const { getContextRuntime } = await import("../runtime.js");
107
- const runtime = await getContextRuntime(params.env);
108
- const db = runtime?.db;
122
+ const runtime = await getContextRuntimeServices(params.runtime);
123
+ return await createPersistedContextStepStreamForRuntime(runtime, params);
124
+ }
125
+ export async function finalizePersistedContextStepStreamForRuntime(params) {
126
+ const db = params.runtime?.db;
109
127
  const writer = params.session.stream.getWriter();
110
128
  try {
111
129
  if (params.mode === "abort") {
@@ -116,7 +134,9 @@ async function finalizePersistedContextStepStream(params) {
116
134
  }
117
135
  }
118
136
  finally {
119
- writer.releaseLock();
137
+ if (typeof writer?.releaseLock === "function") {
138
+ writer.releaseLock();
139
+ }
120
140
  }
121
141
  const now = new Date();
122
142
  const txs = [
@@ -138,21 +158,124 @@ async function finalizePersistedContextStepStream(params) {
138
158
  txs.push(unsetActive);
139
159
  await db.transact(txs);
140
160
  }
161
+ async function finalizePersistedContextStepStream(params) {
162
+ "use step";
163
+ const runtime = await getContextRuntimeServices(params.runtime);
164
+ return await finalizePersistedContextStepStreamForRuntime({
165
+ runtime,
166
+ session: params.session,
167
+ mode: params.mode,
168
+ abortReason: params.abortReason,
169
+ });
170
+ }
141
171
  export async function closePersistedContextStepStream(params) {
142
172
  return await finalizePersistedContextStepStream({
143
- env: params.env,
173
+ runtime: params.runtime,
144
174
  session: params.session,
145
175
  mode: "close",
146
176
  });
147
177
  }
148
178
  export async function abortPersistedContextStepStream(params) {
149
179
  return await finalizePersistedContextStepStream({
150
- env: params.env,
180
+ runtime: params.runtime,
151
181
  session: params.session,
152
182
  mode: "abort",
153
183
  abortReason: params.reason,
154
184
  });
155
185
  }
186
+ export async function writeActionResultPartChunksToSession(params) {
187
+ if (!params.session || params.actionResults.length === 0)
188
+ return [];
189
+ const writer = params.session.stream.getWriter();
190
+ const events = [];
191
+ const sequenceBase = Date.now();
192
+ try {
193
+ for (let index = 0; index < params.actionResults.length; index += 1) {
194
+ const result = params.actionResults[index];
195
+ const actionRef = String(result.actionRequest.actionRef || "");
196
+ const actionName = String(result.actionRequest.actionName || "");
197
+ if (!actionRef || !actionName)
198
+ continue;
199
+ const chunkType = result.success
200
+ ? "chunk.action_completed"
201
+ : "chunk.action_failed";
202
+ const identity = resolveContextPartChunkIdentity({
203
+ stepId: params.session.stepId,
204
+ provider: "ekairos",
205
+ providerPartId: actionRef,
206
+ chunkType,
207
+ });
208
+ if (!identity)
209
+ continue;
210
+ const data = result.success
211
+ ? {
212
+ actionRef,
213
+ actionCallId: actionRef,
214
+ actionName,
215
+ toolCallId: actionRef,
216
+ toolName: actionName,
217
+ output: toJsonSafeRecord(result.output),
218
+ }
219
+ : {
220
+ actionRef,
221
+ actionCallId: actionRef,
222
+ actionName,
223
+ toolCallId: actionRef,
224
+ toolName: actionName,
225
+ error: {
226
+ message: String(result.errorText || "Action failed."),
227
+ },
228
+ };
229
+ const at = new Date().toISOString();
230
+ const sequence = sequenceBase + index;
231
+ const persistedChunk = createContextStepStreamChunk({
232
+ at,
233
+ sequence,
234
+ chunkType,
235
+ stepId: params.session.stepId,
236
+ partId: identity.partId,
237
+ providerPartId: identity.providerPartId,
238
+ partType: identity.partType,
239
+ partSlot: identity.partSlot,
240
+ provider: "ekairos",
241
+ providerChunkType: result.success
242
+ ? "action_completed"
243
+ : "action_failed",
244
+ actionRef,
245
+ data,
246
+ });
247
+ await writer.write(encodeContextStepStreamChunk(persistedChunk, {
248
+ stepId: params.session.stepId,
249
+ }));
250
+ events.push({
251
+ type: "chunk.emitted",
252
+ at,
253
+ chunkType,
254
+ contextId: params.contextId,
255
+ executionId: params.executionId,
256
+ stepId: params.session.stepId,
257
+ itemId: params.itemId,
258
+ sequence,
259
+ provider: "ekairos",
260
+ providerChunkType: result.success
261
+ ? "action_completed"
262
+ : "action_failed",
263
+ actionRef,
264
+ partId: identity.partId,
265
+ providerPartId: identity.providerPartId,
266
+ partType: identity.partType,
267
+ partSlot: identity.partSlot,
268
+ data,
269
+ });
270
+ }
271
+ }
272
+ finally {
273
+ if (typeof writer?.releaseLock === "function") {
274
+ writer.releaseLock();
275
+ }
276
+ }
277
+ return events;
278
+ }
156
279
  export async function readPersistedContextStepStream(params) {
157
280
  if (!params.db?.streams?.createReadStream) {
158
281
  throw new Error("InstantDB streams are not available on the provided runtime.");
@@ -1,5 +1,6 @@
1
1
  import "../polyfills/dom-events.js";
2
2
  import type { ContextEnvironment } from "../context.config.js";
3
+ import type { ContextRuntimeServiceHandle } from "../context.runtime.js";
3
4
  import type { TraceEventKind } from "../context.contract.js";
4
5
  export type ContextTraceEventWrite = {
5
6
  workflowRunId: string;
@@ -32,7 +33,8 @@ export type ContextTraceEventWrite = {
32
33
  payload?: unknown;
33
34
  testId?: string;
34
35
  };
35
- export declare function writeContextTraceEvents(params: {
36
- env: ContextEnvironment;
36
+ export declare function writeContextTraceEvents<Env extends ContextEnvironment = ContextEnvironment>(params: {
37
+ runtime?: ContextRuntimeServiceHandle;
38
+ env?: Env;
37
39
  events: ContextTraceEventWrite[];
38
40
  }): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import "../polyfills/dom-events.js";
2
+ import { getContextRuntimeServices } from "../context.runtime.js";
2
3
  import { lookup } from "@instantdb/admin";
3
4
  function requireBaseUrl() {
4
5
  const baseUrl = process.env.EKAIROS_CORE_BASE_URL ||
@@ -17,6 +18,20 @@ function requireToken() {
17
18
  throw new Error("[context/trace] Missing EKAIROS_CLERK_API_KEY");
18
19
  }
19
20
  let jwtCache = null;
21
+ function asRecord(value) {
22
+ return value && typeof value === "object" ? value : {};
23
+ }
24
+ function asTraceEnv(value) {
25
+ const record = asRecord(value);
26
+ if (Object.keys(record).length === 0)
27
+ return undefined;
28
+ return {
29
+ baseUrl: typeof record.baseUrl === "string" ? record.baseUrl : undefined,
30
+ apiKey: typeof record.apiKey === "string" ? record.apiKey : undefined,
31
+ projectId: typeof record.projectId === "string" ? record.projectId : undefined,
32
+ strict: record.strict === true,
33
+ };
34
+ }
20
35
  function parseJwtExpMs(token) {
21
36
  const parts = token.split(".");
22
37
  if (parts.length !== 3)
@@ -46,8 +61,8 @@ async function getTraceAuthHeader(baseUrl, projectId) {
46
61
  body: JSON.stringify({ projectId }),
47
62
  });
48
63
  if (res.ok) {
49
- const json = (await res.json());
50
- const token = typeof json?.token === "string" ? json.token : "";
64
+ const json = asRecord(await res.json());
65
+ const token = typeof json.token === "string" ? json.token : "";
51
66
  const expMs = parseJwtExpMs(token) ?? now + 60 * 60 * 1000;
52
67
  if (token) {
53
68
  jwtCache = { token, expMs };
@@ -78,19 +93,22 @@ async function readProjectId() {
78
93
  export async function writeContextTraceEvents(params) {
79
94
  if (!params.events?.length)
80
95
  return;
81
- const envTrace = params.env?.traces;
96
+ const envRecord = asRecord(params.env);
97
+ const envTrace = asTraceEnv(envRecord.traces);
82
98
  // Tracing must NEVER break workflows by default.
83
99
  // Use EKAIROS_TRACES_STRICT=1 if you want to fail hard.
84
100
  const strict = envTrace?.strict === true || process.env.EKAIROS_TRACES_STRICT === "1";
85
101
  // 1) Local trace persistence (InstantDB source of truth).
86
102
  try {
87
- const { getContextRuntime } = await import("../runtime.js");
88
- const runtime = await getContextRuntime(params.env);
89
- const db = runtime?.db;
103
+ if (!params.runtime) {
104
+ throw new Error("[context/trace] runtime is required");
105
+ }
106
+ const runtime = await getContextRuntimeServices(params.runtime);
107
+ const db = runtime.db;
90
108
  if (db) {
91
109
  const now = new Date();
92
- const orgId = typeof params.env?.orgId === "string"
93
- ? String(params.env.orgId)
110
+ const orgId = typeof envRecord.orgId === "string"
111
+ ? String(envRecord.orgId)
94
112
  : "";
95
113
  const projectId = await readProjectId();
96
114
  const byRun = new Map();
@@ -1,7 +1,7 @@
1
1
  import "../polyfills/dom-events.js";
2
- import type { DomainSchemaResult } from "@ekairos/domain";
2
+ import type { DomainLike } from "@ekairos/domain";
3
3
  import type { ModelMessage } from "ai";
4
- import type { ContextItem, ContextIdentifier, ContextStatus, StoredContext, ContextStore } from "../context.store.js";
4
+ import type { ContextItem, ContextIdentifier, ContextResource, ContextStatus, StoredContextResource, StoredContext, ContextStore } from "../context.store.js";
5
5
  export { parseAndStoreDocument } from "./instant.document-parser.js";
6
6
  export { coerceDocumentTextPages, expandEventsWithInstantDocuments, } from "./instant.documents.js";
7
7
  export type InstantStoreDb = any;
@@ -14,8 +14,20 @@ export declare class InstantStore implements ContextStore {
14
14
  getOrCreateContext<C>(contextIdentifier: ContextIdentifier | null): Promise<StoredContext<C>>;
15
15
  getContext<C>(contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>;
16
16
  updateContextContent<C>(contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
17
+ updateContextDefinition<C>(contextIdentifier: ContextIdentifier, definition: {
18
+ description?: string | null;
19
+ goal?: string | null;
20
+ }): Promise<StoredContext<C>>;
21
+ updateContextReactor<C>(contextIdentifier: ContextIdentifier, reactor: {
22
+ kind: string;
23
+ state?: Record<string, unknown> | null;
24
+ }): Promise<StoredContext<C>>;
17
25
  updateContextStatus(contextIdentifier: ContextIdentifier, status: ContextStatus): Promise<void>;
18
26
  private resolveContext;
27
+ private normalizeContextResource;
28
+ private normalizeContextResources;
29
+ getContextResources(contextIdentifier: ContextIdentifier): Promise<StoredContextResource[]>;
30
+ upsertContextResources(contextIdentifier: ContextIdentifier, resources: ContextResource[]): Promise<StoredContextResource[]>;
19
31
  saveItem(contextIdentifier: ContextIdentifier, event: ContextItem): Promise<ContextItem>;
20
32
  updateItem(eventId: string, event: ContextItem): Promise<ContextItem>;
21
33
  getItem(eventId: string): Promise<ContextItem | null>;
@@ -34,14 +46,6 @@ export declare class InstantStore implements ContextStore {
34
46
  }>;
35
47
  updateStep(stepId: string, patch: Partial<{
36
48
  status: "running" | "completed" | "failed";
37
- kind: "message" | "action_execute" | "action_result";
38
- actionName: string;
39
- actionInput: unknown;
40
- actionOutput: unknown;
41
- actionError: string;
42
- actionRequests: any;
43
- actionResults: any;
44
- continueLoop: boolean;
45
49
  errorText: string;
46
50
  updatedAt: Date;
47
51
  }>): Promise<void>;
@@ -58,7 +62,7 @@ export declare class InstantStore implements ContextStore {
58
62
  export declare function createInstantStoreRuntime(params: {
59
63
  getDb: (orgId: string) => Promise<InstantStoreDb> | InstantStoreDb;
60
64
  getOrgId?: (env: Record<string, unknown>) => string;
61
- domain?: DomainSchemaResult;
65
+ domain?: DomainLike;
62
66
  }): (env: Record<string, unknown>) => Promise<{
63
67
  store: InstantStore;
64
68
  db: InstantStoreDb;
@@ -71,6 +71,43 @@ function ensureValidEntityId(value, label) {
71
71
  }
72
72
  return normalized;
73
73
  }
74
+ function sanitizeInstantString(value) {
75
+ return value.includes("\u0000") ? value.replace(/\u0000/g, "") : value;
76
+ }
77
+ function isOpaqueJsonValue(value) {
78
+ return (value instanceof Date ||
79
+ value instanceof ArrayBuffer ||
80
+ ArrayBuffer.isView(value));
81
+ }
82
+ function sanitizeInstantValue(value, seen = new WeakMap()) {
83
+ if (typeof value === "string") {
84
+ return sanitizeInstantString(value);
85
+ }
86
+ if (value === null || value === undefined || typeof value !== "object") {
87
+ return value;
88
+ }
89
+ if (isOpaqueJsonValue(value)) {
90
+ return value;
91
+ }
92
+ const cached = seen.get(value);
93
+ if (cached) {
94
+ return cached;
95
+ }
96
+ if (Array.isArray(value)) {
97
+ const out = [];
98
+ seen.set(value, out);
99
+ for (const item of value) {
100
+ out.push(sanitizeInstantValue(item, seen));
101
+ }
102
+ return out;
103
+ }
104
+ const out = {};
105
+ seen.set(value, out);
106
+ for (const [key, entryValue] of Object.entries(value)) {
107
+ out[sanitizeInstantString(key)] = sanitizeInstantValue(entryValue, seen);
108
+ }
109
+ return out;
110
+ }
74
111
  function logInstantTransactFailure(params) {
75
112
  if (!shouldDebugInstantStore())
76
113
  return;
@@ -118,6 +155,12 @@ export class InstantStore {
118
155
  ? new Date(row.updatedAt)
119
156
  : undefined,
120
157
  content: row?.content ?? null,
158
+ description: typeof row?.description === "string" ? row.description : null,
159
+ goal: typeof row?.goal === "string" ? row.goal : null,
160
+ resources: this.normalizeContextResources(row?.resources),
161
+ reactor: row?.reactor && typeof row.reactor === "object"
162
+ ? row.reactor
163
+ : null,
121
164
  };
122
165
  }
123
166
  async ensureContextKey(context, expectedKey) {
@@ -144,6 +187,10 @@ export class InstantStore {
144
187
  key,
145
188
  status: "open_idle",
146
189
  content: {},
190
+ description: undefined,
191
+ goal: undefined,
192
+ resources: [],
193
+ reactor: undefined,
147
194
  }),
148
195
  ]);
149
196
  const context = await this.getContext({ id: contextId });
@@ -203,6 +250,43 @@ export class InstantStore {
203
250
  throw new Error("InstantStore: context not found after update");
204
251
  return updated;
205
252
  }
253
+ async updateContextDefinition(contextIdentifier, definition) {
254
+ const context = await this.getContext(contextIdentifier);
255
+ if (!context?.id)
256
+ throw new Error("InstantStore: context not found");
257
+ const update = {
258
+ updatedAt: new Date(),
259
+ };
260
+ if (definition.description !== undefined) {
261
+ update.description =
262
+ typeof definition.description === "string" ? definition.description : undefined;
263
+ }
264
+ if (definition.goal !== undefined) {
265
+ update.goal = typeof definition.goal === "string" ? definition.goal : undefined;
266
+ }
267
+ await this.db.transact([
268
+ this.db.tx.event_contexts[context.id].update(update),
269
+ ]);
270
+ const updated = await this.getContext({ id: context.id });
271
+ if (!updated)
272
+ throw new Error("InstantStore: context not found after definition update");
273
+ return updated;
274
+ }
275
+ async updateContextReactor(contextIdentifier, reactor) {
276
+ const context = await this.getContext(contextIdentifier);
277
+ if (!context?.id)
278
+ throw new Error("InstantStore: context not found");
279
+ await this.db.transact([
280
+ this.db.tx.event_contexts[context.id].update({
281
+ reactor: reactor,
282
+ updatedAt: new Date(),
283
+ }),
284
+ ]);
285
+ const updated = await this.getContext({ id: context.id });
286
+ if (!updated)
287
+ throw new Error("InstantStore: context not found after reactor update");
288
+ return updated;
289
+ }
206
290
  async updateContextStatus(contextIdentifier, status) {
207
291
  const context = await this.getContext(contextIdentifier);
208
292
  if (!context?.id)
@@ -223,8 +307,69 @@ export class InstantStore {
223
307
  throw new Error("InstantStore: context not found");
224
308
  return context;
225
309
  }
310
+ normalizeContextResource(resource) {
311
+ if (!resource || typeof resource !== "object")
312
+ return null;
313
+ const record = resource;
314
+ const key = typeof record.key === "string" ? record.key.trim() : "";
315
+ const type = typeof record.type === "string" ? record.type.trim() : "";
316
+ const name = typeof record.name === "string" ? record.name.trim() : "";
317
+ const description = typeof record.description === "string" ? record.description.trim() : "";
318
+ if (!key || !type || !name || !description)
319
+ return null;
320
+ return {
321
+ ...record,
322
+ key,
323
+ type,
324
+ name,
325
+ description,
326
+ };
327
+ }
328
+ normalizeContextResources(value) {
329
+ if (!Array.isArray(value))
330
+ return [];
331
+ return value.flatMap((resource) => {
332
+ const normalized = this.normalizeContextResource(resource);
333
+ return normalized ? [normalized] : [];
334
+ });
335
+ }
336
+ async getContextResources(contextIdentifier) {
337
+ const context = await this.resolveContext(contextIdentifier);
338
+ return context.resources ?? [];
339
+ }
340
+ async upsertContextResources(contextIdentifier, resources) {
341
+ const context = await this.resolveContext(contextIdentifier);
342
+ const now = new Date();
343
+ const storedResources = [];
344
+ for (const resource of resources) {
345
+ const resourceKey = typeof resource.key === "string" ? resource.key.trim() : "";
346
+ const type = typeof resource.type === "string" ? resource.type.trim() : "";
347
+ const name = typeof resource.name === "string" ? resource.name.trim() : "";
348
+ const description = typeof resource.description === "string" ? resource.description.trim() : "";
349
+ if (!resourceKey || !type || !name || !description) {
350
+ throw new Error("InstantStore: context resources require key, type, name, and description.");
351
+ }
352
+ const sanitizedResource = sanitizeInstantValue(resource);
353
+ const storedResource = {
354
+ ...sanitizedResource,
355
+ key: resourceKey,
356
+ type,
357
+ name,
358
+ description,
359
+ };
360
+ storedResources.push(storedResource);
361
+ }
362
+ await this.db.transact([
363
+ this.db.tx.event_contexts[context.id].update({
364
+ resources: storedResources,
365
+ updatedAt: now,
366
+ }),
367
+ ]);
368
+ return await this.getContextResources({ id: context.id });
369
+ }
226
370
  async saveItem(contextIdentifier, event) {
227
371
  const eventId = ensureValidEntityId(event?.id, "event.id");
372
+ const sanitizedEvent = sanitizeInstantValue(event);
228
373
  const context = await this.resolveContext(contextIdentifier);
229
374
  const existing = await this.getItem(eventId);
230
375
  if (existing?.status && existing.status !== "stored") {
@@ -232,7 +377,7 @@ export class InstantStore {
232
377
  }
233
378
  const txs = [
234
379
  this.db.tx.event_items[eventId].update({
235
- ...event,
380
+ ...sanitizedEvent,
236
381
  id: eventId,
237
382
  status: "stored",
238
383
  }),
@@ -258,7 +403,7 @@ export class InstantStore {
258
403
  throw error;
259
404
  }
260
405
  return {
261
- ...event,
406
+ ...sanitizedEvent,
262
407
  id: eventId,
263
408
  status: "stored",
264
409
  };
@@ -268,10 +413,11 @@ export class InstantStore {
268
413
  if (current?.status && event.status && current.status !== event.status) {
269
414
  assertItemTransition(current.status, event.status);
270
415
  }
271
- await this.db.transact([this.db.tx.event_items[eventId].update(event)]);
416
+ const sanitizedEvent = sanitizeInstantValue(event);
417
+ await this.db.transact([this.db.tx.event_items[eventId].update(sanitizedEvent)]);
272
418
  return {
273
419
  ...current,
274
- ...event,
420
+ ...sanitizedEvent,
275
421
  id: eventId,
276
422
  };
277
423
  }
@@ -498,9 +644,12 @@ export class InstantStore {
498
644
  }
499
645
  }
500
646
  const update = {
501
- ...patch,
502
647
  updatedAt: patch.updatedAt ?? new Date(),
503
648
  };
649
+ if (patch.status !== undefined)
650
+ update.status = patch.status;
651
+ if (patch.errorText !== undefined)
652
+ update.errorText = patch.errorText;
504
653
  await this.db.transact([this.db.tx.event_steps[stepId].update(update)]);
505
654
  }
506
655
  async linkItemToExecution(params) {
@@ -509,7 +658,7 @@ export class InstantStore {
509
658
  ]);
510
659
  }
511
660
  async saveStepParts(params) {
512
- const parts = normalizePartsForPersistence(Array.isArray(params.parts) ? params.parts : []);
661
+ const parts = sanitizeInstantValue(normalizePartsForPersistence(Array.isArray(params.parts) ? params.parts : []));
513
662
  if (parts.length === 0)
514
663
  return;
515
664
  const txs = parts.map((part, idx) => {
@@ -1,4 +1,3 @@
1
- import { type Tool } from "ai";
2
1
  /**
3
2
  * Serializable "tool" shape to pass across the Workflow step boundary.
4
3
  *
@@ -6,14 +5,51 @@ import { type Tool } from "ai";
6
5
  * - Keep Zod/function values out of step arguments
7
6
  * - Convert tool input schemas to plain JSON Schema in workflow context
8
7
  */
9
- export type SerializableToolForModel = {
8
+ export type SerializableFunctionActionSpec = {
9
+ type?: "function";
10
10
  description?: string;
11
11
  inputSchema: unknown;
12
+ outputSchema?: unknown;
13
+ providerOptions?: unknown;
12
14
  };
15
+ export type SerializableProviderDefinedActionSpec = {
16
+ type: "provider-defined";
17
+ id: string;
18
+ name?: string;
19
+ args?: Record<string, unknown>;
20
+ };
21
+ export type SerializableActionSpec = SerializableFunctionActionSpec | SerializableProviderDefinedActionSpec;
22
+ /**
23
+ * @deprecated Use SerializableActionSpec.
24
+ */
25
+ export type SerializableToolForModel = SerializableActionSpec;
13
26
  /**
14
27
  * Convert AI SDK tools to a serializable representation that can be passed to `"use-step"` functions.
15
28
  *
16
29
  * This matches DurableAgent's internal `toolsToModelTools` behavior:
17
30
  * `inputSchema: asSchema(tool.inputSchema).jsonSchema`
18
31
  */
19
- export declare function toolsToModelTools(tools: Record<string, Tool>): Record<string, SerializableToolForModel>;
32
+ export declare function actionsToActionSpecs(tools: Record<string, unknown>): Record<string, SerializableActionSpec>;
33
+ export declare function actionSpecToAiSdkTool(name: string, spec: SerializableActionSpec, wrapJsonSchema: (schema: unknown) => unknown): {
34
+ type: "provider-defined";
35
+ id: string;
36
+ name: string;
37
+ args: Record<string, unknown>;
38
+ description?: undefined;
39
+ inputSchema?: undefined;
40
+ outputSchema?: undefined;
41
+ providerOptions?: undefined;
42
+ } | {
43
+ type: "function";
44
+ description: string | undefined;
45
+ inputSchema: unknown;
46
+ outputSchema: unknown;
47
+ providerOptions: unknown;
48
+ id?: undefined;
49
+ name?: undefined;
50
+ args?: undefined;
51
+ };
52
+ /**
53
+ * @deprecated Use actionsToActionSpecs.
54
+ */
55
+ export declare const toolsToModelTools: typeof actionsToActionSpecs;