@browserlessapi/inferlo 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -2
  3. package/dist/ai/index.d.ts +96 -0
  4. package/dist/ai/index.js +327 -0
  5. package/dist/ai/index.js.map +1 -0
  6. package/dist/ai/providers.d.ts +97 -0
  7. package/dist/ai/providers.js +204 -0
  8. package/dist/ai/providers.js.map +1 -0
  9. package/dist/app.d.ts +94 -0
  10. package/dist/app.js +365 -0
  11. package/dist/app.js.map +1 -0
  12. package/dist/auth.d.ts +29 -0
  13. package/dist/auth.js +61 -0
  14. package/dist/auth.js.map +1 -0
  15. package/dist/cli/main.d.ts +2 -0
  16. package/dist/cli/main.js +467 -0
  17. package/dist/cli/main.js.map +1 -0
  18. package/dist/db/memory.d.ts +2 -0
  19. package/dist/db/memory.js +128 -0
  20. package/dist/db/memory.js.map +1 -0
  21. package/dist/db/migrate.d.ts +84 -0
  22. package/dist/db/migrate.js +355 -0
  23. package/dist/db/migrate.js.map +1 -0
  24. package/dist/db/postgres.d.ts +37 -0
  25. package/dist/db/postgres.js +338 -0
  26. package/dist/db/postgres.js.map +1 -0
  27. package/dist/db/table.d.ts +72 -0
  28. package/dist/db/table.js +177 -0
  29. package/dist/db/table.js.map +1 -0
  30. package/dist/db/types.d.ts +36 -0
  31. package/dist/db/types.js +2 -0
  32. package/dist/db/types.js.map +1 -0
  33. package/dist/describe.d.ts +56 -0
  34. package/dist/describe.js +64 -0
  35. package/dist/describe.js.map +1 -0
  36. package/dist/env.d.ts +19 -0
  37. package/dist/env.js +72 -0
  38. package/dist/env.js.map +1 -0
  39. package/dist/errors.d.ts +40 -0
  40. package/dist/errors.js +99 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/index.d.ts +26 -0
  43. package/dist/index.js +18 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/mcp.d.ts +18 -0
  46. package/dist/mcp.js +166 -0
  47. package/dist/mcp.js.map +1 -0
  48. package/dist/model.d.ts +36 -0
  49. package/dist/model.js +76 -0
  50. package/dist/model.js.map +1 -0
  51. package/dist/openapi.d.ts +6 -0
  52. package/dist/openapi.js +71 -0
  53. package/dist/openapi.js.map +1 -0
  54. package/dist/route.d.ts +125 -0
  55. package/dist/route.js +28 -0
  56. package/dist/route.js.map +1 -0
  57. package/dist/schema.d.ts +156 -0
  58. package/dist/schema.js +430 -0
  59. package/dist/schema.js.map +1 -0
  60. package/dist/serve.d.ts +11 -0
  61. package/dist/serve.js +83 -0
  62. package/dist/serve.js.map +1 -0
  63. package/dist/testing.d.ts +16 -0
  64. package/dist/testing.js +30 -0
  65. package/dist/testing.js.map +1 -0
  66. package/llms.txt +27 -0
  67. package/package.json +82 -4
  68. package/templates/app/AGENTS.md +53 -0
  69. package/templates/app/CLAUDE.md +1 -0
  70. package/templates/app/README.md +14 -0
  71. package/templates/app/_env.example +5 -0
  72. package/templates/app/_gitignore +3 -0
  73. package/templates/app/package.json.tpl +31 -0
  74. package/templates/app/src/app.ts +38 -0
  75. package/templates/app/src/models.ts +31 -0
  76. package/templates/app/src/routes/health.ts +3 -0
  77. package/templates/app/src/routes/notes.ts +56 -0
  78. package/templates/app/src/server.ts +16 -0
  79. package/templates/app/test/notes.test.ts +50 -0
  80. package/templates/app/tsconfig.json +17 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 BrowserlessAPI (Nero Softwares & IT Services Pvt. Ltd.)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,128 @@
1
- # Temporary Holding Version
1
+ # Inferlo
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **The TypeScript backend framework with built-in AI model support.**
4
+
5
+ Inferlo is a batteries-included TypeScript backend framework with AI models built into its core. Connect Anthropic, OpenAI, Gemini, DeepSeek, Qwen, local models through Ollama or any OpenAI-compatible server, and call them from any route with one API: automatic fallback between models, typed structured output, streaming, embeddings, and per-user usage and cost tracking. Routing, validation, database, auth, OpenAPI and an MCP server come in the same package, with zero runtime dependencies.
6
+
7
+ ```ts
8
+ import { model, route, t } from "@browserlessapi/inferlo";
9
+
10
+ export const Ticket = model("tickets", {
11
+ title: t.string().min(3).max(200),
12
+ body: t.text(),
13
+ priority: t.enum(["low", "normal", "urgent"]).default("normal"),
14
+ ownerId: t.ref("users"),
15
+ });
16
+
17
+ export const createTicket = route
18
+ .post("/tickets", { body: Ticket.pick("title", "body"), tool: true })
19
+ .handle(({ body, user, db }) => db.tickets.insert({ ...body, ownerId: user.id }));
20
+
21
+ export const triageTicket = route
22
+ .post("/tickets/:id/triage", { params: t.object({ id: t.uuid() }), auth: "agent" })
23
+ .handle(async ({ params, db, ai, user }) => {
24
+ const ticket = await db.tickets.get(params.id);
25
+ const { object } = await ai.generate({
26
+ model: "fast",
27
+ prompt: ticket.body,
28
+ output: t.object({ priority: Ticket.fields.priority, summary: t.string().max(300) }),
29
+ for: user.id,
30
+ });
31
+ return db.tickets.update(ticket.id, object);
32
+ });
33
+ ```
34
+
35
+ That one model definition gives you the database table, insert and update validation, TypeScript types, OpenAPI docs, an MCP tool and the AI output schema.
36
+
37
+ ## AI models built in
38
+
39
+ - **Every major provider, one API.** Anthropic, OpenAI, Gemini, Ollama and any OpenAI-compatible server (DeepSeek, Qwen, Groq, OpenRouter, vLLM and more).
40
+ - **Model aliases with fallback.** Routes ask for `"fast"` or `"smart"`; if the first model is down or rate limited, Inferlo tries the next one.
41
+ - **Typed structured output.** Pass a schema and get validated, typed data back. Invalid answers are repaired automatically.
42
+ - **Streaming.** Send model output to the browser as it is generated with one call.
43
+ - **Embeddings** for search and recommendations.
44
+ - **Usage, cost and budgets.** Every call is tracked per user, so you can bill customers and stop calls when their credits run out.
45
+ - **MCP server.** Mark a route `tool: true` and AI agents can call your API, with the same permissions as any other client.
46
+
47
+ ## Why Inferlo
48
+
49
+ | | NestJS | Hono | AdonisJS | Express | **Inferlo** |
50
+ |---|---|---|---|---|---|
51
+ | Batteries included (DB, validation, auth) | Partial | No | Yes | No | **Yes** |
52
+ | Runs on Node, Bun, Deno and edge | No | Yes | No | No | **Yes** |
53
+ | One schema for DB, validation, API docs and AI | No | No | No | No | **Yes** |
54
+ | AI providers, fallback, structured output, streaming in core | No | No | No | No | **Yes** |
55
+ | Built-in MCP server from your routes | No | No | No | No | **Yes** |
56
+ | Token usage tracking and budgets | No | No | No | No | **Yes** |
57
+ | Private routes by default | No | No | No | No | **Yes** |
58
+ | Errors with codes, fixes and docs links | No | No | Partial | No | **Yes** |
59
+ | Zero runtime dependencies | No | Yes | No | No | **Yes** |
60
+
61
+ ## Easy to build with AI coding tools
62
+
63
+ Inferlo is also designed so AI coding tools (Claude Code, Cursor, Codex, NeonCodex and others) write correct Inferlo code on the first try:
64
+
65
+ - **Familiar shapes.** Hono-style routes and Zod-style schemas: patterns models already know.
66
+ - **One way to do things.** One route API, one schema API, one query API, one AI API.
67
+ - **No hidden behaviour.** No decorators, no dependency injection, no global registration. Everything a handler needs is in its file.
68
+ - **Types catch invented code.** Misspelled fields, missing tables and wrong types fail at compile time. At runtime, unknown fields are rejected with "Did you mean ...?".
69
+ - **Errors that explain the fix.** Every error has a stable code (`IL1001`), the cause, the fix and a docs link.
70
+ - **Tools for agents.** `inferlo describe --json` returns the whole app map. `inferlo check --json` returns typecheck, load and test results as JSON. `inferlo add resource` generates correct CRUD code.
71
+ - **Docs for machines.** [`llms.txt`](llms.txt), [`llms-full.txt`](llms-full.txt), and every new project ships with `AGENTS.md` and `CLAUDE.md`.
72
+ - **Secure by default.** Routes require a signed-in user unless marked public, every query is parameterised, and every insert is validated, so AI-written code stays safe even with light review.
73
+
74
+ ## Quick start
75
+
76
+ Requires Node.js 22.18+ or Bun 1.3+. TypeScript runs directly with no build step.
77
+
78
+ Every release is tested on Node.js 22.18, 22, 24 and the current release; Bun 1.3.0 and latest; PostgreSQL 14, 15, 16, 17, 18 and latest; and TypeScript 5.9 and latest.
79
+
80
+ ```bash
81
+ npx @browserlessapi/inferlo new my-app
82
+ cd my-app && npm install && npm run dev
83
+ ```
84
+
85
+ Or add it to an existing project:
86
+
87
+ ```bash
88
+ npm install @browserlessapi/inferlo
89
+ ```
90
+
91
+ ## Features
92
+
93
+ - **Routing:** `route.get/post/put/patch/delete`, typed path params, query coercion, CORS, middleware, body limits
94
+ - **Schemas:** `t.string()`, `t.email()`, `t.enum()`, `t.ref()`, ... with `.optional()`, `.default()`, `.pick()`, `.partial()`, JSON Schema output
95
+ - **Database:** typed tables (`db.tickets.findMany(...)`), PostgreSQL and in-memory adapters, `inferlo db push`, versioned migrations (`inferlo db migrate`), transactions, unique and foreign keys
96
+ - **Auth:** `auth.resolve(req)`, `bearer()` API keys, roles, password hashing with Web Crypto
97
+ - **AI:** Anthropic, OpenAI, Gemini, Ollama and any OpenAI-compatible server; aliases with fallback; structured output with automatic repair; streaming to SSE; embeddings; per-user usage and cost tracking; budgets
98
+ - **MCP:** routes with `tool: true` become MCP tools at `/mcp`, with the same auth as HTTP
99
+ - **OpenAPI 3.1** at `/openapi.json`
100
+ - **Testing:** `app.request(path, { json, as: user })`, `mockProvider()`, `memory()`
101
+ - **CLI:** `new`, `dev`, `describe`, `check`, `db push`, `db migrate`, `openapi`, `add resource`
102
+
103
+ ## Documentation
104
+
105
+ - [Getting started](docs/getting-started.md)
106
+ - [Schemas](docs/schema.md)
107
+ - [Models and database](docs/database.md)
108
+ - [Routes](docs/routes.md)
109
+ - [Auth](docs/auth.md)
110
+ - [AI](docs/ai.md)
111
+ - [MCP, OpenAPI and describe](docs/mcp.md)
112
+ - [CLI](docs/cli.md)
113
+ - [Testing](docs/testing.md)
114
+ - [Deployment](docs/deploy.md)
115
+ - [Error codes](docs/errors.md)
116
+ - [Example: helpdesk with AI triage](examples/helpdesk)
117
+
118
+ ## Status
119
+
120
+ Inferlo is at **v0.1**. The core API is usable and tested on Node and Bun with PostgreSQL. See [ROADMAP.md](ROADMAP.md) for what is next and [CHANGELOG.md](CHANGELOG.md) for what changed.
121
+
122
+ ## Contributing
123
+
124
+ See [CONTRIBUTING.md](CONTRIBUTING.md). AI agents working on this repository: read [AGENTS.md](AGENTS.md).
125
+
126
+ ## License
127
+
128
+ [MIT](LICENSE)
@@ -0,0 +1,96 @@
1
+ import { type AnySchema, type Infer } from "../schema.ts";
2
+ import { type Message, type Provider } from "./providers.ts";
3
+ export * from "./providers.ts";
4
+ export interface Pricing {
5
+ /** USD per million input tokens. */
6
+ input: number;
7
+ /** USD per million output tokens. */
8
+ output: number;
9
+ }
10
+ export interface Usage {
11
+ /** Alias or model id you asked for. */
12
+ requested: string;
13
+ /** "provider:model" that actually answered. */
14
+ model: string;
15
+ inputTokens: number;
16
+ outputTokens: number;
17
+ /** USD, when pricing is configured for the model. Otherwise 0. */
18
+ cost: number;
19
+ /** Who to bill: the userId / tenant you passed as `for`. */
20
+ for?: string;
21
+ kind: "generate" | "stream" | "embed";
22
+ durationMs: number;
23
+ }
24
+ export interface AIConfig {
25
+ /** Named providers: { anthropic: anthropic({...}), local: ollama() }. */
26
+ providers: Record<string, Provider>;
27
+ /** Aliases to "provider:model" ids. A list means fallback order. */
28
+ models?: Record<string, string | string[]>;
29
+ /** Alias or id used when a call does not name a model. */
30
+ defaultModel?: string;
31
+ /** Prices per model id ("anthropic:claude-haiku-4-5") for cost tracking. Inferlo ships no prices because they change. */
32
+ pricing?: Record<string, Pricing>;
33
+ /** Called after every call. Store it, bill it, log it. */
34
+ onUsage?: (usage: Usage) => void | Promise<void>;
35
+ /**
36
+ * Called before a call that has `for` set. Return false (or throw) to block it,
37
+ * e.g. when a user has used up their credits. Blocked calls raise IL5004 (HTTP 402).
38
+ */
39
+ allow?: (info: {
40
+ for: string;
41
+ model: string;
42
+ }) => boolean | Promise<boolean>;
43
+ }
44
+ export interface GenerateOptions<O extends AnySchema | undefined> {
45
+ /** Alias ("fast") or "provider:model". */
46
+ model?: string;
47
+ /** Shorthand for a single user message. */
48
+ prompt?: string;
49
+ system?: string;
50
+ messages?: Message[];
51
+ /** Schema for structured output. The result's `object` is validated and typed. */
52
+ output?: O;
53
+ temperature?: number;
54
+ maxTokens?: number;
55
+ /** Who this call is for (user or tenant id), for usage tracking and budgets. */
56
+ for?: string;
57
+ signal?: AbortSignal;
58
+ /** Extra attempts when structured output does not match the schema (default 1). */
59
+ repairAttempts?: number;
60
+ }
61
+ export interface GenerateResult<O> {
62
+ text: string;
63
+ object: O;
64
+ usage: Usage;
65
+ }
66
+ export interface StreamResult {
67
+ /** Text chunks as they arrive. */
68
+ [Symbol.asyncIterator](): AsyncIterator<string>;
69
+ /** Full text once the stream finishes. */
70
+ text(): Promise<string>;
71
+ /** A server-sent events Response for browsers (events: "text", then "done" with usage). */
72
+ toResponse(init?: ResponseInit): Response;
73
+ /** Usage once the stream finishes. */
74
+ usage(): Promise<Usage>;
75
+ }
76
+ export interface AI {
77
+ generate<O extends AnySchema | undefined = undefined>(options: GenerateOptions<O>): Promise<GenerateResult<O extends AnySchema ? Infer<O> : undefined>>;
78
+ stream(options: Omit<GenerateOptions<undefined>, "output">): StreamResult;
79
+ embed(options: {
80
+ model?: string;
81
+ input: string | string[];
82
+ for?: string;
83
+ signal?: AbortSignal;
84
+ }): Promise<{
85
+ embeddings: number[][];
86
+ usage: Usage;
87
+ }>;
88
+ /** Configured aliases, for describe(). */
89
+ readonly aliases: Record<string, string[]>;
90
+ readonly configured: boolean;
91
+ }
92
+ /** Pull a JSON value out of model text, tolerating ```json fences and leading prose. */
93
+ export declare function extractJson(text: string): unknown;
94
+ export declare function createAI(config?: AIConfig): AI;
95
+ /** Cosine similarity of two vectors, for small in-memory searches. */
96
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Inferlo AI: one API for every model provider, with model aliases, automatic fallback,
3
+ * typed structured output, streaming, embeddings, usage tracking and budgets.
4
+ *
5
+ * ai: {
6
+ * providers: { anthropic: anthropic({ apiKey: env("ANTHROPIC_API_KEY") }) },
7
+ * models: { fast: ["anthropic:claude-haiku-4-5", "openai:gpt-5-mini"] },
8
+ * }
9
+ *
10
+ * const { object } = await ctx.ai.generate({ model: "fast", prompt, output: Triage })
11
+ */
12
+ import { InferloError, didYouMean } from "../errors.js";
13
+ import { toJSONSchema } from "../schema.js";
14
+ import { ProviderError } from "./providers.js";
15
+ export * from "./providers.js";
16
+ function buildMessages(o) {
17
+ const messages = [];
18
+ if (o.system)
19
+ messages.push({ role: "system", content: o.system });
20
+ if (o.messages)
21
+ messages.push(...o.messages);
22
+ if (o.prompt !== undefined)
23
+ messages.push({ role: "user", content: o.prompt });
24
+ if (!messages.some((m) => m.role !== "system")) {
25
+ throw new InferloError("IL5007", "ai.generate() needs a prompt or messages.", { fix: 'Pass prompt: "..." or messages: [{ role: "user", content: "..." }].' });
26
+ }
27
+ return messages;
28
+ }
29
+ /** Pull a JSON value out of model text, tolerating ```json fences and leading prose. */
30
+ export function extractJson(text) {
31
+ const trimmed = text.trim();
32
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(trimmed);
33
+ const candidate = fenced ? fenced[1].trim() : trimmed;
34
+ try {
35
+ return JSON.parse(candidate);
36
+ }
37
+ catch {
38
+ const start = candidate.search(/[[{]/);
39
+ const end = Math.max(candidate.lastIndexOf("}"), candidate.lastIndexOf("]"));
40
+ if (start !== -1 && end > start)
41
+ return JSON.parse(candidate.slice(start, end + 1));
42
+ throw new SyntaxError("No JSON found in model output");
43
+ }
44
+ }
45
+ export function createAI(config) {
46
+ const providers = config?.providers ?? {};
47
+ const aliases = {};
48
+ for (const [alias, ids] of Object.entries(config?.models ?? {}))
49
+ aliases[alias] = Array.isArray(ids) ? ids : [ids];
50
+ const resolve = (requested) => {
51
+ const name = requested ?? config?.defaultModel ?? Object.keys(aliases)[0];
52
+ if (!Object.keys(providers).length) {
53
+ throw new InferloError("IL5001", "No AI providers are configured.", {
54
+ fix: 'Add createApp({ ai: { providers: { anthropic: anthropic({ apiKey: env("ANTHROPIC_API_KEY") }) }, models: { fast: "anthropic:claude-haiku-4-5" } } }).',
55
+ });
56
+ }
57
+ if (!name)
58
+ throw new InferloError("IL5001", "No model given and no default model configured.", { fix: 'Pass model: "provider:model" or set ai.defaultModel.' });
59
+ const ids = aliases[name] ?? [name];
60
+ return ids.map((id) => {
61
+ const colon = id.indexOf(":");
62
+ if (colon === -1) {
63
+ throw new InferloError("IL5001", `Unknown model or alias "${id}".${didYouMean(id, Object.keys(aliases))}`, {
64
+ fix: `Use an alias (${Object.keys(aliases).join(", ") || "none configured"}) or "provider:model", e.g. "anthropic:claude-haiku-4-5".`,
65
+ });
66
+ }
67
+ const providerName = id.slice(0, colon);
68
+ const provider = providers[providerName];
69
+ if (!provider) {
70
+ throw new InferloError("IL5001", `AI provider "${providerName}" is not configured.${didYouMean(providerName, Object.keys(providers))}`, {
71
+ fix: `Configured providers: ${Object.keys(providers).join(", ")}.`,
72
+ });
73
+ }
74
+ return { provider, providerName, model: id.slice(colon + 1), id };
75
+ });
76
+ };
77
+ const cost = (id, usage) => {
78
+ const price = config?.pricing?.[id];
79
+ if (!price)
80
+ return 0;
81
+ return (usage.inputTokens * price.input + usage.outputTokens * price.output) / 1_000_000;
82
+ };
83
+ const record = async (usage) => {
84
+ try {
85
+ await config?.onUsage?.(usage);
86
+ }
87
+ catch (error) {
88
+ console.error("[inferlo] ai.onUsage failed:", error);
89
+ }
90
+ };
91
+ const guard = async (forId, model) => {
92
+ if (!forId || !config?.allow)
93
+ return;
94
+ let allowed;
95
+ try {
96
+ allowed = await config.allow({ for: forId, model });
97
+ }
98
+ catch (error) {
99
+ if (error instanceof InferloError)
100
+ throw error;
101
+ allowed = false;
102
+ }
103
+ if (!allowed)
104
+ throw new InferloError("IL5004", "AI usage limit reached.", { status: 402, fix: "Add credits or raise this account's limit." });
105
+ };
106
+ /** Try each target in order, moving on only for retryable provider errors. */
107
+ const withFallback = async (targets, run) => {
108
+ const errors = [];
109
+ for (const target of targets) {
110
+ try {
111
+ return await run(target);
112
+ }
113
+ catch (error) {
114
+ if (error instanceof ProviderError && error.retryable) {
115
+ errors.push(`${target.id}: ${error.message}`);
116
+ continue;
117
+ }
118
+ throw error;
119
+ }
120
+ }
121
+ throw new InferloError("IL5003", `All models failed: ${targets.map((t) => t.id).join(", ")}.`, { status: 502, expose: false, details: errors });
122
+ };
123
+ const ai = {
124
+ aliases,
125
+ configured: Object.keys(providers).length > 0,
126
+ async generate(options) {
127
+ const requested = options.model ?? config?.defaultModel ?? Object.keys(aliases)[0] ?? "";
128
+ const targets = resolve(options.model);
129
+ await guard(options.for, requested);
130
+ const messages = buildMessages(options);
131
+ const schema = options.output;
132
+ const jsonSchema = schema ? toJSONSchema(schema) : undefined;
133
+ if (schema) {
134
+ const instruction = "Respond with only a JSON value that matches this JSON Schema. No prose, no code fences.\n" + JSON.stringify(jsonSchema);
135
+ const sys = messages.find((m) => m.role === "system");
136
+ if (sys)
137
+ sys.content += "\n\n" + instruction;
138
+ else
139
+ messages.unshift({ role: "system", content: instruction });
140
+ }
141
+ const started = Date.now();
142
+ return withFallback(targets, async (target) => {
143
+ const total = { inputTokens: 0, outputTokens: 0 };
144
+ const convo = messages.map((m) => ({ ...m }));
145
+ const attempts = schema ? 1 + Math.max(0, options.repairAttempts ?? 1) : 1;
146
+ let lastIssues = "";
147
+ for (let attempt = 0; attempt < attempts; attempt++) {
148
+ const response = await target.provider.generate({
149
+ model: target.model,
150
+ messages: convo,
151
+ temperature: options.temperature,
152
+ maxTokens: options.maxTokens,
153
+ json: Boolean(schema),
154
+ jsonSchema,
155
+ signal: options.signal,
156
+ });
157
+ total.inputTokens += response.usage.inputTokens;
158
+ total.outputTokens += response.usage.outputTokens;
159
+ const usage = {
160
+ requested,
161
+ model: target.id,
162
+ ...total,
163
+ cost: cost(target.id, total),
164
+ for: options.for,
165
+ kind: "generate",
166
+ durationMs: Date.now() - started,
167
+ };
168
+ if (!schema) {
169
+ await record(usage);
170
+ return { text: response.text, object: undefined, usage };
171
+ }
172
+ let parsed;
173
+ try {
174
+ parsed = extractJson(response.text);
175
+ }
176
+ catch {
177
+ lastIssues = "The response was not valid JSON.";
178
+ convo.push({ role: "assistant", content: response.text }, { role: "user", content: `${lastIssues} Reply with only the JSON value.` });
179
+ if (attempt === attempts - 1)
180
+ await record(usage);
181
+ continue;
182
+ }
183
+ const result = schema.safeParse(parsed);
184
+ if (result.ok) {
185
+ await record(usage);
186
+ return { text: response.text, object: result.value, usage };
187
+ }
188
+ lastIssues = result.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
189
+ convo.push({ role: "assistant", content: response.text }, { role: "user", content: `That JSON does not match the schema: ${lastIssues}. Reply with corrected JSON only.` });
190
+ if (attempt === attempts - 1)
191
+ await record(usage);
192
+ }
193
+ throw new InferloError("IL5002", `Model ${target.id} did not return output matching the schema. ${lastIssues}`, {
194
+ status: 502,
195
+ expose: false,
196
+ fix: "Simplify the output schema, add .describe() hints to fields, or use a stronger model.",
197
+ });
198
+ });
199
+ },
200
+ stream(options) {
201
+ const requested = options.model ?? config?.defaultModel ?? Object.keys(aliases)[0] ?? "";
202
+ let resolveText;
203
+ let rejectText;
204
+ let resolveUsage;
205
+ const textPromise = new Promise((res, rej) => ((resolveText = res), (rejectText = rej)));
206
+ const usagePromise = new Promise((res) => (resolveUsage = res));
207
+ textPromise.catch(() => { });
208
+ let consumed = false;
209
+ async function* run() {
210
+ if (consumed)
211
+ throw new InferloError("IL5008", "A stream can only be read once.", { fix: "Call ai.stream() again, or use await stream.text()." });
212
+ consumed = true;
213
+ const targets = resolve(options.model);
214
+ await guard(options.for, requested);
215
+ const messages = buildMessages(options);
216
+ const started = Date.now();
217
+ let full = "";
218
+ try {
219
+ for (let i = 0; i < targets.length; i++) {
220
+ const target = targets[i];
221
+ if (!target.provider.stream) {
222
+ throw new InferloError("IL5005", `Provider "${target.providerName}" does not support streaming.`);
223
+ }
224
+ let usage = { inputTokens: 0, outputTokens: 0 };
225
+ try {
226
+ for await (const part of target.provider.stream({ model: target.model, messages, temperature: options.temperature, maxTokens: options.maxTokens, signal: options.signal })) {
227
+ if (typeof part === "string") {
228
+ full += part;
229
+ yield part;
230
+ }
231
+ else
232
+ usage = part.usage;
233
+ }
234
+ }
235
+ catch (error) {
236
+ // Fall back only if nothing was sent yet.
237
+ if (error instanceof ProviderError && error.retryable && full === "" && i < targets.length - 1)
238
+ continue;
239
+ throw error;
240
+ }
241
+ const u = { requested, model: target.id, ...usage, cost: cost(target.id, usage), for: options.for, kind: "stream", durationMs: Date.now() - started };
242
+ await record(u);
243
+ resolveUsage(u);
244
+ resolveText(full);
245
+ return;
246
+ }
247
+ }
248
+ catch (error) {
249
+ rejectText(error);
250
+ throw error;
251
+ }
252
+ }
253
+ let iterator;
254
+ const start = () => (iterator ??= run());
255
+ return {
256
+ [Symbol.asyncIterator]: () => start(),
257
+ async text() {
258
+ if (!iterator)
259
+ for await (const _ of start())
260
+ void _;
261
+ return textPromise;
262
+ },
263
+ usage: () => usagePromise,
264
+ toResponse(init) {
265
+ const encoder = new TextEncoder();
266
+ const source = start();
267
+ const body = new ReadableStream({
268
+ async pull(controller) {
269
+ try {
270
+ const { value, done } = await source.next();
271
+ if (done) {
272
+ const usage = await usagePromise;
273
+ controller.enqueue(encoder.encode(`event: done\ndata: ${JSON.stringify({ usage })}\n\n`));
274
+ controller.close();
275
+ return;
276
+ }
277
+ controller.enqueue(encoder.encode(`event: text\ndata: ${JSON.stringify(value)}\n\n`));
278
+ }
279
+ catch (error) {
280
+ const code = error instanceof InferloError ? error.code : "IL9000";
281
+ controller.enqueue(encoder.encode(`event: error\ndata: ${JSON.stringify({ code })}\n\n`));
282
+ controller.close();
283
+ console.error("[inferlo] stream failed:", error);
284
+ }
285
+ },
286
+ cancel() {
287
+ void source.return(undefined);
288
+ },
289
+ });
290
+ return new Response(body, {
291
+ ...init,
292
+ headers: { "content-type": "text/event-stream; charset=utf-8", "cache-control": "no-cache", connection: "keep-alive", ...init?.headers },
293
+ });
294
+ },
295
+ };
296
+ },
297
+ async embed(options) {
298
+ const requested = options.model ?? "embed";
299
+ const targets = resolve(options.model ?? (aliases.embed ? "embed" : undefined));
300
+ await guard(options.for, requested);
301
+ const input = Array.isArray(options.input) ? options.input : [options.input];
302
+ const started = Date.now();
303
+ return withFallback(targets, async (target) => {
304
+ if (!target.provider.embed)
305
+ throw new InferloError("IL5005", `Provider "${target.providerName}" does not support embeddings.`);
306
+ const result = await target.provider.embed({ model: target.model, input, signal: options.signal });
307
+ const usage = { requested, model: target.id, ...result.usage, cost: cost(target.id, result.usage), for: options.for, kind: "embed", durationMs: Date.now() - started };
308
+ await record(usage);
309
+ return { embeddings: result.embeddings, usage };
310
+ });
311
+ },
312
+ };
313
+ return ai;
314
+ }
315
+ /** Cosine similarity of two vectors, for small in-memory searches. */
316
+ export function cosineSimilarity(a, b) {
317
+ let dot = 0;
318
+ let na = 0;
319
+ let nb = 0;
320
+ for (let i = 0; i < a.length; i++) {
321
+ dot += a[i] * b[i];
322
+ na += a[i] * a[i];
323
+ nb += b[i] * b[i];
324
+ }
325
+ return na && nb ? dot / Math.sqrt(na * nb) : 0;
326
+ }
327
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"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"}