mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
feat(agent): Models is the harness's only auth path
Remove AgentHarnessOptions.getApiKeyAndHeaders: turn streaming, compaction, and branch summarization resolve auth exclusively through the injected Models instance. compact()/generateSummary()/ generateBranchSummary() lose their explicit apiKey/headers parameters.
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `AgentHarnessOptions.models` is required: the harness streams turns, compaction, and branch summarization through the provided `Models` instance (`models.streamSimple()`/`completeSimple()`) instead of the pi-ai global stream functions. Build one with `createModels()` + provider factories (or `builtinModels()` from `@earendil-works/pi-ai/providers/all`); tests use `fauxProvider()`. `getApiKeyAndHeaders` still wins per field but is no longer required — without it, requests resolve auth through the providers.
|
||||
- `compact()`, `generateSummary()`, and `generateBranchSummary()` take a `Models` parameter; the explicit `apiKey` is now optional.
|
||||
- `AgentHarnessOptions.models` is required and is the only auth path: the harness streams turns, compaction, and branch summarization through the provided `Models` instance (`models.streamSimple()`/`completeSimple()`), resolving auth through the providers. `AgentHarnessOptions.getApiKeyAndHeaders` is removed — apps that resolved keys per request now express that as provider auth (`ApiKeyAuth`/`OAuthAuth`) on the providers in the `Models` collection. Build one with `createModels()` + provider factories (or `builtinModels()` from `@earendil-works/pi-ai/providers/all`); tests use `fauxProvider()`.
|
||||
- `compact()`, `generateSummary()`, and `generateBranchSummary()` take a `Models` parameter and no longer accept explicit `apiKey`/`headers`.
|
||||
- `StreamFn` is defined structurally (`(model, context, options?) => AssistantMessageEventStream | Promise<...>`); `Models.streamSimple` satisfies it.
|
||||
|
||||
## [0.79.1] - 2026-06-09
|
||||
|
||||
@@ -821,7 +821,7 @@ Check items off as they land. Keep this list current; it is the working state fo
|
||||
### Phase 6 — AgentHarness
|
||||
|
||||
- [x] `AgentHarnessOptions.models` required (`readonly models` on the harness); the harness stream path uses `models.streamSimple()`. `StreamFn` redefined structurally (no compat type dependency); `Models.streamSimple` satisfies it.
|
||||
- [x] Compaction/branch-summarization take the harness `Models` instance; explicit `getApiKeyAndHeaders` auth stays and wins per-field, but is no longer required — requests resolve through provider auth otherwise (the hard "No auth available" throws are gone).
|
||||
- [x] Compaction/branch-summarization take the harness `Models` instance. `getApiKeyAndHeaders` is removed entirely — `Models` is the only auth path; per-request key resolution becomes provider auth on the collection. `compact()`/`generateSummary()`/`generateBranchSummary()` lose their explicit `apiKey`/`headers` parameters.
|
||||
- [x] Harness tests use `createModels()` + `fauxProvider()` with unique per-fake provider ids; no global api-registry state, no unregister bookkeeping.
|
||||
|
||||
### Phase 7 — coding-agent bridge (minimal)
|
||||
|
||||
@@ -69,17 +69,6 @@ function cloneStreamOptions(streamOptions?: AgentHarnessStreamOptions): AgentHar
|
||||
};
|
||||
}
|
||||
|
||||
function mergeHeaders(...headers: Array<Record<string, string> | undefined>): Record<string, string> | undefined {
|
||||
const merged: Record<string, string> = {};
|
||||
let hasHeaders = false;
|
||||
for (const entry of headers) {
|
||||
if (!entry) continue;
|
||||
Object.assign(merged, entry);
|
||||
hasHeaders = true;
|
||||
}
|
||||
return hasHeaders ? merged : undefined;
|
||||
}
|
||||
|
||||
function findDuplicateNames(names: string[]): string[] {
|
||||
const seen = new Set<string>();
|
||||
const duplicates = new Set<string>();
|
||||
@@ -181,7 +170,6 @@ export class AgentHarness<
|
||||
private thinkingLevel: ThinkingLevel;
|
||||
private systemPrompt: AgentHarnessOptions<TSkill, TPromptTemplate, TTool>["systemPrompt"];
|
||||
private streamOptions: AgentHarnessStreamOptions;
|
||||
private getApiKeyAndHeaders?: AgentHarnessOptions["getApiKeyAndHeaders"];
|
||||
private resources: AgentHarnessResources<TSkill, TPromptTemplate>;
|
||||
private tools = new Map<string, TTool>();
|
||||
private activeToolNames: string[];
|
||||
@@ -199,7 +187,6 @@ export class AgentHarness<
|
||||
this.resources = options.resources ?? {};
|
||||
this.streamOptions = cloneStreamOptions(options.streamOptions);
|
||||
this.systemPrompt = options.systemPrompt;
|
||||
this.getApiKeyAndHeaders = options.getApiKeyAndHeaders;
|
||||
this.validateUniqueNames(
|
||||
(options.tools ?? []).map((tool) => tool.name),
|
||||
"Duplicate tool name(s)",
|
||||
@@ -372,11 +359,7 @@ export class AgentHarness<
|
||||
private createStreamFn(getTurnState: () => AgentHarnessTurnState<TSkill, TPromptTemplate, TTool>): StreamFn {
|
||||
return async (model, context, streamOptions) => {
|
||||
const turnState = getTurnState();
|
||||
const auth = await this.getApiKeyAndHeaders?.(model);
|
||||
const snapshotOptions: AgentHarnessStreamOptions = {
|
||||
...turnState.streamOptions,
|
||||
headers: mergeHeaders(turnState.streamOptions.headers, auth?.headers),
|
||||
};
|
||||
const snapshotOptions: AgentHarnessStreamOptions = { ...turnState.streamOptions };
|
||||
const requestOptions = await this.emitBeforeProviderRequest(model, turnState.sessionId, snapshotOptions);
|
||||
return this.models.streamSimple(model, context, {
|
||||
cacheRetention: requestOptions.cacheRetention,
|
||||
@@ -397,7 +380,6 @@ export class AgentHarness<
|
||||
sessionId: turnState.sessionId,
|
||||
timeoutMs: requestOptions.timeoutMs,
|
||||
transport: requestOptions.transport,
|
||||
apiKey: auth?.apiKey,
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -709,8 +691,6 @@ export class AgentHarness<
|
||||
try {
|
||||
const model = this.model;
|
||||
if (!model) throw new AgentHarnessError("invalid_state", "No model set for compaction");
|
||||
// Explicit auth wins; otherwise the request resolves through provider auth.
|
||||
const auth = await this.getApiKeyAndHeaders?.(model);
|
||||
const branchEntries = await this.session.getBranch();
|
||||
const preparationResult = prepareCompaction(branchEntries, DEFAULT_COMPACTION_SETTINGS);
|
||||
if (!preparationResult.ok) throw preparationResult.error;
|
||||
@@ -727,16 +707,7 @@ export class AgentHarness<
|
||||
const provided = hookResult?.compaction;
|
||||
const compactResult = provided
|
||||
? { ok: true as const, value: provided }
|
||||
: await compact(
|
||||
preparation,
|
||||
this.models,
|
||||
model,
|
||||
auth?.apiKey,
|
||||
auth?.headers,
|
||||
customInstructions,
|
||||
undefined,
|
||||
this.thinkingLevel,
|
||||
);
|
||||
: await compact(preparation, this.models, model, customInstructions, undefined, this.thinkingLevel);
|
||||
if (!compactResult.ok) throw compactResult.error;
|
||||
const result = compactResult.value;
|
||||
const entryId = await this.session.appendCompaction(
|
||||
@@ -789,13 +760,9 @@ export class AgentHarness<
|
||||
if (!summaryText && options?.summarize && entries.length > 0) {
|
||||
const model = this.model;
|
||||
if (!model) throw new AgentHarnessError("invalid_state", "No model set for branch summary");
|
||||
// Explicit auth wins; otherwise the request resolves through provider auth.
|
||||
const auth = await this.getApiKeyAndHeaders?.(model);
|
||||
const branchSummary = await generateBranchSummary(entries, {
|
||||
models: this.models,
|
||||
model,
|
||||
apiKey: auth?.apiKey,
|
||||
headers: auth?.headers,
|
||||
signal: new AbortController().signal,
|
||||
customInstructions: hookResult?.customInstructions ?? options?.customInstructions,
|
||||
replaceInstructions: hookResult?.replaceInstructions ?? options?.replaceInstructions,
|
||||
|
||||
@@ -49,14 +49,10 @@ export interface CollectEntriesResult {
|
||||
|
||||
/** Options for generating a branch summary. */
|
||||
export interface GenerateBranchSummaryOptions {
|
||||
/** Provider collection the summarization request goes through. */
|
||||
/** Provider collection the summarization request goes through; owns auth resolution. */
|
||||
models: Models;
|
||||
/** Model used for summarization. */
|
||||
model: Model<any>;
|
||||
/** Explicit API key; wins over provider-resolved auth. */
|
||||
apiKey?: string;
|
||||
/** Optional request headers forwarded to the provider. */
|
||||
headers?: Record<string, string>;
|
||||
/** Abort signal for the summarization request. */
|
||||
signal: AbortSignal;
|
||||
/** Optional instructions appended to or replacing the default prompt. */
|
||||
@@ -204,16 +200,7 @@ export async function generateBranchSummary(
|
||||
entries: SessionTreeEntry[],
|
||||
options: GenerateBranchSummaryOptions,
|
||||
): Promise<Result<BranchSummaryResult, BranchSummaryError>> {
|
||||
const {
|
||||
models,
|
||||
model,
|
||||
apiKey,
|
||||
headers,
|
||||
signal,
|
||||
customInstructions,
|
||||
replaceInstructions,
|
||||
reserveTokens = 16384,
|
||||
} = options;
|
||||
const { models, model, signal, customInstructions, replaceInstructions, reserveTokens = 16384 } = options;
|
||||
const contextWindow = model.contextWindow || 128000;
|
||||
const tokenBudget = contextWindow - reserveTokens;
|
||||
|
||||
@@ -244,7 +231,7 @@ export async function generateBranchSummary(
|
||||
const response = await models.completeSimple(
|
||||
model,
|
||||
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },
|
||||
{ apiKey, headers, signal, maxTokens: 2048 },
|
||||
{ signal, maxTokens: 2048 },
|
||||
);
|
||||
if (response.stopReason === "aborted") {
|
||||
return err(new BranchSummaryError("aborted", response.errorMessage || "Branch summary aborted"));
|
||||
|
||||
@@ -457,8 +457,6 @@ export async function generateSummary(
|
||||
models: Models,
|
||||
model: Model<any>,
|
||||
reserveTokens: number,
|
||||
apiKey?: string,
|
||||
headers?: Record<string, string>,
|
||||
signal?: AbortSignal,
|
||||
customInstructions?: string,
|
||||
previousSummary?: string,
|
||||
@@ -490,8 +488,8 @@ export async function generateSummary(
|
||||
|
||||
const completionOptions =
|
||||
model.reasoning && thinkingLevel && thinkingLevel !== "off"
|
||||
? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }
|
||||
: { maxTokens, signal, apiKey, headers };
|
||||
? { maxTokens, signal, reasoning: thinkingLevel }
|
||||
: { maxTokens, signal };
|
||||
|
||||
const response = await models.completeSimple(
|
||||
model,
|
||||
@@ -628,8 +626,6 @@ export async function compact(
|
||||
preparation: CompactionPreparation,
|
||||
models: Models,
|
||||
model: Model<any>,
|
||||
apiKey?: string,
|
||||
headers?: Record<string, string>,
|
||||
customInstructions?: string,
|
||||
signal?: AbortSignal,
|
||||
thinkingLevel?: ThinkingLevel,
|
||||
@@ -659,24 +655,13 @@ export async function compact(
|
||||
models,
|
||||
model,
|
||||
settings.reserveTokens,
|
||||
apiKey,
|
||||
headers,
|
||||
signal,
|
||||
customInstructions,
|
||||
previousSummary,
|
||||
thinkingLevel,
|
||||
)
|
||||
: Promise.resolve(ok<string, CompactionError>("No prior history.")),
|
||||
generateTurnPrefixSummary(
|
||||
turnPrefixMessages,
|
||||
models,
|
||||
model,
|
||||
settings.reserveTokens,
|
||||
apiKey,
|
||||
headers,
|
||||
signal,
|
||||
thinkingLevel,
|
||||
),
|
||||
generateTurnPrefixSummary(turnPrefixMessages, models, model, settings.reserveTokens, signal, thinkingLevel),
|
||||
]);
|
||||
if (!historyResult.ok) return err(historyResult.error);
|
||||
if (!turnPrefixResult.ok) return err(turnPrefixResult.error);
|
||||
@@ -687,8 +672,6 @@ export async function compact(
|
||||
models,
|
||||
model,
|
||||
settings.reserveTokens,
|
||||
apiKey,
|
||||
headers,
|
||||
signal,
|
||||
customInstructions,
|
||||
previousSummary,
|
||||
@@ -713,8 +696,6 @@ async function generateTurnPrefixSummary(
|
||||
models: Models,
|
||||
model: Model<any>,
|
||||
reserveTokens: number,
|
||||
apiKey?: string,
|
||||
headers?: Record<string, string>,
|
||||
signal?: AbortSignal,
|
||||
thinkingLevel?: ThinkingLevel,
|
||||
): Promise<Result<string, CompactionError>> {
|
||||
@@ -737,8 +718,8 @@ async function generateTurnPrefixSummary(
|
||||
model,
|
||||
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },
|
||||
model.reasoning && thinkingLevel && thinkingLevel !== "off"
|
||||
? { maxTokens, signal, apiKey, headers, reasoning: thinkingLevel }
|
||||
: { maxTokens, signal, apiKey, headers },
|
||||
? { maxTokens, signal, reasoning: thinkingLevel }
|
||||
: { maxTokens, signal },
|
||||
);
|
||||
if (response.stopReason === "aborted") {
|
||||
return err(new CompactionError("aborted", response.errorMessage || "Turn prefix summarization aborted"));
|
||||
|
||||
@@ -805,7 +805,7 @@ export interface AgentHarnessOptions<
|
||||
/**
|
||||
* Provider collection used for all model requests (turn streaming,
|
||||
* compaction, branch summarization). Auth resolves through the providers'
|
||||
* auth; explicit per-request values (`getApiKeyAndHeaders`) win per field.
|
||||
* auth.
|
||||
*/
|
||||
models: Models;
|
||||
tools?: TTool[];
|
||||
@@ -824,9 +824,6 @@ export interface AgentHarnessOptions<
|
||||
activeTools: TTool[];
|
||||
resources: AgentHarnessResources<TSkill, TPromptTemplate>;
|
||||
}) => string | Promise<string>);
|
||||
getApiKeyAndHeaders?: (
|
||||
model: Model<any>,
|
||||
) => Promise<{ apiKey: string; headers?: Record<string, string> } | undefined>;
|
||||
/** Curated stream/provider request options. Snapshotted at turn start. */
|
||||
streamOptions?: AgentHarnessStreamOptions;
|
||||
model: Model<any>;
|
||||
|
||||
@@ -36,7 +36,7 @@ function captureOptions(options: StreamOptions | undefined): StreamOptions {
|
||||
}
|
||||
|
||||
describe("AgentHarness stream configuration", () => {
|
||||
it("snapshots stream options and merges auth headers before provider request hooks", async () => {
|
||||
it("snapshots stream options before provider request hooks", async () => {
|
||||
let capturedOptions: StreamOptions | undefined;
|
||||
const registration = newFaux();
|
||||
registration.setResponses([
|
||||
@@ -60,12 +60,11 @@ describe("AgentHarness stream configuration", () => {
|
||||
metadata: { base: true },
|
||||
cacheRetention: "none",
|
||||
},
|
||||
getApiKeyAndHeaders: async () => ({ apiKey: "secret", headers: { "x-auth": "auth" } }),
|
||||
});
|
||||
|
||||
harness.on("before_provider_request", (event) => {
|
||||
expect(event.sessionId).toBe("session-1");
|
||||
expect(event.streamOptions.headers).toEqual({ "x-base": "base", "x-auth": "auth" });
|
||||
expect(event.streamOptions.headers).toEqual({ "x-base": "base" });
|
||||
return {
|
||||
streamOptions: {
|
||||
headers: { "x-hook": "hook" },
|
||||
@@ -77,14 +76,13 @@ describe("AgentHarness stream configuration", () => {
|
||||
await harness.prompt("hello");
|
||||
|
||||
expect(capturedOptions).toMatchObject({
|
||||
apiKey: "secret",
|
||||
timeoutMs: 1000,
|
||||
maxRetries: 2,
|
||||
maxRetryDelayMs: 3000,
|
||||
sessionId: "session-1",
|
||||
cacheRetention: "none",
|
||||
});
|
||||
expect(capturedOptions?.headers).toEqual({ "x-base": "base", "x-auth": "auth", "x-hook": "hook" });
|
||||
expect(capturedOptions?.headers).toEqual({ "x-base": "base", "x-hook": "hook" });
|
||||
expect(capturedOptions?.metadata).toEqual({ base: true, hook: true });
|
||||
});
|
||||
|
||||
|
||||
@@ -440,20 +440,9 @@ describe("harness compaction", () => {
|
||||
},
|
||||
]);
|
||||
getOrThrow(
|
||||
await generateSummary(
|
||||
messages,
|
||||
models,
|
||||
reasoningModel,
|
||||
2000,
|
||||
"test-key",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
"medium",
|
||||
),
|
||||
await generateSummary(messages, models, reasoningModel, 2000, undefined, undefined, undefined, "medium"),
|
||||
);
|
||||
expect(seenOptions[0]).toMatchObject({ reasoning: "medium", apiKey: "test-key" });
|
||||
expect(seenOptions[0]).toMatchObject({ reasoning: "medium" });
|
||||
|
||||
const { faux: fauxOff, model: offModel } = createFauxModel(true);
|
||||
fauxOff.setResponses([
|
||||
@@ -462,20 +451,7 @@ describe("harness compaction", () => {
|
||||
return fauxAssistantMessage("## Goal\nTest summary");
|
||||
},
|
||||
]);
|
||||
getOrThrow(
|
||||
await generateSummary(
|
||||
messages,
|
||||
models,
|
||||
offModel,
|
||||
2000,
|
||||
"test-key",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
"off",
|
||||
),
|
||||
);
|
||||
getOrThrow(await generateSummary(messages, models, offModel, 2000, undefined, undefined, undefined, "off"));
|
||||
expect(seenOptions[1]).not.toHaveProperty("reasoning");
|
||||
|
||||
const { faux: fauxNonReasoning, model: nonReasoningModel } = createFauxModel(false);
|
||||
@@ -486,18 +462,7 @@ describe("harness compaction", () => {
|
||||
},
|
||||
]);
|
||||
getOrThrow(
|
||||
await generateSummary(
|
||||
messages,
|
||||
models,
|
||||
nonReasoningModel,
|
||||
2000,
|
||||
"test-key",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
"medium",
|
||||
),
|
||||
await generateSummary(messages, models, nonReasoningModel, 2000, undefined, undefined, undefined, "medium"),
|
||||
);
|
||||
expect(seenOptions[2]).not.toHaveProperty("reasoning");
|
||||
});
|
||||
@@ -516,17 +481,7 @@ describe("harness compaction", () => {
|
||||
]);
|
||||
|
||||
const summary = getOrThrow(
|
||||
await generateSummary(
|
||||
messages,
|
||||
models,
|
||||
model,
|
||||
2000,
|
||||
"test-key",
|
||||
{ "x-test": "yes" },
|
||||
undefined,
|
||||
"focus",
|
||||
"old summary",
|
||||
),
|
||||
await generateSummary(messages, models, model, 2000, undefined, "focus", "old summary"),
|
||||
);
|
||||
|
||||
expect(summary).toContain("Test summary");
|
||||
@@ -538,7 +493,7 @@ describe("harness compaction", () => {
|
||||
const messages: AgentMessage[] = [createUserMessage("Summarize this.")];
|
||||
const { faux: errorFaux, model: errorModel } = createFauxModel(false);
|
||||
errorFaux.setResponses([fauxAssistantMessage("", { stopReason: "error", errorMessage: "boom" })]);
|
||||
const errorResult = await generateSummary(messages, models, errorModel, 2000, "test-key");
|
||||
const errorResult = await generateSummary(messages, models, errorModel, 2000);
|
||||
expect(errorResult).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "summarization_failed", message: "Summarization failed: boom" },
|
||||
@@ -546,7 +501,7 @@ describe("harness compaction", () => {
|
||||
|
||||
const { faux: abortedFaux, model: abortedModel } = createFauxModel(false);
|
||||
abortedFaux.setResponses([fauxAssistantMessage("", { stopReason: "aborted", errorMessage: "stopped" })]);
|
||||
const abortedResult = await generateSummary(messages, models, abortedModel, 2000, "test-key");
|
||||
const abortedResult = await generateSummary(messages, models, abortedModel, 2000);
|
||||
expect(abortedResult).toMatchObject({ ok: false, error: { code: "aborted", message: "stopped" } });
|
||||
});
|
||||
|
||||
@@ -574,7 +529,7 @@ describe("harness compaction", () => {
|
||||
settings: { enabled: true, reserveTokens: 500000, keepRecentTokens: 20000 },
|
||||
};
|
||||
|
||||
getOrThrow(await compact(preparation, models, model, "test-key"));
|
||||
getOrThrow(await compact(preparation, models, model));
|
||||
|
||||
expect(seenOptions.map((options) => options?.maxTokens)).toEqual([128000, 128000]);
|
||||
});
|
||||
@@ -592,7 +547,7 @@ describe("harness compaction", () => {
|
||||
};
|
||||
const { faux: historyFaux, model: historyModel } = createFauxModel(false);
|
||||
historyFaux.setResponses([fauxAssistantMessage("", { stopReason: "error", errorMessage: "history failed" })]);
|
||||
expect(await compact(preparation, models, historyModel, "test-key")).toMatchObject({
|
||||
expect(await compact(preparation, models, historyModel)).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "summarization_failed", message: "Summarization failed: history failed" },
|
||||
});
|
||||
@@ -602,7 +557,6 @@ describe("harness compaction", () => {
|
||||
{ ...preparation, messagesToSummarize: [], firstKeptEntryId: "" },
|
||||
models,
|
||||
invalidModel,
|
||||
"test-key",
|
||||
);
|
||||
expect(invalidResult).toMatchObject({ ok: false, error: { code: "invalid_session" } });
|
||||
});
|
||||
@@ -627,7 +581,7 @@ describe("harness compaction", () => {
|
||||
settings: { enabled: true, reserveTokens: 2000, keepRecentTokens: 20 },
|
||||
};
|
||||
|
||||
getOrThrow(await compact(preparation, models, model, "test-key", undefined, undefined, undefined, "high"));
|
||||
getOrThrow(await compact(preparation, models, model, undefined, undefined, "high"));
|
||||
|
||||
expect(seenOptions[0]).toMatchObject({ reasoning: "high" });
|
||||
});
|
||||
@@ -646,14 +600,14 @@ describe("harness compaction", () => {
|
||||
const { faux, model } = createFauxModel(false);
|
||||
faux.setResponses([fauxAssistantMessage("", { stopReason: "error", errorMessage: "prefix failed" })]);
|
||||
|
||||
expect(await compact(preparation, models, model, "test-key")).toMatchObject({
|
||||
expect(await compact(preparation, models, model)).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "summarization_failed", message: "Turn prefix summarization failed: prefix failed" },
|
||||
});
|
||||
|
||||
const { faux: abortedFaux, model: abortedModel } = createFauxModel(false);
|
||||
abortedFaux.setResponses([fauxAssistantMessage("", { stopReason: "aborted", errorMessage: "prefix stopped" })]);
|
||||
expect(await compact(preparation, models, abortedModel, "test-key")).toMatchObject({
|
||||
expect(await compact(preparation, models, abortedModel)).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "aborted", message: "prefix stopped" },
|
||||
});
|
||||
@@ -672,7 +626,7 @@ describe("harness compaction", () => {
|
||||
expect(preparation).toBeDefined();
|
||||
const { faux, model } = createFauxModel(false);
|
||||
faux.setResponses([fauxAssistantMessage("## Goal\nTest summary")]);
|
||||
const result = getOrThrow(await compact(preparation!, models, model, "test-key"));
|
||||
const result = getOrThrow(await compact(preparation!, models, model));
|
||||
expect(result.summary.length).toBeGreaterThan(0);
|
||||
expect(result.firstKeptEntryId).toBeTruthy();
|
||||
expect(result.details).toBeDefined();
|
||||
|
||||
Reference in New Issue
Block a user