Something went wrong. Try again.
fork of prime agent with changes i want but are not upstreamable probqbly (and some fixes)
Something went wrong. Try again.
5.4 kB · 160 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161import { existsSync, mkdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";import { tmpdir } from "node:os";import { join } from "node:path";import { getModel } from "@earendil-works/pi-ai";import { afterEach, beforeEach, describe, expect, it } from "vitest";import { createExtensionRuntime } from "../src/core/extensions/loader.js";import type { ResourceLoader } from "../src/core/resource-loader.js";import { createAgentSession } from "../src/core/sdk.js";import { SessionManager } from "../src/core/session-manager.js";import type { Skill } from "../src/core/skills.js";import { createSyntheticSourceInfo } from "../src/core/source-info.js";
describe("createAgentSession session manager defaults", () => { let tempDir: string; let cwd: string; let agentDir: string;
beforeEach(() => { tempDir = join(tmpdir(), `pi-sdk-session-test-${Date.now()}-${Math.random().toString(36).slice(2)}`); cwd = join(tempDir, "project"); agentDir = join(tempDir, "agent"); mkdirSync(cwd, { recursive: true }); mkdirSync(agentDir, { recursive: true }); });
afterEach(() => { if (tempDir && existsSync(tempDir)) { rmSync(tempDir, { recursive: true, force: true }); } });
it("uses agentDir for the default persisted session path", async () => { const model = getModel("anthropic", "claude-sonnet-4-5"); expect(model).toBeTruthy();
const { session } = await createAgentSession({ cwd, agentDir, model: model!, });
const expectedSessionDir = join(agentDir, "sessions"); const sessionDir = session.sessionManager.getSessionDir(); const sessionFile = session.sessionManager.getSessionFile();
expect(sessionDir).toBe(expectedSessionDir); expect(sessionFile?.startsWith(`${expectedSessionDir}/`)).toBe(true);
session.dispose(); });
it("keeps an explicit sessionManager override", async () => { const model = getModel("anthropic", "claude-sonnet-4-5"); expect(model).toBeTruthy();
const sessionManager = SessionManager.inMemory(cwd); const { session } = await createAgentSession({ cwd, agentDir, model: model!, sessionManager, });
expect(session.sessionManager).toBe(sessionManager); expect(session.sessionManager.isPersisted()).toBe(false);
session.dispose(); });
it("derives cwd from an explicit sessionManager when cwd is omitted", async () => { const model = getModel("anthropic", "claude-sonnet-4-5"); expect(model).toBeTruthy();
const sessionCwd = join(tempDir, "session-project"); mkdirSync(sessionCwd, { recursive: true }); const sessionManager = SessionManager.inMemory(sessionCwd); const { session } = await createAgentSession({ agentDir, model: model!, sessionManager, tools: ["ipython"], });
expect(session.sessionManager).toBe(sessionManager); expect(session.systemPrompt).toContain(`Working directory: ${sessionCwd}`);
const ipythonTool = session.agent.state.tools.find((tool) => tool.name === "ipython"); expect(ipythonTool).toBeTruthy(); const result = await ipythonTool!.execute("test", { code: "import os\nprint(os.getcwd())" }); const output = result.content .filter((item): item is { type: "text"; text: string } => item.type === "text") .map((item) => item.text) .join("");
expect(realpathSync(output.trim())).toBe(realpathSync(sessionCwd));
session.dispose(); }, 120_000);
describe("createAgentSession skills option wiring", () => { const stubLoader = (skills: Skill[]): ResourceLoader => ({ getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }), getSkills: () => ({ skills, diagnostics: [] }), getPrompts: () => ({ prompts: [], diagnostics: [] }), getThemes: () => ({ themes: [], diagnostics: [] }), getAgentsFiles: () => ({ agentsFiles: [] }), getSystemPrompt: () => undefined, getAppendSystemPrompt: () => [], extendResources: () => {}, reload: async () => {}, });
it("discovers skills from agentDir by default", async () => { const skillDir = join(agentDir, "skills", "test-skill"); mkdirSync(skillDir, { recursive: true }); writeFileSync( join(skillDir, "SKILL.md"), "---\nname: test-skill\ndescription: A test skill for SDK tests.\n---\n\n# Test Skill\n", );
const { session } = await createAgentSession({ cwd: agentDir, agentDir, sessionManager: SessionManager.inMemory(), });
expect(session.resourceLoader.getSkills().skills.some((s) => s.name === "test-skill")).toBe(true); session.dispose(); });
it.each([ ["no skills (--no-skills)", [] as Skill[]], [ "skills supplied by the loader", [ { name: "custom-skill", description: "A custom skill", filePath: "/fake/path/SKILL.md", baseDir: "/fake/path", sourceInfo: createSyntheticSourceInfo("/fake/path/SKILL.md", { source: "sdk" }), disableModelInvocation: false, kind: "markdown" as const, }, ] as Skill[], ], ])("passes through an explicit resource loader with %s", async (_label, skills) => { const { session } = await createAgentSession({ cwd: agentDir, agentDir, sessionManager: SessionManager.inMemory(), resourceLoader: stubLoader(skills), });
expect(session.resourceLoader.getSkills().skills).toEqual(skills); expect(session.resourceLoader.getSkills().diagnostics).toEqual([]); session.dispose(); }); });});