@perstack/core 0.0.53 → 0.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/src/adapters/event-creators.d.ts +26 -0
  2. package/dist/src/adapters/event-creators.d.ts.map +1 -0
  3. package/dist/src/adapters/event-creators.js +126 -0
  4. package/dist/src/adapters/event-creators.js.map +1 -0
  5. package/dist/src/adapters/index.d.ts +2 -0
  6. package/dist/src/adapters/index.d.ts.map +1 -0
  7. package/dist/src/adapters/index.js +2 -0
  8. package/dist/src/adapters/index.js.map +1 -0
  9. package/dist/src/constants/constants.d.ts +11 -0
  10. package/dist/src/constants/constants.d.ts.map +1 -0
  11. package/dist/src/constants/constants.js +13 -0
  12. package/dist/src/constants/constants.js.map +1 -0
  13. package/dist/src/errors.d.ts +4 -0
  14. package/dist/src/errors.d.ts.map +1 -0
  15. package/dist/src/errors.js +7 -0
  16. package/dist/src/errors.js.map +1 -0
  17. package/dist/src/index.d.ts +28 -6357
  18. package/dist/src/index.d.ts.map +1 -0
  19. package/dist/src/index.js +28 -1972
  20. package/dist/src/index.js.map +1 -1
  21. package/dist/src/known-models/index.d.ts +9 -0
  22. package/dist/src/known-models/index.d.ts.map +1 -0
  23. package/dist/src/known-models/index.js +216 -0
  24. package/dist/src/known-models/index.js.map +1 -0
  25. package/dist/src/schemas/activity.d.ts +2159 -0
  26. package/dist/src/schemas/activity.d.ts.map +1 -0
  27. package/dist/src/schemas/activity.js +209 -0
  28. package/dist/src/schemas/activity.js.map +1 -0
  29. package/dist/src/schemas/checkpoint.d.ts +338 -0
  30. package/dist/src/schemas/checkpoint.d.ts.map +1 -0
  31. package/dist/src/schemas/checkpoint.js +69 -0
  32. package/dist/src/schemas/checkpoint.js.map +1 -0
  33. package/dist/src/schemas/expert.d.ts +309 -0
  34. package/dist/src/schemas/expert.d.ts.map +1 -0
  35. package/dist/src/schemas/expert.js +70 -0
  36. package/dist/src/schemas/expert.js.map +1 -0
  37. package/dist/src/schemas/job.d.ts +44 -0
  38. package/dist/src/schemas/job.d.ts.map +1 -0
  39. package/dist/src/schemas/job.js +22 -0
  40. package/dist/src/schemas/job.js.map +1 -0
  41. package/dist/src/schemas/lockfile.d.ts +143 -0
  42. package/dist/src/schemas/lockfile.d.ts.map +1 -0
  43. package/dist/src/schemas/lockfile.js +26 -0
  44. package/dist/src/schemas/lockfile.js.map +1 -0
  45. package/dist/src/schemas/message-part.d.ts +239 -0
  46. package/dist/src/schemas/message-part.d.ts.map +1 -0
  47. package/dist/src/schemas/message-part.js +80 -0
  48. package/dist/src/schemas/message-part.js.map +1 -0
  49. package/dist/src/schemas/message.d.ts +236 -0
  50. package/dist/src/schemas/message.d.ts.map +1 -0
  51. package/dist/src/schemas/message.js +44 -0
  52. package/dist/src/schemas/message.js.map +1 -0
  53. package/dist/src/schemas/perstack-toml.d.ts +366 -0
  54. package/dist/src/schemas/perstack-toml.d.ts.map +1 -0
  55. package/dist/src/schemas/perstack-toml.js +175 -0
  56. package/dist/src/schemas/perstack-toml.js.map +1 -0
  57. package/dist/src/schemas/provider-config.d.ts +216 -0
  58. package/dist/src/schemas/provider-config.d.ts.map +1 -0
  59. package/dist/src/schemas/provider-config.js +86 -0
  60. package/dist/src/schemas/provider-config.js.map +1 -0
  61. package/dist/src/schemas/provider-tools.d.ts +93 -0
  62. package/dist/src/schemas/provider-tools.d.ts.map +1 -0
  63. package/dist/src/schemas/provider-tools.js +60 -0
  64. package/dist/src/schemas/provider-tools.js.map +1 -0
  65. package/dist/src/schemas/run-command.d.ts +127 -0
  66. package/dist/src/schemas/run-command.d.ts.map +1 -0
  67. package/dist/src/schemas/run-command.js +82 -0
  68. package/dist/src/schemas/run-command.js.map +1 -0
  69. package/dist/src/schemas/runtime-version.d.ts +4 -0
  70. package/dist/src/schemas/runtime-version.d.ts.map +1 -0
  71. package/dist/src/schemas/runtime-version.js +6 -0
  72. package/dist/src/schemas/runtime-version.js.map +1 -0
  73. package/dist/src/schemas/runtime.d.ts +1317 -0
  74. package/dist/src/schemas/runtime.d.ts.map +1 -0
  75. package/dist/src/schemas/runtime.js +205 -0
  76. package/dist/src/schemas/runtime.js.map +1 -0
  77. package/dist/src/schemas/skill-manager.d.ts +64 -0
  78. package/dist/src/schemas/skill-manager.d.ts.map +1 -0
  79. package/dist/src/schemas/skill-manager.js +2 -0
  80. package/dist/src/schemas/skill-manager.js.map +1 -0
  81. package/dist/src/schemas/skill.d.ts +147 -0
  82. package/dist/src/schemas/skill.d.ts.map +1 -0
  83. package/dist/src/schemas/skill.js +99 -0
  84. package/dist/src/schemas/skill.js.map +1 -0
  85. package/dist/src/schemas/step.d.ts +370 -0
  86. package/dist/src/schemas/step.d.ts.map +1 -0
  87. package/dist/src/schemas/step.js +21 -0
  88. package/dist/src/schemas/step.js.map +1 -0
  89. package/dist/src/schemas/tool-call.d.ts +19 -0
  90. package/dist/src/schemas/tool-call.d.ts.map +1 -0
  91. package/dist/src/schemas/tool-call.js +10 -0
  92. package/dist/src/schemas/tool-call.js.map +1 -0
  93. package/dist/src/schemas/tool-result.d.ts +86 -0
  94. package/dist/src/schemas/tool-result.d.ts.map +1 -0
  95. package/dist/src/schemas/tool-result.js +11 -0
  96. package/dist/src/schemas/tool-result.js.map +1 -0
  97. package/dist/src/schemas/usage.d.ts +22 -0
  98. package/dist/src/schemas/usage.d.ts.map +1 -0
  99. package/dist/src/schemas/usage.js +10 -0
  100. package/dist/src/schemas/usage.js.map +1 -0
  101. package/dist/src/utils/activity.d.ts +20 -0
  102. package/dist/src/utils/activity.d.ts.map +1 -0
  103. package/dist/src/utils/activity.js +449 -0
  104. package/dist/src/utils/activity.js.map +1 -0
  105. package/dist/src/utils/env-filter.d.ts +4 -0
  106. package/dist/src/utils/env-filter.d.ts.map +1 -0
  107. package/dist/src/utils/env-filter.js +50 -0
  108. package/dist/src/utils/env-filter.js.map +1 -0
  109. package/dist/src/utils/event-filter.d.ts +16 -0
  110. package/dist/src/utils/event-filter.d.ts.map +1 -0
  111. package/dist/src/utils/event-filter.js +31 -0
  112. package/dist/src/utils/event-filter.js.map +1 -0
  113. package/dist/src/utils/expert-type.d.ts +38 -0
  114. package/dist/src/utils/expert-type.d.ts.map +1 -0
  115. package/dist/src/utils/expert-type.js +88 -0
  116. package/dist/src/utils/expert-type.js.map +1 -0
  117. package/dist/src/utils/zod-error.d.ts +4 -0
  118. package/dist/src/utils/zod-error.d.ts.map +1 -0
  119. package/dist/src/utils/zod-error.js +17 -0
  120. package/dist/src/utils/zod-error.js.map +1 -0
  121. package/package.json +18 -16
  122. package/LICENSE +0 -202
package/dist/src/index.js CHANGED
@@ -1,1973 +1,29 @@
1
- import { createId } from "@paralleldrive/cuid2";
2
- import { z } from "zod";
3
-
4
- //#region src/adapters/event-creators.ts
5
- function createEmptyUsage() {
6
- return {
7
- inputTokens: 0,
8
- outputTokens: 0,
9
- reasoningTokens: 0,
10
- totalTokens: 0,
11
- cachedInputTokens: 0
12
- };
13
- }
14
- function createNormalizedCheckpoint(params) {
15
- const { jobId, runId, expert, output } = params;
16
- return {
17
- id: createId(),
18
- jobId,
19
- runId,
20
- status: "completed",
21
- stepNumber: 1,
22
- messages: [{
23
- id: createId(),
24
- type: "expertMessage",
25
- contents: [{
26
- type: "textPart",
27
- id: createId(),
28
- text: output
29
- }]
30
- }],
31
- expert: {
32
- key: expert.key,
33
- name: expert.name,
34
- version: expert.version
35
- },
36
- usage: createEmptyUsage()
37
- };
38
- }
39
- function createStartRunEvent(jobId, runId, expertKey, checkpoint) {
40
- return {
41
- type: "startRun",
42
- id: createId(),
43
- expertKey,
44
- timestamp: Date.now(),
45
- jobId,
46
- runId,
47
- stepNumber: checkpoint.stepNumber,
48
- initialCheckpoint: checkpoint,
49
- inputMessages: []
50
- };
51
- }
52
- function createRuntimeInitEvent(jobId, runId, expertName, version, query) {
53
- return {
54
- type: "initializeRuntime",
55
- id: createId(),
56
- timestamp: Date.now(),
57
- jobId,
58
- runId,
59
- runtimeVersion: version,
60
- expertName,
61
- experts: [],
62
- model: "local:default",
63
- maxRetries: 0,
64
- timeout: 0,
65
- query
66
- };
67
- }
68
- function createCompleteRunEvent(jobId, runId, expertKey, checkpoint, output, startedAt) {
69
- const lastMessage = checkpoint.messages[checkpoint.messages.length - 1];
70
- return {
71
- type: "completeRun",
72
- id: createId(),
73
- expertKey,
74
- timestamp: Date.now(),
75
- jobId,
76
- runId,
77
- stepNumber: checkpoint.stepNumber,
78
- checkpoint,
79
- step: {
80
- stepNumber: checkpoint.stepNumber,
81
- newMessages: lastMessage ? [lastMessage] : [],
82
- usage: createEmptyUsage(),
83
- startedAt: startedAt ?? Date.now()
84
- },
85
- text: output,
86
- usage: createEmptyUsage()
87
- };
88
- }
89
- function createCallToolsEvent(jobId, runId, expertKey, stepNumber, toolCalls, _checkpoint) {
90
- const expertMessage = {
91
- id: createId(),
92
- type: "expertMessage",
93
- contents: []
94
- };
95
- return {
96
- type: "callTools",
97
- id: createId(),
98
- expertKey,
99
- timestamp: Date.now(),
100
- jobId,
101
- runId,
102
- stepNumber,
103
- newMessage: expertMessage,
104
- toolCalls,
105
- usage: createEmptyUsage()
106
- };
107
- }
108
- function createResolveToolResultsEvent(jobId, runId, expertKey, stepNumber, toolResults) {
109
- return {
110
- type: "resolveToolResults",
111
- id: createId(),
112
- expertKey,
113
- timestamp: Date.now(),
114
- jobId,
115
- runId,
116
- stepNumber,
117
- toolResults
118
- };
119
- }
120
- function createToolMessage(toolCallId, toolName, resultText) {
121
- return {
122
- id: createId(),
123
- type: "toolMessage",
124
- contents: [{
125
- type: "toolResultPart",
126
- id: createId(),
127
- toolCallId,
128
- toolName,
129
- contents: [{
130
- type: "textPart",
131
- id: createId(),
132
- text: resultText
133
- }]
134
- }]
135
- };
136
- }
137
-
138
- //#endregion
139
- //#region src/constants/constants.ts
140
- const defaultPerstackApiBaseUrl = "https://api.perstack.ai";
141
- const expertKeyRegex = /^((?:@[a-z0-9][a-z0-9_.-]*\/)?[a-z0-9][a-z0-9_.-]*)(?:@((?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?)|@([a-z0-9][a-z0-9_.-]*))?$/;
142
- const expertNameRegex = /^(@[a-z0-9][a-z0-9_-]*\/)?[a-z0-9][a-z0-9_-]*$/;
143
- const expertVersionRegex = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
144
- const tagNameRegex = /^[a-z0-9][a-z0-9_-]*$/;
145
- const maxExpertNameLength = 255;
146
- const defaultMaxRetries = 5;
147
- const defaultTimeout = 5 * 1e3 * 60;
148
- const maxSkillNameLength = 255;
149
- const maxSkillToolNameLength = 255;
150
-
151
- //#endregion
152
- //#region src/errors.ts
153
- var PerstackError = class extends Error {
154
- constructor(message) {
155
- super(message);
156
- this.name = "PerstackError";
157
- }
158
- };
159
-
160
- //#endregion
161
- //#region src/known-models/index.ts
162
- const knownModels = [
163
- {
164
- provider: "anthropic",
165
- models: [
166
- {
167
- name: "claude-opus-4-6",
168
- contextWindow: 2e5,
169
- maxOutputTokens: 128e3
170
- },
171
- {
172
- name: "claude-opus-4-5",
173
- contextWindow: 2e5,
174
- maxOutputTokens: 32e3
175
- },
176
- {
177
- name: "claude-opus-4-1",
178
- contextWindow: 2e5,
179
- maxOutputTokens: 32e3
180
- },
181
- {
182
- name: "claude-opus-4-20250514",
183
- contextWindow: 2e5,
184
- maxOutputTokens: 32e3
185
- },
186
- {
187
- name: "claude-sonnet-4-5",
188
- contextWindow: 2e5,
189
- maxOutputTokens: 64e3
190
- },
191
- {
192
- name: "claude-sonnet-4-20250514",
193
- contextWindow: 2e5,
194
- maxOutputTokens: 64e3
195
- },
196
- {
197
- name: "claude-3-7-sonnet-20250219",
198
- contextWindow: 2e5,
199
- maxOutputTokens: 64e3
200
- },
201
- {
202
- name: "claude-haiku-4-5",
203
- contextWindow: 2e5,
204
- maxOutputTokens: 8192
205
- },
206
- {
207
- name: "claude-3-5-haiku-latest",
208
- contextWindow: 2e5,
209
- maxOutputTokens: 8192
210
- }
211
- ]
212
- },
213
- {
214
- provider: "google",
215
- models: [
216
- {
217
- name: "gemini-3-flash-preview",
218
- contextWindow: 1048576,
219
- maxOutputTokens: 65536
220
- },
221
- {
222
- name: "gemini-3-pro-preview",
223
- contextWindow: 1048576,
224
- maxOutputTokens: 65536
225
- },
226
- {
227
- name: "gemini-2.5-pro",
228
- contextWindow: 1048576,
229
- maxOutputTokens: 65536
230
- },
231
- {
232
- name: "gemini-2.5-flash",
233
- contextWindow: 1048576,
234
- maxOutputTokens: 65536
235
- },
236
- {
237
- name: "gemini-2.5-flash-lite",
238
- contextWindow: 1048576,
239
- maxOutputTokens: 65536
240
- }
241
- ]
242
- },
243
- {
244
- provider: "openai",
245
- models: [
246
- {
247
- name: "gpt-5",
248
- contextWindow: 4e5,
249
- maxOutputTokens: 128e3
250
- },
251
- {
252
- name: "gpt-5-mini",
253
- contextWindow: 4e5,
254
- maxOutputTokens: 128e3
255
- },
256
- {
257
- name: "gpt-5-nano",
258
- contextWindow: 4e5,
259
- maxOutputTokens: 128e3
260
- },
261
- {
262
- name: "gpt-5.2",
263
- contextWindow: 4e5,
264
- maxOutputTokens: 128e3
265
- },
266
- {
267
- name: "gpt-5.2-pro",
268
- contextWindow: 4e5,
269
- maxOutputTokens: 128e3
270
- },
271
- {
272
- name: "gpt-5.1",
273
- contextWindow: 4e5,
274
- maxOutputTokens: 128e3
275
- },
276
- {
277
- name: "gpt-5-chat-latest",
278
- contextWindow: 128e3,
279
- maxOutputTokens: 16384
280
- },
281
- {
282
- name: "o4-mini",
283
- contextWindow: 2e5,
284
- maxOutputTokens: 1e5
285
- },
286
- {
287
- name: "o3",
288
- contextWindow: 2e5,
289
- maxOutputTokens: 1e4
290
- },
291
- {
292
- name: "o3-mini",
293
- contextWindow: 2e5,
294
- maxOutputTokens: 1e4
295
- },
296
- {
297
- name: "gpt-4.1",
298
- contextWindow: 1047576,
299
- maxOutputTokens: 32768
300
- }
301
- ]
302
- },
303
- {
304
- provider: "deepseek",
305
- models: [{
306
- name: "deepseek-chat",
307
- contextWindow: 128e3,
308
- maxOutputTokens: 8192
309
- }, {
310
- name: "deepseek-reasoner",
311
- contextWindow: 128e3,
312
- maxOutputTokens: 64e3
313
- }]
314
- },
315
- {
316
- provider: "ollama",
317
- models: [
318
- {
319
- name: "gpt-oss:20b",
320
- contextWindow: 131072,
321
- maxOutputTokens: 131072
322
- },
323
- {
324
- name: "gpt-oss:120b",
325
- contextWindow: 131072,
326
- maxOutputTokens: 131072
327
- },
328
- {
329
- name: "gemma3:1b",
330
- contextWindow: 32e3,
331
- maxOutputTokens: 32e3
332
- },
333
- {
334
- name: "gemma3:4b",
335
- contextWindow: 128e3,
336
- maxOutputTokens: 128e3
337
- },
338
- {
339
- name: "gemma3:12b",
340
- contextWindow: 128e3,
341
- maxOutputTokens: 128e3
342
- },
343
- {
344
- name: "gemma3:27b",
345
- contextWindow: 128e3,
346
- maxOutputTokens: 128e3
347
- }
348
- ]
349
- }
350
- ];
351
-
352
- //#endregion
353
- //#region src/schemas/message-part.ts
354
- const basePartSchema = z.object({ id: z.string() });
355
- const textPartSchema = basePartSchema.extend({
356
- type: z.literal("textPart"),
357
- text: z.string()
358
- });
359
- const imageUrlPartSchema = basePartSchema.extend({
360
- type: z.literal("imageUrlPart"),
361
- url: z.url(),
362
- mimeType: z.string()
363
- });
364
- const imageInlinePartSchema = basePartSchema.extend({
365
- type: z.literal("imageInlinePart"),
366
- encodedData: z.string(),
367
- mimeType: z.string()
368
- });
369
- const imageBinaryPartSchema = basePartSchema.extend({
370
- type: z.literal("imageBinaryPart"),
371
- data: z.string(),
372
- mimeType: z.string()
373
- });
374
- const fileUrlPartSchema = basePartSchema.extend({
375
- type: z.literal("fileUrlPart"),
376
- url: z.string().url(),
377
- mimeType: z.string()
378
- });
379
- const fileInlinePartSchema = basePartSchema.extend({
380
- type: z.literal("fileInlinePart"),
381
- encodedData: z.string(),
382
- mimeType: z.string()
383
- });
384
- const fileBinaryPartSchema = basePartSchema.extend({
385
- type: z.literal("fileBinaryPart"),
386
- data: z.string(),
387
- mimeType: z.string()
388
- });
389
- const toolCallPartSchema = basePartSchema.extend({
390
- type: z.literal("toolCallPart"),
391
- toolCallId: z.string(),
392
- toolName: z.string(),
393
- args: z.record(z.string(), z.unknown())
394
- });
395
- const thinkingPartSchema = basePartSchema.extend({
396
- type: z.literal("thinkingPart"),
397
- thinking: z.string(),
398
- signature: z.string().optional()
399
- });
400
- const toolResultPartSchema = basePartSchema.extend({
401
- type: z.literal("toolResultPart"),
402
- toolCallId: z.string(),
403
- toolName: z.string(),
404
- contents: z.array(z.union([
405
- textPartSchema,
406
- imageInlinePartSchema,
407
- fileInlinePartSchema
408
- ])),
409
- isError: z.boolean().optional()
410
- });
411
- const messagePartSchema = z.discriminatedUnion("type", [
412
- textPartSchema,
413
- imageUrlPartSchema,
414
- imageInlinePartSchema,
415
- imageBinaryPartSchema,
416
- fileUrlPartSchema,
417
- fileInlinePartSchema,
418
- fileBinaryPartSchema,
419
- toolCallPartSchema,
420
- toolResultPartSchema,
421
- thinkingPartSchema
422
- ]);
423
-
424
- //#endregion
425
- //#region src/schemas/activity.ts
426
- const baseActivitySchema = z.object({
427
- id: z.string(),
428
- expertKey: z.string(),
429
- runId: z.string(),
430
- previousActivityId: z.string().optional(),
431
- delegatedBy: z.object({
432
- expertKey: z.string(),
433
- runId: z.string()
434
- }).optional(),
435
- reasoning: z.string().optional()
436
- });
437
- const queryActivitySchema = baseActivitySchema.extend({
438
- type: z.literal("query"),
439
- text: z.string()
440
- });
441
- const retryActivitySchema = baseActivitySchema.extend({
442
- type: z.literal("retry"),
443
- error: z.string(),
444
- message: z.string()
445
- });
446
- const completeActivitySchema = baseActivitySchema.extend({
447
- type: z.literal("complete"),
448
- text: z.string()
449
- });
450
- const errorActivitySchema = baseActivitySchema.extend({
451
- type: z.literal("error"),
452
- error: z.string().optional(),
453
- errorName: z.string().optional(),
454
- isRetryable: z.boolean().optional()
455
- });
456
- const attemptCompletionActivitySchema = baseActivitySchema.extend({
457
- type: z.literal("attemptCompletion"),
458
- remainingTodos: z.array(z.object({
459
- id: z.number(),
460
- title: z.string(),
461
- completed: z.boolean()
462
- })).optional(),
463
- error: z.string().optional()
464
- });
465
- const todoActivitySchema = baseActivitySchema.extend({
466
- type: z.literal("todo"),
467
- newTodos: z.array(z.string()).optional(),
468
- completedTodos: z.array(z.number()).optional(),
469
- todos: z.array(z.object({
470
- id: z.number(),
471
- title: z.string(),
472
- completed: z.boolean()
473
- })),
474
- error: z.string().optional()
475
- });
476
- const clearTodoActivitySchema = baseActivitySchema.extend({
477
- type: z.literal("clearTodo"),
478
- error: z.string().optional()
479
- });
480
- const readImageFileActivitySchema = baseActivitySchema.extend({
481
- type: z.literal("readImageFile"),
482
- path: z.string(),
483
- mimeType: z.string().optional(),
484
- size: z.number().optional(),
485
- error: z.string().optional()
486
- });
487
- const readPdfFileActivitySchema = baseActivitySchema.extend({
488
- type: z.literal("readPdfFile"),
489
- path: z.string(),
490
- mimeType: z.string().optional(),
491
- size: z.number().optional(),
492
- error: z.string().optional()
493
- });
494
- const readTextFileActivitySchema = baseActivitySchema.extend({
495
- type: z.literal("readTextFile"),
496
- path: z.string(),
497
- content: z.string().optional(),
498
- from: z.number().optional(),
499
- to: z.number().optional(),
500
- error: z.string().optional()
501
- });
502
- const editTextFileActivitySchema = baseActivitySchema.extend({
503
- type: z.literal("editTextFile"),
504
- path: z.string(),
505
- newText: z.string(),
506
- oldText: z.string(),
507
- error: z.string().optional()
508
- });
509
- const writeTextFileActivitySchema = baseActivitySchema.extend({
510
- type: z.literal("writeTextFile"),
511
- path: z.string(),
512
- text: z.string(),
513
- error: z.string().optional()
514
- });
515
- const execActivitySchema = baseActivitySchema.extend({
516
- type: z.literal("exec"),
517
- command: z.string(),
518
- args: z.array(z.string()),
519
- cwd: z.string(),
520
- output: z.string().optional(),
521
- error: z.string().optional(),
522
- stdout: z.string().optional(),
523
- stderr: z.string().optional()
524
- });
525
- const delegateActivitySchema = baseActivitySchema.extend({
526
- type: z.literal("delegate"),
527
- delegateExpertKey: z.string(),
528
- query: z.string()
529
- });
530
- const delegationCompleteActivitySchema = baseActivitySchema.extend({
531
- type: z.literal("delegationComplete"),
532
- count: z.number()
533
- });
534
- const interactiveToolActivitySchema = baseActivitySchema.extend({
535
- type: z.literal("interactiveTool"),
536
- skillName: z.string(),
537
- toolName: z.string(),
538
- args: z.record(z.string(), z.unknown())
539
- });
540
- const generalToolActivitySchema = baseActivitySchema.extend({
541
- type: z.literal("generalTool"),
542
- skillName: z.string(),
543
- toolName: z.string(),
544
- args: z.record(z.string(), z.unknown()),
545
- result: z.array(messagePartSchema).optional(),
546
- error: z.string().optional()
547
- });
548
- const addSkillActivitySchema = baseActivitySchema.extend({
549
- type: z.literal("addSkill"),
550
- name: z.string(),
551
- skillType: z.string(),
552
- tools: z.array(z.string()).optional(),
553
- error: z.string().optional()
554
- });
555
- const removeSkillActivitySchema = baseActivitySchema.extend({
556
- type: z.literal("removeSkill"),
557
- skillName: z.string(),
558
- error: z.string().optional()
559
- });
560
- const addDelegateActivitySchema = baseActivitySchema.extend({
561
- type: z.literal("addDelegate"),
562
- targetExpertKey: z.string(),
563
- delegateToolName: z.string().optional(),
564
- error: z.string().optional()
565
- });
566
- const removeDelegateActivitySchema = baseActivitySchema.extend({
567
- type: z.literal("removeDelegate"),
568
- expertName: z.string(),
569
- error: z.string().optional()
570
- });
571
- const createExpertActivitySchema = baseActivitySchema.extend({
572
- type: z.literal("createExpert"),
573
- targetKey: z.string(),
574
- description: z.string().optional(),
575
- resultExpertKey: z.string().optional(),
576
- error: z.string().optional()
577
- });
578
- const activitySchema = z.discriminatedUnion("type", [
579
- queryActivitySchema,
580
- retryActivitySchema,
581
- completeActivitySchema,
582
- errorActivitySchema,
583
- attemptCompletionActivitySchema,
584
- todoActivitySchema,
585
- clearTodoActivitySchema,
586
- readImageFileActivitySchema,
587
- readPdfFileActivitySchema,
588
- readTextFileActivitySchema,
589
- editTextFileActivitySchema,
590
- writeTextFileActivitySchema,
591
- execActivitySchema,
592
- delegateActivitySchema,
593
- delegationCompleteActivitySchema,
594
- interactiveToolActivitySchema,
595
- generalToolActivitySchema,
596
- addSkillActivitySchema,
597
- removeSkillActivitySchema,
598
- addDelegateActivitySchema,
599
- removeDelegateActivitySchema,
600
- createExpertActivitySchema
601
- ]);
602
- const parallelActivitiesGroupSchema = z.object({
603
- type: z.literal("parallelGroup"),
604
- id: z.string(),
605
- expertKey: z.string(),
606
- runId: z.string(),
607
- reasoning: z.string().optional(),
608
- activities: z.array(activitySchema)
609
- });
610
- const activityOrGroupSchema = z.union([activitySchema, parallelActivitiesGroupSchema]);
611
-
612
- //#endregion
613
- //#region src/schemas/message.ts
614
- const baseMessageSchema = z.object({ id: z.string() });
615
- const instructionMessageSchema = baseMessageSchema.extend({
616
- type: z.literal("instructionMessage"),
617
- contents: z.array(textPartSchema),
618
- cache: z.boolean().optional()
619
- });
620
- const userMessageSchema = baseMessageSchema.extend({
621
- type: z.literal("userMessage"),
622
- contents: z.array(z.union([
623
- textPartSchema,
624
- imageUrlPartSchema,
625
- imageInlinePartSchema,
626
- imageBinaryPartSchema,
627
- fileUrlPartSchema,
628
- fileInlinePartSchema,
629
- fileBinaryPartSchema
630
- ])),
631
- cache: z.boolean().optional()
632
- });
633
- const expertMessageSchema = baseMessageSchema.extend({
634
- type: z.literal("expertMessage"),
635
- contents: z.array(z.union([
636
- textPartSchema,
637
- toolCallPartSchema,
638
- thinkingPartSchema
639
- ])),
640
- cache: z.boolean().optional()
641
- });
642
- const toolMessageSchema = baseMessageSchema.extend({
643
- type: z.literal("toolMessage"),
644
- contents: z.array(toolResultPartSchema),
645
- cache: z.boolean().optional()
646
- });
647
- const messageSchema = z.union([
648
- instructionMessageSchema,
649
- userMessageSchema,
650
- expertMessageSchema,
651
- toolMessageSchema
652
- ]);
653
-
654
- //#endregion
655
- //#region src/schemas/tool-call.ts
656
- const toolCallSchema = z.object({
657
- id: z.string().min(1).max(255),
658
- skillName: z.string().min(1).max(maxSkillNameLength),
659
- toolName: z.string().min(1).max(maxSkillToolNameLength),
660
- args: z.record(z.string().min(1), z.unknown())
661
- });
662
-
663
- //#endregion
664
- //#region src/schemas/tool-result.ts
665
- const toolResultSchema = z.object({
666
- id: z.string().min(1).max(255),
667
- skillName: z.string().min(1).max(maxSkillNameLength),
668
- toolName: z.string().min(1).max(maxSkillToolNameLength),
669
- result: z.array(messagePartSchema)
670
- });
671
-
672
- //#endregion
673
- //#region src/schemas/usage.ts
674
- const usageSchema = z.object({
675
- inputTokens: z.number(),
676
- outputTokens: z.number(),
677
- reasoningTokens: z.number(),
678
- totalTokens: z.number(),
679
- cachedInputTokens: z.number()
680
- });
681
-
682
- //#endregion
683
- //#region src/schemas/checkpoint.ts
684
- const checkpointStatusSchema = z.enum([
685
- "init",
686
- "proceeding",
687
- "completed",
688
- "stoppedByInteractiveTool",
689
- "stoppedByDelegate",
690
- "stoppedByError",
691
- "stoppedByCancellation"
692
- ]);
693
- const delegationTargetSchema = z.object({
694
- expert: z.object({
695
- key: z.string(),
696
- name: z.string(),
697
- version: z.string()
698
- }),
699
- toolCallId: z.string(),
700
- toolName: z.string(),
701
- query: z.string()
702
- });
703
- const checkpointSchema = z.object({
704
- id: z.string(),
705
- jobId: z.string(),
706
- runId: z.string(),
707
- status: checkpointStatusSchema,
708
- stepNumber: z.number(),
709
- messages: z.array(messageSchema),
710
- expert: z.object({
711
- key: z.string(),
712
- name: z.string(),
713
- version: z.string()
714
- }),
715
- delegateTo: z.array(delegationTargetSchema).optional(),
716
- delegatedBy: z.object({
717
- expert: z.object({
718
- key: z.string(),
719
- name: z.string(),
720
- version: z.string()
721
- }),
722
- toolCallId: z.string(),
723
- toolName: z.string(),
724
- checkpointId: z.string(),
725
- runId: z.string()
726
- }).optional(),
727
- usage: usageSchema,
728
- contextWindow: z.number().optional(),
729
- contextWindowUsage: z.number().optional(),
730
- pendingToolCalls: z.array(toolCallSchema).optional(),
731
- partialToolResults: z.array(toolResultSchema).optional(),
732
- metadata: z.object({}).passthrough().optional(),
733
- error: z.object({
734
- name: z.string(),
735
- message: z.string(),
736
- statusCode: z.number().optional(),
737
- isRetryable: z.boolean()
738
- }).optional(),
739
- retryCount: z.number().optional()
740
- });
741
-
742
- //#endregion
743
- //#region src/utils/expert-type.ts
744
- function getExpertType(expertName) {
745
- return expertName.startsWith("@") ? "delegate" : "coordinator";
746
- }
747
- function isCoordinatorExpert(expertName) {
748
- return getExpertType(expertName) === "coordinator";
749
- }
750
- function isDelegateExpert(expertName) {
751
- return getExpertType(expertName) === "delegate";
752
- }
753
- /**
754
- * Returns the scope of an expert.
755
- * - Coordinator "game-producer" -> "game-producer"
756
- * - Delegate "@game-producer/designer" -> "game-producer"
757
- */
758
- function getExpertScope(expertName) {
759
- if (isDelegateExpert(expertName)) {
760
- const withoutAt = expertName.slice(1);
761
- const slashIndex = withoutAt.indexOf("/");
762
- return slashIndex === -1 ? withoutAt : withoutAt.slice(0, slashIndex);
763
- }
764
- return expertName;
765
- }
766
- /**
767
- * Returns the short name of an expert.
768
- * - Coordinator "game-producer" -> "game-producer"
769
- * - Delegate "@game-producer/designer" -> "designer"
770
- */
771
- function getExpertShortName(expertName) {
772
- if (isDelegateExpert(expertName)) {
773
- const slashIndex = expertName.indexOf("/");
774
- return slashIndex === -1 ? expertName : expertName.slice(slashIndex + 1);
775
- }
776
- return expertName;
777
- }
778
- /**
779
- * Validates whether a delegation from source to target is allowed.
780
- * Returns null if valid, an error message string if invalid.
781
- *
782
- * Rules:
783
- * - No self-delegation
784
- * - If target is a delegate (@scope/name), source must be in the same scope
785
- * - A delegate cannot delegate to its own coordinator
786
- */
787
- function validateDelegation(source, target) {
788
- if (source === target) return `Expert "${source}" cannot delegate to itself`;
789
- const sourceScope = getExpertScope(source);
790
- if (isDelegateExpert(target)) {
791
- if (sourceScope !== getExpertScope(target)) return `Expert "${source}" cannot delegate to out-of-scope delegate "${target}"`;
792
- }
793
- if (isDelegateExpert(source) && isCoordinatorExpert(target) && target === sourceScope) return `Delegate "${source}" cannot delegate to its own coordinator "${target}"`;
794
- return null;
795
- }
796
- /**
797
- * Validates all delegations for an expert.
798
- * Returns an array of error messages (empty if all valid).
799
- */
800
- function validateAllDelegations(expertName, delegates) {
801
- const errors = [];
802
- for (const delegate of delegates) {
803
- const error = validateDelegation(expertName, delegate);
804
- if (error) errors.push(error);
805
- }
806
- return errors;
807
- }
808
-
809
- //#endregion
810
- //#region src/schemas/provider-tools.ts
811
- const anthropicProviderToolNameSchema = z.enum([
812
- "webSearch",
813
- "webFetch",
814
- "codeExecution"
815
- ]);
816
- const builtinAnthropicSkillSchema = z.object({
817
- type: z.literal("builtin"),
818
- skillId: z.enum([
819
- "pdf",
820
- "docx",
821
- "pptx",
822
- "xlsx"
823
- ])
824
- });
825
- const customAnthropicSkillSchema = z.object({
826
- type: z.literal("custom"),
827
- name: z.string().min(1),
828
- definition: z.string().min(1)
829
- });
830
- const anthropicProviderSkillSchema = z.discriminatedUnion("type", [builtinAnthropicSkillSchema, customAnthropicSkillSchema]);
831
- const openaiProviderToolNameSchema = z.enum([
832
- "webSearch",
833
- "fileSearch",
834
- "codeInterpreter",
835
- "imageGeneration"
836
- ]);
837
- const googleProviderToolNameSchema = z.enum([
838
- "googleSearch",
839
- "codeExecution",
840
- "urlContext",
841
- "fileSearch",
842
- "googleMaps"
843
- ]);
844
- const azureOpenAIProviderToolNameSchema = z.enum([
845
- "webSearchPreview",
846
- "fileSearch",
847
- "codeInterpreter",
848
- "imageGeneration"
849
- ]);
850
- const vertexProviderToolNameSchema = z.enum([
851
- "codeExecution",
852
- "urlContext",
853
- "googleSearch",
854
- "enterpriseWebSearch",
855
- "googleMaps"
856
- ]);
857
- const webSearchOptionsSchema = z.object({
858
- maxUses: z.number().int().positive().optional(),
859
- allowedDomains: z.array(z.string()).optional()
860
- });
861
- const webFetchOptionsSchema = z.object({ maxUses: z.number().int().positive().optional() });
862
- const fileSearchOptionsSchema = z.object({
863
- vectorStoreIds: z.array(z.string()).optional(),
864
- maxNumResults: z.number().int().positive().optional()
865
- });
866
- const providerToolOptionsSchema = z.object({
867
- webSearch: webSearchOptionsSchema.optional(),
868
- webFetch: webFetchOptionsSchema.optional(),
869
- fileSearch: fileSearchOptionsSchema.optional()
870
- }).optional();
871
-
872
- //#endregion
873
- //#region src/schemas/runtime-version.ts
874
- const runtimeVersionSchema = z.string().regex(/^v\d+\.\d+$/, "Runtime version must be in format \"vX.Y\" (e.g., \"v1.0\")").transform((v) => v);
875
-
876
- //#endregion
877
- //#region src/schemas/skill.ts
878
- function isPrivateOrLocalIP(hostname) {
879
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "0.0.0.0") return true;
880
- const ipv4Match = hostname.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
881
- if (ipv4Match) {
882
- const a = Number(ipv4Match[1]);
883
- const b = Number(ipv4Match[2]);
884
- if (a === 10) return true;
885
- if (a === 172 && b >= 16 && b <= 31) return true;
886
- if (a === 192 && b === 168) return true;
887
- if (a === 169 && b === 254) return true;
888
- if (a === 127) return true;
889
- }
890
- if (hostname.includes(":")) {
891
- if (hostname.startsWith("fe80:") || hostname.startsWith("fc") || hostname.startsWith("fd")) return true;
892
- }
893
- if (hostname.startsWith("::ffff:")) {
894
- if (isPrivateOrLocalIP(hostname.slice(7))) return true;
895
- }
896
- return false;
897
- }
898
- const sseEndpointSchema$1 = z.string().url().refine((url) => {
899
- try {
900
- const parsed = new URL(url);
901
- if (parsed.protocol !== "https:") return false;
902
- if (isPrivateOrLocalIP(parsed.hostname)) return false;
903
- return true;
904
- } catch {
905
- return false;
906
- }
907
- }, { message: "Endpoint must be a public HTTPS URL" });
908
- const mcpStdioSkillSchema = z.object({
909
- type: z.literal("mcpStdioSkill"),
910
- name: z.string(),
911
- description: z.string().optional(),
912
- rule: z.string().optional(),
913
- pick: z.array(z.string()).optional().default([]),
914
- omit: z.array(z.string()).optional().default([]),
915
- command: z.string(),
916
- packageName: z.string().optional(),
917
- args: z.array(z.string()).optional().default([]),
918
- requiredEnv: z.array(z.string()).optional().default([])
919
- });
920
- const mcpSseSkillSchema = z.object({
921
- type: z.literal("mcpSseSkill"),
922
- name: z.string(),
923
- description: z.string().optional(),
924
- rule: z.string().optional(),
925
- pick: z.array(z.string()).optional().default([]),
926
- omit: z.array(z.string()).optional().default([]),
927
- endpoint: sseEndpointSchema$1
928
- });
929
- const interactiveToolSchema = z.object({
930
- name: z.string(),
931
- description: z.string().optional(),
932
- inputJsonSchema: z.string()
933
- });
934
- const interactiveSkillSchema = z.object({
935
- type: z.literal("interactiveSkill"),
936
- name: z.string(),
937
- description: z.string().optional(),
938
- rule: z.string().optional(),
939
- tools: z.record(z.string(), interactiveToolSchema.omit({ name: true })).transform((tools) => {
940
- return Object.fromEntries(Object.entries(tools).map(([key, toolWithoutName]) => [key, interactiveToolSchema.parse({
941
- ...toolWithoutName,
942
- name: key
943
- })]));
944
- })
945
- });
946
- const skillSchema = z.discriminatedUnion("type", [
947
- mcpStdioSkillSchema,
948
- mcpSseSkillSchema,
949
- interactiveSkillSchema
950
- ]);
951
-
952
- //#endregion
953
- //#region src/schemas/expert.ts
954
- /**
955
- * Base object schema for Expert. Use this for `.omit()` / `.pick()` operations.
956
- * For parsing with delegation validation, use `expertSchema` instead.
957
- */
958
- const expertBaseSchema = z.object({
959
- key: z.string().regex(expertKeyRegex).min(1),
960
- name: z.string().regex(expertNameRegex).min(1).max(maxExpertNameLength),
961
- version: z.string().regex(expertVersionRegex),
962
- description: z.string().max(1024 * 2).optional(),
963
- instruction: z.string().min(1).max(1024 * 20),
964
- skills: z.record(z.string(), z.discriminatedUnion("type", [
965
- mcpStdioSkillSchema.omit({ name: true }),
966
- mcpSseSkillSchema.omit({ name: true }),
967
- interactiveSkillSchema.omit({ name: true })
968
- ])).optional().default({ "@perstack/base": {
969
- type: "mcpStdioSkill",
970
- description: "Base skill",
971
- command: "npx",
972
- args: ["-y", "@perstack/base"],
973
- pick: [],
974
- omit: [],
975
- requiredEnv: []
976
- } }).transform((skills) => {
977
- return Object.fromEntries(Object.entries(skills).map(([key, skillWithoutName]) => [key, z.discriminatedUnion("type", [
978
- mcpStdioSkillSchema,
979
- mcpSseSkillSchema,
980
- interactiveSkillSchema
981
- ]).parse({
982
- ...skillWithoutName,
983
- name: key
984
- })]));
985
- }),
986
- delegates: z.array(z.string().regex(expertKeyRegex).min(1)).optional().default([]),
987
- tags: z.array(z.string().regex(tagNameRegex).min(1)).optional().default([]),
988
- minRuntimeVersion: runtimeVersionSchema.default("v1.0"),
989
- providerTools: z.array(z.string()).optional(),
990
- providerSkills: z.array(anthropicProviderSkillSchema).optional(),
991
- providerToolOptions: providerToolOptionsSchema
992
- });
993
- /**
994
- * Expert schema with delegation rule validation.
995
- * Rejects self-delegation, out-of-scope delegates, and delegate-to-own-coordinator.
996
- */
997
- const expertSchema = expertBaseSchema.superRefine((data, ctx) => {
998
- const errors = validateAllDelegations(data.key, data.delegates);
999
- for (const error of errors) ctx.addIssue({
1000
- code: z.ZodIssueCode.custom,
1001
- message: error,
1002
- path: ["delegates"]
1003
- });
1004
- });
1005
-
1006
- //#endregion
1007
- //#region src/schemas/job.ts
1008
- const jobStatusSchema = z.enum([
1009
- "running",
1010
- "completed",
1011
- "stoppedByInteractiveTool",
1012
- "stoppedByError",
1013
- "stoppedByCancellation"
1014
- ]);
1015
- const jobSchema = z.object({
1016
- id: z.string(),
1017
- status: jobStatusSchema,
1018
- coordinatorExpertKey: z.string(),
1019
- runtimeVersion: runtimeVersionSchema,
1020
- totalSteps: z.number(),
1021
- usage: usageSchema,
1022
- startedAt: z.number(),
1023
- finishedAt: z.number().optional()
1024
- });
1025
-
1026
- //#endregion
1027
- //#region src/schemas/lockfile.ts
1028
- const lockfileToolDefinitionSchema = z.object({
1029
- skillName: z.string(),
1030
- name: z.string(),
1031
- description: z.string().optional(),
1032
- inputSchema: z.record(z.string(), z.unknown())
1033
- });
1034
- const lockfileExpertSchema = z.object({
1035
- key: z.string(),
1036
- name: z.string(),
1037
- version: z.string(),
1038
- description: z.string().optional(),
1039
- instruction: z.string(),
1040
- skills: z.record(z.string(), skillSchema),
1041
- delegates: z.array(z.string()),
1042
- tags: z.array(z.string()),
1043
- toolDefinitions: z.array(lockfileToolDefinitionSchema)
1044
- });
1045
- const lockfileSchema = z.object({
1046
- version: z.literal("1"),
1047
- generatedAt: z.number(),
1048
- configPath: z.string(),
1049
- experts: z.record(z.string(), lockfileExpertSchema)
1050
- });
1051
-
1052
- //#endregion
1053
- //#region src/schemas/provider-config.ts
1054
- const headersSchema = z.record(z.string(), z.string()).optional();
1055
- const providerNameSchema = z.enum([
1056
- "anthropic",
1057
- "google",
1058
- "openai",
1059
- "ollama",
1060
- "azure-openai",
1061
- "amazon-bedrock",
1062
- "google-vertex",
1063
- "deepseek"
1064
- ]);
1065
- const anthropicProviderConfigSchema = z.object({
1066
- providerName: z.literal(providerNameSchema.enum.anthropic),
1067
- apiKey: z.string(),
1068
- baseUrl: z.string().optional(),
1069
- headers: headersSchema
1070
- });
1071
- const googleGenerativeAiProviderConfigSchema = z.object({
1072
- providerName: z.literal(providerNameSchema.enum.google),
1073
- apiKey: z.string(),
1074
- baseUrl: z.string().optional(),
1075
- headers: headersSchema
1076
- });
1077
- const openAiProviderConfigSchema = z.object({
1078
- providerName: z.literal(providerNameSchema.enum.openai),
1079
- apiKey: z.string(),
1080
- baseUrl: z.string().optional(),
1081
- organization: z.string().optional(),
1082
- project: z.string().optional(),
1083
- name: z.string().optional(),
1084
- headers: headersSchema
1085
- });
1086
- const ollamaProviderConfigSchema = z.object({
1087
- providerName: z.literal(providerNameSchema.enum.ollama),
1088
- baseUrl: z.string().optional(),
1089
- headers: headersSchema
1090
- });
1091
- const azureOpenAiProviderConfigSchema = z.object({
1092
- providerName: z.literal(providerNameSchema.enum["azure-openai"]),
1093
- apiKey: z.string(),
1094
- resourceName: z.string().optional(),
1095
- apiVersion: z.string().optional(),
1096
- baseUrl: z.string().optional(),
1097
- headers: headersSchema,
1098
- useDeploymentBasedUrls: z.boolean().optional()
1099
- });
1100
- const amazonBedrockProviderConfigSchema = z.object({
1101
- providerName: z.literal(providerNameSchema.enum["amazon-bedrock"]),
1102
- accessKeyId: z.string(),
1103
- secretAccessKey: z.string(),
1104
- region: z.string(),
1105
- sessionToken: z.string().optional()
1106
- });
1107
- const googleVertexProviderConfigSchema = z.object({
1108
- providerName: z.literal(providerNameSchema.enum["google-vertex"]),
1109
- project: z.string().optional(),
1110
- location: z.string().optional(),
1111
- baseUrl: z.string().optional(),
1112
- headers: headersSchema
1113
- });
1114
- const deepseekProviderConfigSchema = z.object({
1115
- providerName: z.literal(providerNameSchema.enum.deepseek),
1116
- apiKey: z.string(),
1117
- baseUrl: z.string().optional(),
1118
- headers: headersSchema
1119
- });
1120
- const providerConfigSchema = z.discriminatedUnion("providerName", [
1121
- anthropicProviderConfigSchema,
1122
- googleGenerativeAiProviderConfigSchema,
1123
- openAiProviderConfigSchema,
1124
- ollamaProviderConfigSchema,
1125
- azureOpenAiProviderConfigSchema,
1126
- amazonBedrockProviderConfigSchema,
1127
- googleVertexProviderConfigSchema,
1128
- deepseekProviderConfigSchema
1129
- ]);
1130
-
1131
- //#endregion
1132
- //#region src/schemas/perstack-toml.ts
1133
- /** Default reasoning budget - enables extended thinking by default */
1134
- const defaultReasoningBudget = "low";
1135
- const reasoningBudgetSchema = z.union([z.enum([
1136
- "none",
1137
- "minimal",
1138
- "low",
1139
- "medium",
1140
- "high"
1141
- ]), z.number().int().nonnegative()]);
1142
- const domainPatternRegex = /^(\*\.)?[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/;
1143
- const punycodeRegex = /(?:^|\.)(xn--)/i;
1144
- const domainPatternSchema = z.string().regex(domainPatternRegex, { message: "Invalid domain pattern. Use exact domain (example.com) or wildcard prefix (*.example.com)" }).refine((domain) => !punycodeRegex.test(domain), { message: "Punycode domains (xn--) are not allowed to prevent homograph attacks. Use ASCII domains only." });
1145
- const sseEndpointSchema = z.string().url().refine((url) => {
1146
- try {
1147
- const parsed = new URL(url);
1148
- if (parsed.protocol !== "https:") return false;
1149
- if (isPrivateOrLocalIP(parsed.hostname)) return false;
1150
- return true;
1151
- } catch {
1152
- return false;
1153
- }
1154
- }, { message: "SSE endpoint must be a public HTTPS URL" });
1155
- const httpsUrlSchema = z.string().url().refine((url) => url.startsWith("https://"), { message: "URL must use HTTPS" });
1156
- const anthropicSettingSchema = z.object({
1157
- baseUrl: httpsUrlSchema.optional(),
1158
- headers: headersSchema
1159
- });
1160
- const googleSettingSchema = z.object({
1161
- baseUrl: httpsUrlSchema.optional(),
1162
- headers: headersSchema
1163
- });
1164
- const openAiSettingSchema = z.object({
1165
- baseUrl: httpsUrlSchema.optional(),
1166
- organization: z.string().optional(),
1167
- project: z.string().optional(),
1168
- name: z.string().optional(),
1169
- headers: headersSchema
1170
- });
1171
- const ollamaSettingSchema = z.object({
1172
- baseUrl: z.string().optional(),
1173
- headers: headersSchema
1174
- });
1175
- const azureOpenAiSettingSchema = z.object({
1176
- resourceName: z.string().optional(),
1177
- apiVersion: z.string().optional(),
1178
- baseUrl: httpsUrlSchema.optional(),
1179
- headers: headersSchema,
1180
- useDeploymentBasedUrls: z.boolean().optional()
1181
- });
1182
- const amazonBedrockSettingSchema = z.object({ region: z.string().optional() });
1183
- const googleVertexSettingSchema = z.object({
1184
- project: z.string().optional(),
1185
- location: z.string().optional(),
1186
- baseUrl: httpsUrlSchema.optional(),
1187
- headers: headersSchema
1188
- });
1189
- const deepseekSettingSchema = z.object({
1190
- baseUrl: httpsUrlSchema.optional(),
1191
- headers: headersSchema
1192
- });
1193
- const providerTableSchema = z.discriminatedUnion("providerName", [
1194
- z.object({
1195
- providerName: z.literal("anthropic"),
1196
- setting: anthropicSettingSchema.optional()
1197
- }),
1198
- z.object({
1199
- providerName: z.literal("google"),
1200
- setting: googleSettingSchema.optional()
1201
- }),
1202
- z.object({
1203
- providerName: z.literal("openai"),
1204
- setting: openAiSettingSchema.optional()
1205
- }),
1206
- z.object({
1207
- providerName: z.literal("ollama"),
1208
- setting: ollamaSettingSchema.optional()
1209
- }),
1210
- z.object({
1211
- providerName: z.literal("azure-openai"),
1212
- setting: azureOpenAiSettingSchema.optional()
1213
- }),
1214
- z.object({
1215
- providerName: z.literal("amazon-bedrock"),
1216
- setting: amazonBedrockSettingSchema.optional()
1217
- }),
1218
- z.object({
1219
- providerName: z.literal("google-vertex"),
1220
- setting: googleVertexSettingSchema.optional()
1221
- }),
1222
- z.object({
1223
- providerName: z.literal("deepseek"),
1224
- setting: deepseekSettingSchema.optional()
1225
- })
1226
- ]);
1227
- const perstackConfigSchema = z.object({
1228
- provider: providerTableSchema.optional(),
1229
- model: z.string().optional(),
1230
- reasoningBudget: reasoningBudgetSchema.optional(),
1231
- maxRetries: z.number().optional(),
1232
- timeout: z.number().optional(),
1233
- experts: z.record(z.string(), z.object({
1234
- version: z.string().optional(),
1235
- minRuntimeVersion: runtimeVersionSchema.optional(),
1236
- description: z.string().optional(),
1237
- instruction: z.string(),
1238
- skills: z.record(z.string(), z.discriminatedUnion("type", [
1239
- z.object({
1240
- type: z.literal("mcpStdioSkill"),
1241
- description: z.string().optional(),
1242
- rule: z.string().optional(),
1243
- pick: z.array(z.string()).optional(),
1244
- omit: z.array(z.string()).optional(),
1245
- command: z.string(),
1246
- packageName: z.string().optional(),
1247
- args: z.array(z.string()).optional(),
1248
- requiredEnv: z.array(z.string()).optional(),
1249
- allowedDomains: z.array(domainPatternSchema).optional()
1250
- }),
1251
- z.object({
1252
- type: z.literal("mcpSseSkill"),
1253
- description: z.string().optional(),
1254
- rule: z.string().optional(),
1255
- pick: z.array(z.string()).optional(),
1256
- omit: z.array(z.string()).optional(),
1257
- endpoint: sseEndpointSchema,
1258
- allowedDomains: z.array(domainPatternSchema).optional()
1259
- }),
1260
- z.object({
1261
- type: z.literal("interactiveSkill"),
1262
- description: z.string().optional(),
1263
- rule: z.string().optional(),
1264
- tools: z.record(z.string(), z.object({
1265
- description: z.string().optional(),
1266
- inputJsonSchema: z.string()
1267
- }))
1268
- })
1269
- ])).optional(),
1270
- delegates: z.array(z.string()).optional(),
1271
- tags: z.array(z.string()).optional(),
1272
- providerTools: z.array(z.string()).optional(),
1273
- providerSkills: z.array(anthropicProviderSkillSchema).optional(),
1274
- providerToolOptions: providerToolOptionsSchema
1275
- })).optional(),
1276
- perstackApiBaseUrl: z.url().refine((url) => url.startsWith("https://"), { message: "perstackApiBaseUrl must use HTTPS" }).optional(),
1277
- perstackBaseSkillCommand: z.array(z.string()).optional(),
1278
- envPath: z.array(z.string()).optional()
1279
- });
1280
-
1281
- //#endregion
1282
- //#region src/schemas/run-command.ts
1283
- const commandOptionsSchema = z.object({
1284
- config: z.string().optional(),
1285
- provider: providerNameSchema.optional(),
1286
- model: z.string().optional(),
1287
- reasoningBudget: z.string().optional().transform((value) => {
1288
- if (value === void 0) return void 0;
1289
- if ([
1290
- "none",
1291
- "minimal",
1292
- "low",
1293
- "medium",
1294
- "high"
1295
- ].includes(value)) return value;
1296
- const parsedValue = Number.parseInt(value, 10);
1297
- if (Number.isNaN(parsedValue)) return void 0;
1298
- return parsedValue;
1299
- }).pipe(reasoningBudgetSchema.optional()),
1300
- maxRetries: z.string().optional().transform((value) => {
1301
- if (value === void 0) return void 0;
1302
- const parsedValue = Number.parseInt(value, 10);
1303
- if (Number.isNaN(parsedValue)) return void 0;
1304
- return parsedValue;
1305
- }),
1306
- timeout: z.string().optional().transform((value) => {
1307
- if (value === void 0) return void 0;
1308
- const parsedValue = Number.parseInt(value, 10);
1309
- if (Number.isNaN(parsedValue)) return void 0;
1310
- return parsedValue;
1311
- }),
1312
- jobId: z.string().optional(),
1313
- runId: z.string().optional(),
1314
- envPath: z.array(z.string()).optional().transform((value) => value && value.length > 0 ? value : void 0),
1315
- verbose: z.boolean().optional(),
1316
- continue: z.boolean().optional(),
1317
- continueJob: z.string().optional(),
1318
- resumeFrom: z.string().optional(),
1319
- interactiveToolCallResult: z.boolean().optional(),
1320
- filter: z.string().optional().transform((value) => {
1321
- if (value === void 0) return void 0;
1322
- return value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
1323
- }).pipe(z.array(z.string()).optional())
1324
- });
1325
- const runCommandInputSchema = z.object({
1326
- expertKey: z.string(),
1327
- query: z.string(),
1328
- options: commandOptionsSchema
1329
- });
1330
- const startCommandInputSchema = z.object({
1331
- expertKey: z.string().optional(),
1332
- query: z.string().optional(),
1333
- options: commandOptionsSchema
1334
- });
1335
-
1336
- //#endregion
1337
- //#region src/schemas/runtime.ts
1338
- /** Parse an expert key into its components */
1339
- function parseExpertKey(expertKey) {
1340
- const match = expertKey.match(expertKeyRegex);
1341
- if (!match) throw new PerstackError(`Invalid expert key format: ${expertKey}`);
1342
- const [key, name, version, tag] = match;
1343
- if (!name) throw new PerstackError(`Invalid expert key format: ${expertKey}`);
1344
- return {
1345
- key,
1346
- name,
1347
- version,
1348
- tag
1349
- };
1350
- }
1351
- const runSettingSchema = z.object({
1352
- model: z.string(),
1353
- providerConfig: providerConfigSchema,
1354
- jobId: z.string(),
1355
- runId: z.string(),
1356
- expertKey: z.string().min(1).regex(expertKeyRegex),
1357
- input: z.object({
1358
- text: z.string().optional(),
1359
- interactiveToolCallResult: z.object({
1360
- toolCallId: z.string(),
1361
- toolName: z.string(),
1362
- skillName: z.string(),
1363
- text: z.string()
1364
- }).optional()
1365
- }),
1366
- experts: z.record(z.string(), expertSchema),
1367
- reasoningBudget: reasoningBudgetSchema.default(defaultReasoningBudget),
1368
- maxRetries: z.number().min(0),
1369
- timeout: z.number().min(0),
1370
- startedAt: z.number(),
1371
- updatedAt: z.number(),
1372
- perstackApiBaseUrl: z.string().url(),
1373
- perstackApiKey: z.string().optional(),
1374
- perstackBaseSkillCommand: z.array(z.string()).optional(),
1375
- env: z.record(z.string(), z.string()),
1376
- proxyUrl: z.string().optional(),
1377
- verbose: z.boolean().optional()
1378
- });
1379
- const runParamsSchema = z.object({
1380
- setting: z.object({
1381
- model: z.string(),
1382
- providerConfig: providerConfigSchema,
1383
- jobId: z.string().optional().default(() => createId()),
1384
- runId: z.string().optional().default(() => createId()),
1385
- expertKey: z.string().min(1).regex(expertKeyRegex),
1386
- input: z.object({
1387
- text: z.string().optional(),
1388
- interactiveToolCallResult: z.object({
1389
- toolCallId: z.string(),
1390
- toolName: z.string(),
1391
- skillName: z.string(),
1392
- text: z.string()
1393
- }).optional()
1394
- }),
1395
- experts: z.record(z.string().min(1).regex(expertKeyRegex), expertBaseSchema.omit({ key: true })).optional().default({}).transform((experts) => Object.fromEntries(Object.entries(experts).map(([key, expertWithoutKey]) => [key, expertSchema.parse({
1396
- ...expertWithoutKey,
1397
- key
1398
- })]))),
1399
- reasoningBudget: reasoningBudgetSchema.optional().default(defaultReasoningBudget),
1400
- maxRetries: z.number().min(0).optional().default(defaultMaxRetries),
1401
- timeout: z.number().min(0).optional().default(defaultTimeout),
1402
- startedAt: z.number().optional().default(Date.now()),
1403
- updatedAt: z.number().optional().default(Date.now()),
1404
- perstackApiBaseUrl: z.url().optional().default(defaultPerstackApiBaseUrl),
1405
- perstackApiKey: z.string().optional(),
1406
- perstackBaseSkillCommand: z.array(z.string()).optional(),
1407
- env: z.record(z.string(), z.string()).optional().default({}),
1408
- proxyUrl: z.string().optional(),
1409
- verbose: z.boolean().optional()
1410
- }),
1411
- checkpoint: checkpointSchema.optional()
1412
- });
1413
- /** Factory function to create expert state events */
1414
- function createEvent(type) {
1415
- return (setting, checkpoint, data) => {
1416
- return {
1417
- type,
1418
- id: createId(),
1419
- expertKey: checkpoint.expert.key,
1420
- timestamp: Date.now(),
1421
- jobId: setting.jobId,
1422
- runId: setting.runId,
1423
- stepNumber: checkpoint.stepNumber,
1424
- ...data
1425
- };
1426
- };
1427
- }
1428
- /** Factory function to create streaming events */
1429
- function createStreamingEvent(type, setting, checkpoint, data) {
1430
- return {
1431
- type,
1432
- id: createId(),
1433
- expertKey: checkpoint.expert.key,
1434
- timestamp: Date.now(),
1435
- jobId: setting.jobId,
1436
- runId: setting.runId,
1437
- stepNumber: checkpoint.stepNumber,
1438
- ...data
1439
- };
1440
- }
1441
- const startRun = createEvent("startRun");
1442
- const resumeFromStop = createEvent("resumeFromStop");
1443
- const proceedToInteractiveTools = createEvent("proceedToInteractiveTools");
1444
- const startGeneration = createEvent("startGeneration");
1445
- const retry = createEvent("retry");
1446
- const callTools = createEvent("callTools");
1447
- const finishMcpTools = createEvent("finishMcpTools");
1448
- const skipDelegates = createEvent("skipDelegates");
1449
- const resolveToolResults = createEvent("resolveToolResults");
1450
- const finishToolCall = createEvent("finishToolCall");
1451
- const resumeToolCalls = createEvent("resumeToolCalls");
1452
- const completeRun = createEvent("completeRun");
1453
- const stopRunByInteractiveTool = createEvent("stopRunByInteractiveTool");
1454
- const stopRunByDelegate = createEvent("stopRunByDelegate");
1455
- const stopRunByError = createEvent("stopRunByError");
1456
- const continueToNextStep = createEvent("continueToNextStep");
1457
- /** Factory function to create runtime events */
1458
- function createRuntimeEvent(type, jobId, runId, data) {
1459
- return {
1460
- type,
1461
- id: createId(),
1462
- timestamp: Date.now(),
1463
- jobId,
1464
- runId,
1465
- ...data
1466
- };
1467
- }
1468
- /**
1469
- * Valid expert state event types (state machine transitions)
1470
- */
1471
- const EXPERT_STATE_EVENT_TYPES = new Set([
1472
- "startRun",
1473
- "resumeFromStop",
1474
- "proceedToInteractiveTools",
1475
- "startGeneration",
1476
- "retry",
1477
- "callTools",
1478
- "finishMcpTools",
1479
- "skipDelegates",
1480
- "resolveToolResults",
1481
- "finishToolCall",
1482
- "resumeToolCalls",
1483
- "continueToNextStep",
1484
- "stopRunByInteractiveTool",
1485
- "stopRunByDelegate",
1486
- "stopRunByError",
1487
- "completeRun"
1488
- ]);
1489
- /**
1490
- * Valid streaming event types
1491
- */
1492
- const STREAMING_EVENT_TYPES = new Set([
1493
- "startStreamingReasoning",
1494
- "streamReasoning",
1495
- "completeStreamingReasoning",
1496
- "startStreamingRunResult",
1497
- "streamRunResult",
1498
- "completeStreamingRunResult"
1499
- ]);
1500
- /**
1501
- * Valid runtime event types (infrastructure-level events)
1502
- */
1503
- const RUNTIME_EVENT_TYPES = new Set([
1504
- "initializeRuntime",
1505
- "skillStarting",
1506
- "skillConnected",
1507
- "skillStderr",
1508
- "skillDisconnected"
1509
- ]);
1510
- /** Validate if a string is a valid RunEvent type (ExpertStateEvent or StreamingEvent) */
1511
- function isValidEventType(type) {
1512
- return EXPERT_STATE_EVENT_TYPES.has(type) || STREAMING_EVENT_TYPES.has(type);
1513
- }
1514
- /** Validate if a string is a valid RuntimeEvent type */
1515
- function isValidRuntimeEventType(type) {
1516
- return RUNTIME_EVENT_TYPES.has(type);
1517
- }
1518
-
1519
- //#endregion
1520
- //#region src/schemas/step.ts
1521
- const stepSchema = z.object({
1522
- stepNumber: z.number(),
1523
- inputMessages: z.array(z.union([
1524
- instructionMessageSchema,
1525
- userMessageSchema,
1526
- toolMessageSchema
1527
- ])).optional(),
1528
- newMessages: z.array(messageSchema),
1529
- toolCalls: z.array(toolCallSchema).optional(),
1530
- toolResults: z.array(toolResultSchema).optional(),
1531
- pendingToolCalls: z.array(toolCallSchema).optional(),
1532
- partialToolResults: z.array(toolResultSchema).optional(),
1533
- usage: usageSchema,
1534
- startedAt: z.number(),
1535
- finishedAt: z.number().optional()
1536
- });
1537
-
1538
- //#endregion
1539
- //#region src/utils/activity.ts
1540
- const BASE_SKILL_PREFIX = "@perstack/base";
1541
- /**
1542
- * Extracts reasoning from Step.newMessages by finding thinkingParts.
1543
- */
1544
- function extractReasoning(newMessages) {
1545
- const thinkingParts = [];
1546
- for (const message of newMessages) for (const content of message.contents) if (content.type === "thinkingPart") thinkingParts.push(content);
1547
- if (thinkingParts.length === 0) return void 0;
1548
- return thinkingParts.map((p) => p.thinking).join("\n\n");
1549
- }
1550
- /**
1551
- * Wraps multiple activities into a ParallelActivitiesGroup when they share reasoning.
1552
- * Single activities are returned as-is.
1553
- */
1554
- function wrapInGroupIfParallel(activities, reasoning, expertKey, runId, stepNumber) {
1555
- if (activities.length <= 1) return activities;
1556
- const activitiesWithoutReasoning = activities.map((a) => {
1557
- const { reasoning: _, ...rest } = a;
1558
- return rest;
1559
- });
1560
- return [{
1561
- type: "parallelGroup",
1562
- id: `parallel-${runId}-step${stepNumber}`,
1563
- expertKey,
1564
- runId,
1565
- reasoning,
1566
- activities: activitiesWithoutReasoning
1567
- }];
1568
- }
1569
- /**
1570
- * Computes activities from a checkpoint and step.
1571
- * Returns an array of activities or activity groups, supporting parallel tool calls and delegations.
1572
- * When multiple activities are produced from a single step, they are wrapped in a ParallelActivitiesGroup
1573
- * with shared reasoning.
1574
- */
1575
- function getActivities(params) {
1576
- const { checkpoint, step } = params;
1577
- const { status, delegateTo, runId, stepNumber } = checkpoint;
1578
- const expertKey = checkpoint.expert.key;
1579
- const reasoning = extractReasoning(step.newMessages);
1580
- let queryActivity;
1581
- if (stepNumber === 1 && step.inputMessages) {
1582
- const userMessage = step.inputMessages.find((m) => m.type === "userMessage");
1583
- if (userMessage) {
1584
- const textPart = userMessage.contents.find((c) => c.type === "textPart");
1585
- if (textPart && "text" in textPart) queryActivity = {
1586
- type: "query",
1587
- id: "",
1588
- expertKey,
1589
- runId,
1590
- text: textPart.text
1591
- };
1592
- }
1593
- }
1594
- const prependQuery = (result) => queryActivity ? [queryActivity, ...result] : result;
1595
- if (status === "stoppedByError") return prependQuery([createErrorActivity(checkpoint, reasoning)]);
1596
- if (status === "stoppedByDelegate") {
1597
- if (!delegateTo || delegateTo.length === 0) return prependQuery([createRetryActivity(step.newMessages, reasoning, "Delegate status but no delegation targets")]);
1598
- return prependQuery(wrapInGroupIfParallel(delegateTo.map((d) => createDelegateActivity(d, reasoning)), reasoning, expertKey, runId, stepNumber));
1599
- }
1600
- if (status === "stoppedByInteractiveTool") {
1601
- const toolCalls = step.toolCalls ?? [];
1602
- if (toolCalls.length === 0) return prependQuery([createRetryActivity(step.newMessages, reasoning)]);
1603
- return prependQuery(wrapInGroupIfParallel(toolCalls.map((tc) => createInteractiveToolActivity(tc.skillName, tc.toolName, tc, reasoning)), reasoning, expertKey, runId, stepNumber));
1604
- }
1605
- const toolCalls = step.toolCalls ?? [];
1606
- const toolResults = step.toolResults ?? [];
1607
- if (toolCalls.length === 0) {
1608
- if (status === "completed") return prependQuery([createCompleteActivity(step.newMessages, reasoning)]);
1609
- if (status === "proceeding" || status === "init") return prependQuery([]);
1610
- return prependQuery([createRetryActivity(step.newMessages, reasoning)]);
1611
- }
1612
- const toolActivities = [];
1613
- for (const toolCall of toolCalls) {
1614
- const toolResult = toolResults.find((tr) => tr.id === toolCall.id);
1615
- if (!toolResult) continue;
1616
- const { skillName, toolName } = toolCall;
1617
- if (skillName.startsWith(BASE_SKILL_PREFIX)) toolActivities.push(createBaseToolActivity(toolName, toolCall, toolResult, reasoning));
1618
- else toolActivities.push(createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning));
1619
- }
1620
- if (toolActivities.length === 0) {
1621
- if (status === "completed") return prependQuery([createCompleteActivity(step.newMessages, reasoning)]);
1622
- if (status === "proceeding" || status === "init") return prependQuery([]);
1623
- return prependQuery([createRetryActivity(step.newMessages, reasoning)]);
1624
- }
1625
- const result = wrapInGroupIfParallel(toolActivities, reasoning, expertKey, runId, stepNumber);
1626
- if (status === "completed") result.push(createCompleteActivity(step.newMessages, void 0));
1627
- return prependQuery(result);
1628
- }
1629
- function createCompleteActivity(newMessages, reasoning) {
1630
- return {
1631
- type: "complete",
1632
- id: "",
1633
- expertKey: "",
1634
- runId: "",
1635
- reasoning,
1636
- text: ([...newMessages].reverse().find((m) => m.type === "expertMessage")?.contents.find((c) => c.type === "textPart"))?.text ?? ""
1637
- };
1638
- }
1639
- function createDelegateActivity(delegate, reasoning) {
1640
- return {
1641
- type: "delegate",
1642
- id: "",
1643
- expertKey: "",
1644
- runId: "",
1645
- reasoning,
1646
- delegateExpertKey: delegate.expert.key,
1647
- query: delegate.query
1648
- };
1649
- }
1650
- function createInteractiveToolActivity(skillName, toolName, toolCall, reasoning) {
1651
- return {
1652
- type: "interactiveTool",
1653
- id: "",
1654
- expertKey: "",
1655
- runId: "",
1656
- reasoning,
1657
- skillName,
1658
- toolName,
1659
- args: toolCall.args
1660
- };
1661
- }
1662
- function createRetryActivity(newMessages, reasoning, customError) {
1663
- const textPart = newMessages[newMessages.length - 1]?.contents.find((c) => c.type === "textPart");
1664
- return {
1665
- type: "retry",
1666
- id: "",
1667
- expertKey: "",
1668
- runId: "",
1669
- reasoning,
1670
- error: customError ?? "No tool call or result found",
1671
- message: textPart?.text ?? ""
1672
- };
1673
- }
1674
- function createErrorActivity(checkpoint, reasoning) {
1675
- const error = checkpoint.error;
1676
- return {
1677
- type: "error",
1678
- id: "",
1679
- expertKey: "",
1680
- runId: "",
1681
- reasoning,
1682
- error: error?.message ?? "Unknown error",
1683
- errorName: error?.name,
1684
- isRetryable: error?.isRetryable
1685
- };
1686
- }
1687
- function createBaseToolActivity(toolName, toolCall, toolResult, reasoning) {
1688
- const args = toolCall.args;
1689
- const resultContents = toolResult.result;
1690
- const errorText = getErrorFromResult(resultContents);
1691
- const baseFields = {
1692
- id: "",
1693
- expertKey: "",
1694
- runId: "",
1695
- reasoning
1696
- };
1697
- switch (toolName) {
1698
- case "attemptCompletion": {
1699
- const remainingTodos = parseRemainingTodosFromResult(resultContents);
1700
- return {
1701
- type: "attemptCompletion",
1702
- ...baseFields,
1703
- remainingTodos,
1704
- error: errorText
1705
- };
1706
- }
1707
- case "todo": {
1708
- const todos = parseTodosFromResult(resultContents);
1709
- return {
1710
- type: "todo",
1711
- ...baseFields,
1712
- newTodos: Array.isArray(args["newTodos"]) ? args["newTodos"].map(String) : void 0,
1713
- completedTodos: Array.isArray(args["completedTodos"]) ? args["completedTodos"].map(Number) : void 0,
1714
- todos,
1715
- error: errorText
1716
- };
1717
- }
1718
- case "clearTodo": return {
1719
- type: "clearTodo",
1720
- ...baseFields,
1721
- error: errorText
1722
- };
1723
- case "readImageFile": return {
1724
- type: "readImageFile",
1725
- ...baseFields,
1726
- path: String(args["path"] ?? ""),
1727
- mimeType: parseStringField(resultContents, "mimeType"),
1728
- size: parseNumberField(resultContents, "size"),
1729
- error: errorText
1730
- };
1731
- case "readPdfFile": return {
1732
- type: "readPdfFile",
1733
- ...baseFields,
1734
- path: String(args["path"] ?? ""),
1735
- mimeType: parseStringField(resultContents, "mimeType"),
1736
- size: parseNumberField(resultContents, "size"),
1737
- error: errorText
1738
- };
1739
- case "readTextFile": return {
1740
- type: "readTextFile",
1741
- ...baseFields,
1742
- path: String(args["path"] ?? ""),
1743
- content: parseStringField(resultContents, "content"),
1744
- from: typeof args["from"] === "number" ? args["from"] : void 0,
1745
- to: typeof args["to"] === "number" ? args["to"] : void 0,
1746
- error: errorText
1747
- };
1748
- case "editTextFile": return {
1749
- type: "editTextFile",
1750
- ...baseFields,
1751
- path: String(args["path"] ?? ""),
1752
- newText: String(args["newText"] ?? ""),
1753
- oldText: String(args["oldText"] ?? ""),
1754
- error: errorText
1755
- };
1756
- case "writeTextFile": return {
1757
- type: "writeTextFile",
1758
- ...baseFields,
1759
- path: String(args["path"] ?? ""),
1760
- text: String(args["text"] ?? ""),
1761
- error: errorText
1762
- };
1763
- case "exec": return {
1764
- type: "exec",
1765
- ...baseFields,
1766
- command: String(args["command"] ?? ""),
1767
- args: Array.isArray(args["args"]) ? args["args"].map(String) : [],
1768
- cwd: String(args["cwd"] ?? ""),
1769
- output: parseStringField(resultContents, "output"),
1770
- error: errorText,
1771
- stdout: parseStringField(resultContents, "stdout"),
1772
- stderr: parseStringField(resultContents, "stderr")
1773
- };
1774
- case "addSkill": return {
1775
- type: "addSkill",
1776
- ...baseFields,
1777
- name: String(args["name"] ?? ""),
1778
- skillType: String(args["type"] ?? ""),
1779
- tools: parseStringArrayField(resultContents, "tools"),
1780
- error: errorText
1781
- };
1782
- case "removeSkill": return {
1783
- type: "removeSkill",
1784
- ...baseFields,
1785
- skillName: String(args["skillName"] ?? ""),
1786
- error: errorText
1787
- };
1788
- case "addDelegate": return {
1789
- type: "addDelegate",
1790
- ...baseFields,
1791
- targetExpertKey: String(args["expertKey"] ?? ""),
1792
- delegateToolName: parseStringField(resultContents, "delegateToolName"),
1793
- error: errorText
1794
- };
1795
- case "removeDelegate": return {
1796
- type: "removeDelegate",
1797
- ...baseFields,
1798
- expertName: String(args["expertName"] ?? ""),
1799
- error: errorText
1800
- };
1801
- case "createExpert": return {
1802
- type: "createExpert",
1803
- ...baseFields,
1804
- targetKey: String(args["key"] ?? ""),
1805
- description: typeof args["description"] === "string" ? args["description"] : void 0,
1806
- resultExpertKey: parseStringField(resultContents, "expertKey"),
1807
- error: errorText
1808
- };
1809
- default: return createGeneralToolActivity(toolCall.skillName, toolName, toolCall, toolResult, reasoning);
1810
- }
1811
- }
1812
- function createGeneralToolActivity(skillName, toolName, toolCall, toolResult, reasoning) {
1813
- const errorText = getErrorFromResult(toolResult.result);
1814
- return {
1815
- type: "generalTool",
1816
- id: "",
1817
- expertKey: "",
1818
- runId: "",
1819
- reasoning,
1820
- skillName,
1821
- toolName,
1822
- args: toolCall.args,
1823
- result: toolResult.result,
1824
- error: errorText
1825
- };
1826
- }
1827
- function getErrorFromResult(result) {
1828
- const textPart = result.find((p) => p.type === "textPart");
1829
- if (!textPart?.text) return void 0;
1830
- try {
1831
- const parsed = JSON.parse(textPart.text);
1832
- if (typeof parsed.error === "string") return parsed.error;
1833
- } catch {
1834
- const trimmed = textPart.text.trim();
1835
- if (trimmed.toLowerCase().startsWith("error:") || trimmed.toLowerCase().startsWith("error ")) return textPart.text;
1836
- }
1837
- }
1838
- function parseStringField(result, field) {
1839
- const textPart = result.find((p) => p.type === "textPart");
1840
- if (!textPart?.text) return void 0;
1841
- try {
1842
- const parsed = JSON.parse(textPart.text);
1843
- return typeof parsed[field] === "string" ? parsed[field] : void 0;
1844
- } catch {
1845
- return;
1846
- }
1847
- }
1848
- function parseNumberField(result, field) {
1849
- const textPart = result.find((p) => p.type === "textPart");
1850
- if (!textPart?.text) return void 0;
1851
- try {
1852
- const parsed = JSON.parse(textPart.text);
1853
- return typeof parsed[field] === "number" ? parsed[field] : void 0;
1854
- } catch {
1855
- return;
1856
- }
1857
- }
1858
- function parseStringArrayField(result, field) {
1859
- const textPart = result.find((p) => p.type === "textPart");
1860
- if (!textPart?.text) return void 0;
1861
- try {
1862
- const parsed = JSON.parse(textPart.text);
1863
- if (Array.isArray(parsed[field])) return parsed[field].map(String);
1864
- } catch {}
1865
- }
1866
- function parseRemainingTodosFromResult(result) {
1867
- const textPart = result.find((p) => p.type === "textPart");
1868
- if (!textPart?.text) return void 0;
1869
- try {
1870
- const parsed = JSON.parse(textPart.text);
1871
- if (Array.isArray(parsed.remainingTodos)) return parsed.remainingTodos.map((t, i) => ({
1872
- id: typeof t.id === "number" ? t.id : i,
1873
- title: typeof t.title === "string" ? t.title : "",
1874
- completed: typeof t.completed === "boolean" ? t.completed : false
1875
- }));
1876
- } catch {}
1877
- }
1878
- function parseTodosFromResult(result) {
1879
- const textPart = result.find((p) => p.type === "textPart");
1880
- if (!textPart?.text) return [];
1881
- try {
1882
- const parsed = JSON.parse(textPart.text);
1883
- if (Array.isArray(parsed.todos)) return parsed.todos.map((t, i) => ({
1884
- id: typeof t.id === "number" ? t.id : i,
1885
- title: typeof t.title === "string" ? t.title : "",
1886
- completed: typeof t.completed === "boolean" ? t.completed : false
1887
- }));
1888
- } catch {}
1889
- return [];
1890
- }
1891
-
1892
- //#endregion
1893
- //#region src/utils/env-filter.ts
1894
- const SAFE_ENV_VARS = [
1895
- "PATH",
1896
- "HOME",
1897
- "SHELL",
1898
- "TERM",
1899
- "NODE_PATH",
1900
- "HTTP_PROXY",
1901
- "HTTPS_PROXY",
1902
- "http_proxy",
1903
- "https_proxy",
1904
- "NO_PROXY",
1905
- "no_proxy",
1906
- "PERSTACK_PROXY_URL",
1907
- "NPM_CONFIG_PROXY",
1908
- "NPM_CONFIG_HTTPS_PROXY"
1909
- ];
1910
- const PROTECTED_ENV_VARS = new Set([
1911
- "PATH",
1912
- "HOME",
1913
- "SHELL",
1914
- "NODE_PATH",
1915
- "LD_PRELOAD",
1916
- "LD_LIBRARY_PATH",
1917
- "DYLD_INSERT_LIBRARIES",
1918
- "DYLD_LIBRARY_PATH",
1919
- "NODE_OPTIONS",
1920
- "PYTHONPATH",
1921
- "PERL5LIB",
1922
- "RUBYLIB"
1923
- ]);
1924
- function getFilteredEnv(additional) {
1925
- const filtered = {};
1926
- for (const key of SAFE_ENV_VARS) if (process.env[key]) filtered[key] = process.env[key];
1927
- if (additional) {
1928
- for (const [key, value] of Object.entries(additional)) if (!PROTECTED_ENV_VARS.has(key.toUpperCase())) filtered[key] = value;
1929
- }
1930
- return filtered;
1931
- }
1932
-
1933
- //#endregion
1934
- //#region src/utils/event-filter.ts
1935
- /**
1936
- * Validate and parse event filter option
1937
- * @param filter - Array of event type strings to validate
1938
- * @returns The validated filter array
1939
- * @throws Error if any event type is invalid
1940
- */
1941
- function validateEventFilter(filter) {
1942
- const invalid = filter.filter((type) => !isValidEventType(type) && !isValidRuntimeEventType(type));
1943
- if (invalid.length > 0) throw new PerstackError(`Invalid event type(s): ${invalid.join(", ")}. Valid event types are: startRun, completeRun, stopRunByError, callTools, etc. See documentation for full list.`);
1944
- return filter;
1945
- }
1946
- /**
1947
- * Create a filtered event listener that only emits events of allowed types
1948
- * @param listener - The original event listener to wrap
1949
- * @param allowedTypes - Set of event types to allow through
1950
- * @returns A filtered event listener
1951
- */
1952
- function createFilteredEventListener(listener, allowedTypes) {
1953
- return (event) => {
1954
- if (allowedTypes.has(event.type)) listener(event);
1955
- };
1956
- }
1957
-
1958
- //#endregion
1959
- //#region src/utils/zod-error.ts
1960
- function formatZodError(error) {
1961
- return `Validation failed:\n${error.issues.map((issue) => {
1962
- return ` - ${issue.path.length > 0 ? `${issue.path.join(".")}: ` : ""}${issue.message}`;
1963
- }).join("\n")}`;
1964
- }
1965
- function parseWithFriendlyError(schema, data, context) {
1966
- const result = schema.safeParse(data);
1967
- if (result.success) return result.data;
1968
- throw new PerstackError(`${context ? `${context}: ` : ""}${formatZodError(result.error)}`);
1969
- }
1970
-
1971
- //#endregion
1972
- export { BASE_SKILL_PREFIX, PerstackError, SAFE_ENV_VARS, activityOrGroupSchema, activitySchema, addDelegateActivitySchema, addSkillActivitySchema, amazonBedrockProviderConfigSchema, anthropicProviderConfigSchema, anthropicProviderSkillSchema, anthropicProviderToolNameSchema, attemptCompletionActivitySchema, azureOpenAIProviderToolNameSchema, azureOpenAiProviderConfigSchema, basePartSchema, builtinAnthropicSkillSchema, callTools, checkpointSchema, checkpointStatusSchema, clearTodoActivitySchema, completeActivitySchema, completeRun, continueToNextStep, createBaseToolActivity, createCallToolsEvent, createCompleteRunEvent, createEmptyUsage, createEvent, createExpertActivitySchema, createFilteredEventListener, createGeneralToolActivity, createNormalizedCheckpoint, createResolveToolResultsEvent, createRuntimeEvent, createRuntimeInitEvent, createStartRunEvent, createStreamingEvent, createToolMessage, customAnthropicSkillSchema, deepseekProviderConfigSchema, defaultMaxRetries, defaultPerstackApiBaseUrl, defaultReasoningBudget, defaultTimeout, delegateActivitySchema, delegationCompleteActivitySchema, delegationTargetSchema, domainPatternSchema, editTextFileActivitySchema, errorActivitySchema, execActivitySchema, expertBaseSchema, expertKeyRegex, expertMessageSchema, expertNameRegex, expertSchema, expertVersionRegex, fileBinaryPartSchema, fileInlinePartSchema, fileSearchOptionsSchema, fileUrlPartSchema, finishMcpTools, finishToolCall, formatZodError, generalToolActivitySchema, getActivities, getExpertScope, getExpertShortName, getExpertType, getFilteredEnv, googleGenerativeAiProviderConfigSchema, googleProviderToolNameSchema, googleVertexProviderConfigSchema, headersSchema, imageBinaryPartSchema, imageInlinePartSchema, imageUrlPartSchema, instructionMessageSchema, interactiveSkillSchema, interactiveToolActivitySchema, interactiveToolSchema, isCoordinatorExpert, isDelegateExpert, isPrivateOrLocalIP, isValidEventType, isValidRuntimeEventType, jobSchema, jobStatusSchema, knownModels, lockfileExpertSchema, lockfileSchema, lockfileToolDefinitionSchema, maxExpertNameLength, maxSkillNameLength, maxSkillToolNameLength, mcpSseSkillSchema, mcpStdioSkillSchema, messagePartSchema, messageSchema, ollamaProviderConfigSchema, openAiProviderConfigSchema, openaiProviderToolNameSchema, parallelActivitiesGroupSchema, parseExpertKey, parseWithFriendlyError, perstackConfigSchema, proceedToInteractiveTools, providerConfigSchema, providerNameSchema, providerTableSchema, providerToolOptionsSchema, queryActivitySchema, readImageFileActivitySchema, readPdfFileActivitySchema, readTextFileActivitySchema, reasoningBudgetSchema, removeDelegateActivitySchema, removeSkillActivitySchema, resolveToolResults, resumeFromStop, resumeToolCalls, retry, retryActivitySchema, runCommandInputSchema, runParamsSchema, runSettingSchema, runtimeVersionSchema, skillSchema, skipDelegates, startCommandInputSchema, startGeneration, startRun, stepSchema, stopRunByDelegate, stopRunByError, stopRunByInteractiveTool, tagNameRegex, textPartSchema, thinkingPartSchema, todoActivitySchema, toolCallPartSchema, toolCallSchema, toolMessageSchema, toolResultPartSchema, toolResultSchema, usageSchema, userMessageSchema, validateAllDelegations, validateDelegation, validateEventFilter, vertexProviderToolNameSchema, webFetchOptionsSchema, webSearchOptionsSchema, writeTextFileActivitySchema };
1
+ export * from "./adapters/index.js";
2
+ export * from "./constants/constants.js";
3
+ export * from "./errors.js";
4
+ export * from "./known-models/index.js";
5
+ export * from "./schemas/activity.js";
6
+ export * from "./schemas/checkpoint.js";
7
+ export * from "./schemas/expert.js";
8
+ export * from "./schemas/job.js";
9
+ export * from "./schemas/lockfile.js";
10
+ export * from "./schemas/message.js";
11
+ export * from "./schemas/message-part.js";
12
+ export * from "./schemas/perstack-toml.js";
13
+ export * from "./schemas/provider-config.js";
14
+ export * from "./schemas/provider-tools.js";
15
+ export * from "./schemas/run-command.js";
16
+ export * from "./schemas/runtime.js";
17
+ export * from "./schemas/runtime-version.js";
18
+ export * from "./schemas/skill.js";
19
+ export * from "./schemas/skill-manager.js";
20
+ export * from "./schemas/step.js";
21
+ export * from "./schemas/tool-call.js";
22
+ export * from "./schemas/tool-result.js";
23
+ export * from "./schemas/usage.js";
24
+ export * from "./utils/activity.js";
25
+ export * from "./utils/env-filter.js";
26
+ export * from "./utils/event-filter.js";
27
+ export * from "./utils/expert-type.js";
28
+ export * from "./utils/zod-error.js";
1973
29
  //# sourceMappingURL=index.js.map