chore(vendor): import pi 0.85.1
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
98
third_party/pi/packages/ai/src/api/lazy.ts
vendored
Normal file
98
third_party/pi/packages/ai/src/api/lazy.ts
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
import type { Api, AssistantMessage, AssistantMessageEvent, Model, ProviderStreams } from "../types.ts";
|
||||
import { AssistantMessageEventStream } from "../utils/event-stream.ts";
|
||||
|
||||
function createSetupErrorMessage(model: Model<Api>, error: unknown): AssistantMessage {
|
||||
return {
|
||||
role: "assistant",
|
||||
content: [],
|
||||
api: model.api,
|
||||
provider: model.provider,
|
||||
model: model.id,
|
||||
usage: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 0,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
stopReason: "error",
|
||||
errorMessage: error instanceof Error ? error.message : String(error),
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function hasResult(
|
||||
source: AsyncIterable<AssistantMessageEvent>,
|
||||
): source is AsyncIterable<AssistantMessageEvent> & { result(): Promise<AssistantMessage> } {
|
||||
return typeof (source as { result?: unknown }).result === "function";
|
||||
}
|
||||
|
||||
async function forwardStream(
|
||||
target: AssistantMessageEventStream,
|
||||
source: AsyncIterable<AssistantMessageEvent>,
|
||||
): Promise<void> {
|
||||
for await (const event of source) {
|
||||
target.push(event);
|
||||
}
|
||||
target.end(hasResult(source) ? await source.result() : undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream synchronously while running async setup (auth resolution,
|
||||
* lazy module loading) behind it. Setup failures terminate the stream with an
|
||||
* error event.
|
||||
*/
|
||||
export function lazyStream(
|
||||
model: Model<Api>,
|
||||
setup: () => Promise<AsyncIterable<AssistantMessageEvent>>,
|
||||
): AssistantMessageEventStream {
|
||||
const outer = new AssistantMessageEventStream();
|
||||
|
||||
setup()
|
||||
.then((inner) => forwardStream(outer, inner))
|
||||
.catch((error) => {
|
||||
const message = createSetupErrorMessage(model, error);
|
||||
outer.push({ type: "error", reason: "error", error: message });
|
||||
outer.end(message);
|
||||
});
|
||||
|
||||
return outer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a dynamically imported API implementation module as `ProviderStreams`.
|
||||
* The module loads on first stream call; the host's import cache deduplicates
|
||||
* loads. Load failures terminate the returned stream with an error event.
|
||||
*/
|
||||
export interface LazyApiCapabilities {
|
||||
fetchDeferred?: boolean;
|
||||
cancelDeferred?: boolean;
|
||||
}
|
||||
|
||||
export function lazyApi(load: () => Promise<ProviderStreams>, capabilities?: LazyApiCapabilities): ProviderStreams {
|
||||
const api: ProviderStreams = {
|
||||
stream: (model, context, options) =>
|
||||
lazyStream(model, async () => (await load()).stream(model, context, options)),
|
||||
streamSimple: (model, context, options) =>
|
||||
lazyStream(model, async () => (await load()).streamSimple(model, context, options)),
|
||||
};
|
||||
|
||||
if (capabilities?.fetchDeferred) {
|
||||
api.fetchDeferred = (model, handle, options) =>
|
||||
lazyStream(model, async () => {
|
||||
const implementation = await load();
|
||||
if (!implementation.fetchDeferred) throw new Error("API does not support deferred responses");
|
||||
return implementation.fetchDeferred(model, handle, options);
|
||||
});
|
||||
}
|
||||
if (capabilities?.cancelDeferred) {
|
||||
api.cancelDeferred = async (model, handle, options) => {
|
||||
const implementation = await load();
|
||||
if (!implementation.cancelDeferred) throw new Error("API cannot cancel deferred responses");
|
||||
await implementation.cancelDeferred(model, handle, options);
|
||||
};
|
||||
}
|
||||
|
||||
return api;
|
||||
}
|
||||
Reference in New Issue
Block a user