Forge AI is Forge-owned, profile-scoped model routing for deployed applications. Applications declare what an AI use case may do; Forge supplies the private runtime capability, provider credential, budget enforcement, and metadata-only usage receipt.
Forge AI is not a raw OpenAI proxy. Application code cannot choose provider URLs, credentials, arbitrary model IDs, gateway headers, or another tenant's billing identity.
Forge AI is one service in the Forge Sites application-services
stack. Site owners can discover it from the
repository's Sites page, then configure it beside Build and Identity in
forgeBuild.ts. The future Forge Agent is a separate roadmap capability; Forge
AI does not grant an end user agent or repository authority.
| Capability | Current Alpha contract |
|---|---|
| Logical model routes | forge/text-fast@1, forge/text-quality@1, forge/text-reasoning@1 |
| Funding | Host funded only |
| Runtime | Server-side, non-streaming text messages |
| Native Forge JS | env.forge.ai.responses.create(...) |
| Connected Cloudflare Worker | env.FORGE_AI.responsesCreate(...) |
| Structured output | JSON Schema request, parsing, and Forge-side schema validation on fast and quality routes |
| Privacy | Prompt and completion content is not retained in Forge logs or usage rows |
| Production provider for connected Workers | Workers AI, selected by Forge |
BYOK, browser-direct invocation, streaming, tools, images, audio, embeddings, arbitrary models, caller-defined provider headers, and public HTTPS inference are not available. Forge has internal OpenAI-compatible adapters for OpenAI, Gemini, and Featherless, but applications cannot select them and connected Workers currently always use Workers AI.
The routes are stable application contracts, not provider aliases:
| Forge route | Intended use | Initial backend |
|---|---|---|
forge/text-fast@1 |
Frequent commentary and banter | Forge's current inexpensive Workers AI model |
forge/text-quality@1 |
Coaching, strategy, polished explanations | Llama 3.3 70B Instruct FP8 Fast |
forge/text-reasoning@1 |
User-triggered or sampled deep analysis | DeepSeek V4 Flash 0731 |
Quality and reasoning are enabled per account for controlled rollout. The reasoning route also requires paid Workers AI entitlement. Forge may canary or replace an internal backend without changing a profile or application call. The initial backend capabilities and prices are pinned from Cloudflare's Llama 3.3 70B model page, DeepSeek V4 Flash model page, and Workers AI pricing.
Add the policy to app.ai.profiles in the project's forgeBuild.ts. Profile
names are the application-facing API; provider and model details stay behind
the logical Forge route.
import { defineForge, importWrangler } from '@smolai/forge/config';
export default defineForge({
version: 1,
name: 'overgrid',
build: { command: 'pnpm run build', workingDirectory: '.' },
app: {
entrypoint: 'dist/server/index.js',
assets: { directory: 'dist/client' },
ai: {
profiles: {
gameCommentary: {
model: 'forge/text-fast@1',
audience: 'server',
funding: ['host'],
maxInputTokens: 2_500,
maxOutputTokens: 180,
response: {
type: 'json_schema',
name: 'game_commentary',
schema: {
type: 'object',
additionalProperties: false,
required: ['line', 'factIds'],
properties: {
line: { type: 'string', maxLength: 320 },
factIds: {
type: 'array',
minItems: 1,
maxItems: 12,
items: { type: 'string' },
},
},
},
},
limits: {
requestsPerMinute: 10,
hostCostMicrosPerDay: 1_000_000,
previewHostCostMicrosPerDay: 50_000,
},
privacy: { contentLogging: 'off' },
},
trainingCoach: {
model: 'forge/text-quality@1',
audience: 'server',
funding: ['host'],
maxInputTokens: 6_000,
maxOutputTokens: 700,
response: {
type: 'json_schema',
name: 'training_coach',
schema: {
type: 'object',
additionalProperties: false,
required: ['answer', 'factIds'],
properties: {
answer: { type: 'string' },
factIds: { type: 'array', items: { type: 'string' } },
},
},
},
limits: { requestsPerMinute: 10, hostCostMicrosPerDay: 5_000_000 },
privacy: { contentLogging: 'off' },
},
},
},
},
routes: [
{ pattern: '/assets/*', to: 'app.assets' },
{ pattern: '/*', to: 'app.http' },
],
provider: {
cloudflare: {
wrangler: importWrangler('wrangler.toml', {
shareProductionResources: true,
}),
},
},
});Use audience: 'server' for connected Workers. Although the manifest parser
reserves signed_in and anonymous, connected RPC does not carry visitor
identity and there is no browser-direct capability in this release.
Changing or adding a profile changes the immutable deployment policy. Commit
the forgeBuild.ts update and publish a new Forge release before calling the
new profile.
Forge publishes one private, Forge-managed service binding into the connected Worker Version:
interface ForgeAiBinding {
responsesCreate(input: {
profile: string;
input: Array<{
role: 'system' | 'user' | 'assistant';
content: string;
}>;
billing?: { source: 'host' };
idempotencyKey: string;
}): Promise<ForgeAiResult>;
}
interface Env {
FORGE_AI?: ForgeAiBinding;
}
const result = await env.FORGE_AI.responsesCreate({
profile: 'gameCommentary',
input: [
{
role: 'system',
content: 'Use only the supplied approved public facts.',
},
{
role: 'user',
content: JSON.stringify({ facts: approvedPublicFacts }),
},
],
billing: { source: 'host' },
idempotencyKey: `commentary:${eventDigest}`,
});Do not declare FORGE_AI in wrangler.toml. Forge owns that binding and
rejects repository-authored or inherited conflicts. The binding targets the
private ConnectedForgeAi RPC entrypoint; there is no public inference URL.
Forge seals the capability to one account, project, release, provider-target generation, manifest digest, and profiles digest. Those values are revalidated against mutable account, entitlement, project, target, and production-pointer state on each call. Application code never supplies them.
Native Forge JS receives the same normalized service through the trusted runtime facade:
const result = await env.forge.ai.responses.create({
profile: 'gameCommentary',
input: [{ role: 'user', content: JSON.stringify(approvedPublicFacts) }],
billing: { source: 'host' },
idempotencyKey: `commentary:${eventDigest}`,
});interface ForgeAiResult {
id: string;
outputText: string;
outputJson?: unknown;
route:
| 'forge/text-fast@1'
| 'forge/text-quality@1'
| 'forge/text-reasoning@1';
usage: {
inputTokens: number;
outputTokens: number;
estimatedCostMicros: number;
billedTo: 'host';
cached: false;
};
receipt: {
policyDigest: string;
pricingVersion: string;
limitResetAt?: string;
};
}response.type: 'json_schema' requests JSON output and causes Forge to parse
and validate it against the supplied JSON Schema before returning outputJson.
An invalid provider result fails with output_invalid. Applications should
still validate product-specific invariants such as allowed fact IDs and retain
a deterministic fallback. Structured output is rejected at deploy time for the
reasoning route because that backend capability is not part of its v1 contract.
Workers AI also documents that JSON Schema adherence is not guaranteed, which
is why Forge treats provider output as untrusted and validates it independently;
see JSON Mode.
Use an application timeout and retain deterministic behavior:
const fallback = deterministicCommentary(approvedPublicFacts);
if (!env.FORGE_AI) return fallback;
try {
const result = await withTimeout(
env.FORGE_AI.responsesCreate(request),
5_000,
);
return validateCommentary(result.outputJson) ?? fallback;
} catch {
return fallback;
}Forge AI should normally explain or transform an authoritative application result. It should not become the source of truth for game moves, permissions, prices, scoring, or other deterministic product behavior.
[A-Za-z][A-Za-z0-9_-]{0,63}.system, user, or assistant and each message is bounded to
100,000 characters.idempotencyKey is required and contains 8–128 characters.maxInputTokens defaults to 2,500 and may be 1–32,000.forge/text-quality@1, the input and output ceilings together may not
exceed its 24,000-token context window.maxOutputTokens defaults to 256 and may be 1–4,096.Forge reserves the route-specific worst case before inference, then reports and
settles a cost estimate from actual token usage when the provider supplies it.
estimatedCostMicros remains a pricing-table estimate rather than a reconciled
provider invoice. cached is currently always false.
Derive the key from the immutable logical event and normalized input. Reusing a
key with different input returns idempotency_conflict and never starts a
second provider call. Reusing the same key and input prevents a second charge,
but this Alpha does not replay the previous output; callers currently receive a
provider-unavailable failure instead. Keep a successful result in application
state when needed and use the deterministic fallback after an ambiguous retry.
Forge normalizes failures to these codes:
ai_disabledprofile_not_foundidentity_requiredbyok_consent_requiredbudget_exhaustedrate_limitedinput_too_largeoutput_invalidprovider_unavailableidempotency_conflictNative runtime failures expose the code on the returned error. Connected RPC callers should catch defensively; the capability may be absent in local development, disabled by entitlement or project state, rate limited, or unable to complete provider work.
Browser code must call a narrow application-owned server route. The application
route remains responsible for request-body validation, authentication or
Turnstile, per-user abuse controls, response validation, and a bounded timeout.
audience: 'server' protects the Forge capability; it does not automatically
protect a public application endpoint from abuse.
/.forge/ai is reserved but provides no browser or cross-account capability in
this release. A future signed HTTPS transport is needed only for Workers in a
different Cloudflare account or applications outside Cloudflare.
The intended OverGrid route policy is:
gameCommentary: short structured { line, factIds } output with 2,500
input tokens and 180 output tokens on forge/text-fast@1.trainingCoach: structured { answer, factIds } output with 6,000 input
tokens and 700 output tokens on forge/text-quality@1.forge/text-reasoning@1; ordinary move commentary does not.The ordinary profiles are host-funded, server-only, limited to 10 requests per minute, use a five-second application timeout, validate model output against approved fact IDs, and fall back to deterministic explanations. Commentary receives only the public tactical receipt after the authoritative game engine commits a move. The training coach also uses an application session, Turnstile, and rate limiters.
For local tests, mock FORGE_AI.responsesCreate. Forge injects the real binding
only into published connected Worker Versions.
Tell an application coding agent to:
forgeBuild.ts and publish a
new Forge release before using a new profile.outputJson.FORGE_AI binding, raw model IDs,
browser-direct calls, streaming, tools, or arbitrary upstream URLs.