@mammothb/pi-eval 1.0.0 → 1.1.0
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/package.json +1 -1
- package/src/config.ts +58 -0
- package/src/eval.ts +12 -20
package/package.json
CHANGED
package/src/config.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
|
|
5
|
+
export interface EvalConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Path to a python3 binary (e.g., '.venv/bin/python3' for venvs).
|
|
8
|
+
* When set, this binary is used for all Python evaluations instead of
|
|
9
|
+
* searching PATH for 'python3'.
|
|
10
|
+
*/
|
|
11
|
+
pythonPath?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Path to a node_modules directory. When set, NODE_PATH is passed
|
|
14
|
+
* to the Node.js subprocess so require() resolves from this directory.
|
|
15
|
+
* Use './node_modules' for project-local packages.
|
|
16
|
+
*/
|
|
17
|
+
nodeModulesPath?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_CONFIG: EvalConfig = {};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Load config from JSON files. Project config (`.pi/pi-eval.json`)
|
|
24
|
+
* overrides global config (`~/.pi/agent/pi-eval.json`).
|
|
25
|
+
*
|
|
26
|
+
* Returns the default config if no config files exist.
|
|
27
|
+
*/
|
|
28
|
+
export function loadConfig(cwd: string): EvalConfig {
|
|
29
|
+
const globalPath = join(getAgentDir(), "pi-eval.json");
|
|
30
|
+
const projectPath = join(cwd, ".pi", "pi-eval.json");
|
|
31
|
+
|
|
32
|
+
let global: Partial<EvalConfig> | undefined;
|
|
33
|
+
let project: Partial<EvalConfig> | undefined;
|
|
34
|
+
|
|
35
|
+
if (existsSync(globalPath)) {
|
|
36
|
+
try {
|
|
37
|
+
global = JSON.parse(readFileSync(globalPath, "utf-8"));
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error(`Failed to load global config from ${globalPath}: ${err}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (existsSync(projectPath)) {
|
|
44
|
+
try {
|
|
45
|
+
project = JSON.parse(readFileSync(projectPath, "utf-8"));
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error(
|
|
48
|
+
`Failed to load project config from ${projectPath}: ${err}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...DEFAULT_CONFIG,
|
|
55
|
+
...global,
|
|
56
|
+
...project,
|
|
57
|
+
};
|
|
58
|
+
}
|
package/src/eval.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
|
+
import { loadConfig } from "./config.js";
|
|
3
4
|
import { executeJavaScript } from "./javascript.js";
|
|
4
5
|
import { executePython } from "./python.js";
|
|
5
6
|
import {
|
|
@@ -13,21 +14,6 @@ export const TIMEOUT_MS = 30_000;
|
|
|
13
14
|
const Parameters = Type.Object({
|
|
14
15
|
language: Type.Union([Type.Literal("javascript"), Type.Literal("python")]),
|
|
15
16
|
code: Type.String({ description: "Code to execute" }),
|
|
16
|
-
pythonPath: Type.Optional(
|
|
17
|
-
Type.String({
|
|
18
|
-
description:
|
|
19
|
-
"Path to python3 binary (e.g., '.venv/bin/python3' for venvs). " +
|
|
20
|
-
"Defaults to 'python3'.",
|
|
21
|
-
}),
|
|
22
|
-
),
|
|
23
|
-
nodeModulesPath: Type.Optional(
|
|
24
|
-
Type.String({
|
|
25
|
-
description:
|
|
26
|
-
"Path to a node_modules directory. When set, NODE_PATH is passed " +
|
|
27
|
-
"to the subprocess so require() resolves from this directory. " +
|
|
28
|
-
"Use './node_modules' for project-local packages.",
|
|
29
|
-
}),
|
|
30
|
-
),
|
|
31
17
|
});
|
|
32
18
|
|
|
33
19
|
export function createEvalTool(): ToolDefinition<
|
|
@@ -42,13 +28,13 @@ export function createEvalTool(): ToolDefinition<
|
|
|
42
28
|
- Each call is a fresh subprocess — no state persists between calls
|
|
43
29
|
- 30-second timeout; press Escape to cancel a running evaluation
|
|
44
30
|
- Working directory is the agent's current working directory (like bash)
|
|
45
|
-
-
|
|
46
|
-
- Use pythonPath to target a virtual environment`,
|
|
31
|
+
- Set pythonPath or nodeModulesPath in ~/.pi/agent/pi-eval.json (global) or .pi/pi-eval.json (project) to configure the runtime for all eval calls`,
|
|
47
32
|
promptSnippet:
|
|
48
33
|
"Execute JavaScript or Python code in an isolated subprocess",
|
|
49
34
|
parameters: Parameters,
|
|
50
35
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
51
|
-
const { language, code
|
|
36
|
+
const { language, code } = params;
|
|
37
|
+
const config = loadConfig(ctx.cwd);
|
|
52
38
|
|
|
53
39
|
// Validate language (belt-and-suspenders: TypeBox schema already constrains it,
|
|
54
40
|
// but a raw API call could bypass validation)
|
|
@@ -69,13 +55,19 @@ export function createEvalTool(): ToolDefinition<
|
|
|
69
55
|
}
|
|
70
56
|
|
|
71
57
|
if (language === "python") {
|
|
72
|
-
return executePython(
|
|
58
|
+
return executePython(
|
|
59
|
+
code,
|
|
60
|
+
config.pythonPath,
|
|
61
|
+
signal,
|
|
62
|
+
timeoutSignal,
|
|
63
|
+
ctx.cwd,
|
|
64
|
+
);
|
|
73
65
|
}
|
|
74
66
|
|
|
75
67
|
// ── JavaScript execution via temp file + node subprocess ──
|
|
76
68
|
return executeJavaScript(
|
|
77
69
|
code,
|
|
78
|
-
nodeModulesPath,
|
|
70
|
+
config.nodeModulesPath,
|
|
79
71
|
signal,
|
|
80
72
|
timeoutSignal,
|
|
81
73
|
ctx.cwd,
|