feat(agent): AgentHarness streams through a required Models instance (phase 6)
AgentHarnessOptions.models is required; the harness stream path, compaction, and branch summarization go through models.streamSimple()/ completeSimple() instead of the compat globals. getApiKeyAndHeaders stays and wins per-field over provider-resolved auth, but is no longer required: without it, requests resolve through provider auth. compact()/generateSummary()/generateBranchSummary() take a Models parameter; explicit apiKey becomes optional. StreamFn is redefined structurally (Models.streamSimple satisfies it), dropping the compat type dependency from agent types. Harness tests build per-file Models collections with fauxProvider() and unique provider ids instead of mutating the global api-registry.
This commit is contained in:
@@ -1,18 +1,27 @@
|
||||
import { fauxAssistantMessage, fauxToolCall, registerFauxProvider, type StreamOptions } from "@earendil-works/pi-ai";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
createModels,
|
||||
type FauxProviderHandle,
|
||||
fauxAssistantMessage,
|
||||
fauxProvider,
|
||||
fauxToolCall,
|
||||
type StreamOptions,
|
||||
} from "@earendil-works/pi-ai";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { AgentHarness } from "../../src/harness/agent-harness.ts";
|
||||
import { NodeExecutionEnv } from "../../src/harness/env/nodejs.ts";
|
||||
import { InMemorySessionStorage } from "../../src/harness/session/memory-storage.ts";
|
||||
import { Session } from "../../src/harness/session/session.ts";
|
||||
import { calculateTool } from "../utils/calculate.ts";
|
||||
|
||||
const registrations: Array<{ unregister(): void }> = [];
|
||||
/** Shared collection; each faux provider gets a unique id so coexisting fakes route correctly. */
|
||||
const models = createModels();
|
||||
let fauxCount = 0;
|
||||
|
||||
afterEach(() => {
|
||||
for (const registration of registrations.splice(0)) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
function newFaux(): FauxProviderHandle {
|
||||
const faux = fauxProvider({ provider: `faux-${++fauxCount}` });
|
||||
models.setProvider(faux.provider);
|
||||
return faux;
|
||||
}
|
||||
|
||||
function createHarness(options: ConstructorParameters<typeof AgentHarness>[0]): AgentHarness {
|
||||
return new AgentHarness(options);
|
||||
@@ -29,8 +38,7 @@ function captureOptions(options: StreamOptions | undefined): StreamOptions {
|
||||
describe("AgentHarness stream configuration", () => {
|
||||
it("snapshots stream options and merges auth headers before provider request hooks", async () => {
|
||||
let capturedOptions: StreamOptions | undefined;
|
||||
const registration = registerFauxProvider();
|
||||
registrations.push(registration);
|
||||
const registration = newFaux();
|
||||
registration.setResponses([
|
||||
(_context, options) => {
|
||||
capturedOptions = options;
|
||||
@@ -40,6 +48,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
|
||||
const session = new Session(new InMemorySessionStorage({ metadata: { id: "session-1", createdAt: "now" } }));
|
||||
const harness = createHarness({
|
||||
models,
|
||||
env: new NodeExecutionEnv({ cwd: process.cwd() }),
|
||||
session,
|
||||
model: registration.getModel(),
|
||||
@@ -81,8 +90,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
|
||||
it("chains provider request patches and supports deletion semantics", async () => {
|
||||
let capturedOptions: StreamOptions | undefined;
|
||||
const registration = registerFauxProvider();
|
||||
registrations.push(registration);
|
||||
const registration = newFaux();
|
||||
registration.setResponses([
|
||||
(_context, options) => {
|
||||
capturedOptions = options;
|
||||
@@ -91,6 +99,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
]);
|
||||
|
||||
const harness = createHarness({
|
||||
models,
|
||||
env: new NodeExecutionEnv({ cwd: process.cwd() }),
|
||||
session: new Session(new InMemorySessionStorage()),
|
||||
model: registration.getModel(),
|
||||
@@ -133,8 +142,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
|
||||
it("uses updated stream options for save-point snapshots without mutating the active request", async () => {
|
||||
const capturedOptions: StreamOptions[] = [];
|
||||
const registration = registerFauxProvider();
|
||||
registrations.push(registration);
|
||||
const registration = newFaux();
|
||||
registration.setResponses([
|
||||
(_context, options) => {
|
||||
capturedOptions.push(captureOptions(options));
|
||||
@@ -149,6 +157,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
]);
|
||||
|
||||
const harness = createHarness({
|
||||
models,
|
||||
env: new NodeExecutionEnv({ cwd: process.cwd() }),
|
||||
session: new Session(new InMemorySessionStorage()),
|
||||
model: registration.getModel(),
|
||||
@@ -174,8 +183,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
it("chains provider payload hooks", async () => {
|
||||
const seenPayloads: unknown[] = [];
|
||||
let finalPayload: unknown;
|
||||
const registration = registerFauxProvider();
|
||||
registrations.push(registration);
|
||||
const registration = newFaux();
|
||||
registration.setResponses([
|
||||
async (_context, options, _state, model) => {
|
||||
finalPayload = await options?.onPayload?.({ steps: ["provider"] }, model);
|
||||
@@ -184,6 +192,7 @@ describe("AgentHarness stream configuration", () => {
|
||||
]);
|
||||
|
||||
const harness = createHarness({
|
||||
models,
|
||||
env: new NodeExecutionEnv({ cwd: process.cwd() }),
|
||||
session: new Session(new InMemorySessionStorage()),
|
||||
model: registration.getModel(),
|
||||
|
||||
Reference in New Issue
Block a user