AI
Spring AI–aligned chat, tools, RAG, MCP, and agents for TypeScript. Portable model abstractions sit on top of OpenAI-compatible and Anthropic HTTP adapters (no vendor SDKs). Domain services stay on @di-framework/core; this package is the AI layer — wire it with annotations (@AiService, @Agent, @Tool, …) or configureAi.
Features
Annotation DX:
@AiService/@Agentassistants,@Tool/@ToolSetbeans,@WithMemory/@WithRag/@WithTools, workflows (@Chain,@Route, …).ChatClient: fluent prompt / call / stream API with an advisor chain (memory, tools, RAG, logging, observation).
Prototype builder: inject
AiTokens.CHAT_CLIENT_BUILDER(fresh per resolve), like Spring’sChatClient.Builder.Providers:
OpenAiChatModelandAnthropicChatModeloverfetch— no official SDKs.createChatModel()selects API or CLI subscription access (OpenAI, Anthropic, xAI, and subscription-only CLIs).Tools:
functionToolCallback, method-level@Toolon DI beans, automatic tool-calling loops.Structured output: JSON Schema converters and
call().entity(...).Memory / RAG / MCP / agents: same runtime as the imperative APIs, annotation-friendly.
Agent Skills / plugins: not in this package — see Agents (
@di-framework/ai-utils).
Installation
Peer: @di-framework/core. Runtime dependency: @modelcontextprotocol/sdk (MCP helpers).
Set OPENAI_API_KEY, ANTHROPIC_API_KEY, or XAI_API_KEY when using the HTTP API route.
Decorators need TypeScript 5 and experimentalDecorators. emitDecoratorMetadata is not required. Parameter decorators are factories — call them with parentheses: @UserMessageAnn(), @MemoryId(), @ToolParam().
Quick Start (annotations)
configureAi registers the chat model, a singleton ChatClient, a prototype ChatClient.Builder, optional memory/tools/advisors, and (by default) scans annotations so @AiService/@Agent classes become resolvable factories.
Inject a prototype ChatClient.Builder
Each resolve of AiTokens.CHAT_CLIENT_BUILDER yields a fresh builder (Spring @Scope("prototype") style). Customize per service without mutating a shared client.
Imperative ChatClient
Advisors, default tools, and default system text can be attached on the builder before build(), or per prompt.
DI with configureAi
Useful options:
Option | Default | Meaning |
|---|---|---|
| — | Instance or factory; required unless already registered |
|
| Register singleton |
|
| Register prototype builder |
| — | Beans scanned for |
| — |
|
| — | Extra advisors on the default client |
| — | Emit redacted |
|
| Register annotated assistants / agents / workflows |
| — | Register a default |
Fine-grained helpers: registerChatModel, registerChatClient, registerChatClientBuilder, registerChatMemory, registerToolCallbacks, registerChatAgent, plus matching resolve* functions.
Tools
Two equivalent paths:
Bean methods —
@ToolSet()+@Tool({ description, inputSchema })on a@Container()class; pass the class totoolBeansor@AiService({ tools: [...] }).Callbacks —
functionToolCallback({ name, description, inputSchema }, handler)for imperative wiring.
Tool-calling loops run through the advisor chain (ToolCallingAdvisor). Duplicate tool names are deduped (last registration wins) when combining toolBeans and per-assistant tools.
Memory and advisors
@MemoryId()/@ConversationId() bind a method parameter to the chat-memory conversation id. Other advisor stereotypes: @WithRag/@RetrievalAugmented, @WithTools, @AiObserved/@Observed, plus @AiAdvisor/@AdvisorOrder for custom advisor beans.
RAG
Imperative pieces: SimpleVectorStore, FakeEmbeddingModel/ embedding models, VectorStoreDocumentRetriever, RetrievalAugmentationAdvisor. Annotation markers (@VectorStoreAnn, @EmbeddingModelAnn, @Retriever, @IndexedDocument, @WithRag) declare intent for scanning; wire stores and embeddings through configureAi({ embeddingModel, vectorStore }) or manual registration under AiTokens.
Agents and workflows
ChatAgent— multi-turn chat with tools/memory; build viaChatAgent.create(...),chatAgent(...), orChatAgent.fromBuilder(builder).@Agent/@ChatAgentBean— declarative bean resolved withresolveAnnotatedAgent.Workflows (imperative + stereotypes):
ChainWorkflow,RoutingWorkflow,ParallelizationWorkflow,OrchestratorWorkersWorkflow,EvaluatorOptimizerWorkflow, with matching@Chain,@Route/@Router,@Parallel,@Orchestrator/@Worker,@Evaluate/@Optimize.GraphWorkflow— typed graph runtime for arbitrary control flow (linear, branch, loop, nested subgraphs). Fluent builder with async edge predicates/transforms,AbortSignal,maxSteps, build-time validation, and lifecycle hooks. Helpers:chatToolLoopGraph,simpleAgentGraph. Graph stereotypes are deferred until the imperative API is stable.PlannerExecutorWorkflow— plan → act → replan loop onChatClient+ tools, with step limits and cycle protection.A2ABus— thin in-process agent-to-agent message bus with optional human-in-the-loop hooks (local only; not a network protocol).
MCP
Uses @modelcontextprotocol/sdk. Adapt an SDK client and expose remote tools as ToolCallbacks, or mark beans with @McpClient/@McpTool. Token: AiTokens.MCP_CLIENT.
Network A2A 1.0 (Agent-to-Agent Protocol over HTTP)
@di-framework/ai implements the standard AAIF Agent-to-Agent (A2A) 1.0 Protocol over HTTP JSON-RPC.
Agent Cards: Discover skills and capabilities at
GET {url}/.well-known/agent-card.json.JSON-RPC Operations: Standard 1.0 methods (
SendMessage,GetTask,ListTasks,CancelTask) over HTTP POST.Task Lifecycle: Strict states (
submitted→working→completed|failed|canceled|rejected|input-required|auth-required).Discovery:
A2ADirectoryfetches cards from registered origins and returns connectedA2AClientinstances.Process Boundary Opacity: Wire representation carries only messages, tasks, and artifacts. Internal prompts, tool definitions (MCP), and memory keys remain completely private inside the serving process.
MCP vs A2A: MCP equips agents with internal tools and resources; A2A dispatches tasks and work across independent agent services over the network.
Exposing an Agent over A2A
Discovering and Dispatching Work via A2ADirectory and A2AClient
In-process Local Bus (Non-network)
Agent Skills
Reusable SKILL.md folders and .agents/plugins discovery live in @di-framework/ai-utils, not this package. Prefer SkillsAgent.builder()/SkillsToolbox.builder() for skills, and validatePluginCatalog/loadPluginDirectory for plugins. For network agent capability advertising, use A2A Agent Card skills on @Agent({ skills, a2a }).
See Agents.
Providers
Both speak HTTP via fetch. Point baseUrl at any OpenAI-compatible gateway when needed.
Select API or subscription access
createChatModel() synchronously selects a model. There is no fallback from subscription to API on missing CLIs, login errors, or provider failures.
Explicit provider, auth, and model override PROVIDER, AUTH, and MODEL. A provider is required. api.model also precedes MODEL; the top-level model wins over both.
Provider | API route | Subscription route |
|---|---|---|
| OpenAI; existing default model | Codex CLI |
| Anthropic; existing default model | Claude CLI |
| xAI OpenAI-compatible endpoint; model required | Grok CLI |
| Unsupported | AGY CLI |
| Unsupported | Junie CLI |
| Unsupported | Local Nous proxy; model required |
Vendor names default to API access. Aliases codex, claude, and grok, and subscription-only providers, default to subscription access. Explicit auth always wins. API keys come from api.apiKey or OPENAI_API_KEY/ANTHROPIC_API_KEY/XAI_API_KEY; xAI never borrows an OpenAI key. Existing HTTP constructors keep their original behavior.
CLI inference requires Bun and the selected CLI on PATH (codex login, Claude login, grok login, AGY Google sign-in, or Junie including JUNIE_API_KEY). Hermes uses http://127.0.0.1:8645/v1; start hermes proxy start --provider nous separately.
api accepts the existing HTTP provider options (including a custom fetch). subscription accepts timeoutMs (default 120000), maxCalls (default 32), executable, toolCallingManager, and onEvent. Irrelevant route options are rejected. Native CLIs own their model/tool loop; framework callbacks go through a private MCP child. Streaming, token usage, sampling controls, media, and provider output schemas are unsupported on the subscription route.
Testing
Also available: FakeChatModel for fixed-content replies. Prefer scripted models in unit tests so tool loops stay deterministic.
Name collisions
Chat message types (SystemMessage, UserMessage, AssistantMessage) and other runtime types keep their names. Where a decorator would collide, the package exports an *Ann (or renamed) decorator:
Decorator export | Collides with |
|---|---|
| Message types |
| Model / client / memory types |
| Store / document / embedding types |
|
|
|
|
|
|
Tokens
Prefer AiTokens over ad-hoc strings:
Token | Default string | Role |
|---|---|---|
|
| Primary chat model |
|
| Alias |
|
| Singleton client |
|
| Prototype builder |
|
| Default agent |
|
| Memory bean |
| … | RAG |
|
| Aggregated tools |
|
| Aggregated advisors |
|
| MCP session |
|
| A2A server task store |
|
| A2A Fetch HTTP handler |
Decorator catalog (selection)
Decorator | Purpose |
|---|---|
| Declarative chat assistant (class → proxy) |
| Declarative |
| Prompt + session wiring |
| Tool methods on beans |
| Attach advisors |
| Bootstrap scanning + |
| Workflow stereotypes |
API Reference
Export | Description |
|---|---|
| Bootstrap model, client, builder, annotations, A2A |
| Fluent chat API |
| HTTP providers |
| Annotated assistants |
| Annotated agents |
| Imperative / builder agents |
| Tools |
| Memory |
| RAG |
| Fixed-pattern workflows |
| Graph agent runtime |
| Plan → act → replan |
| Registry and remote A2A agent discovery |
| HTTP JSON-RPC client for A2A operations |
| In-memory task state lifecycle store |
| JSON-RPC 2.0 A2A request dispatcher |
| Standard Web Fetch |
| Bearer token auth handler via |
| In-process multi-agent messages (local bus) |
| Tests |
| Well-known DI tokens |
| Typed errors |
Non-goals (v1)
Official vendor SDKs — HTTP adapters only; bring your own SDK behind a custom
ChatModelif needed.Hosting / orchestration platforms — no LangSmith, Bedrock Agents console, or cloud agent runtimes.
Full prompt IDE / playground — library APIs and annotations only.
Authorization of tool calls — tools run as wired; gate them in your handlers.
Persistent vector DBs as first-party drivers — in-memory / simple store plus interfaces; plug your own
VectorStore.
Example
Package tests under packages/di-framework-ai/tests cover ChatClient, tools, memory, RAG, MCP, agents, A2A 1.0, and the annotation DX.