Files
pi_harness/packages/ai/test/scratch.ts
T
Mario Zechner fec0c3d12f feat(ai): provider factories, per-provider catalogs, createProvider (phase 3)
Auth helpers in src/auth/helpers.ts: envApiKeyAuth() (stored key wins,
then env vars in order, with secret-prompt login) and lazyOAuth()
(flow loads on first use through bundler-opaque dynamic imports in
utils/oauth/load.ts; the OAuthAuth flow exports land in phase 4).
There is no OAuth factory toggle: providers that support OAuth always
attach it, advertising costs nothing until login/refresh runs.

createProvider() in models.ts builds providers from parts: single API
implementation or a map dispatched on model.api (mixed-API providers
like opencode and github-copilot); unknown api yields a stream error.

generate-models.ts now emits one providers/<id>.models.ts catalog per
provider (35 files, biome-excluded like models.generated.ts) and
models.generated.ts becomes a generated aggregator, so importing one
provider factory pulls one catalog. Typed getModel globals unchanged.

One factory per built-in provider under src/providers/: envApiKeyAuth
for standard providers, OAuth for anthropic/openai-codex/github-copilot,
ambient ApiKeyAuth for amazon-bedrock (AWS env/profile/IAM) and
google-vertex (explicit key or ADC+project+location).

providers/all.ts: builtinProviders(), builtinModels(), getBuiltin*
re-exports. fauxProvider() factory returns a real Provider for tests;
legacy registerFauxProvider() unchanged.
2026-06-10 20:33:20 +02:00

58 lines
2.3 KiB
TypeScript

// Scratch script showing real-world use of the new Models API.
// Run from packages/ai: node test/scratch.ts
// Requires ANTHROPIC_API_KEY.
import { createModels } from "../src/models.ts";
import { anthropicProvider } from "../src/providers/anthropic.ts";
import type { Context } from "../src/types.ts";
// ---------------------------------------------------------------------------
// 1. Build a Models runtime and register a built-in provider factory.
// (Apps wanting everything use `builtinModels()` from providers/all.)
// ---------------------------------------------------------------------------
const models = createModels();
models.setProvider(anthropicProvider());
// ---------------------------------------------------------------------------
// 2. Look up a model and check auth.
// ---------------------------------------------------------------------------
const model = await models.getModel("anthropic", "claude-haiku-4-5");
if (!model) throw new Error("model not found");
const auth = await models.getAuth(model);
console.log(`model: ${model.provider}/${model.id}`);
console.log(`auth: ${auth ? `configured via ${auth.source}` : "not configured"}\n`);
if (!auth) process.exit(1);
const context: Context = {
systemPrompt: "You are terse.",
messages: [{ role: "user", content: "Say exactly: ok", timestamp: Date.now() }],
};
// ---------------------------------------------------------------------------
// 3. Simple completion (request-level auth resolution happens inside).
// ---------------------------------------------------------------------------
const message = await models.completeSimple(model, context);
console.log(`completeSimple -> [${message.stopReason}]`, message.content);
// ---------------------------------------------------------------------------
// 4. Streaming with deltas.
// ---------------------------------------------------------------------------
context.messages.push(message, {
role: "user",
content: "Now count from 1 to 5, one number per line.",
timestamp: Date.now(),
});
process.stdout.write("streamSimple -> ");
const stream = models.streamSimple(model, context);
for await (const event of stream) {
if (event.type === "text_delta") process.stdout.write(event.delta.replaceAll("\n", " "));
}
const final = await stream.result();
console.log(`[${final.stopReason}] cost: $${final.usage.cost.total.toFixed(6)}`);