Files
oh-my-pi/packages/coding-agent/test/core/python-prelude.test.ts
T
can1357 92ec2550d2 refactor(coding-agent): reorganized test files to proper test directory structure
- Moved test files from src/core to test/core directory.
- Moved test files from src/core/tools to test/tools directory.
- Moved test files from src/discovery to test/discovery directory.
- Updated import paths to reflect new test file locations.
2026-01-19 00:07:23 +01:00

141 lines
4.0 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import { existsSync } from "node:fs";
import { join } from "node:path";
import { resetPreludeDocsCache, warmPythonEnvironment } from "../../src/core/python-executor";
import { createPythonTool, getPythonToolDescription } from "../../src/core/tools/python";
const resolvePythonPath = (): string | null => {
const venvPath = process.env.VIRTUAL_ENV;
const candidates = [venvPath, join(process.cwd(), ".venv"), join(process.cwd(), "venv")].filter(Boolean) as string[];
for (const candidate of candidates) {
const binDir = process.platform === "win32" ? "Scripts" : "bin";
const exeName = process.platform === "win32" ? "python.exe" : "python";
const pythonCandidate = join(candidate, binDir, exeName);
if (existsSync(pythonCandidate)) {
return pythonCandidate;
}
}
return Bun.which("python") ?? Bun.which("python3");
};
const pythonPath = resolvePythonPath();
const hasKernelDeps = (() => {
if (!pythonPath) return false;
const result = Bun.spawnSync(
[
pythonPath,
"-c",
"import importlib.util,sys;sys.exit(0 if importlib.util.find_spec('kernel_gateway') and importlib.util.find_spec('ipykernel') else 1)",
],
{ stdin: "ignore", stdout: "pipe", stderr: "pipe" },
);
return result.exitCode === 0;
})();
const shouldRun = Boolean(pythonPath) && hasKernelDeps;
describe.skipIf(!shouldRun)("PYTHON_PRELUDE integration", () => {
it("exposes prelude helpers via python tool", async () => {
const helpers = [
"pwd",
"cd",
"env",
"read",
"write",
"append",
"mkdir",
"rm",
"mv",
"cp",
"ls",
"cat",
"touch",
"find",
"grep",
"rgrep",
"head",
"tail",
"replace",
"sed",
"rsed",
"wc",
"sort_lines",
"uniq",
"cols",
"tree",
"stat",
"diff",
"glob_files",
"batch",
"lines",
"delete_lines",
"delete_matching",
"insert_at",
"git_status",
"git_diff",
"git_log",
"git_show",
"git_file_at",
"git_branch",
"git_has_changes",
"run",
"sh",
];
const session = {
cwd: process.cwd(),
hasUI: false,
getSessionFile: () => null,
getSessionSpawns: () => null,
settings: {
getImageAutoResize: () => true,
getLspFormatOnWrite: () => false,
getLspDiagnosticsOnWrite: () => false,
getLspDiagnosticsOnEdit: () => false,
getEditFuzzyMatch: () => true,
getGitToolEnabled: () => true,
getBashInterceptorEnabled: () => true,
getBashInterceptorSimpleLsEnabled: () => true,
getBashInterceptorRules: () => [],
getPythonToolMode: () => "ipy-only" as const,
getPythonKernelMode: () => "per-call" as const,
},
};
const tool = createPythonTool(session);
const code = `
helpers = ${JSON.stringify(helpers)}
missing = [name for name in helpers if name not in globals() or not callable(globals()[name])]
docs = __omp_prelude_docs__()
doc_names = [d.get("name") for d in docs]
doc_categories = [d.get("category") for d in docs]
print("HELPERS_OK=" + ("1" if not missing else "0"))
print("DOCS_OK=" + ("1" if "pwd" in doc_names and "Navigation" in doc_categories else "0"))
if missing:
print("MISSING=" + ",".join(missing))
`;
const result = await tool.execute("tool-call-1", { code });
const output = result.content.find((item) => item.type === "text")?.text ?? "";
expect(output).toContain("HELPERS_OK=1");
expect(output).toContain("DOCS_OK=1");
});
it("exposes prelude docs via warmup", async () => {
resetPreludeDocsCache();
const result = await warmPythonEnvironment(process.cwd(), undefined, false);
expect(result.ok).toBe(true);
const names = result.docs.map((doc) => doc.name);
expect(names).toContain("pwd");
});
it("renders prelude docs in python tool description", async () => {
resetPreludeDocsCache();
const result = await warmPythonEnvironment(process.cwd(), undefined, false);
expect(result.ok).toBe(true);
const description = getPythonToolDescription();
expect(description).toContain("pwd");
expect(description).not.toContain("Documentation unavailable");
});
});