@perstack/runtime 0.0.68 → 0.0.69

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.
@@ -11,10 +11,10 @@ import { ProxyAgent, fetch } from 'undici';
11
11
  import { setup, assign, createActor } from 'xstate';
12
12
  import { generateText, tool, jsonSchema } from 'ai';
13
13
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
14
- import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
15
- import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
16
14
  import { McpError } from '@modelcontextprotocol/sdk/types.js';
17
15
  import { createId } from '@paralleldrive/cuid2';
16
+ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
17
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
18
18
  import { readFile } from 'fs/promises';
19
19
  import { dedent } from 'ts-dedent';
20
20
  import { ApiV1Client } from '@perstack/api-client/v1';
@@ -22,7 +22,7 @@ import { ApiV1Client } from '@perstack/api-client/v1';
22
22
  // package.json
23
23
  var package_default = {
24
24
  name: "@perstack/runtime",
25
- version: "0.0.68",
25
+ version: "0.0.69",
26
26
  description: "Perstack Runtime",
27
27
  author: "Wintermute Technologies, Inc.",
28
28
  license: "Apache-2.0",
@@ -54,9 +54,6 @@ var package_default = {
54
54
  typecheck: "tsc --noEmit"
55
55
  },
56
56
  dependencies: {
57
- commander: "^14.0.2",
58
- dotenv: "^17.2.3",
59
- "smol-toml": "^1.5.2",
60
57
  "@ai-sdk/amazon-bedrock": "^3.0.62",
61
58
  "@ai-sdk/anthropic": "^2.0.50",
62
59
  "@ai-sdk/azure": "^2.0.77",
@@ -69,14 +66,18 @@ var package_default = {
69
66
  "@perstack/api-client": "workspace:*",
70
67
  "@perstack/core": "workspace:*",
71
68
  ai: "^5.0.104",
69
+ commander: "^14.0.2",
70
+ dotenv: "^17.2.3",
72
71
  "ollama-ai-provider-v2": "^1.5.5",
72
+ "smol-toml": "^1.5.2",
73
73
  "ts-dedent": "^2.2.0",
74
- xstate: "^5.24.0",
75
- undici: "^7.9.0"
74
+ undici: "^7.9.0",
75
+ xstate: "^5.24.0"
76
76
  },
77
77
  devDependencies: {
78
78
  "@tsconfig/node22": "^22.0.5",
79
79
  "@types/node": "^24.10.1",
80
+ memfs: "^4.51.1",
80
81
  tsup: "^8.5.1",
81
82
  typescript: "^5.9.3",
82
83
  vitest: "^4.0.14"
@@ -260,11 +261,11 @@ var BaseSkillManager = class {
260
261
  this._initializing = void 0;
261
262
  }
262
263
  async getToolDefinitions() {
263
- if (!this.isInitialized() && !this.lazyInit) {
264
- throw new Error(`Skill ${this.name} is not initialized`);
264
+ if (!this.isInitialized() && this._initializing) {
265
+ await this._initializing;
265
266
  }
266
- if (!this.isInitialized() && this.lazyInit) {
267
- return [];
267
+ if (!this.isInitialized()) {
268
+ throw new Error(`Skill ${this.name} is not initialized`);
268
269
  }
269
270
  return this._filterTools(this._toolDefinitions);
270
271
  }
@@ -273,6 +274,22 @@ var BaseSkillManager = class {
273
274
  }
274
275
  };
275
276
 
277
+ // src/skill-manager/command-args.ts
278
+ function getCommandArgs(skill) {
279
+ const { name, command, packageName, args } = skill;
280
+ if (!packageName && (!args || args.length === 0)) {
281
+ throw new Error(`Skill ${name} has no packageName or args. Please provide one of them.`);
282
+ }
283
+ if (packageName && args && args.length > 0) {
284
+ throw new Error(`Skill ${name} has both packageName and args. Please provide only one of them.`);
285
+ }
286
+ let newArgs = args && args.length > 0 ? args : [packageName];
287
+ if (command === "npx" && !newArgs.includes("-y")) {
288
+ newArgs = ["-y", ...newArgs];
289
+ }
290
+ return { command, args: newArgs };
291
+ }
292
+
276
293
  // src/skill-manager/delegate.ts
277
294
  var DelegateSkillManager = class extends BaseSkillManager {
278
295
  name;
@@ -334,6 +351,114 @@ var InteractiveSkillManager = class extends BaseSkillManager {
334
351
  return [];
335
352
  }
336
353
  };
354
+
355
+ // src/skill-manager/ip-validator.ts
356
+ function isPrivateOrLocalIP(hostname) {
357
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "0.0.0.0") {
358
+ return true;
359
+ }
360
+ const ipv4Match = hostname.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
361
+ if (ipv4Match) {
362
+ const [, a, b] = ipv4Match.map(Number);
363
+ if (a === 10) return true;
364
+ if (a === 172 && b >= 16 && b <= 31) return true;
365
+ if (a === 192 && b === 168) return true;
366
+ if (a === 169 && b === 254) return true;
367
+ if (a === 127) return true;
368
+ }
369
+ if (hostname.includes(":")) {
370
+ if (hostname.startsWith("fe80:")) return true;
371
+ if (hostname.startsWith("fc") || hostname.startsWith("fd")) return true;
372
+ }
373
+ if (hostname.startsWith("::ffff:")) {
374
+ const ipv4Part = hostname.slice(7);
375
+ if (isPrivateOrLocalIP(ipv4Part)) {
376
+ return true;
377
+ }
378
+ }
379
+ return false;
380
+ }
381
+ function handleToolError(error, toolName, McpErrorClass) {
382
+ if (error instanceof McpErrorClass) {
383
+ return [
384
+ {
385
+ type: "textPart",
386
+ text: `Error calling tool ${toolName}: ${error.message}`,
387
+ id: createId()
388
+ }
389
+ ];
390
+ }
391
+ throw error;
392
+ }
393
+ function convertToolResult(result, toolName, input) {
394
+ if (!result.content || result.content.length === 0) {
395
+ return [
396
+ {
397
+ type: "textPart",
398
+ text: `Tool ${toolName} returned nothing with arguments: ${JSON.stringify(input)}`,
399
+ id: createId()
400
+ }
401
+ ];
402
+ }
403
+ return result.content.filter((part) => part.type !== "audio" && part.type !== "resource_link").map((part) => convertPart(part));
404
+ }
405
+ function convertPart(part) {
406
+ switch (part.type) {
407
+ case "text":
408
+ if (!part.text || part.text === "") {
409
+ return { type: "textPart", text: "Error: No content", id: createId() };
410
+ }
411
+ return { type: "textPart", text: part.text, id: createId() };
412
+ case "image":
413
+ if (!part.data || !part.mimeType) {
414
+ throw new Error("Image part must have both data and mimeType");
415
+ }
416
+ return {
417
+ type: "imageInlinePart",
418
+ encodedData: part.data,
419
+ mimeType: part.mimeType,
420
+ id: createId()
421
+ };
422
+ case "resource":
423
+ if (!part.resource) {
424
+ throw new Error("Resource part must have resource content");
425
+ }
426
+ return convertResource(part.resource);
427
+ }
428
+ }
429
+ function convertResource(resource) {
430
+ if (!resource.mimeType) {
431
+ throw new Error(`Resource ${JSON.stringify(resource)} has no mimeType`);
432
+ }
433
+ if (resource.text && typeof resource.text === "string") {
434
+ return { type: "textPart", text: resource.text, id: createId() };
435
+ }
436
+ if (resource.blob && typeof resource.blob === "string") {
437
+ return {
438
+ type: "fileInlinePart",
439
+ encodedData: resource.blob,
440
+ mimeType: resource.mimeType,
441
+ id: createId()
442
+ };
443
+ }
444
+ throw new Error(`Unsupported resource type: ${JSON.stringify(resource)}`);
445
+ }
446
+ var DefaultTransportFactory = class {
447
+ createStdio(options) {
448
+ return new StdioClientTransport({
449
+ command: options.command,
450
+ args: options.args,
451
+ env: options.env,
452
+ stderr: options.stderr
453
+ });
454
+ }
455
+ createSse(options) {
456
+ return new SSEClientTransport(options.url);
457
+ }
458
+ };
459
+ var defaultTransportFactory = new DefaultTransportFactory();
460
+
461
+ // src/skill-manager/mcp.ts
337
462
  var McpSkillManager = class extends BaseSkillManager {
338
463
  name;
339
464
  type = "mcp";
@@ -341,11 +466,13 @@ var McpSkillManager = class extends BaseSkillManager {
341
466
  skill;
342
467
  _mcpClient;
343
468
  _env;
344
- constructor(skill, env, jobId, runId, eventListener) {
469
+ _transportFactory;
470
+ constructor(skill, env, jobId, runId, eventListener, options) {
345
471
  super(jobId, runId, eventListener);
346
472
  this.name = skill.name;
347
473
  this.skill = skill;
348
474
  this._env = env;
475
+ this._transportFactory = options?.transportFactory ?? defaultTransportFactory;
349
476
  this.lazyInit = skill.type === "mcpStdioSkill" && skill.lazyInit && skill.name !== "@perstack/base";
350
477
  }
351
478
  async _doInit() {
@@ -396,7 +523,7 @@ var McpSkillManager = class extends BaseSkillManager {
396
523
  }
397
524
  const env = getFilteredEnv(requiredEnv);
398
525
  const startTime = Date.now();
399
- const { command, args } = this._getCommandArgs(skill);
526
+ const { command, args } = getCommandArgs(skill);
400
527
  if (this._eventListener) {
401
528
  const event = createRuntimeEvent("skillStarting", this._jobId, this._runId, {
402
529
  skillName: skill.name,
@@ -405,7 +532,7 @@ var McpSkillManager = class extends BaseSkillManager {
405
532
  });
406
533
  this._eventListener(event);
407
534
  }
408
- const transport = new StdioClientTransport({ command, args, env, stderr: "pipe" });
535
+ const transport = this._transportFactory.createStdio({ command, args, env, stderr: "pipe" });
409
536
  const spawnDurationMs = Date.now() - startTime;
410
537
  if (transport.stderr) {
411
538
  transport.stderr.on("data", (chunk) => {
@@ -437,56 +564,14 @@ var McpSkillManager = class extends BaseSkillManager {
437
564
  if (url.protocol !== "https:") {
438
565
  throw new Error(`Skill ${skill.name} SSE endpoint must use HTTPS: ${skill.endpoint}`);
439
566
  }
440
- if (this._isPrivateOrLocalIP(url.hostname)) {
567
+ if (isPrivateOrLocalIP(url.hostname)) {
441
568
  throw new Error(
442
569
  `Skill ${skill.name} SSE endpoint cannot use private/local IP: ${skill.endpoint}`
443
570
  );
444
571
  }
445
- const transport = new SSEClientTransport(url);
572
+ const transport = this._transportFactory.createSse({ url });
446
573
  await this._mcpClient.connect(transport);
447
574
  }
448
- _isPrivateOrLocalIP(hostname) {
449
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "0.0.0.0") {
450
- return true;
451
- }
452
- const ipv4Match = hostname.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
453
- if (ipv4Match) {
454
- const [, a, b] = ipv4Match.map(Number);
455
- if (a === 10) return true;
456
- if (a === 172 && b >= 16 && b <= 31) return true;
457
- if (a === 192 && b === 168) return true;
458
- if (a === 169 && b === 254) return true;
459
- if (a === 127) return true;
460
- }
461
- if (hostname.includes(":")) {
462
- if (hostname.startsWith("fe80:") || hostname.startsWith("fc") || hostname.startsWith("fd")) {
463
- return true;
464
- }
465
- }
466
- if (hostname.startsWith("::ffff:")) {
467
- const ipv4Part = hostname.slice(7);
468
- if (this._isPrivateOrLocalIP(ipv4Part)) {
469
- return true;
470
- }
471
- }
472
- return false;
473
- }
474
- _getCommandArgs(skill) {
475
- const { name, command, packageName, args } = skill;
476
- if (!packageName && (!args || args.length === 0)) {
477
- throw new Error(`Skill ${name} has no packageName or args. Please provide one of them.`);
478
- }
479
- if (packageName && args && args.length > 0) {
480
- throw new Error(
481
- `Skill ${name} has both packageName and args. Please provide only one of them.`
482
- );
483
- }
484
- let newArgs = args && args.length > 0 ? args : [packageName];
485
- if (command === "npx" && !newArgs.includes("-y")) {
486
- newArgs = ["-y", ...newArgs];
487
- }
488
- return { command, args: newArgs };
489
- }
490
575
  async close() {
491
576
  if (this._mcpClient) {
492
577
  await this._mcpClient.close();
@@ -512,77 +597,33 @@ var McpSkillManager = class extends BaseSkillManager {
512
597
  name: toolName,
513
598
  arguments: input
514
599
  });
515
- return this._convertToolResult(result, toolName, input);
600
+ return convertToolResult(result, toolName, input);
516
601
  } catch (error) {
517
- return this._handleToolError(error, toolName);
602
+ return handleToolError(error, toolName, McpError);
518
603
  }
519
604
  }
520
- _handleToolError(error, toolName) {
521
- if (error instanceof McpError) {
522
- return [
523
- {
524
- type: "textPart",
525
- text: `Error calling tool ${toolName}: ${error.message}`,
526
- id: createId()
527
- }
528
- ];
529
- }
530
- throw error;
605
+ };
606
+
607
+ // src/skill-manager/skill-manager-factory.ts
608
+ var DefaultSkillManagerFactory = class {
609
+ createMcp(skill, context) {
610
+ return new McpSkillManager(
611
+ skill,
612
+ context.env,
613
+ context.jobId,
614
+ context.runId,
615
+ context.eventListener,
616
+ context.mcpOptions
617
+ );
531
618
  }
532
- _convertToolResult(result, toolName, input) {
533
- if (!result.content || result.content.length === 0) {
534
- return [
535
- {
536
- type: "textPart",
537
- text: `Tool ${toolName} returned nothing with arguments: ${JSON.stringify(input)}`,
538
- id: createId()
539
- }
540
- ];
541
- }
542
- return result.content.filter((part) => part.type !== "audio" && part.type !== "resource_link").map((part) => this._convertPart(part));
619
+ createInteractive(skill, context) {
620
+ return new InteractiveSkillManager(skill, context.jobId, context.runId, context.eventListener);
543
621
  }
544
- _convertPart(part) {
545
- switch (part.type) {
546
- case "text":
547
- if (!part.text || part.text === "") {
548
- return { type: "textPart", text: "Error: No content", id: createId() };
549
- }
550
- return { type: "textPart", text: part.text, id: createId() };
551
- case "image":
552
- if (!part.data || !part.mimeType) {
553
- throw new Error("Image part must have both data and mimeType");
554
- }
555
- return {
556
- type: "imageInlinePart",
557
- encodedData: part.data,
558
- mimeType: part.mimeType,
559
- id: createId()
560
- };
561
- case "resource":
562
- if (!part.resource) {
563
- throw new Error("Resource part must have resource content");
564
- }
565
- return this._convertResource(part.resource);
566
- }
567
- }
568
- _convertResource(resource) {
569
- if (!resource.mimeType) {
570
- throw new Error(`Resource ${JSON.stringify(resource)} has no mimeType`);
571
- }
572
- if (resource.text && typeof resource.text === "string") {
573
- return { type: "textPart", text: resource.text, id: createId() };
574
- }
575
- if (resource.blob && typeof resource.blob === "string") {
576
- return {
577
- type: "fileInlinePart",
578
- encodedData: resource.blob,
579
- mimeType: resource.mimeType,
580
- id: createId()
581
- };
582
- }
583
- throw new Error(`Unsupported resource type: ${JSON.stringify(resource)}`);
622
+ createDelegate(expert, context) {
623
+ return new DelegateSkillManager(expert, context.jobId, context.runId, context.eventListener);
584
624
  }
585
625
  };
626
+ var defaultSkillManagerFactory = new DefaultSkillManagerFactory();
586
627
 
587
628
  // src/skill-manager/helpers.ts
588
629
  async function initSkillManagersWithCleanup(managers, allManagers) {
@@ -597,11 +638,20 @@ async function initSkillManagersWithCleanup(managers, allManagers) {
597
638
  async function getSkillManagers(expert, experts, setting, eventListener, options) {
598
639
  const { perstackBaseSkillCommand, env, jobId, runId } = setting;
599
640
  const { skills } = expert;
641
+ const factory = options?.factory ?? defaultSkillManagerFactory;
600
642
  if (!skills["@perstack/base"]) {
601
643
  throw new Error("Base skill is not defined");
602
644
  }
645
+ const factoryContext = {
646
+ env,
647
+ jobId,
648
+ runId,
649
+ eventListener
650
+ };
603
651
  const allManagers = [];
604
- const mcpSkills = Object.values(skills).filter((skill) => skill.type === "mcpStdioSkill" || skill.type === "mcpSseSkill").map((skill) => {
652
+ const mcpSkills = Object.values(skills).filter(
653
+ (skill) => skill.type === "mcpStdioSkill" || skill.type === "mcpSseSkill"
654
+ ).map((skill) => {
605
655
  if (perstackBaseSkillCommand && skill.type === "mcpStdioSkill") {
606
656
  const matchesBaseByPackage = skill.command === "npx" && skill.packageName === "@perstack/base";
607
657
  const matchesBaseByArgs = skill.command === "npx" && Array.isArray(skill.args) && skill.args.includes("@perstack/base");
@@ -622,7 +672,7 @@ async function getSkillManagers(expert, experts, setting, eventListener, options
622
672
  return skill;
623
673
  });
624
674
  const mcpSkillManagers = mcpSkills.map((skill) => {
625
- const manager = new McpSkillManager(skill, env, jobId, runId, eventListener);
675
+ const manager = factory.createMcp(skill, factoryContext);
626
676
  allManagers.push(manager);
627
677
  return manager;
628
678
  });
@@ -632,7 +682,7 @@ async function getSkillManagers(expert, experts, setting, eventListener, options
632
682
  (skill) => skill.type === "interactiveSkill"
633
683
  );
634
684
  const interactiveSkillManagers = interactiveSkills.map((interactiveSkill) => {
635
- const manager = new InteractiveSkillManager(interactiveSkill, jobId, runId, eventListener);
685
+ const manager = factory.createInteractive(interactiveSkill, factoryContext);
636
686
  allManagers.push(manager);
637
687
  return manager;
638
688
  });
@@ -646,7 +696,7 @@ async function getSkillManagers(expert, experts, setting, eventListener, options
646
696
  })));
647
697
  throw new Error(`Delegate expert "${delegateExpertName}" not found in experts`);
648
698
  }
649
- const manager = new DelegateSkillManager(delegate, jobId, runId, eventListener);
699
+ const manager = factory.createDelegate(delegate, factoryContext);
650
700
  allManagers.push(manager);
651
701
  delegateSkillManagers.push(manager);
652
702
  }
@@ -1973,63 +2023,113 @@ var StateMachineLogics = {
1973
2023
  CallingDelegate: callingDelegateLogic,
1974
2024
  FinishingStep: finishingStepLogic
1975
2025
  };
1976
- async function executeStateMachine(params) {
1977
- const {
1978
- setting,
1979
- initialCheckpoint,
1980
- eventListener,
1981
- skillManagers,
1982
- eventEmitter,
1983
- storeCheckpoint,
1984
- shouldContinueRun
1985
- } = params;
1986
- const runActor = createActor(runtimeStateMachine, {
1987
- input: {
1988
- setting,
1989
- initialCheckpoint,
1990
- eventListener,
1991
- skillManagers
1992
- }
1993
- });
1994
- return new Promise((resolve, reject) => {
1995
- runActor.subscribe(async (runState) => {
1996
- try {
1997
- if (runState.value === "Stopped") {
1998
- const { checkpoint, skillManagers: skillManagers2 } = runState.context;
1999
- if (!checkpoint) {
2000
- throw new Error("Checkpoint is undefined");
2001
- }
2002
- await closeSkillManagers(skillManagers2);
2003
- resolve(checkpoint);
2004
- } else {
2005
- const event = await StateMachineLogics[runState.value](runState.context);
2006
- if ("checkpoint" in event) {
2007
- await storeCheckpoint(event.checkpoint);
2008
- }
2009
- await eventEmitter.emit(event);
2010
- if (shouldContinueRun) {
2011
- const shouldContinue = await shouldContinueRun(
2012
- runState.context.setting,
2013
- runState.context.checkpoint,
2014
- runState.context.step
2015
- );
2016
- if (!shouldContinue) {
2017
- runActor.stop();
2018
- await closeSkillManagers(runState.context.skillManagers);
2019
- resolve(runState.context.checkpoint);
2020
- return;
2021
- }
2022
- }
2023
- runActor.send(event);
2024
- }
2025
- } catch (error) {
2026
- await closeSkillManagers(skillManagers).catch(() => {
2026
+ var DefaultActorFactory = class {
2027
+ create(input) {
2028
+ return createActor(runtimeStateMachine, input);
2029
+ }
2030
+ };
2031
+ var defaultActorFactory = new DefaultActorFactory();
2032
+
2033
+ // src/state-machine/coordinator.ts
2034
+ var StateMachineCoordinator = class {
2035
+ constructor(params, deps = {}) {
2036
+ this.params = params;
2037
+ this.actorFactory = deps.actorFactory ?? defaultActorFactory;
2038
+ this.closeManagers = deps.closeSkillManagers ?? closeSkillManagers;
2039
+ this.logics = deps.logics ?? StateMachineLogics;
2040
+ }
2041
+ actorFactory;
2042
+ closeManagers;
2043
+ logics;
2044
+ actor = null;
2045
+ resolvePromise = null;
2046
+ rejectPromise = null;
2047
+ /**
2048
+ * Execute the state machine and return the final checkpoint.
2049
+ */
2050
+ async execute() {
2051
+ const { setting, initialCheckpoint, eventListener, skillManagers } = this.params;
2052
+ this.actor = this.actorFactory.create({
2053
+ input: {
2054
+ setting,
2055
+ initialCheckpoint,
2056
+ eventListener,
2057
+ skillManagers
2058
+ }
2059
+ });
2060
+ return new Promise((resolve, reject) => {
2061
+ this.resolvePromise = resolve;
2062
+ this.rejectPromise = reject;
2063
+ this.actor.subscribe((runState) => {
2064
+ this.handleStateChange(runState).catch((error) => {
2065
+ this.handleError(error);
2027
2066
  });
2028
- reject(error);
2067
+ });
2068
+ this.actor.start();
2069
+ });
2070
+ }
2071
+ /**
2072
+ * Handle state changes from the actor.
2073
+ * Exported for testing purposes.
2074
+ */
2075
+ async handleStateChange(runState) {
2076
+ if (runState.value === "Stopped") {
2077
+ await this.handleStoppedState(runState);
2078
+ } else {
2079
+ await this.handleActiveState(runState);
2080
+ }
2081
+ }
2082
+ /**
2083
+ * Handle the stopped state - cleanup and resolve.
2084
+ */
2085
+ async handleStoppedState(runState) {
2086
+ const { checkpoint, skillManagers } = runState.context;
2087
+ if (!checkpoint) {
2088
+ throw new Error("Checkpoint is undefined");
2089
+ }
2090
+ await this.closeManagers(skillManagers);
2091
+ this.resolvePromise?.(checkpoint);
2092
+ }
2093
+ /**
2094
+ * Handle active states - execute logic, store checkpoint, emit events.
2095
+ */
2096
+ async handleActiveState(runState) {
2097
+ const { eventEmitter, storeCheckpoint, shouldContinueRun } = this.params;
2098
+ const stateValue = runState.value;
2099
+ const event = await this.logics[stateValue](runState.context);
2100
+ if ("checkpoint" in event) {
2101
+ await storeCheckpoint(event.checkpoint);
2102
+ }
2103
+ await eventEmitter.emit(event);
2104
+ if (shouldContinueRun) {
2105
+ const shouldContinue = await shouldContinueRun(
2106
+ runState.context.setting,
2107
+ runState.context.checkpoint,
2108
+ runState.context.step
2109
+ );
2110
+ if (!shouldContinue) {
2111
+ this.actor?.stop();
2112
+ await this.closeManagers(runState.context.skillManagers);
2113
+ this.resolvePromise?.(runState.context.checkpoint);
2114
+ return;
2029
2115
  }
2116
+ }
2117
+ this.actor?.send(event);
2118
+ }
2119
+ /**
2120
+ * Handle errors - cleanup and reject.
2121
+ */
2122
+ async handleError(error) {
2123
+ await this.closeManagers(this.params.skillManagers).catch(() => {
2030
2124
  });
2031
- runActor.start();
2032
- });
2125
+ this.rejectPromise?.(error instanceof Error ? error : new Error(String(error)));
2126
+ }
2127
+ };
2128
+
2129
+ // src/state-machine/executor.ts
2130
+ async function executeStateMachine(params) {
2131
+ const coordinator = new StateMachineCoordinator(params);
2132
+ return coordinator.execute();
2033
2133
  }
2034
2134
 
2035
2135
  // src/helpers/checkpoint.ts
@@ -2534,5 +2634,5 @@ async function run(runInput, options) {
2534
2634
  }
2535
2635
 
2536
2636
  export { getModel, package_default, run, runtimeStateMachine };
2537
- //# sourceMappingURL=chunk-7QLRRSNX.js.map
2538
- //# sourceMappingURL=chunk-7QLRRSNX.js.map
2637
+ //# sourceMappingURL=chunk-H65LPOAK.js.map
2638
+ //# sourceMappingURL=chunk-H65LPOAK.js.map