@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.
- package/README.md +58 -83
- package/dist/codex.d.ts +11 -2
- package/dist/codex.js +16 -8
- package/dist/context.action-calls.d.ts +48 -0
- package/dist/context.action-calls.js +123 -0
- package/dist/context.action.d.ts +55 -0
- package/dist/context.action.js +25 -0
- package/dist/context.builder.d.ts +71 -43
- package/dist/context.builder.js +123 -28
- package/dist/context.config.d.ts +2 -1
- package/dist/context.config.js +8 -3
- package/dist/context.contract.d.ts +2 -4
- package/dist/context.contract.js +3 -9
- package/dist/context.d.ts +3 -2
- package/dist/context.engine.d.ts +75 -46
- package/dist/context.engine.js +538 -302
- package/dist/context.events.js +28 -87
- package/dist/context.js +1 -0
- package/dist/context.part-identity.d.ts +40 -0
- package/dist/context.part-identity.js +270 -0
- package/dist/context.parts.d.ts +389 -164
- package/dist/context.parts.js +343 -218
- package/dist/context.registry.d.ts +1 -1
- package/dist/context.runtime.d.ts +21 -0
- package/dist/context.runtime.js +39 -0
- package/dist/context.step-stream.d.ts +16 -2
- package/dist/context.step-stream.js +58 -16
- package/dist/context.store.d.ts +63 -10
- package/dist/context.stream.d.ts +14 -4
- package/dist/context.stream.js +31 -3
- package/dist/domain.d.ts +1 -0
- package/dist/domain.js +1 -0
- package/dist/index.d.ts +13 -10
- package/dist/index.js +7 -6
- package/dist/react.context-event-parts.d.ts +18 -0
- package/dist/react.context-event-parts.js +509 -0
- package/dist/react.d.ts +7 -42
- package/dist/react.js +4 -87
- package/dist/react.step-stream.d.ts +39 -0
- package/dist/react.step-stream.js +625 -0
- package/dist/react.types.d.ts +121 -0
- package/dist/react.types.js +2 -0
- package/dist/react.use-context.d.ts +7 -0
- package/dist/react.use-context.js +867 -0
- package/dist/reactors/ai-sdk.chunk-map.d.ts +1 -0
- package/dist/reactors/ai-sdk.chunk-map.js +56 -5
- package/dist/reactors/ai-sdk.reactor.d.ts +8 -5
- package/dist/reactors/ai-sdk.reactor.js +10 -9
- package/dist/reactors/ai-sdk.step.d.ts +6 -6
- package/dist/reactors/ai-sdk.step.js +32 -24
- package/dist/reactors/scripted.reactor.d.ts +7 -4
- package/dist/reactors/types.d.ts +23 -8
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.js +9 -0
- package/dist/runtime.step.js +2 -2
- package/dist/schema.d.ts +268 -2
- package/dist/schema.js +5 -9
- package/dist/steps/do-context-stream-step.d.ts +2 -2
- package/dist/steps/do-context-stream-step.js +6 -8
- package/dist/steps/durable.steps.d.ts +28 -0
- package/dist/steps/durable.steps.js +34 -0
- package/dist/steps/store.steps.d.ts +121 -39
- package/dist/steps/store.steps.js +266 -111
- package/dist/steps/stream.steps.d.ts +36 -3
- package/dist/steps/stream.steps.js +137 -14
- package/dist/steps/trace.steps.d.ts +4 -2
- package/dist/steps/trace.steps.js +26 -8
- package/dist/stores/instant.store.d.ts +15 -11
- package/dist/stores/instant.store.js +155 -6
- package/dist/tools-to-model-tools.d.ts +39 -3
- package/dist/tools-to-model-tools.js +63 -6
- package/package.json +20 -6
- package/dist/context.toolcalls.d.ts +0 -60
- package/dist/context.toolcalls.js +0 -117
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
120
|
+
export async function createPersistedContextStepStream(params) {
|
|
105
121
|
"use step";
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
93
|
-
? String(
|
|
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 {
|
|
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?:
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
|
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
|
|
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;
|