Skip to content

Model and media ​

The /model subpath defines provider-neutral model requests, responses, profiles, and content contracts. Live media generation and transcription ports are published independently at /media. ModelRequest carries messages, tools, response format, sampling, and redacted metadata. ModelResponse represents either a completion or a structured error. ModelError.code distinguishes provider cancellation (cancelled) from an elapsed deadline (timeout), so callers do not retry an explicit abort as a timeout.

Content uses a closed union: text, JSON, inline binary, media reference, reasoning, tool call, and tool result. A media-ref points to a ResourceRef; an authorized resolver supplies its bytes only when execution needs them.

ts
import { createBuiltinModel, type ModelRequest } from "@geekist/llm-core/model";
import { newCoreId, type InvocationContext, type InvocationId } from "@geekist/llm-core/contracts";
import type { ImageGenerationPort, TranscriptionPort } from "@geekist/llm-core/media";

const context: InvocationContext = {
  invocationId: newCoreId<InvocationId>("0190bd0c-0000-7000-8000-000000002410"),
};
const request: ModelRequest = {
  messages: [{ role: "user", content: [{ kind: "text", text: "hello" }] }],
};

const response = await createBuiltinModel().generate({ request, context });

declare const images: ImageGenerationPort;
declare const transcription: TranscriptionPort;

await images.generate({ request: { prompt: "A contour map", count: 1 }, context });
await transcription.transcribe({
  request: { audio: { kind: "bytes", mediaType: "audio/wav", bytes: new Uint8Array() } },
  context,
});

void response;

Profiles describe verified behavior ​

A ModelProfile records model, provider, deployment, contract version, and evidence-backed capability claims. It is portable data, not a provider client. Registering a profile validates, clones, and freezes it.

Resolve a model binding ​

ModelRef expresses logical selection intent. ProviderRef identifies a service dialect, while DeploymentRef identifies one configured endpoint. None carries a credential or executable client.

ts
import type { CapabilityRequirement } from "@geekist/llm-core/contracts";
import { createModelResolver, modelRef, type ModelBinding } from "@geekist/llm-core/model/runtime";

declare const bindings: readonly ModelBinding[];
declare const requiredCapabilities: readonly CapabilityRequirement[];

const resolver = createModelResolver({
  constraintEvaluator: () => true,
  policyEvaluator: ({ binding }) => binding.provider !== "provider.blocked",
});

const outcome = resolver.resolve({
  selection: modelRef("model.reasoning"),
  bindings,
  requiredCapabilities,
  policy: {
    defaultModel: modelRef("model.standard"),
  },
});

if (outcome.kind === "unresolved") {
  throw new Error(JSON.stringify(outcome.diagnostics));
}

console.log(outcome.resolution.matchedBy, outcome.resolution.binding.bindingId);

createModelResolver evaluates bindings deterministically:

  1. an exact ModelRef match wins before aliases;
  2. without an explicit selection, a named policy.defaultModel is required;
  3. policy allow-lists and required evidence-backed capabilities filter matches;
  4. constraints require a trusted evaluator and fail closed on throws or non-boolean results;
  5. zero eligible bindings and multiple eligible bindings return unresolved outcomes with diagnostics.

The resolver never selects the first candidate, reads credentials, silently downgrades a requirement, or turns a provider/deployment identity into model selection intent.

The built-in model is deterministic and useful for local composition and tests. Provider integrations remain qualified adapter imports, for example:

ts
import { createAiSdk7Model } from "@geekist/llm-core/adapters/ai-sdk";

The adapter receives live provider dependencies during composition. Provider metadata crosses the boundary only after a trusted redactor projects safe JSON into a namespaced extension.

Preserve resolved identity for usage evidence ​

createResolvedModelIdentity snapshots the exact model, provider, deployment, profile ID, and profile version selected for an invocation. When a live Model is already available, resolvedModelIdentityFromProfile(model.profile) derives the same identity without copying profile claims, extensions, or a provider client.

Pass that identity to the evidence capability when recording observed usage. This binds a usage receipt to what was actually resolved while keeping model selection, credentials, and pricing outside the receipt.

Media ports ​

ImageGenerationPort, SpeechGenerationPort, and TranscriptionPort accept live bytes or authorized resource references and return portable media. A MediaOutputProjector decides whether output is safe to inline or should become a resource reference.

Schema identity and resource identity stay separate from the live resolvers that interpret schemas or load bytes.