@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 +90 -1
- package/bin/cli.ts +93 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +247 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/chunk-C7AFEVYF.js +2355 -0
- package/dist/chunk-C7AFEVYF.js.map +1 -0
- package/dist/src/index.d.ts +30 -38
- package/dist/src/index.js +158 -2427
- package/dist/src/index.js.map +1 -1
- package/package.json +27 -14
- package/LICENSE +0 -202
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
|
package/dist/bin/cli.js
ADDED
|
@@ -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":";;;;;;;;;AAEO,SAAS,OAAO,OAAA,EAA2C;AAChE,EAAA,MAAM,MAA8B,MAAA,CAAO,WAAA;AAAA,IACzC,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA,CACvB,OAAO,CAAC,CAAC,CAAA,EAAG,KAAK,CAAA,KAAM,CAAC,CAAC,KAAK,CAAA,CAC9B,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM,CAAC,GAAA,EAAK,KAAe,CAAC;AAAA,GACjD;AACA,EAAA,MAAA,CAAO,MAAA,CAAO,EAAE,IAAA,EAAM,OAAA,EAAS,YAAY,GAAA,EAAK,KAAA,EAAO,MAAM,CAAA;AAC7D,EAAA,OAAO,GAAA;AACT;ACLA,eAAsB,kBAAkB,UAAA,EAA8C;AACpF,EAAA,MAAM,YAAA,GAAe,MAAM,wBAAA,CAAyB,UAAU,CAAA;AAC9D,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,MAAM,IAAI,MAAM,+DAA+D,CAAA;AAAA,EACjF;AACA,EAAA,OAAO,MAAM,oBAAoB,YAAY,CAAA;AAC/C;AAEA,eAAe,yBAAyB,UAAA,EAA6C;AACnF,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,MAAM,QAAA,CAAS,IAAA,CAAK,OAAA,CAAQ,QAAQ,GAAA,EAAI,EAAG,UAAU,CAAA,EAAG,OAAO,CAAA;AAClF,MAAA,OAAO,UAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AACN,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,UAAU,CAAA,cAAA,CAAgB,CAAA;AAAA,IAClE;AAAA,EACF;AACA,EAAA,OAAO,MAAM,mCAAA,CAAoC,IAAA,CAAK,QAAQ,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAA;AAC9E;AAEA,eAAe,oCAAoC,GAAA,EAAqC;AACtF,EAAA,IAAI;AACF,IAAA,MAAM,UAAA,GAAa,MAAM,QAAA,CAAS,IAAA,CAAK,QAAQ,GAAA,EAAK,eAAe,GAAG,OAAO,CAAA;AAC7E,IAAA,OAAO,UAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,IAAI,GAAA,KAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,EAAE,IAAA,EAAM;AAChC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,MAAM,mCAAA,CAAoC,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,EACpE;AACF;AAEA,eAAe,oBAAoB,MAAA,EAAyC;AAC1E,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,MAAA,IAAU,EAAE,CAAA;AACpC,EAAA,OAAO,sBAAA,CAAuB,oBAAA,EAAsB,IAAA,EAAM,eAAe,CAAA;AAC3E;;;ACpCO,SAAS,iBAAA,CACd,QAAA,EACA,GAAA,EACA,aAAA,EACgB;AAChB,EAAA,MAAM,OAAA,GAAW,aAAA,EAAe,OAAA,IAAW,EAAC;AAC5C,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAK,WAAA,EAAa;AAChB,MAAA,MAAM,SAAS,GAAA,CAAI,iBAAA;AACnB,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAC3D,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,WAAA;AAAA,QACd,MAAA;AAAA,QACA,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,kBAAA;AAAA,QACxD,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF;AAAA,IACA,KAAK,QAAA,EAAU;AACb,MAAA,MAAM,SAAS,GAAA,CAAI,4BAAA;AACnB,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,yCAAyC,CAAA;AACtE,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,QAAA;AAAA,QACd,MAAA;AAAA,QACA,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,6BAAA;AAAA,QACxD,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF;AAAA,IACA,KAAK,QAAA,EAAU;AACb,MAAA,MAAM,SAAS,GAAA,CAAI,cAAA;AACnB,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,2BAA2B,CAAA;AACxD,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,QAAA;AAAA,QACd,MAAA;AAAA,QACA,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,eAAA;AAAA,QACxD,YAAA,EAAe,OAAA,CAAQ,YAAA,IAAuC,GAAA,CAAI,mBAAA;AAAA,QAClE,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,cAAA;AAAA,QACxD,MAAM,OAAA,CAAQ,IAAA;AAAA,QACd,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF;AAAA,IACA,KAAK,QAAA,EAAU;AACb,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,QAAA;AAAA,QACd,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,eAAA;AAAA,QACxD,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF;AAAA,IACA,KAAK,cAAA,EAAgB;AACnB,MAAA,MAAM,SAAS,GAAA,CAAI,aAAA;AACnB,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,0BAA0B,CAAA;AACvD,MAAA,MAAM,YAAA,GAAgB,OAAA,CAAQ,YAAA,IAAuC,GAAA,CAAI,mBAAA;AACzE,MAAA,MAAM,OAAA,GAAW,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,cAAA;AAC/D,MAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,SAAS,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAC1F,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,cAAA;AAAA,QACd,MAAA;AAAA,QACA,YAAA;AAAA,QACA,UAAA,EAAa,OAAA,CAAQ,UAAA,IAAqC,GAAA,CAAI,iBAAA;AAAA,QAC9D,OAAA;AAAA,QACA,SAAS,OAAA,CAAQ,OAAA;AAAA,QACjB,wBAAwB,OAAA,CAAQ;AAAA,OAClC;AAAA,IACF;AAAA,IACA,KAAK,gBAAA,EAAkB;AACrB,MAAA,MAAM,cAAc,GAAA,CAAI,iBAAA;AACxB,MAAA,MAAM,kBAAkB,GAAA,CAAI,qBAAA;AAC5B,MAAA,MAAM,eAAe,GAAA,CAAI,iBAAA;AACzB,MAAA,IAAI,CAAC,WAAA,EAAa,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAChE,MAAA,IAAI,CAAC,eAAA,EAAiB,MAAM,IAAI,MAAM,kCAAkC,CAAA;AACxE,MAAA,MAAM,MAAA,GAAU,OAAA,CAAQ,MAAA,IAAiC,GAAA,CAAI,UAAA;AAC7D,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,uBAAuB,CAAA;AACpD,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,gBAAA;AAAA,QACd,WAAA;AAAA,QACA,eAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAAA,IACA,KAAK,eAAA,EAAiB;AACpB,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,eAAA;AAAA,QACd,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,qBAAA;AAAA,QACxD,QAAA,EAAW,OAAA,CAAQ,QAAA,IAAmC,GAAA,CAAI,sBAAA;AAAA,QAC1D,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,sBAAA;AAAA,QACxD,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF;AAAA,IACA,KAAK,UAAA,EAAY;AACf,MAAA,MAAM,SAAS,GAAA,CAAI,gBAAA;AACnB,MAAA,IAAI,CAAC,MAAA,EAAQ,MAAM,IAAI,MAAM,6BAA6B,CAAA;AAC1D,MAAA,OAAO;AAAA,QACL,YAAA,EAAc,UAAA;AAAA,QACd,MAAA;AAAA,QACA,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAkC,GAAA,CAAI,iBAAA;AAAA,QACxD,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF;AAAA;AAEJ;;;AClGA,IAAM,eAAA,GAAgC,WAAA;AACtC,IAAM,YAAA,GAAe,mBAAA;AAmBrB,eAAsB,kBAAkB,KAAA,EAAoD;AAC1F,EAAA,MAAM,cAAA,GAAiB,MAAM,iBAAA,CAAkB,KAAA,CAAM,UAAU,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,OAAO,KAAA,CAAM,OAAA,IAAW,eAAe,OAAA,IAAW,CAAC,MAAA,EAAQ,YAAY,CAAC,CAAA;AACpF,EAAA,MAAM,QAAA,GAAY,KAAA,CAAM,QAAA,IACtB,cAAA,CAAe,UAAU,YAAA,IACzB,eAAA;AACF,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,IAAS,cAAA,CAAe,KAAA,IAAS,YAAA;AACrD,EAAA,MAAM,cAAA,GAAiB,iBAAA,CAAkB,QAAA,EAAU,GAAA,EAAK,eAAe,QAAQ,CAAA;AAC/E,EAAA,MAAM,UAAU,MAAA,CAAO,WAAA;AAAA,IACrB,MAAA,CAAO,OAAA,CAAQ,cAAA,CAAe,OAAA,IAAW,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,MAAM,CAAA,KAAM;AACnE,MAAA,OAAO;AAAA,QACL,IAAA;AAAA,QACA;AAAA,UACE,GAAA,EAAK,IAAA;AAAA,UACL,IAAA;AAAA,UACA,OAAA,EAAS,OAAO,OAAA,IAAW,OAAA;AAAA,UAC3B,aAAa,MAAA,CAAO,WAAA;AAAA,UACpB,aAAa,MAAA,CAAO,WAAA;AAAA,UACpB,MAAA,EAAQ,MAAA,CAAO,MAAA,IAAU,EAAC;AAAA,UAC1B,SAAA,EAAW,MAAA,CAAO,SAAA,IAAa,EAAC;AAAA,UAChC,IAAA,EAAM,MAAA,CAAO,IAAA,IAAQ;AAAC;AACxB,OACF;AAAA,IACF,CAAC;AAAA,GACH;AACA,EAAA,OAAO;AAAA,IACL,cAAA;AAAA,IACA,GAAA;AAAA,IACA,cAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GAIF;AACF;;;ACnDA,IAAM,oBAAA,GAAuB,CAAC,KAAA,KAAmC,OAAA,CAAQ,IAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAElG,IAAM,eAAA,uBAAsB,GAAA,EAAwB;AACpD,IAAM,eAAA,GAAkB,OAAO,UAAA,KAA2B;AACxD,EAAA,eAAA,CAAgB,GAAA,CAAI,UAAA,CAAW,EAAA,EAAI,UAAU,CAAA;AAC/C,CAAA;AACA,IAAM,kBAAA,GAAqB,OAAO,MAAA,EAAgB,YAAA,KAAyB;AACzE,EAAA,MAAM,UAAA,GAAa,eAAA,CAAgB,GAAA,CAAI,YAAY,CAAA;AACnD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,YAAY,CAAA,CAAE,CAAA;AAAA,EACzD;AACA,EAAA,OAAO,UAAA;AACT,CAAA;AAEA,IAAM,OAAA,GAAU,IAAI,OAAA,EAAQ,CACzB,IAAA,CAAK,kBAAkB,CAAA,CACvB,WAAA,CAAY,iDAAiD,CAAA,CAC7D,OAAA,CAAQ,eAAA,CAAI,OAAO,CAAA;AAEtB,OAAA,CACG,OAAA,CAAQ,KAAK,CAAA,CACb,WAAA,CAAY,sCAAsC,CAAA,CAClD,QAAA,CAAS,aAAA,EAAe,mBAAmB,CAAA,CAC3C,QAAA,CAAS,SAAA,EAAW,cAAc,CAAA,CAClC,MAAA,CAAO,uBAAA,EAAyB,mCAAmC,CAAA,CACnE,MAAA,CAAO,uBAAA,EAAyB,iBAAiB,CAAA,CACjD,MAAA,CAAO,iBAAA,EAAmB,cAAc,CAAA,CACxC,MAAA,CAAO,6BAAA,EAA+B,2CAA2C,CAAA,CACjF,MAAA;AAAA,EACC,wBAAA;AAAA,EACA;AACF,CAAA,CACC,MAAA,CAAO,4BAAA,EAA8B,oDAAoD,CAAA,CACzF,MAAA;AAAA,EACC,qBAAA;AAAA,EACA;AACF,CAAA,CACC,MAAA,CAAO,oBAAoB,gCAAgC,CAAA,CAC3D,OAAO,kBAAA,EAAoB,gCAAgC,EAC3D,MAAA,CAAO,yBAAA,EAA2B,8DAA8D,CAAA,CAChG,MAAA,CAAO,aAAa,wBAAwB,CAAA,CAC5C,OAAO,OAAO,SAAA,EAAW,OAAO,OAAA,KAAY;AAC3C,EAAA,MAAM,QAAQA,sBAAAA,CAAuB,qBAAA,EAAuB,EAAE,SAAA,EAAW,KAAA,EAAO,SAAS,CAAA;AACzF,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,gBAAgB,GAAA,EAAK,cAAA,EAAgB,OAAO,OAAA,EAAQ,GAAI,MAAM,iBAAA,CAAkB;AAAA,MACtF,UAAA,EAAY,MAAM,OAAA,CAAQ,MAAA;AAAA,MAC1B,QAAA,EAAU,MAAM,OAAA,CAAQ,QAAA;AAAA,MACxB,KAAA,EAAO,MAAM,OAAA,CAAQ,KAAA;AAAA,MACrB,OAAA,EAAS,MAAM,OAAA,CAAQ;AAAA,KACxB,CAAA;AACD,IAAA,MAAM,GAAA;AAAA,MACJ;AAAA,QACE,OAAA,EAAS;AAAA,UACP,KAAA,EAAO,MAAM,OAAA,CAAQ,KAAA;AAAA,UACrB,KAAA,EAAO,MAAM,OAAA,CAAQ,KAAA;AAAA,UACrB,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,KAAA,EAAO,EAAE,IAAA,EAAM,KAAA,CAAM,KAAA,EAAM;AAAA,UAC3B,OAAA;AAAA,UACA,KAAA;AAAA,UACA,cAAA;AAAA,UACA,WAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,WAAA,IAAe,cAAA,CAAe,WAAA;AAAA,UACzD,QAAA,EAAU,KAAA,CAAM,OAAA,CAAQ,QAAA,IAAY,cAAA,CAAe,QAAA;AAAA,UACnD,UAAA,EAAY,KAAA,CAAM,OAAA,CAAQ,UAAA,IAAc,cAAA,CAAe,UAAA;AAAA,UACvD,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,OAAA,IAAW,cAAA,CAAe,OAAA;AAAA,UACjD,oBAAoB,cAAA,CAAe,kBAAA;AAAA,UACnC,gBAAgB,GAAA,CAAI,gBAAA;AAAA,UACpB,0BAA0B,cAAA,CAAe,wBAAA;AAAA,UACzC,GAAA;AAAA,UACA,QAAA,EAAU,QAAQ,GAAA,CAAI;AAAA;AACxB,OACF;AAAA,MACA,EAAE,aAAA,EAAe,oBAAA,EAAsB,eAAA,EAAiB,kBAAA;AAAmB,KAC7E;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,MAAA,OAAA,CAAQ,KAAA,CAAM,MAAM,OAAO,CAAA;AAAA,IAC7B,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,IACrB;AACA,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF,CAAC,CAAA;AAEH,OAAA,CAAQ,KAAA,EAAM","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"]}
|