diff --git a/packages/agent/src/harness/agent-harness.ts b/packages/agent/src/harness/agent-harness.ts index 03518d12..67db5ea6 100644 --- a/packages/agent/src/harness/agent-harness.ts +++ b/packages/agent/src/harness/agent-harness.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { readFileSync } from "node:fs"; import type { ImageContent, Model } from "@mariozechner/pi-ai"; -import type { Agent } from "../agent.js"; +import { Agent } from "../agent.js"; import type { AgentEvent, AgentMessage, AgentTool, ThinkingLevel } from "../types.js"; import { collectEntriesForBranchSummary, generateBranchSummary } from "./compaction/branch-summarization.js"; import { compact, DEFAULT_COMPACTION_SETTINGS, prepareCompaction } from "./compaction/compaction.js"; @@ -68,7 +68,7 @@ export class DefaultAgentHarness implements AgentHarness { >(); constructor(options: AgentHarnessOptions) { - this.agent = options.agent; + this.agent = new Agent({}); this.env = options.env; this.session = options.session; this.promptTemplates = options.promptTemplates ?? []; diff --git a/packages/agent/src/harness/factory.ts b/packages/agent/src/harness/factory.ts index 58edaca2..2c10ccc5 100644 --- a/packages/agent/src/harness/factory.ts +++ b/packages/agent/src/harness/factory.ts @@ -1,11 +1,11 @@ import { DefaultAgentHarness } from "./agent-harness.js"; -import { DefaultSession } from "./session/session.js"; -import type { AgentHarness, AgentHarnessOptions, Session, SessionMetadata, SessionStorage } from "./types.js"; +import { Session } from "./session/session.js"; +import type { AgentHarness, AgentHarnessOptions, SessionMetadata, SessionStorage } from "./types.js"; export function createSession( storage: SessionStorage, ): Session { - return new DefaultSession(storage); + return new Session(storage); } export function createAgentHarness(options: AgentHarnessOptions): AgentHarness { diff --git a/packages/agent/src/harness/session/repo/shared.ts b/packages/agent/src/harness/session/repo/shared.ts index f6395614..eb359fc2 100644 --- a/packages/agent/src/harness/session/repo/shared.ts +++ b/packages/agent/src/harness/session/repo/shared.ts @@ -1,6 +1,6 @@ import { v7 as uuidv7 } from "uuid"; -import type { Session, SessionMetadata, SessionStorage, SessionTreeEntry } from "../../types.js"; -import { DefaultSession } from "../session.js"; +import type { SessionMetadata, SessionStorage, SessionTreeEntry } from "../../types.js"; +import { Session } from "../session.js"; export function createSessionId(): string { return uuidv7(); @@ -11,7 +11,7 @@ export function createTimestamp(): string { } export function toSession(storage: SessionStorage): Session { - return new DefaultSession(storage); + return new Session(storage); } export async function getEntriesToFork( diff --git a/packages/agent/src/harness/session/session.ts b/packages/agent/src/harness/session/session.ts index 62f59c38..889c6b58 100644 --- a/packages/agent/src/harness/session/session.ts +++ b/packages/agent/src/harness/session/session.ts @@ -9,7 +9,6 @@ import type { LabelEntry, MessageEntry, ModelChangeEntry, - Session, SessionContext, SessionInfoEntry, SessionMetadata, @@ -75,7 +74,7 @@ export function buildSessionContext(pathEntries: SessionTreeEntry[]): SessionCon return { messages, thinkingLevel, model }; } -export class DefaultSession implements Session { +export class Session { private storage: SessionStorage; constructor(storage: SessionStorage) { diff --git a/packages/agent/src/harness/types.ts b/packages/agent/src/harness/types.ts index 605fe447..625a9ccb 100644 --- a/packages/agent/src/harness/types.ts +++ b/packages/agent/src/harness/types.ts @@ -1,5 +1,6 @@ import type { ImageContent, Model, TextContent } from "@mariozechner/pi-ai"; import type { Agent, AgentEvent, AgentMessage, ThinkingLevel } from "../index.js"; +import type { Session } from "./session/session.js"; export type SourceScope = "user" | "project" | "temporary"; export type SourceOrigin = "package" | "top-level"; @@ -183,43 +184,7 @@ export interface SessionStorage; } -export interface Session { - getMetadata(): Promise; - getStorage(): SessionStorage; - - getLeafId(): Promise; - getEntry(id: string): Promise; - getEntries(): Promise; - getBranch(fromId?: string): Promise; - buildContext(): Promise; - getLabel(id: string): Promise; - getSessionName(): Promise; - - appendMessage(message: AgentMessage): Promise; - appendThinkingLevelChange(thinkingLevel: string): Promise; - appendModelChange(provider: string, modelId: string): Promise; - appendCompaction( - summary: string, - firstKeptEntryId: string, - tokensBefore: number, - details?: T, - fromHook?: boolean, - ): Promise; - appendCustomEntry(customType: string, data?: unknown): Promise; - appendCustomMessageEntry( - customType: string, - content: string | (TextContent | ImageContent)[], - display: boolean, - details?: T, - ): Promise; - appendLabel(targetId: string, label: string | undefined): Promise; - appendSessionName(name: string): Promise; - - moveTo( - entryId: string | null, - summary?: { summary: string; details?: unknown; fromHook?: boolean }, - ): Promise; -} +export type { Session } from "./session/session.js"; export interface SessionCreateOptions { id?: string; @@ -554,7 +519,6 @@ export interface BranchSummaryResult { } export interface AgentHarnessOptions { - agent: Agent; env: ExecutionEnv; session: Session; promptTemplates?: PromptTemplate[]; diff --git a/packages/agent/test/harness/factory.test.ts b/packages/agent/test/harness/factory.test.ts index ec00b1c4..e303477b 100644 --- a/packages/agent/test/harness/factory.test.ts +++ b/packages/agent/test/harness/factory.test.ts @@ -1,5 +1,4 @@ import { describe, expect, it } from "vitest"; -import { Agent } from "../../src/agent.js"; import { NodeExecutionEnv } from "../../src/harness/execution-env.js"; import { createAgentHarness, createSession } from "../../src/harness/factory.js"; import { InMemorySessionStorage } from "../../src/harness/session/storage/memory.js"; @@ -17,9 +16,8 @@ describe("harness factories", () => { it("creates agent harnesses", () => { const session = createSession(new InMemorySessionStorage()); const env = new NodeExecutionEnv({ cwd: process.cwd() }); - const agent = new Agent(); - const harness = createAgentHarness({ agent, env, session }); - expect(harness.agent).toBe(agent); + const harness = createAgentHarness({ env, session }); + expect(harness.env).toBe(env); expect(harness.conversation.session).toBe(session); }); }); diff --git a/packages/agent/test/harness/session-tree.test.ts b/packages/agent/test/harness/session-tree.test.ts index 6fa49594..d6b7f365 100644 --- a/packages/agent/test/harness/session-tree.test.ts +++ b/packages/agent/test/harness/session-tree.test.ts @@ -1,7 +1,7 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -import { DefaultSession } from "../../src/harness/session/session.js"; +import { Session } from "../../src/harness/session/session.js"; import { JsonlSessionStorage } from "../../src/harness/session/storage/jsonl.js"; import { InMemorySessionStorage } from "../../src/harness/session/storage/memory.js"; import type { SessionStorage } from "../../src/harness/types.js"; @@ -14,7 +14,7 @@ async function runSessionSuite( ) { describe(name, () => { it("appends messages and builds context in order", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); await session.appendMessage(createUserMessage("one")); await session.appendMessage(createAssistantMessage("two")); const context = await session.buildContext(); @@ -22,7 +22,7 @@ async function runSessionSuite( }); it("tracks model and thinking level changes", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); await session.appendMessage(createUserMessage("one")); await session.appendModelChange("openai", "gpt-4.1"); await session.appendThinkingLevelChange("high"); @@ -32,7 +32,7 @@ async function runSessionSuite( }); it("supports branching by moving the leaf and appending a new branch", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); const user1 = await session.appendMessage(createUserMessage("one")); const assistant1 = await session.appendMessage(createAssistantMessage("two")); await session.appendMessage(createUserMessage("three")); @@ -46,7 +46,7 @@ async function runSessionSuite( }); it("supports moving the leaf to root", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); await session.appendMessage(createUserMessage("one")); await session.moveTo(null); expect(await session.getLeafId()).toBeNull(); @@ -54,7 +54,7 @@ async function runSessionSuite( }); it("reconstructs compaction summaries in context", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); await session.appendMessage(createUserMessage("one")); await session.appendMessage(createAssistantMessage("two")); const user2 = await session.appendMessage(createUserMessage("three")); @@ -67,7 +67,7 @@ async function runSessionSuite( }); it("supports moving with branch summary entries in context", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); const user1 = await session.appendMessage(createUserMessage("one")); const summaryId = await session.moveTo(user1, { summary: "summary text" }); expect(summaryId).toBeTruthy(); @@ -78,7 +78,7 @@ async function runSessionSuite( }); it("supports custom message entries in context", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); await session.appendMessage(createUserMessage("one")); await session.appendCustomMessageEntry("custom", "hello", true, { ok: true }); const context = await session.buildContext(); @@ -86,7 +86,7 @@ async function runSessionSuite( }); it("supports labels and session info entries without affecting context", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); const user1 = await session.appendMessage(createUserMessage("one")); await session.appendLabel(user1, "checkpoint"); await session.appendSessionName("name"); @@ -99,20 +99,20 @@ async function runSessionSuite( }); it("rejects labels for missing entries", async () => { - const session = new DefaultSession(await createStorage()); + const session = new Session(await createStorage()); await expect(session.appendLabel("missing", "checkpoint")).rejects.toThrow("Entry missing not found"); }); it("persists leaf changes and appended entries via storage", async () => { const storage = await createStorage(); - const session = new DefaultSession(storage); + const session = new Session(storage); const user1 = await session.appendMessage(createUserMessage("one")); await session.appendMessage(createAssistantMessage("two")); await session.appendLabel(user1, "checkpoint"); await session.appendSessionName("name"); await session.moveTo(user1); await session.appendMessage(createAssistantMessage("branched")); - const session2 = new DefaultSession(storage); + const session2 = new Session(storage); const context = await session2.buildContext(); expect(context.messages.map((message) => message.role)).toEqual(["user", "assistant"]); expect(await session2.getLabel(user1)).toBe("checkpoint");