@ekairos/structure 1.22.46-beta.development.0 → 1.22.47-beta.development.0

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.
@@ -1,24 +1,5 @@
1
1
  import { linkStructureOutputFileToContextByKey } from "../contextPersistence.js";
2
- function isToolCompletePart(value) {
3
- if (!value || typeof value !== "object")
4
- return false;
5
- const v = value;
6
- return v.type === "tool-complete" && v.state === "output-available";
7
- }
8
- function findLatestCompleteToolOutput(events) {
9
- for (let i = events.length - 1; i >= 0; i--) {
10
- const parts = events[i]?.content?.parts;
11
- if (!Array.isArray(parts))
12
- continue;
13
- for (let j = parts.length - 1; j >= 0; j--) {
14
- const p = parts[j];
15
- if (!isToolCompletePart(p))
16
- continue;
17
- return p.output;
18
- }
19
- }
20
- return null;
21
- }
2
+ import { findLatestCompleteToolOutput } from "./completeOutput.js";
22
3
  export async function structureCommitFromEventsStep(params) {
23
4
  "use step";
24
5
  const contextKey = `structure:${params.structureId}`;
@@ -0,0 +1 @@
1
+ export declare function findLatestCompleteToolOutput(events: unknown[]): unknown | null;
@@ -0,0 +1,43 @@
1
+ function asRecord(value) {
2
+ if (!value || typeof value !== "object")
3
+ return null;
4
+ return value;
5
+ }
6
+ function readPart(value) {
7
+ const record = asRecord(value);
8
+ if (!record)
9
+ return null;
10
+ const nestedPart = asRecord(record.part);
11
+ return nestedPart ?? record;
12
+ }
13
+ function readCompleteOutputFromPart(value) {
14
+ const part = readPart(value);
15
+ if (!part)
16
+ return null;
17
+ if (part.type === "tool-complete" && part.state === "output-available") {
18
+ return part.output ?? null;
19
+ }
20
+ if (part.type !== "action")
21
+ return null;
22
+ const content = asRecord(part.content);
23
+ if (content?.status !== "completed" ||
24
+ content?.actionName !== "complete") {
25
+ return null;
26
+ }
27
+ return content.output ?? null;
28
+ }
29
+ export function findLatestCompleteToolOutput(events) {
30
+ for (let i = events.length - 1; i >= 0; i--) {
31
+ const event = asRecord(events[i]);
32
+ const content = asRecord(event?.content);
33
+ const parts = Array.isArray(content?.parts) ? content.parts : null;
34
+ if (!parts)
35
+ continue;
36
+ for (let j = parts.length - 1; j >= 0; j--) {
37
+ const output = readCompleteOutputFromPart(parts[j]);
38
+ if (output !== null)
39
+ return output;
40
+ }
41
+ }
42
+ return null;
43
+ }
@@ -85,6 +85,10 @@ export async function ensureExecutionTrailStep(params) {
85
85
  });
86
86
  if (!outputItem?.id)
87
87
  return;
88
+ const context = await store.getContext?.({ key: params.contextKey });
89
+ if (context?.status === "closed" && store?.updateContextStatus) {
90
+ await store.updateContextStatus({ key: params.contextKey }, "open_idle");
91
+ }
88
92
  const execution = await store.createExecution({ key: params.contextKey }, requestItemId, outputItem.id);
89
93
  await store.linkItemToExecution({
90
94
  itemId: requestItemId,
@@ -1,3 +1,4 @@
1
+ import { findLatestCompleteToolOutput } from "./completeOutput.js";
1
2
  function extractJsonObject(text) {
2
3
  const trimmed = text.trim();
3
4
  if (!trimmed)
@@ -40,10 +41,37 @@ export async function persistObjectResultFromStoryStep(params) {
40
41
  const runtime = (await getContextRuntime(params.env));
41
42
  const store = runtime.store;
42
43
  const contextKey = `structure:${params.datasetId}`;
43
- const events = await store.getEvents({ key: contextKey });
44
+ const events = typeof store.getItems === "function"
45
+ ? await store.getItems({ key: contextKey })
46
+ : await store.getEvents({ key: contextKey });
44
47
  const { structurePatchContextContentStep, structureGetContextStep } = await import("../dataset/steps.js");
45
48
  const ctxResult = await structureGetContextStep({ env: params.env, contextKey });
46
49
  const existingContent = ctxResult.ok ? (ctxResult.data?.content ?? {}) : {};
50
+ const completedOutput = findLatestCompleteToolOutput(events ?? []);
51
+ if (completedOutput?.success === true && "result" in completedOutput) {
52
+ const patchResult = await structurePatchContextContentStep({
53
+ env: params.env,
54
+ contextKey,
55
+ patch: {
56
+ structure: {
57
+ kind: "ekairos.structure",
58
+ version: 1,
59
+ structureId: params.datasetId,
60
+ updatedAt: Date.now(),
61
+ state: "completed",
62
+ outputs: {
63
+ ...(existingContent?.structure?.outputs ?? {}),
64
+ object: { value: completedOutput.result },
65
+ },
66
+ },
67
+ },
68
+ });
69
+ if (!patchResult?.ok) {
70
+ const err = patchResult?.error ?? "Failed to persist object result";
71
+ throw new Error(err);
72
+ }
73
+ return { ok: true };
74
+ }
47
75
  for (let i = events.length - 1; i >= 0; i--) {
48
76
  const e = events[i];
49
77
  const parts = e?.content?.parts;
@@ -1,3 +1,4 @@
1
+ import type { ContextModelInit } from "@ekairos/events";
1
2
  import { type StructureRowsOutputPagingCursor } from "./rowsOutputPaging.js";
2
3
  import type { SandboxConfig } from "@ekairos/sandbox";
3
4
  export type StructureSource = {
@@ -66,10 +67,32 @@ export type StructureBuildResult = {
66
67
  */
67
68
  dataset?: any;
68
69
  };
70
+ type StructureStoryConfig = {
71
+ datasetId: string;
72
+ sources: StructureSource[];
73
+ instructions?: string;
74
+ mode: StructureMode;
75
+ output: StructureOutput;
76
+ outputSchema?: any;
77
+ sandboxId?: string;
78
+ model?: ContextModelInit;
79
+ sandboxConfig?: SandboxConfig;
80
+ };
81
+ export declare function structureRunStoryStep<Env extends {
82
+ orgId: string;
83
+ }>(params: {
84
+ env: Env;
85
+ contextKey: string;
86
+ config: StructureStoryConfig;
87
+ event: any;
88
+ }): Promise<{
89
+ ok: boolean;
90
+ }>;
69
91
  export declare function structure<Env extends {
70
92
  orgId: string;
71
93
  }>(env: Env, opts?: {
72
94
  datasetId?: string;
95
+ model?: ContextModelInit;
73
96
  sandboxConfig?: SandboxConfig;
74
97
  }): {
75
98
  datasetId: string;
@@ -79,5 +102,7 @@ export declare function structure<Env extends {
79
102
  schema(schema: any): /*elided*/ any;
80
103
  asRows(): /*elided*/ any;
81
104
  asObject(): /*elided*/ any;
105
+ model(nextModel: ContextModelInit): /*elided*/ any;
82
106
  build(userPrompt?: string): Promise<StructureBuildResult>;
83
107
  };
108
+ export {};
package/dist/structure.js CHANGED
@@ -410,6 +410,35 @@ function createStructureStoryDefinition(config) {
410
410
  .model(model);
411
411
  return { datasetId, story };
412
412
  }
413
+ export async function structureRunStoryStep(params) {
414
+ "use step";
415
+ const { story, datasetId } = createStructureStoryDefinition(params.config);
416
+ const { getContextRuntime } = await import("@ekairos/events/runtime");
417
+ const runtime = await getContextRuntime(params.env);
418
+ const shell = await story.react(params.event, {
419
+ env: params.env,
420
+ runtime,
421
+ context: { key: params.contextKey },
422
+ durable: false,
423
+ options: {
424
+ silent: true,
425
+ preventClose: true,
426
+ sendFinish: false,
427
+ maxIterations: 40,
428
+ maxModelSteps: 10,
429
+ },
430
+ });
431
+ await shell.run;
432
+ // Tools are intentionally pure: persist completion outputs post-react by reading tool results from events.
433
+ const commit = await structureCommitFromEventsStep({
434
+ env: params.env,
435
+ structureId: datasetId,
436
+ });
437
+ if (!commit.ok) {
438
+ throw new Error(commit.error);
439
+ }
440
+ return { ok: true };
441
+ }
413
442
  export function structure(env, opts) {
414
443
  const datasetId = opts?.datasetId ?? createUuidV4();
415
444
  const sources = [];
@@ -417,6 +446,7 @@ export function structure(env, opts) {
417
446
  let mode = "auto";
418
447
  let output = "rows";
419
448
  let outputSchema;
449
+ let model = opts?.model;
420
450
  const sandboxConfig = opts?.sandboxConfig;
421
451
  const api = {
422
452
  datasetId,
@@ -446,6 +476,10 @@ export function structure(env, opts) {
446
476
  output = "object";
447
477
  return api;
448
478
  },
479
+ model(nextModel) {
480
+ model = nextModel;
481
+ return api;
482
+ },
449
483
  async build(userPrompt) {
450
484
  // Guardrail: structure build MUST run inside workflow runtime ("use workflow").
451
485
  const workflowMeta = assertRunningInsideWorkflow({ datasetId });
@@ -458,6 +492,7 @@ export function structure(env, opts) {
458
492
  mode,
459
493
  output,
460
494
  outputSchema,
495
+ model,
461
496
  sandboxConfig,
462
497
  };
463
498
  const { story } = createStructureStoryDefinition(storyConfig);
@@ -495,18 +530,12 @@ export function structure(env, opts) {
495
530
  }
496
531
  }
497
532
  async function runStory(evt) {
498
- const shell = await story.react(evt, {
533
+ await structureRunStoryStep({
499
534
  env,
500
- context: { key: contextKey },
501
- durable: false,
502
- options: { silent: true, preventClose: true, sendFinish: false, maxIterations: 40, maxModelSteps: 10 },
535
+ contextKey,
536
+ config: storyConfig,
537
+ event: evt,
503
538
  });
504
- await shell.run;
505
- // Tools are intentionally pure: persist completion outputs post-react by reading tool results from events.
506
- const commit = await structureCommitFromEventsStep({ env, structureId: datasetId });
507
- if (!commit.ok) {
508
- throw new Error(commit.error);
509
- }
510
539
  }
511
540
  async function getContextOrThrow() {
512
541
  const ctxResult = await structureGetContextStep({ env, contextKey });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekairos/structure",
3
- "version": "1.22.46-beta.development.0",
3
+ "version": "1.22.47-beta.development.0",
4
4
  "description": "Ekairos Structure - Unified structured extraction (rows or object) from file/text/dataset inputs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,8 +36,8 @@
36
36
  "typecheck": "tsc --noEmit"
37
37
  },
38
38
  "dependencies": {
39
- "@ekairos/domain": "^1.22.46-beta.development.0",
40
- "@ekairos/sandbox": "^1.22.46-beta.development.0",
39
+ "@ekairos/domain": "^1.22.47-beta.development.0",
40
+ "@ekairos/sandbox": "^1.22.47-beta.development.0",
41
41
  "@instantdb/admin": "0.22.126",
42
42
  "@instantdb/core": "0.22.126",
43
43
  "ai": "^5.0.95",