mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(durable): beforeProviderRequest generation hook (#11619)
Adds a `beforeProviderRequest` generation hook so extensions can replace the provider request body before it is sent. It is the durable counterpart of coding-agent's `before_provider_request`. Durable calls `streamSimple()`, so apps can't set provider-specific fields such as Anthropic's `thinking.display: "updates"` (#10804) without wrapping `Models`. Now it's an extension: ```ts hook(GenerationTask, { beforeProviderRequest: ({ model, payload }) => { if (model.api !== "anthropic-messages") return undefined; // change payload return { payload }; }, }) ```
This commit is contained in:
parent
3bbb06aad7
commit
d280e1ffa2
6 changed files with 109 additions and 2 deletions
|
|
@ -752,6 +752,75 @@ describe("generation hooks", () => {
|
|||
await harness.close(context);
|
||||
});
|
||||
|
||||
it("chains beforeProviderRequest over every provider request body", async () => {
|
||||
const setup = chatSetup();
|
||||
const seen: { hook: string; model: string; payload: unknown }[] = [];
|
||||
addHooks(setup.registry, GenerationTask, {
|
||||
beforeProviderRequest: ({ model, payload }) => {
|
||||
seen.push({ hook: "first", model: `${model.provider}/${model.id}`, payload });
|
||||
return { payload: { ...(payload as object), first: true } };
|
||||
},
|
||||
});
|
||||
addHooks(setup.registry, GenerationTask, {
|
||||
beforeProviderRequest: ({ model, payload }) => {
|
||||
seen.push({ hook: "keep", model: `${model.provider}/${model.id}`, payload });
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
addHooks(setup.registry, GenerationTask, {
|
||||
beforeProviderRequest: ({ payload }) => ({ payload: { ...(payload as object), last: true } }),
|
||||
});
|
||||
const sent: unknown[] = [];
|
||||
// pi-ai builds a body per provider call, and again when it resends within one attempt.
|
||||
const respond: FauxResponseStep = async (_context, options, _state, model) => {
|
||||
sent.push(await options!.onPayload!({ body: 1 }, model));
|
||||
sent.push(await options!.onPayload!({ body: 2 }, model));
|
||||
return DONE;
|
||||
};
|
||||
const { harness, status } = await run(setup, [respond]);
|
||||
expect(status).toBe("done");
|
||||
expect(sent).toEqual([
|
||||
{ body: 1, first: true, last: true },
|
||||
{ body: 2, first: true, last: true },
|
||||
]);
|
||||
expect(seen).toEqual([
|
||||
{ hook: "first", model: "faux/faux-1", payload: { body: 1 } },
|
||||
{ hook: "keep", model: "faux/faux-1", payload: { body: 1, first: true } },
|
||||
{ hook: "first", model: "faux/faux-1", payload: { body: 2 } },
|
||||
{ hook: "keep", model: "faux/faux-1", payload: { body: 2, first: true } },
|
||||
]);
|
||||
await harness.close(context);
|
||||
});
|
||||
|
||||
it("reports a throwing beforeProviderRequest hook and continues the chain", async () => {
|
||||
const setup = chatSetup();
|
||||
addHooks(
|
||||
setup.registry,
|
||||
GenerationTask,
|
||||
{
|
||||
beforeProviderRequest: () => {
|
||||
throw new Error("broken hook");
|
||||
},
|
||||
},
|
||||
"broken",
|
||||
);
|
||||
addHooks(setup.registry, GenerationTask, {
|
||||
beforeProviderRequest: ({ payload }) => ({ payload: { ...(payload as object), after: true } }),
|
||||
});
|
||||
let sent: unknown;
|
||||
const respond: FauxResponseStep = async (_context, options, _state, model) => {
|
||||
sent = await options!.onPayload!({ body: 1 }, model);
|
||||
return DONE;
|
||||
};
|
||||
const { harness, status } = await run(setup, [respond]);
|
||||
expect(status).toBe("done");
|
||||
expect(sent).toEqual({ body: 1, after: true });
|
||||
expect(setup.infos.filter((info) => info.kind === "extension_error")).toEqual([
|
||||
expect.objectContaining({ extension: "broken" }),
|
||||
]);
|
||||
await harness.close(context);
|
||||
});
|
||||
|
||||
it("keeps the run's input open across an onYield continuation and answers it with the final answer", async () => {
|
||||
const setup = chatSetup();
|
||||
let yields = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue