@perstack/runtime 0.0.37 → 0.0.39

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/dist/src/index.js CHANGED
@@ -1,24 +1,25 @@
1
- import { setup, assign, createActor } from 'xstate';
2
1
  import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
3
2
  import { createAnthropic } from '@ai-sdk/anthropic';
4
3
  import { createAzure } from '@ai-sdk/azure';
5
4
  import { createGoogleGenerativeAI } from '@ai-sdk/google';
6
5
  import { createOpenAI } from '@ai-sdk/openai';
7
- import { knownModels, stopRunByDelegate, stopRunByInteractiveTool, resolveThought, attemptCompletion, resolvePdfFile, resolveImageFile, resolveToolResult, stopRunByExceededMaxSteps, continueToNextStep, retry, completeRun, callDelegate, callInteractiveTool, callTool, startRun, startGeneration, finishToolCall, runParamsSchema, checkpointSchema } from '@perstack/core';
6
+ import { knownModels, stopRunByDelegate, stopRunByInteractiveTool, resolveThought, attemptCompletion, resolvePdfFile, resolveImageFile, resolveToolResult, stopRunByExceededMaxSteps, continueToNextStep, retry, completeRun, callDelegate, callInteractiveTool, callTool, startRun, startGeneration, finishToolCall, runParamsSchema, createRuntimeEvent, checkpointSchema } from '@perstack/core';
8
7
  import { createOllama } from 'ollama-ai-provider-v2';
8
+ import { existsSync } from 'fs';
9
+ import { readFile, writeFile, mkdir, readdir } from 'fs/promises';
10
+ import path from 'path';
11
+ import { createId } from '@paralleldrive/cuid2';
12
+ import { setup, assign, createActor } from 'xstate';
13
+ import { ApiV1Client } from '@perstack/api-client/v1';
9
14
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
10
15
  import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
11
16
  import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
12
17
  import { McpError } from '@modelcontextprotocol/sdk/types.js';
13
- import { createId } from '@paralleldrive/cuid2';
14
18
  import { generateText, tool, jsonSchema } from 'ai';
15
19
  import { dedent } from 'ts-dedent';
16
- import { readFile, writeFile, mkdir, readdir } from 'fs/promises';
17
- import { existsSync } from 'fs';
18
- import path from 'path';
19
- import { ApiV1Client } from '@perstack/api-client/v1';
20
+ import { createRequire } from 'module';
20
21
 
21
- // src/runtime-state-machine.ts
22
+ // src/model.ts
22
23
  function getModel(modelId, providerConfig) {
23
24
  switch (providerConfig.name) {
24
25
  case "anthropic": {
@@ -76,39 +77,142 @@ function getContextWindow(providerName, modelId) {
76
77
  function calculateContextWindowUsage(usage, contextWindow) {
77
78
  return (usage.inputTokens + usage.cachedInputTokens + usage.outputTokens) / contextWindow;
78
79
  }
80
+ async function defaultRetrieveCheckpoint(runId, checkpointId) {
81
+ const runDir = getRunDir(runId);
82
+ const checkpointFiles = await readdir(runDir, { withFileTypes: true }).then(
83
+ (files) => files.filter((file) => file.isFile() && file.name.startsWith("checkpoint-"))
84
+ );
85
+ const checkpointFile = checkpointFiles.find((file) => file.name.endsWith(`-${checkpointId}.json`));
86
+ if (!checkpointFile) {
87
+ throw new Error(`checkpoint not found: ${runId} ${checkpointId}`);
88
+ }
89
+ const checkpointPath = `${runDir}/${checkpointFile.name}`;
90
+ const checkpoint = await readFile(checkpointPath, "utf8");
91
+ return checkpointSchema.parse(JSON.parse(checkpoint));
92
+ }
93
+ async function defaultStoreCheckpoint(checkpoint, timestamp) {
94
+ const { id, runId, stepNumber } = checkpoint;
95
+ const runDir = getRunDir(runId);
96
+ const checkpointPath = `${runDir}/checkpoint-${timestamp}-${stepNumber}-${id}.json`;
97
+ await mkdir(runDir, { recursive: true });
98
+ await writeFile(checkpointPath, JSON.stringify(checkpoint));
99
+ }
100
+ async function defaultStoreEvent(event) {
101
+ const { timestamp, runId, stepNumber, type } = event;
102
+ const runDir = getRunDir(runId);
103
+ const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
104
+ await mkdir(runDir, { recursive: true });
105
+ await writeFile(eventPath, JSON.stringify(event));
106
+ }
107
+ var RunEventEmitter = class {
108
+ listeners = [];
109
+ subscribe(listener) {
110
+ this.listeners.push(listener);
111
+ }
112
+ async emit(event) {
113
+ for (const listener of this.listeners) {
114
+ await listener({
115
+ ...event,
116
+ id: createId(),
117
+ timestamp: Date.now()
118
+ });
119
+ }
120
+ }
121
+ };
122
+ async function resolveExpertToRun(expertKey, experts, clientOptions) {
123
+ if (experts[expertKey]) {
124
+ return experts[expertKey];
125
+ }
126
+ const client = new ApiV1Client({
127
+ baseUrl: clientOptions.perstackApiBaseUrl,
128
+ apiKey: clientOptions.perstackApiKey
129
+ });
130
+ const { expert } = await client.registry.experts.get({ expertKey });
131
+ experts[expertKey] = toRuntimeExpert(expert);
132
+ return experts[expertKey];
133
+ }
134
+ function toRuntimeExpert(expert) {
135
+ const skills = Object.fromEntries(
136
+ Object.entries(expert.skills).map(([name, skill]) => {
137
+ switch (skill.type) {
138
+ case "mcpStdioSkill":
139
+ return [name, { ...skill, name }];
140
+ case "mcpSseSkill":
141
+ return [name, { ...skill, name }];
142
+ case "interactiveSkill":
143
+ return [name, { ...skill, name }];
144
+ default: {
145
+ throw new Error(`Unknown skill type: ${skill.type}`);
146
+ }
147
+ }
148
+ })
149
+ );
150
+ return { ...expert, skills };
151
+ }
79
152
  var SkillManager = class {
80
153
  _toolDefinitions = [];
81
154
  _initialized = false;
155
+ _initializing;
82
156
  name;
83
157
  type;
158
+ lazyInit;
84
159
  skill;
85
160
  interactiveSkill;
86
161
  expert;
87
162
  _mcpClient;
88
163
  _params;
89
164
  _env;
90
- constructor(params) {
165
+ _runId;
166
+ _eventListener;
167
+ constructor(params, runId, eventListener) {
91
168
  this._params = params;
169
+ this._runId = runId;
170
+ this._eventListener = eventListener;
92
171
  this.type = params.type;
93
172
  switch (params.type) {
94
173
  case "mcp":
95
174
  this.name = params.skill.name;
96
175
  this.skill = params.skill;
97
176
  this._env = params.env;
177
+ this.lazyInit = this.skill.type === "mcpStdioSkill" && this.skill.lazyInit && this.skill.name !== "@perstack/base";
98
178
  break;
99
179
  case "interactive":
100
180
  this.name = params.interactiveSkill.name;
101
181
  this.interactiveSkill = params.interactiveSkill;
102
182
  this._env = {};
183
+ this.lazyInit = false;
103
184
  break;
104
185
  case "delegate":
105
186
  this.name = params.expert.name;
106
187
  this.expert = params.expert;
107
188
  this._env = {};
189
+ this.lazyInit = false;
108
190
  break;
109
191
  }
110
192
  }
111
193
  async init() {
194
+ if (this._initialized) {
195
+ throw new Error(`Skill ${this.name} is already initialized`);
196
+ }
197
+ if (this._initializing) {
198
+ throw new Error(`Skill ${this.name} is already initializing`);
199
+ }
200
+ const initPromise = this._performInit();
201
+ this._initializing = initPromise;
202
+ if (!this.lazyInit) {
203
+ try {
204
+ await initPromise;
205
+ } catch (error) {
206
+ this._initialized = false;
207
+ this._initializing = void 0;
208
+ throw error;
209
+ }
210
+ }
211
+ }
212
+ isInitialized() {
213
+ return this._initialized;
214
+ }
215
+ async _performInit() {
112
216
  switch (this._params.type) {
113
217
  case "mcp": {
114
218
  await this._initMcpSkill(this._params);
@@ -123,8 +227,13 @@ var SkillManager = class {
123
227
  break;
124
228
  }
125
229
  }
230
+ this._initialized = true;
231
+ this._initializing = void 0;
126
232
  }
127
233
  async _initMcpSkill(params) {
234
+ if (this.isInitialized()) {
235
+ throw new Error(`Skill ${params.skill.name} is already initialized`);
236
+ }
128
237
  this._mcpClient = new Client({
129
238
  name: `${params.skill.name}-mcp-client`,
130
239
  version: "1.0.0"
@@ -143,8 +252,16 @@ var SkillManager = class {
143
252
  env[envName] = this._env[envName];
144
253
  }
145
254
  const { command, args } = this._getCommandArgs(params.skill);
146
- const transport = new StdioClientTransport({ command, args, env });
255
+ const transport = new StdioClientTransport({ command, args, env, stderr: "ignore" });
147
256
  await this._mcpClient.connect(transport);
257
+ if (this._eventListener) {
258
+ const serverInfo = this._mcpClient.getServerVersion();
259
+ const event = createRuntimeEvent("skillConnected", this._runId, {
260
+ skillName: params.skill.name,
261
+ serverInfo: serverInfo ? { name: serverInfo.name, version: serverInfo.version } : void 0
262
+ });
263
+ this._eventListener(event);
264
+ }
148
265
  break;
149
266
  }
150
267
  case "mcpSseSkill": {
@@ -164,7 +281,6 @@ var SkillManager = class {
164
281
  inputSchema: tool2.inputSchema,
165
282
  interactive: false
166
283
  }));
167
- this._initialized = true;
168
284
  }
169
285
  _getCommandArgs(skill) {
170
286
  const { name, command, packageName, args } = skill;
@@ -183,6 +299,9 @@ var SkillManager = class {
183
299
  return { command, args: newArgs };
184
300
  }
185
301
  async _initInteractiveSkill(params) {
302
+ if (this.isInitialized()) {
303
+ throw new Error(`Skill ${params.interactiveSkill.name} is already initialized`);
304
+ }
186
305
  this._toolDefinitions = Object.values(params.interactiveSkill.tools).map((tool2) => ({
187
306
  skillName: params.interactiveSkill.name,
188
307
  name: tool2.name,
@@ -190,9 +309,11 @@ var SkillManager = class {
190
309
  inputSchema: JSON.parse(tool2.inputJsonSchema),
191
310
  interactive: true
192
311
  }));
193
- this._initialized = true;
194
312
  }
195
313
  async _initDelegate(params) {
314
+ if (this.isInitialized()) {
315
+ throw new Error(`Skill ${params.expert.name} is already initialized`);
316
+ }
196
317
  this._toolDefinitions = [
197
318
  {
198
319
  skillName: params.expert.name,
@@ -206,16 +327,24 @@ var SkillManager = class {
206
327
  interactive: false
207
328
  }
208
329
  ];
209
- this._initialized = true;
210
330
  }
211
331
  async close() {
212
332
  if (this._mcpClient) {
213
333
  await this._mcpClient.close();
334
+ if (this._eventListener && this.skill) {
335
+ const event = createRuntimeEvent("skillDisconnected", this._runId, {
336
+ skillName: this.skill.name
337
+ });
338
+ this._eventListener(event);
339
+ }
214
340
  }
215
341
  }
216
342
  async getToolDefinitions() {
217
- if (!this._initialized) {
218
- throw new Error(`${this.name} is not initialized`);
343
+ if (!this.isInitialized() && !this.lazyInit) {
344
+ throw new Error(`Skill ${this.name} is not initialized`);
345
+ }
346
+ if (!this.isInitialized() && this.lazyInit) {
347
+ return [];
219
348
  }
220
349
  if (this._params.type === "mcp") {
221
350
  const omit = this._params.skill.omit ?? [];
@@ -227,7 +356,7 @@ var SkillManager = class {
227
356
  async callTool(toolName, input) {
228
357
  switch (this._params.type) {
229
358
  case "mcp": {
230
- if (!this._mcpClient) {
359
+ if (!this.isInitialized() || !this._mcpClient) {
231
360
  throw new Error(`${this.name} is not initialized`);
232
361
  }
233
362
  try {
@@ -314,8 +443,8 @@ var SkillManager = class {
314
443
  throw new Error(`Unsupported resource type: ${JSON.stringify(resource)}`);
315
444
  }
316
445
  };
317
- async function getSkillManagers(expert, experts, setting) {
318
- const { perstackBaseSkillCommand, env } = setting;
446
+ async function getSkillManagers(expert, experts, setting, eventListener) {
447
+ const { perstackBaseSkillCommand, env, runId } = setting;
319
448
  const skillManagers = {};
320
449
  const { skills } = expert;
321
450
  if (!skills["@perstack/base"]) {
@@ -334,23 +463,32 @@ async function getSkillManagers(expert, experts, setting) {
334
463
  skill.command = overrideCommand;
335
464
  skill.packageName = void 0;
336
465
  skill.args = overrideArgs;
466
+ skill.lazyInit = false;
337
467
  }
338
468
  }
339
- const skillManager = new SkillManager({
340
- type: "mcp",
341
- skill,
342
- env
343
- });
469
+ const skillManager = new SkillManager(
470
+ {
471
+ type: "mcp",
472
+ skill,
473
+ env
474
+ },
475
+ runId,
476
+ eventListener
477
+ );
344
478
  await skillManager.init();
345
479
  return skillManager;
346
480
  })
347
481
  );
348
482
  const interactiveSkillManagers = await Promise.all(
349
483
  Object.values(skills).filter((skill) => skill.type === "interactiveSkill").map(async (interactiveSkill) => {
350
- const skillManager = new SkillManager({
351
- type: "interactive",
352
- interactiveSkill
353
- });
484
+ const skillManager = new SkillManager(
485
+ {
486
+ type: "interactive",
487
+ interactiveSkill
488
+ },
489
+ runId,
490
+ eventListener
491
+ );
354
492
  await skillManager.init();
355
493
  return skillManager;
356
494
  })
@@ -358,10 +496,14 @@ async function getSkillManagers(expert, experts, setting) {
358
496
  const delegateSkillManagers = await Promise.all(
359
497
  expert.delegates.map(async (delegateExpertName) => {
360
498
  const delegate = experts[delegateExpertName];
361
- const skillManager = new SkillManager({
362
- type: "delegate",
363
- expert: delegate
364
- });
499
+ const skillManager = new SkillManager(
500
+ {
501
+ type: "delegate",
502
+ expert: delegate
503
+ },
504
+ runId,
505
+ eventListener
506
+ );
365
507
  await skillManager.init();
366
508
  return skillManager;
367
509
  })
@@ -1579,266 +1721,20 @@ var StateMachineLogics = {
1579
1721
  CallingDelegate: callingDelegateLogic,
1580
1722
  FinishingStep: finishingStepLogic
1581
1723
  };
1582
- async function defaultRetrieveCheckpoint(runId, checkpointId) {
1583
- const runDir = getRunDir(runId);
1584
- const checkpointFiles = await readdir(runDir, { withFileTypes: true }).then(
1585
- (files) => files.filter((file) => file.isFile() && file.name.startsWith("checkpoint-"))
1586
- );
1587
- const checkpointFile = checkpointFiles.find((file) => file.name.endsWith(`-${checkpointId}.json`));
1588
- if (!checkpointFile) {
1589
- throw new Error(`checkpoint not found: ${runId} ${checkpointId}`);
1724
+ var getVersion = () => {
1725
+ if (typeof __RUNTIME_VERSION__ !== "undefined") {
1726
+ return __RUNTIME_VERSION__;
1590
1727
  }
1591
- const checkpointPath = `${runDir}/${checkpointFile.name}`;
1592
- const checkpoint = await readFile(checkpointPath, "utf8");
1593
- return checkpointSchema.parse(JSON.parse(checkpoint));
1594
- }
1595
- async function defaultStoreCheckpoint(checkpoint, timestamp) {
1596
- const { id, runId, stepNumber } = checkpoint;
1597
- const runDir = getRunDir(runId);
1598
- const checkpointPath = `${runDir}/checkpoint-${timestamp}-${stepNumber}-${id}.json`;
1599
- await mkdir(runDir, { recursive: true });
1600
- await writeFile(checkpointPath, JSON.stringify(checkpoint, null, 2));
1601
- }
1602
- async function defaultStoreEvent(event) {
1603
- const { timestamp, runId, stepNumber, type } = event;
1604
- const runDir = getRunDir(runId);
1605
- const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
1606
- await mkdir(runDir, { recursive: true });
1607
- await writeFile(eventPath, JSON.stringify(event, null, 2));
1608
- }
1609
-
1610
- // package.json
1611
- var package_default = {
1612
- version: "0.0.37"};
1613
-
1614
- // src/events/default-event-listener.ts
1615
- var log = console.info;
1616
- var debug = console.debug;
1617
- var header = (e) => {
1618
- const t = (/* @__PURE__ */ new Date()).toISOString();
1619
- const stepNumber = e.stepNumber;
1620
- const key = e.expertKey;
1621
- return `${t} ${stepNumber} ${key}`;
1728
+ const require2 = createRequire(import.meta.url);
1729
+ const pkg = require2("../package.json");
1730
+ return pkg.version;
1622
1731
  };
1623
- async function defaultEventListener(e) {
1624
- await defaultStoreEvent(e);
1625
- switch (e.type) {
1626
- case "startRun": {
1627
- log(`${header(e)} Perstack@${package_default.version} started`);
1628
- break;
1629
- }
1630
- case "startGeneration": {
1631
- log(`${header(e)} Generating tool call`);
1632
- break;
1633
- }
1634
- case "retry": {
1635
- log(`${header(e)} Retrying tool call generation`);
1636
- debug(e.reason);
1637
- break;
1638
- }
1639
- case "callTool": {
1640
- log(`${header(e)} Calling tool`);
1641
- if (e.toolCall.skillName === "@perstack/base") {
1642
- switch (e.toolCall.toolName) {
1643
- case "think": {
1644
- const thought = e.toolCall.args.thought;
1645
- log(`${header(e)} Thought Updated:`);
1646
- debug(thought);
1647
- break;
1648
- }
1649
- case "readPdfFile": {
1650
- const path2 = e.toolCall.args.path;
1651
- log(`${header(e)} Reading PDF: ${path2}`);
1652
- break;
1653
- }
1654
- case "readImageFile": {
1655
- const path2 = e.toolCall.args.path;
1656
- log(`${header(e)} Reading Image: ${path2}`);
1657
- break;
1658
- }
1659
- default: {
1660
- log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
1661
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1662
- break;
1663
- }
1664
- }
1665
- } else {
1666
- log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
1667
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1668
- }
1669
- break;
1670
- }
1671
- case "callInteractiveTool": {
1672
- log(`${header(e)} Calling interactive tool`);
1673
- log(`${header(e)} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
1674
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1675
- break;
1676
- }
1677
- case "callDelegate": {
1678
- log(`${header(e)} Calling delegate`);
1679
- log(`${header(e)} Tool: ${e.toolCall.toolName}`);
1680
- debug(`${header(e)} Args: ${JSON.stringify(e.toolCall.args, null, 2)}`);
1681
- break;
1682
- }
1683
- case "resolveToolResult": {
1684
- log(`${header(e)} Resolved Tool Result`);
1685
- if (e.toolResult.skillName === "@perstack/base") {
1686
- switch (e.toolResult.toolName) {
1687
- case "todo": {
1688
- const text = e.toolResult.result.find((r) => r.type === "textPart")?.text;
1689
- const { todos } = JSON.parse(text ?? "{}");
1690
- log(`${header(e)} Todo:`);
1691
- for (const todo of todos) {
1692
- debug(`${todo.completed ? "[x]" : "[ ]"} ${todo.id}: ${todo.title}`);
1693
- }
1694
- break;
1695
- }
1696
- default: {
1697
- log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
1698
- debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
1699
- break;
1700
- }
1701
- }
1702
- } else {
1703
- log(`${header(e)} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
1704
- debug(`${header(e)} Result: ${JSON.stringify(e.toolResult.result, null, 2)}`);
1705
- }
1706
- break;
1707
- }
1708
- case "resolveThought": {
1709
- log(`${header(e)} Resolved Thought:`, e.toolResult);
1710
- break;
1711
- }
1712
- case "resolvePdfFile": {
1713
- log(`${header(e)} Resolved PDF:`, e.toolResult);
1714
- break;
1715
- }
1716
- case "resolveImageFile": {
1717
- log(`${header(e)} Resolved Image:`, e.toolResult);
1718
- break;
1719
- }
1720
- case "attemptCompletion": {
1721
- log(`${header(e)} Attempting completion`);
1722
- break;
1723
- }
1724
- case "completeRun": {
1725
- logUsage(e);
1726
- log(`${header(e)} Completing run`);
1727
- debug(`${header(e)} Result:`, e.text);
1728
- break;
1729
- }
1730
- case "stopRunByInteractiveTool": {
1731
- logUsage(e);
1732
- log(`${header(e)} Stopping run by interactive tool`);
1733
- break;
1734
- }
1735
- case "stopRunByDelegate": {
1736
- logUsage(e);
1737
- log(`${header(e)} Stopping run by delegate`);
1738
- break;
1739
- }
1740
- case "stopRunByExceededMaxSteps": {
1741
- logUsage(e);
1742
- log(`${header(e)} Stopping run by exceeded max steps`);
1743
- break;
1744
- }
1745
- case "continueToNextStep": {
1746
- logUsage(e);
1747
- log(`${header(e)} Continuing to next step`);
1748
- if (e.checkpoint.contextWindowUsage) {
1749
- log(`${header(e)} Context window usage: ${e.checkpoint.contextWindowUsage.toFixed(2)}%`);
1750
- }
1751
- break;
1752
- }
1753
- }
1754
- }
1755
- function logUsage(e) {
1756
- const usageByStep = [
1757
- `In: ${e.step.usage.inputTokens.toLocaleString()}`,
1758
- `Reasoning: ${e.step.usage.reasoningTokens.toLocaleString()}`,
1759
- `Out: ${e.step.usage.outputTokens.toLocaleString()}`,
1760
- `Total: ${e.step.usage.totalTokens.toLocaleString()}`,
1761
- `Cache-read: ${e.step.usage.cachedInputTokens.toLocaleString()}`
1762
- ].join(", ");
1763
- const usageByRun = [
1764
- `In: ${e.checkpoint.usage.inputTokens.toLocaleString()}`,
1765
- `Reasoning: ${e.checkpoint.usage.reasoningTokens.toLocaleString()}`,
1766
- `Out: ${e.checkpoint.usage.outputTokens.toLocaleString()}`,
1767
- `Total: ${e.checkpoint.usage.totalTokens.toLocaleString()}`,
1768
- `Cache-read: ${e.checkpoint.usage.cachedInputTokens.toLocaleString()}`
1769
- ].join(", ");
1770
- log(`${header(e)} Tokens usage by step: ${usageByStep}`);
1771
- log(`${header(e)} Tokens usage by run: ${usageByRun}`);
1772
- }
1773
- var RunEventEmitter = class {
1774
- listeners = [];
1775
- subscribe(listener) {
1776
- this.listeners.push(listener);
1777
- }
1778
- async emit(event) {
1779
- for (const listener of this.listeners) {
1780
- await listener({
1781
- ...event,
1782
- id: createId(),
1783
- timestamp: Date.now()
1784
- });
1785
- }
1786
- }
1787
- };
1788
- async function resolveExpertToRun(expertKey, experts, clientOptions) {
1789
- console.log(experts);
1790
- if (experts[expertKey]) {
1791
- return experts[expertKey];
1792
- }
1793
- const client = new ApiV1Client({
1794
- baseUrl: clientOptions.perstackApiBaseUrl,
1795
- apiKey: clientOptions.perstackApiKey
1796
- });
1797
- const { expert } = await client.registry.experts.get({ expertKey });
1798
- experts[expertKey] = toRuntimeExpert(expert);
1799
- return experts[expertKey];
1800
- }
1801
- function toRuntimeExpert(expert) {
1802
- const skills = Object.fromEntries(
1803
- Object.entries(expert.skills).map(([name, skill]) => {
1804
- switch (skill.type) {
1805
- case "mcpStdioSkill":
1806
- return [
1807
- name,
1808
- {
1809
- ...skill,
1810
- name
1811
- }
1812
- ];
1813
- case "mcpSseSkill":
1814
- return [
1815
- name,
1816
- {
1817
- ...skill,
1818
- name
1819
- }
1820
- ];
1821
- case "interactiveSkill":
1822
- return [
1823
- name,
1824
- {
1825
- ...skill,
1826
- name
1827
- }
1828
- ];
1829
- }
1830
- })
1831
- );
1832
- return {
1833
- ...expert,
1834
- skills
1835
- };
1836
- }
1732
+ var RUNTIME_VERSION = getVersion();
1837
1733
 
1838
1734
  // src/runtime.ts
1839
1735
  async function run(runInput, options) {
1840
1736
  const runParams = runParamsSchema.parse(runInput);
1841
- const eventListener = options?.eventListener ?? defaultEventListener;
1737
+ const eventListener = getEventListener(options);
1842
1738
  const retrieveCheckpoint = options?.retrieveCheckpoint ?? defaultRetrieveCheckpoint;
1843
1739
  const storeCheckpoint = options?.storeCheckpoint ?? defaultStoreCheckpoint;
1844
1740
  const eventEmitter = new RunEventEmitter();
@@ -1854,8 +1750,27 @@ async function run(runInput, options) {
1854
1750
  await storeRunSetting(setting);
1855
1751
  while (true) {
1856
1752
  const { expertToRun, experts } = await setupExperts(setting);
1857
- printRunSetting(expertToRun.name, experts, setting);
1858
- const skillManagers = await getSkillManagers(expertToRun, experts, setting);
1753
+ if (options?.eventListener) {
1754
+ const initEvent = createRuntimeEvent("initializeRuntime", setting.runId, {
1755
+ runtimeVersion: RUNTIME_VERSION,
1756
+ expertName: expertToRun.name,
1757
+ experts: Object.keys(experts),
1758
+ model: setting.model,
1759
+ temperature: setting.temperature,
1760
+ maxSteps: setting.maxSteps,
1761
+ maxRetries: setting.maxRetries,
1762
+ timeout: setting.timeout,
1763
+ query: setting.input.text,
1764
+ interactiveToolCall: setting.input.interactiveToolCallResult
1765
+ });
1766
+ options.eventListener(initEvent);
1767
+ }
1768
+ const skillManagers = await getSkillManagers(
1769
+ expertToRun,
1770
+ experts,
1771
+ setting,
1772
+ options?.eventListener
1773
+ );
1859
1774
  const runActor = createActor(runtimeStateMachine, {
1860
1775
  input: {
1861
1776
  setting: {
@@ -2021,23 +1936,14 @@ async function setupExperts(setting) {
2021
1936
  }
2022
1937
  return { expertToRun, experts };
2023
1938
  }
2024
- function printRunSetting(expertName, experts, setting) {
2025
- console.log("Starting Perstack");
2026
- console.log(`Expert To Run: ${expertName}`);
2027
- console.log(`Experts: ${Object.keys(experts).join(", ")}`);
2028
- console.log(`Model: ${setting.model}`);
2029
- console.log(`Temperature: ${setting.temperature}`);
2030
- console.log(`Max Steps: ${setting.maxSteps}`);
2031
- console.log(`Max Retries: ${setting.maxRetries}`);
2032
- console.log(`Timeout: ${setting.timeout}`);
2033
- if (setting.input.text) {
2034
- console.log(`Query: ${setting.input.text}`);
2035
- }
2036
- if (setting.input.interactiveToolCallResult) {
2037
- console.log(`Tool: ${setting.input.interactiveToolCallResult.toolName}`);
2038
- console.log(`Tool Call ID: ${setting.input.interactiveToolCallResult.toolCallId}`);
2039
- console.log(`Tool Result: ${setting.input.interactiveToolCallResult.text}`);
2040
- }
1939
+ function getEventListener(options) {
1940
+ const listener = options?.eventListener ?? ((e) => console.log(JSON.stringify(e)));
1941
+ return async (event) => {
1942
+ if ("stepNumber" in event) {
1943
+ await defaultStoreEvent(event);
1944
+ }
1945
+ listener(event);
1946
+ };
2041
1947
  }
2042
1948
  async function storeRunSetting(setting) {
2043
1949
  const runDir = getRunDir(setting.runId);
@@ -2045,20 +1951,16 @@ async function storeRunSetting(setting) {
2045
1951
  const runSettingPath = path.resolve(runDir, "run-setting.json");
2046
1952
  const runSetting = JSON.parse(await readFile(runSettingPath, "utf-8"));
2047
1953
  runSetting.updatedAt = Date.now();
2048
- await writeFile(runSettingPath, JSON.stringify(runSetting, null, 2), "utf-8");
1954
+ await writeFile(runSettingPath, JSON.stringify(runSetting), "utf-8");
2049
1955
  } else {
2050
1956
  await mkdir(runDir, { recursive: true });
2051
- await writeFile(
2052
- path.resolve(runDir, "run-setting.json"),
2053
- JSON.stringify(setting, null, 2),
2054
- "utf-8"
2055
- );
1957
+ await writeFile(path.resolve(runDir, "run-setting.json"), JSON.stringify(setting), "utf-8");
2056
1958
  }
2057
1959
  }
2058
1960
  function getRunDir(runId) {
2059
1961
  return `${process.cwd()}/perstack/runs/${runId}`;
2060
1962
  }
2061
1963
 
2062
- export { StateMachineLogics, calculateContextWindowUsage, defaultEventListener, getContextWindow, getModel, getRunDir, run, runtimeStateMachine };
1964
+ export { RUNTIME_VERSION, StateMachineLogics, calculateContextWindowUsage, getContextWindow, getModel, getRunDir, run, runtimeStateMachine };
2063
1965
  //# sourceMappingURL=index.js.map
2064
1966
  //# sourceMappingURL=index.js.map