Skip to main content
Alpha

@netscript/plugin-ai-core

The contract-only core for the NetScript AI plugin: the oRPC /v1/ai route surface — an SSE-framed chat stream plus models, tools/{name}, embed, and transcribe — that a connector implements and the typed client calls. This page is generated from the package's public surface with deno doc (US-2). For the full index of packages and plugins return to the reference overview.

The package ships zero service implementation (Archetype 1 — Small Contract). It declares the route shapes and their Zod IO vocabulary; a connector (@netscript/plugin-ai) binds the contract to a host and the @netscript/fresh/ai client generates a typed caller from it. Every route schema mirrors an engine type from @netscript/ai/contracts, and a compile-time drift guard (z.ZodType<EngineType> = schema) asserts the mirror cannot silently diverge from the domain contract.

Entrypoints

The package publishes two entrypoints. Each is generated from its own deno doc surface.

Export Entrypoint Purpose
@netscript/plugin-ai-core ./mod.ts Contract handles, router helpers, and route IO types (documented below).
@netscript/plugin-ai-core/contracts/v1 ./src/contracts/v1/mod.ts Full contract surface: the Zod *Schema validators plus the engine-derived vocabulary types.

The root path curates to the handles and IO types a typical consumer imports (staying within the ≤20-export doctrine budget); the ./contracts/v1 subpath exposes the complete schema and engine-vocabulary set a connector wires.

Root surface (@netscript/plugin-ai-core)

Contract handles and router helpers

Symbol Kind Description
aiContract variable AI service contract definition for client generation (the real, fully-inferred oRPC contract router — no erasure cast).
aiContractV1 variable The implemented, context-bindable v1 contract (implement(definition)); .$context<Ctx>() returns the precisely-typed router implementer.
createAiRouter function Bind a complete in-process AI implementation to the v1 contract, returning the oRPC handlers for each route.
AiRouterContext type alias Request context accepted by the generated AI router (Record<PropertyKey, unknown>).
ContextualAiRouter type alias The router implementer returned by aiContractV1.$context<TContext>().
AiRouteHandler type alias Handler function type for a single named route under a bound context.
AiRouterImplementation interface Per-route handler functions that implement every route in aiContractV1.
BoundAiRoute type alias The bound handler type produced by router.<route>.handler(...).
BoundAiRouter interface Contract-bound route handlers returned by createAiRouter.

Route IO and capability types

Symbol Kind Description
AiContract / AiContractDefinition / AiContractV1 type alias The fully-typed v1 contract shape and its context-binding implementer type.
AiRouter type alias The context-bound AI router implementer (ReturnType<typeof aiContractV1.$context<...>>).
AiCapabilities interface The capabilities document returned by the mandatory describe route (a named alias of PluginCapabilities).
ChatInput type alias Input accepted by the chat streaming endpoint.
ChatChunk type alias A single streamed chat frame — alias of the engine AgentChunk union.
ModelsResponse type alias Response returned by the models endpoint.
ToolInvokeInput / ToolInvokeResponse type alias Input and response for the tools/{name} invocation endpoint.
EmbedInput / EmbedResponse type alias Input and response for the embed endpoint.
TranscribeInput / TranscribeResponse type alias Input and response for the transcribe endpoint.

Full contract surface (@netscript/plugin-ai-core/contracts/v1)

The subpath re-exports both contract handles (aiContract, aiContractV1), every route IO type above, and the following additional symbols.

Zod IO schemas

Each schema is a named, explicitly-annotated Zod validator (annotated z.ZodType<EngineType> so the module fails to compile if it drifts from the engine contract it mirrors). A connector validates inbound bodies and outbound frames against these.

Symbol Kind Validates
ChatInputSchema variable chat request body (ChatInput).
ChatChunkSchema variable A single streamed chat frame (ChatChunk).
ModelsInputSchema variable Optional models filter ({ provider? }).
ModelsResponseSchema variable models response ({ models: ModelDescriptor[] }).
ToolInvokeInputSchema variable tools/{name} request body.
ToolInvokeResponseSchema variable tools/{name} response.
EmbedInputSchema variable embed request body.
EmbedResponseSchema variable embed response.
TranscribeInputSchema variable transcribe request body.
TranscribeResponseSchema variable transcribe response.

Engine-derived vocabulary types

The subpath re-exports the @netscript/ai/contracts streaming vocabulary verbatim, so a connector references the same domain types the schemas mirror without reaching into the engine package: AgentChunk, AudioContentPart, CompletionTokensDetails, ContentModality, ContentPart, ContentSource, DataContentSource, DocumentContentPart, DoneChunk, ErrorChunk, ImageContentPart, Message, MessageChunk, MessageContent, MessageRole, ModelCapabilities, ModelDescriptor, ModelId, ModelRef, ModelSelector, ModelsInput, PromptTokensDetails, ProviderUsageDetails, TextChunk, TextContentPart, ToolCall, ToolCallChunk, ToolCallState, ToolDescriptor, ToolResult, ToolResultChunk, ToolResultState, UrlContentSource, Usage, UsageChunk, UsageCostBreakdown, VideoContentPart, plus the AiContractDefinitionShape structural type.

The /v1/ai route surface

Route paths are relative; the /v1/ai prefix is applied where the service host mounts the router. The contract layers five plugin-specific routes onto the base seam describe route.

Route Method Path Input Output
chat POST /chat ChatInput SSE eventIterator<ChatChunk>
models GET /models ModelsInput? ModelsResponse
invokeTool POST /tools/{name} ToolInvokeInput ToolInvokeResponse
embed POST /embed EmbedInput EmbedResponse
transcribe POST /transcribe TranscribeInput TranscribeResponse
describe GET /describe AiCapabilities

chat input

ChatInput carries the request the connector forwards to its provider adapter.

Field Type Notes
model ModelRef A "provider:model" string or a { provider, model } selector.
messages readonly Message[] The conversation transcript.
tools readonly ToolDescriptor[] (optional) Tool descriptors offered to the model.
system string (optional) System prompt.
temperature number (optional) Constrained 02 by the schema.
maxTokens number (optional) Positive integer.
metadata Record<string, unknown> (optional) Opaque per-request metadata.

SSE chat contract (durable-CHAT)

chat is the streaming centerpiece. Its output is not a request/response pair but an oRPC eventIterator whose element type is ChatChunk — an alias of the engine AgentChunk union. Because the contract output type is an async event-iterator, a connector's chat handler must be an async generator that yields frames; a buffered single-response implementation does not type-check. Recoverable and terminal errors surface in-stream as the error chunk rather than as an oRPC error, matching the engine's streaming model — so the chat route (built with oc.route, not the base contract) carries an empty error map.

Event (chunk) shapes

Each streamed frame is one of seven discriminated shapes, keyed on type:

type Payload Meaning
text { delta: string } Incremental assistant text appended this tick.
tool-call { toolCall: ToolCall } A tool invocation requested by the model.
tool-result { result: ToolResult } The result of an executed tool, fed back into the loop.
message { message: Message } A fully-assembled message committed to the transcript.
usage { usage: Usage } Token usage for the step or run.
error { error: string, cause?: unknown } A recoverable or terminal error surfaced through the stream.
done { usage?: Usage } Terminal frame closing the run, optionally carrying final usage.

The contract declares frame shapes, not wire headers. @netscript/plugin-ai-core is a transport-agnostic oRPC contract: the text/event-stream wire framing (per-frame data: lines, the response content type) is produced by the oRPC handler at the host mount point when it serves an eventIterator output, not declared in this package. This page documents the event shapes the stream carries; the HTTP framing belongs to the connector's service host.

Base-contract extension

aiContract spreads BASE_PLUGIN_CONTRACT_ROUTES from @netscript/plugin/contract-base verbatim, so it inherits the mandatory describe route (GET /describe) unchanged. describe returns a marketplace-discoverable AiCapabilities document — a named alias of PluginCapabilities:

Field Type Description
pluginName string Canonical plugin package name, e.g. @netscript/plugin-ai.
contractVersions readonly string[] Contract version identifiers served by the plugin.
routeGroups readonly string[] Route group names exposed by the plugin.
capabilities readonly string[] Capability tags advertised by the plugin.

The non-streaming routes (models, invokeTool, embed, transcribe, describe) converge onto the shared plugin error vocabulary from BASE_PLUGIN_ERRORS:

Code HTTP status Default message
NOT_FOUND 404 Resource not found
VALIDATION_ERROR 422 Validation failed
INTERNAL 500 Internal server error

Binding the contract (aiContractV1 / AiRouter)

A connector binds its host request context and implements each route handler. The precise per-route IO types check every handler; there is no erasure cast on the contract or the implementer.

aiContractV1.$context<TContext>() returns the contract-bound implementerAiRouter is the type alias naming its default (empty-context) shape, and ContextualAiRouter<TContext> the context-parameterized one. The implementer is not an assembled handler map: each route on it exposes a .handler() call that binds one implementation function.

import { aiContractV1 } from '@netscript/plugin-ai-core';

// Bind the host request context; each route is then implemented individually.
const router = aiContractV1.$context<{ requestId: string }>();

// The `chat` output is an event-iterator, so the handler MUST stream frames.
const chat = router.chat.handler(async function* ({ input }) {
  for (const message of input.messages) {
    yield { type: 'text' as const, delta: `echo: ${JSON.stringify(message.content)}` };
  }
  yield { type: 'done' as const };
});
// models / invokeTool / embed / transcribe / describe bind the same way.

Assembling all six bound routes by hand is what createAiRouter exists to avoid: it wraps aiContractV1.$context(), binds a complete per-route implementation (AiRouterImplementation) in one call, and returns the bound handler map (BoundAiRouter):

import { createAiRouter } from '@netscript/plugin-ai-core';

const router = createAiRouter({
  describe: () => ({
    pluginName: '@netscript/plugin-ai',
    contractVersions: ['v1'],
    routeGroups: ['ai'],
    capabilities: ['chat'],
  }),
  async *chat() {
    yield { type: 'done' as const };
  },
  models: () => ({ models: [] }),
  invokeTool: () => ({ content: 'No tools registered.', state: 'error' as const }),
  embed: () => ({ embeddings: [] }),
  transcribe: () => ({ text: '' }),
});

Validating IO on the ./contracts/v1 subpath

The Zod validators let a connector parse an inbound request body against the contract and validate each frame before forwarding it down the stream:

import { ChatChunkSchema, ChatInputSchema } from '@netscript/plugin-ai-core/contracts/v1';

// Parse an inbound request body against the streamed-chat input contract.
const request = ChatInputSchema.parse({
  model: 'anthropic:claude-sonnet-4-5',
  messages: [{ role: 'user', content: 'Stream me a haiku.' }],
});

// Validate each frame a provider emits before forwarding it down the SSE stream.
const chunk = ChatChunkSchema.parse({ type: 'text', delta: 'silent...' });
console.log(request.model, chunk.type);

How the AI plugin stack consumes this contract

  • Connector (@netscript/plugin-ai) — re-exports this contract surface from its own ./contracts/v1 (export * from '@netscript/plugin-ai-core/contracts/v1') and declares the loader on its manifest (withContractVersions), so a host binds the AI plugin against a single pinned /v1/ai contract. It binds aiContractV1.$context<Ctx>() and implements each route against a provider adapter.
  • @netscript/fresh/ai client — imports aiContract and generates a typed caller, so a Fresh island streams chat chunks and calls models / embed / transcribe with full type inference and no hand-written request types.
  • Marketplace tooling — reads the describe route's AiCapabilities document to introspect a running AI plugin without parsing source.

Back to the reference overview.