@perstack/runtime 0.0.63 → 0.0.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,38 @@ This package serves as the engine of Perstack. It orchestrates the lifecycle of
10
10
  npm install @perstack/runtime
11
11
  ```
12
12
 
13
- ## Usage
13
+ ## CLI Usage
14
+
15
+ The runtime can be executed as a standalone CLI:
16
+
17
+ ```bash
18
+ perstack-runtime run <expertKey> <query> [options]
19
+ ```
20
+
21
+ ### Options
22
+
23
+ | Option | Description |
24
+ | ----------------------- | ----------------------- |
25
+ | `--config <path>` | Path to perstack.toml |
26
+ | `--provider <provider>` | LLM provider |
27
+ | `--model <model>` | Model name |
28
+ | `--temperature <temp>` | Temperature (0.0-1.0) |
29
+ | `--max-steps <n>` | Maximum steps |
30
+ | `--max-retries <n>` | Maximum retries |
31
+ | `--timeout <ms>` | Timeout in milliseconds |
32
+ | `--job-id <id>` | Job ID |
33
+ | `--run-id <id>` | Run ID |
34
+ | `--env-path <path...>` | Environment file paths |
35
+
36
+ ### Example
37
+
38
+ ```bash
39
+ perstack-runtime run my-expert "What is the weather?" --config ./perstack.toml
40
+ ```
41
+
42
+ Output is JSON events (one per line) to stdout.
43
+
44
+ ## Programmatic Usage
14
45
 
15
46
  The primary entry point is the `run` function. It takes a `JobSetting` object and an optional `RunOptions` object.
16
47
 
@@ -261,8 +292,66 @@ The `status` field in a Checkpoint indicates the current state:
261
292
 
262
293
  For stop reasons and error handling, see [Error Handling](https://docs.perstack.ai/using-experts/error-handling).
263
294
 
295
+ ## Runtime Adapters
296
+
297
+ The runtime supports multiple execution backends through the adapter pattern. External runtime adapters are provided as separate packages:
298
+
299
+ | Package | Runtime Name | Description |
300
+ | ----------------------- | ------------- | -------------------------- |
301
+ | `@perstack/runtime` | `perstack` | Built-in runtime (default) |
302
+ | `@perstack/cursor` | `cursor` | Cursor IDE headless mode |
303
+ | `@perstack/claude-code` | `claude-code` | Claude Code CLI |
304
+ | `@perstack/gemini` | `gemini` | Gemini CLI |
305
+
306
+ ### Registration Pattern
307
+
308
+ External adapters must be registered before use:
309
+
310
+ ```typescript
311
+ import { CursorAdapter } from "@perstack/cursor"
312
+ import { getAdapter, isAdapterAvailable, registerAdapter } from "@perstack/runtime"
313
+
314
+ // Register external adapter
315
+ registerAdapter("cursor", () => new CursorAdapter())
316
+
317
+ // Check availability
318
+ if (isAdapterAvailable("cursor")) {
319
+ const adapter = getAdapter("cursor")
320
+ const result = await adapter.checkPrerequisites()
321
+ if (result.ok) {
322
+ await adapter.run({ setting, eventListener })
323
+ }
324
+ }
325
+ ```
326
+
327
+ ### Creating Custom Adapters
328
+
329
+ Extend `BaseAdapter` from `@perstack/core` for CLI-based runtimes:
330
+
331
+ ```typescript
332
+ import { BaseAdapter, type AdapterRunParams, type AdapterRunResult, type PrerequisiteResult } from "@perstack/core"
333
+
334
+ class MyAdapter extends BaseAdapter {
335
+ readonly name = "my-runtime"
336
+
337
+ async checkPrerequisites(): Promise<PrerequisiteResult> {
338
+ const result = await this.execCommand(["my-cli", "--version"])
339
+ return result.exitCode === 0
340
+ ? { ok: true }
341
+ : { ok: false, error: { type: "cli-not-found", message: "..." } }
342
+ }
343
+
344
+ async run(params: AdapterRunParams): Promise<AdapterRunResult> {
345
+ // Implementation
346
+ }
347
+ }
348
+ ```
349
+
350
+ See [Multi-Runtime Support](https://docs.perstack.ai/using-experts/multi-runtime) for details.
351
+
264
352
  ## Related Documentation
265
353
 
266
354
  - [Runtime](https://docs.perstack.ai/understanding-perstack/runtime) — Full execution model
267
355
  - [State Management](https://docs.perstack.ai/using-experts/state-management) — Jobs, Runs, and Checkpoints
268
356
  - [Running Experts](https://docs.perstack.ai/using-experts/running-experts) — CLI usage
357
+ - [Multi-Runtime](https://docs.perstack.ai/using-experts/multi-runtime) — Multi-runtime support
package/bin/cli.ts ADDED
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+
3
+ import type { Checkpoint, RunEvent, RuntimeEvent } from "@perstack/core"
4
+ import { parseWithFriendlyError, runCommandInputSchema } from "@perstack/core"
5
+ import { Command } from "commander"
6
+ import pkg from "../package.json" with { type: "json" }
7
+ import { resolveRunContext } from "../src/cli/context.js"
8
+ import { run } from "../src/run.js"
9
+
10
+ const defaultEventListener = (event: RunEvent | RuntimeEvent) => console.log(JSON.stringify(event))
11
+
12
+ const checkpointStore = new Map<string, Checkpoint>()
13
+ const storeCheckpoint = async (checkpoint: Checkpoint) => {
14
+ checkpointStore.set(checkpoint.id, checkpoint)
15
+ }
16
+ const retrieveCheckpoint = async (_jobId: string, checkpointId: string) => {
17
+ const checkpoint = checkpointStore.get(checkpointId)
18
+ if (!checkpoint) {
19
+ throw new Error(`Checkpoint not found: ${checkpointId}`)
20
+ }
21
+ return checkpoint
22
+ }
23
+
24
+ const program = new Command()
25
+ .name("perstack-runtime")
26
+ .description("Perstack Runtime CLI - Execute Experts directly")
27
+ .version(pkg.version)
28
+
29
+ program
30
+ .command("run")
31
+ .description("Run an Expert with JSON event output")
32
+ .argument("<expertKey>", "Expert key to run")
33
+ .argument("<query>", "Query to run")
34
+ .option("--config <configPath>", "Path to perstack.toml config file")
35
+ .option("--provider <provider>", "Provider to use")
36
+ .option("--model <model>", "Model to use")
37
+ .option("--temperature <temperature>", "Temperature for the model, default is 0.3")
38
+ .option(
39
+ "--max-steps <maxSteps>",
40
+ "Maximum number of steps to run, default is undefined (no limit)",
41
+ )
42
+ .option("--max-retries <maxRetries>", "Maximum number of generation retries, default is 5")
43
+ .option(
44
+ "--timeout <timeout>",
45
+ "Timeout for each generation in milliseconds, default is 60000 (1 minute)",
46
+ )
47
+ .option("--job-id <jobId>", "Job ID for identifying the job")
48
+ .option("--run-id <runId>", "Run ID for identifying the run")
49
+ .option("--env-path <envPath...>", "Path to the environment file, default is .env and .env.local")
50
+ .option("--verbose", "Enable verbose logging")
51
+ .action(async (expertKey, query, options) => {
52
+ const input = parseWithFriendlyError(runCommandInputSchema, { expertKey, query, options })
53
+ try {
54
+ const { perstackConfig, env, providerConfig, model, experts } = await resolveRunContext({
55
+ configPath: input.options.config,
56
+ provider: input.options.provider,
57
+ model: input.options.model,
58
+ envPath: input.options.envPath,
59
+ })
60
+ await run(
61
+ {
62
+ setting: {
63
+ jobId: input.options.jobId,
64
+ runId: input.options.runId,
65
+ expertKey: input.expertKey,
66
+ input: { text: input.query },
67
+ experts,
68
+ model,
69
+ providerConfig,
70
+ temperature: input.options.temperature ?? perstackConfig.temperature,
71
+ maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,
72
+ maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
73
+ timeout: input.options.timeout ?? perstackConfig.timeout,
74
+ perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,
75
+ perstackApiKey: env.PERSTACK_API_KEY,
76
+ perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,
77
+ env,
78
+ proxyUrl: process.env.PERSTACK_PROXY_URL,
79
+ },
80
+ },
81
+ { eventListener: defaultEventListener, storeCheckpoint, retrieveCheckpoint },
82
+ )
83
+ } catch (error) {
84
+ if (error instanceof Error) {
85
+ console.error(error.message)
86
+ } else {
87
+ console.error(error)
88
+ }
89
+ process.exit(1)
90
+ }
91
+ })
92
+
93
+ program.parse()
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+ import { package_default, run } from '../chunk-C7AFEVYF.js';
3
+ import { parseWithFriendlyError, runCommandInputSchema, perstackConfigSchema } from '@perstack/core';
4
+ import { Command } from 'commander';
5
+ import dotenv from 'dotenv';
6
+ import { readFile } from 'fs/promises';
7
+ import path from 'path';
8
+ import TOML from 'smol-toml';
9
+
10
+ function getEnv(envPath) {
11
+ const env = Object.fromEntries(
12
+ Object.entries(process.env).filter(([_, value]) => !!value).map(([key, value]) => [key, value])
13
+ );
14
+ dotenv.config({ path: envPath, processEnv: env, quiet: true });
15
+ return env;
16
+ }
17
+ async function getPerstackConfig(configPath) {
18
+ const configString = await findPerstackConfigString(configPath);
19
+ if (configString === null) {
20
+ throw new Error("perstack.toml not found. Create one or specify --config path.");
21
+ }
22
+ return await parsePerstackConfig(configString);
23
+ }
24
+ async function findPerstackConfigString(configPath) {
25
+ if (configPath) {
26
+ try {
27
+ const tomlString = await readFile(path.resolve(process.cwd(), configPath), "utf-8");
28
+ return tomlString;
29
+ } catch {
30
+ throw new Error(`Given config path "${configPath}" is not found`);
31
+ }
32
+ }
33
+ return await findPerstackConfigStringRecursively(path.resolve(process.cwd()));
34
+ }
35
+ async function findPerstackConfigStringRecursively(cwd) {
36
+ try {
37
+ const tomlString = await readFile(path.resolve(cwd, "perstack.toml"), "utf-8");
38
+ return tomlString;
39
+ } catch {
40
+ if (cwd === path.parse(cwd).root) {
41
+ return null;
42
+ }
43
+ return await findPerstackConfigStringRecursively(path.dirname(cwd));
44
+ }
45
+ }
46
+ async function parsePerstackConfig(config) {
47
+ const toml = TOML.parse(config ?? "");
48
+ return parseWithFriendlyError(perstackConfigSchema, toml, "perstack.toml");
49
+ }
50
+
51
+ // src/cli/provider-config.ts
52
+ function getProviderConfig(provider, env, providerTable) {
53
+ const setting = providerTable?.setting ?? {};
54
+ switch (provider) {
55
+ case "anthropic": {
56
+ const apiKey = env.ANTHROPIC_API_KEY;
57
+ if (!apiKey) throw new Error("ANTHROPIC_API_KEY is not set");
58
+ return {
59
+ providerName: "anthropic",
60
+ apiKey,
61
+ baseUrl: setting.baseUrl ?? env.ANTHROPIC_BASE_URL,
62
+ headers: setting.headers
63
+ };
64
+ }
65
+ case "google": {
66
+ const apiKey = env.GOOGLE_GENERATIVE_AI_API_KEY;
67
+ if (!apiKey) throw new Error("GOOGLE_GENERATIVE_AI_API_KEY is not set");
68
+ return {
69
+ providerName: "google",
70
+ apiKey,
71
+ baseUrl: setting.baseUrl ?? env.GOOGLE_GENERATIVE_AI_BASE_URL,
72
+ headers: setting.headers
73
+ };
74
+ }
75
+ case "openai": {
76
+ const apiKey = env.OPENAI_API_KEY;
77
+ if (!apiKey) throw new Error("OPENAI_API_KEY is not set");
78
+ return {
79
+ providerName: "openai",
80
+ apiKey,
81
+ baseUrl: setting.baseUrl ?? env.OPENAI_BASE_URL,
82
+ organization: setting.organization ?? env.OPENAI_ORGANIZATION,
83
+ project: setting.project ?? env.OPENAI_PROJECT,
84
+ name: setting.name,
85
+ headers: setting.headers
86
+ };
87
+ }
88
+ case "ollama": {
89
+ return {
90
+ providerName: "ollama",
91
+ baseUrl: setting.baseUrl ?? env.OLLAMA_BASE_URL,
92
+ headers: setting.headers
93
+ };
94
+ }
95
+ case "azure-openai": {
96
+ const apiKey = env.AZURE_API_KEY;
97
+ if (!apiKey) throw new Error("AZURE_API_KEY is not set");
98
+ const resourceName = setting.resourceName ?? env.AZURE_RESOURCE_NAME;
99
+ const baseUrl = setting.baseUrl ?? env.AZURE_BASE_URL;
100
+ if (!resourceName && !baseUrl) throw new Error("AZURE_RESOURCE_NAME or baseUrl is not set");
101
+ return {
102
+ providerName: "azure-openai",
103
+ apiKey,
104
+ resourceName,
105
+ apiVersion: setting.apiVersion ?? env.AZURE_API_VERSION,
106
+ baseUrl,
107
+ headers: setting.headers,
108
+ useDeploymentBasedUrls: setting.useDeploymentBasedUrls
109
+ };
110
+ }
111
+ case "amazon-bedrock": {
112
+ const accessKeyId = env.AWS_ACCESS_KEY_ID;
113
+ const secretAccessKey = env.AWS_SECRET_ACCESS_KEY;
114
+ const sessionToken = env.AWS_SESSION_TOKEN;
115
+ if (!accessKeyId) throw new Error("AWS_ACCESS_KEY_ID is not set");
116
+ if (!secretAccessKey) throw new Error("AWS_SECRET_ACCESS_KEY is not set");
117
+ const region = setting.region ?? env.AWS_REGION;
118
+ if (!region) throw new Error("AWS_REGION is not set");
119
+ return {
120
+ providerName: "amazon-bedrock",
121
+ accessKeyId,
122
+ secretAccessKey,
123
+ region,
124
+ sessionToken
125
+ };
126
+ }
127
+ case "google-vertex": {
128
+ return {
129
+ providerName: "google-vertex",
130
+ project: setting.project ?? env.GOOGLE_VERTEX_PROJECT,
131
+ location: setting.location ?? env.GOOGLE_VERTEX_LOCATION,
132
+ baseUrl: setting.baseUrl ?? env.GOOGLE_VERTEX_BASE_URL,
133
+ headers: setting.headers
134
+ };
135
+ }
136
+ case "deepseek": {
137
+ const apiKey = env.DEEPSEEK_API_KEY;
138
+ if (!apiKey) throw new Error("DEEPSEEK_API_KEY is not set");
139
+ return {
140
+ providerName: "deepseek",
141
+ apiKey,
142
+ baseUrl: setting.baseUrl ?? env.DEEPSEEK_BASE_URL,
143
+ headers: setting.headers
144
+ };
145
+ }
146
+ }
147
+ }
148
+
149
+ // src/cli/context.ts
150
+ var defaultProvider = "anthropic";
151
+ var defaultModel = "claude-sonnet-4-5";
152
+ async function resolveRunContext(input) {
153
+ const perstackConfig = await getPerstackConfig(input.configPath);
154
+ const env = getEnv(input.envPath ?? perstackConfig.envPath ?? [".env", ".env.local"]);
155
+ const provider = input.provider ?? perstackConfig.provider?.providerName ?? defaultProvider;
156
+ const model = input.model ?? perstackConfig.model ?? defaultModel;
157
+ const providerConfig = getProviderConfig(provider, env, perstackConfig.provider);
158
+ const experts = Object.fromEntries(
159
+ Object.entries(perstackConfig.experts ?? {}).map(([name, expert]) => {
160
+ return [
161
+ name,
162
+ {
163
+ key: name,
164
+ name,
165
+ version: expert.version ?? "1.0.0",
166
+ description: expert.description,
167
+ instruction: expert.instruction,
168
+ skills: expert.skills ?? {},
169
+ delegates: expert.delegates ?? [],
170
+ tags: expert.tags ?? []
171
+ }
172
+ ];
173
+ })
174
+ );
175
+ return {
176
+ perstackConfig,
177
+ env,
178
+ providerConfig,
179
+ model,
180
+ experts
181
+ };
182
+ }
183
+
184
+ // bin/cli.ts
185
+ var defaultEventListener = (event) => console.log(JSON.stringify(event));
186
+ var checkpointStore = /* @__PURE__ */ new Map();
187
+ var storeCheckpoint = async (checkpoint) => {
188
+ checkpointStore.set(checkpoint.id, checkpoint);
189
+ };
190
+ var retrieveCheckpoint = async (_jobId, checkpointId) => {
191
+ const checkpoint = checkpointStore.get(checkpointId);
192
+ if (!checkpoint) {
193
+ throw new Error(`Checkpoint not found: ${checkpointId}`);
194
+ }
195
+ return checkpoint;
196
+ };
197
+ var program = new Command().name("perstack-runtime").description("Perstack Runtime CLI - Execute Experts directly").version(package_default.version);
198
+ program.command("run").description("Run an Expert with JSON event output").argument("<expertKey>", "Expert key to run").argument("<query>", "Query to run").option("--config <configPath>", "Path to perstack.toml config file").option("--provider <provider>", "Provider to use").option("--model <model>", "Model to use").option("--temperature <temperature>", "Temperature for the model, default is 0.3").option(
199
+ "--max-steps <maxSteps>",
200
+ "Maximum number of steps to run, default is undefined (no limit)"
201
+ ).option("--max-retries <maxRetries>", "Maximum number of generation retries, default is 5").option(
202
+ "--timeout <timeout>",
203
+ "Timeout for each generation in milliseconds, default is 60000 (1 minute)"
204
+ ).option("--job-id <jobId>", "Job ID for identifying the job").option("--run-id <runId>", "Run ID for identifying the run").option("--env-path <envPath...>", "Path to the environment file, default is .env and .env.local").option("--verbose", "Enable verbose logging").action(async (expertKey, query, options) => {
205
+ const input = parseWithFriendlyError(runCommandInputSchema, { expertKey, query, options });
206
+ try {
207
+ const { perstackConfig, env, providerConfig, model, experts } = await resolveRunContext({
208
+ configPath: input.options.config,
209
+ provider: input.options.provider,
210
+ model: input.options.model,
211
+ envPath: input.options.envPath
212
+ });
213
+ await run(
214
+ {
215
+ setting: {
216
+ jobId: input.options.jobId,
217
+ runId: input.options.runId,
218
+ expertKey: input.expertKey,
219
+ input: { text: input.query },
220
+ experts,
221
+ model,
222
+ providerConfig,
223
+ temperature: input.options.temperature ?? perstackConfig.temperature,
224
+ maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,
225
+ maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
226
+ timeout: input.options.timeout ?? perstackConfig.timeout,
227
+ perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,
228
+ perstackApiKey: env.PERSTACK_API_KEY,
229
+ perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,
230
+ env,
231
+ proxyUrl: process.env.PERSTACK_PROXY_URL
232
+ }
233
+ },
234
+ { eventListener: defaultEventListener, storeCheckpoint, retrieveCheckpoint }
235
+ );
236
+ } catch (error) {
237
+ if (error instanceof Error) {
238
+ console.error(error.message);
239
+ } else {
240
+ console.error(error);
241
+ }
242
+ process.exit(1);
243
+ }
244
+ });
245
+ program.parse();
246
+ //# sourceMappingURL=cli.js.map
247
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/get-env.ts","../../src/cli/perstack-toml.ts","../../src/cli/provider-config.ts","../../src/cli/context.ts","../../bin/cli.ts"],"names":["parseWithFriendlyError"],"mappings":"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","file":"cli.js","sourcesContent":["import dotenv from \"dotenv\"\n\nexport function getEnv(envPath: string[]): Record<string, string> {\n const env: Record<string, string> = Object.fromEntries(\n Object.entries(process.env)\n .filter(([_, value]) => !!value)\n .map(([key, value]) => [key, value as string]),\n )\n dotenv.config({ path: envPath, processEnv: env, quiet: true })\n return env\n}\n","import { readFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { type PerstackConfig, parseWithFriendlyError, perstackConfigSchema } from \"@perstack/core\"\nimport TOML from \"smol-toml\"\n\nexport async function getPerstackConfig(configPath?: string): Promise<PerstackConfig> {\n const configString = await findPerstackConfigString(configPath)\n if (configString === null) {\n throw new Error(\"perstack.toml not found. Create one or specify --config path.\")\n }\n return await parsePerstackConfig(configString)\n}\n\nasync function findPerstackConfigString(configPath?: string): Promise<string | null> {\n if (configPath) {\n try {\n const tomlString = await readFile(path.resolve(process.cwd(), configPath), \"utf-8\")\n return tomlString\n } catch {\n throw new Error(`Given config path \"${configPath}\" is not found`)\n }\n }\n return await findPerstackConfigStringRecursively(path.resolve(process.cwd()))\n}\n\nasync function findPerstackConfigStringRecursively(cwd: string): Promise<string | null> {\n try {\n const tomlString = await readFile(path.resolve(cwd, \"perstack.toml\"), \"utf-8\")\n return tomlString\n } catch {\n if (cwd === path.parse(cwd).root) {\n return null\n }\n return await findPerstackConfigStringRecursively(path.dirname(cwd))\n }\n}\n\nasync function parsePerstackConfig(config: string): Promise<PerstackConfig> {\n const toml = TOML.parse(config ?? \"\")\n return parseWithFriendlyError(perstackConfigSchema, toml, \"perstack.toml\")\n}\n","import type { ProviderConfig, ProviderName, ProviderTable } from \"@perstack/core\"\n\ntype SettingRecord = Record<string, unknown>\n\nexport function getProviderConfig(\n provider: ProviderName,\n env: Record<string, string>,\n providerTable?: ProviderTable,\n): ProviderConfig {\n const setting = (providerTable?.setting ?? {}) as SettingRecord\n switch (provider) {\n case \"anthropic\": {\n const apiKey = env.ANTHROPIC_API_KEY\n if (!apiKey) throw new Error(\"ANTHROPIC_API_KEY is not set\")\n return {\n providerName: \"anthropic\",\n apiKey,\n baseUrl: (setting.baseUrl as string | undefined) ?? env.ANTHROPIC_BASE_URL,\n headers: setting.headers as Record<string, string> | undefined,\n }\n }\n case \"google\": {\n const apiKey = env.GOOGLE_GENERATIVE_AI_API_KEY\n if (!apiKey) throw new Error(\"GOOGLE_GENERATIVE_AI_API_KEY is not set\")\n return {\n providerName: \"google\",\n apiKey,\n baseUrl: (setting.baseUrl as string | undefined) ?? env.GOOGLE_GENERATIVE_AI_BASE_URL,\n headers: setting.headers as Record<string, string> | undefined,\n }\n }\n case \"openai\": {\n const apiKey = env.OPENAI_API_KEY\n if (!apiKey) throw new Error(\"OPENAI_API_KEY is not set\")\n return {\n providerName: \"openai\",\n apiKey,\n baseUrl: (setting.baseUrl as string | undefined) ?? env.OPENAI_BASE_URL,\n organization: (setting.organization as string | undefined) ?? env.OPENAI_ORGANIZATION,\n project: (setting.project as string | undefined) ?? env.OPENAI_PROJECT,\n name: setting.name as string | undefined,\n headers: setting.headers as Record<string, string> | undefined,\n }\n }\n case \"ollama\": {\n return {\n providerName: \"ollama\",\n baseUrl: (setting.baseUrl as string | undefined) ?? env.OLLAMA_BASE_URL,\n headers: setting.headers as Record<string, string> | undefined,\n }\n }\n case \"azure-openai\": {\n const apiKey = env.AZURE_API_KEY\n if (!apiKey) throw new Error(\"AZURE_API_KEY is not set\")\n const resourceName = (setting.resourceName as string | undefined) ?? env.AZURE_RESOURCE_NAME\n const baseUrl = (setting.baseUrl as string | undefined) ?? env.AZURE_BASE_URL\n if (!resourceName && !baseUrl) throw new Error(\"AZURE_RESOURCE_NAME or baseUrl is not set\")\n return {\n providerName: \"azure-openai\",\n apiKey,\n resourceName,\n apiVersion: (setting.apiVersion as string | undefined) ?? env.AZURE_API_VERSION,\n baseUrl,\n headers: setting.headers as Record<string, string> | undefined,\n useDeploymentBasedUrls: setting.useDeploymentBasedUrls as boolean | undefined,\n }\n }\n case \"amazon-bedrock\": {\n const accessKeyId = env.AWS_ACCESS_KEY_ID\n const secretAccessKey = env.AWS_SECRET_ACCESS_KEY\n const sessionToken = env.AWS_SESSION_TOKEN\n if (!accessKeyId) throw new Error(\"AWS_ACCESS_KEY_ID is not set\")\n if (!secretAccessKey) throw new Error(\"AWS_SECRET_ACCESS_KEY is not set\")\n const region = (setting.region as string | undefined) ?? env.AWS_REGION\n if (!region) throw new Error(\"AWS_REGION is not set\")\n return {\n providerName: \"amazon-bedrock\",\n accessKeyId,\n secretAccessKey,\n region,\n sessionToken,\n }\n }\n case \"google-vertex\": {\n return {\n providerName: \"google-vertex\",\n project: (setting.project as string | undefined) ?? env.GOOGLE_VERTEX_PROJECT,\n location: (setting.location as string | undefined) ?? env.GOOGLE_VERTEX_LOCATION,\n baseUrl: (setting.baseUrl as string | undefined) ?? env.GOOGLE_VERTEX_BASE_URL,\n headers: setting.headers as Record<string, string> | undefined,\n }\n }\n case \"deepseek\": {\n const apiKey = env.DEEPSEEK_API_KEY\n if (!apiKey) throw new Error(\"DEEPSEEK_API_KEY is not set\")\n return {\n providerName: \"deepseek\",\n apiKey,\n baseUrl: (setting.baseUrl as string | undefined) ?? env.DEEPSEEK_BASE_URL,\n headers: setting.headers as Record<string, string> | undefined,\n }\n }\n }\n}\n","import type { PerstackConfig, ProviderConfig, ProviderName } from \"@perstack/core\"\nimport { getEnv } from \"./get-env.js\"\nimport { getPerstackConfig } from \"./perstack-toml.js\"\nimport { getProviderConfig } from \"./provider-config.js\"\n\nconst defaultProvider: ProviderName = \"anthropic\"\nconst defaultModel = \"claude-sonnet-4-5\"\n\nexport type ExpertConfig = NonNullable<PerstackConfig[\"experts\"]>[string]\n\nexport type RunContext = {\n perstackConfig: PerstackConfig\n env: Record<string, string>\n providerConfig: ProviderConfig\n model: string\n experts: Record<string, ExpertConfig & { key: string; name: string; version: string }>\n}\n\nexport type ResolveRunContextInput = {\n configPath?: string\n provider?: string\n model?: string\n envPath?: string[]\n}\n\nexport async function resolveRunContext(input: ResolveRunContextInput): Promise<RunContext> {\n const perstackConfig = await getPerstackConfig(input.configPath)\n const env = getEnv(input.envPath ?? perstackConfig.envPath ?? [\".env\", \".env.local\"])\n const provider = (input.provider ??\n perstackConfig.provider?.providerName ??\n defaultProvider) as ProviderName\n const model = input.model ?? perstackConfig.model ?? defaultModel\n const providerConfig = getProviderConfig(provider, env, perstackConfig.provider)\n const experts = Object.fromEntries(\n Object.entries(perstackConfig.experts ?? {}).map(([name, expert]) => {\n return [\n name,\n {\n key: name,\n name,\n version: expert.version ?? \"1.0.0\",\n description: expert.description,\n instruction: expert.instruction,\n skills: expert.skills ?? {},\n delegates: expert.delegates ?? [],\n tags: expert.tags ?? [],\n },\n ]\n }),\n )\n return {\n perstackConfig,\n env,\n providerConfig,\n model,\n experts: experts as Record<\n string,\n ExpertConfig & { key: string; name: string; version: string }\n >,\n }\n}\n","#!/usr/bin/env node\n\nimport type { Checkpoint, RunEvent, RuntimeEvent } from \"@perstack/core\"\nimport { parseWithFriendlyError, runCommandInputSchema } from \"@perstack/core\"\nimport { Command } from \"commander\"\nimport pkg from \"../package.json\" with { type: \"json\" }\nimport { resolveRunContext } from \"../src/cli/context.js\"\nimport { run } from \"../src/run.js\"\n\nconst defaultEventListener = (event: RunEvent | RuntimeEvent) => console.log(JSON.stringify(event))\n\nconst checkpointStore = new Map<string, Checkpoint>()\nconst storeCheckpoint = async (checkpoint: Checkpoint) => {\n checkpointStore.set(checkpoint.id, checkpoint)\n}\nconst retrieveCheckpoint = async (_jobId: string, checkpointId: string) => {\n const checkpoint = checkpointStore.get(checkpointId)\n if (!checkpoint) {\n throw new Error(`Checkpoint not found: ${checkpointId}`)\n }\n return checkpoint\n}\n\nconst program = new Command()\n .name(\"perstack-runtime\")\n .description(\"Perstack Runtime CLI - Execute Experts directly\")\n .version(pkg.version)\n\nprogram\n .command(\"run\")\n .description(\"Run an Expert with JSON event output\")\n .argument(\"<expertKey>\", \"Expert key to run\")\n .argument(\"<query>\", \"Query to run\")\n .option(\"--config <configPath>\", \"Path to perstack.toml config file\")\n .option(\"--provider <provider>\", \"Provider to use\")\n .option(\"--model <model>\", \"Model to use\")\n .option(\"--temperature <temperature>\", \"Temperature for the model, default is 0.3\")\n .option(\n \"--max-steps <maxSteps>\",\n \"Maximum number of steps to run, default is undefined (no limit)\",\n )\n .option(\"--max-retries <maxRetries>\", \"Maximum number of generation retries, default is 5\")\n .option(\n \"--timeout <timeout>\",\n \"Timeout for each generation in milliseconds, default is 60000 (1 minute)\",\n )\n .option(\"--job-id <jobId>\", \"Job ID for identifying the job\")\n .option(\"--run-id <runId>\", \"Run ID for identifying the run\")\n .option(\"--env-path <envPath...>\", \"Path to the environment file, default is .env and .env.local\")\n .option(\"--verbose\", \"Enable verbose logging\")\n .action(async (expertKey, query, options) => {\n const input = parseWithFriendlyError(runCommandInputSchema, { expertKey, query, options })\n try {\n const { perstackConfig, env, providerConfig, model, experts } = await resolveRunContext({\n configPath: input.options.config,\n provider: input.options.provider,\n model: input.options.model,\n envPath: input.options.envPath,\n })\n await run(\n {\n setting: {\n jobId: input.options.jobId,\n runId: input.options.runId,\n expertKey: input.expertKey,\n input: { text: input.query },\n experts,\n model,\n providerConfig,\n temperature: input.options.temperature ?? perstackConfig.temperature,\n maxSteps: input.options.maxSteps ?? perstackConfig.maxSteps,\n maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,\n timeout: input.options.timeout ?? perstackConfig.timeout,\n perstackApiBaseUrl: perstackConfig.perstackApiBaseUrl,\n perstackApiKey: env.PERSTACK_API_KEY,\n perstackBaseSkillCommand: perstackConfig.perstackBaseSkillCommand,\n env,\n proxyUrl: process.env.PERSTACK_PROXY_URL,\n },\n },\n { eventListener: defaultEventListener, storeCheckpoint, retrieveCheckpoint },\n )\n } catch (error) {\n if (error instanceof Error) {\n console.error(error.message)\n } else {\n console.error(error)\n }\n process.exit(1)\n }\n })\n\nprogram.parse()\n"]}