
AGENTO
A TypeScript library for conversational access to REST APIs.
Engineering challenge / AI agent runtime
An API contract needs a conversation runtime.
A REST API already defines what an application can do. Giving a model a list of endpoints leaves the developer with another system to build: argument validation, missing input, dependent calls, session state and approval before a write.
I built AGENTO as a TypeScript library for that shared runtime. Developers describe their API tools in configuration and embed the runtime in their application. The model interprets the request; the library manages the steps required to execute it.
- Existing REST APIs
- Stateful conversations
- Explicit execution
The execution boundary
Approval belongs to an exact action.
The model proposes a tool call. The runtime validates the inputs, resolves dependencies and prepares a request that the user can review.
runtime.confirm()
Selection → preparation → approval
01 / The starting point
Build the shared runtime around the API.
The reusable problem sits between a conversation and an API. A model can suggest an action without having all the fields, a current record identifier or permission to perform it. Those gaps need explicit behavior that survives the next message.
The earlier handler combined trigger detection, model classification, field extraction and HTTP execution. In, I separated those responsibilities into five boundaries. That made it possible to change a model provider or an integration without moving request validation and execution rules into the prompt.
Architecture and migration decisions02 / Inside the library
Five layers. A defined job for each.
These are responsibility boundaries, not five steps that every message must visit. Compilation happens at startup. A no-tool route can go straight to conversation. A selected tool enters orchestration and execution.
- 01
Configuration & compilation
Define what the application allows before a message arrives.
- Receives
- Developer-authored YAML: tools, schemas, mappings and policies.
- Does
- Validate the configuration, compile schemas and check dependencies.
- Produces
- A compiled registry used by routing and execution.
Inside this layer
Zod checks the configuration structure; AJV compiles the tool JSON Schemas. Reference, mapping and cycle checks catch invalid contracts at startup. The model receives names, descriptions and input schemas. URLs, headers, credentials and mapping rules stay in execution configuration.
- 02
Retrieval & routing
Find the relevant tools, then validate the proposed choice.
- Receives
- A message, permitted conversation context and the compiled tool catalog.
- Does
- Build a shortlist, ask for a tool choice and check the returned arguments.
- Produces
- One validated tool choice, or a valid no-tool result.
Inside this layer
Lexical retrieval searches names, descriptions, hints and keywords, with Arabic normalization. When confidence is weak, optional model recall can add candidates from a lightweight catalog. This is model-based recall, not a vector database. Final routing validates candidate membership and supplied arguments; missing required values are handled by orchestration. A provider failure is an error, not an ordinary no-tool decision.
- 03
Orchestration
Keep track of what the operation still needs.
- Receives
- A chosen tool or direct invocation, arguments and session state.
- Does
- Collect missing fields, resolve read dependencies, manage choices and approval.
- Produces
- A request ready for execution, or a structured pause for the host to display.
Inside this layer
Explicit states and dependency frames preserve progress across turns. Selected records remain runtime-owned facts with context and expiry. Missing user fields are collected before dependencies run; automatic dependencies must be read-only. The host resumes a pause through select() or confirm(), or ends it through cancel().
- 04
Request mapping & execution
Turn validated values into the declared HTTP request.
- Receives
- Validated arguments, dependency results and compiled request mappings.
- Does
- Prepare the request; send it once the runtime has satisfied the approval policy.
- Produces
- An API result, optionally checked against an output schema, or an execution error.
Inside this layer
Mappings explicitly choose where each request value comes from. Credentials are attached at the transport boundary. The executor applies timeouts, response-size limits, origin checks, blocked redirects and bounded retry policies. It does not invent an endpoint or grant permission to perform a write.
- 05
Conversation & presentation
Produce a useful reply from the context the runtime permits.
- Receives
- A valid no-tool route, or a completed API result with permitted facts.
- Does
- Answer conversationally or present sanitized, projected output.
- Produces
- A conversational reply, raw API data, an AI explanation, or both result forms.
Inside this layer
This boundary serves two paths: ordinary conversation and the explanation after a tool call. A side question can preserve a pending operation and its original expiry. If presentation fails after a successful action, the completed API result is retained. Neither reply path authorizes execution.
Shared services / used across layers
- Model adapters
- A capability-aware interface connects OpenAI, Anthropic, Mistral, Cohere and Ollama to routing, recall and presentation.
- Read the implementation
- Sessions & credentials
- Session storage keeps frames, facts, references and pending approvals. A separate credential store keeps encrypted opaque tokens for transport.
- Read the implementation
- Redaction & projections
- Known credentials and configured private fields are removed; projections control which API facts can reach presentation.
- Read the implementation
- Operational controls
- Hooks, timing and token-usage reporting, plus rate-limit policies, support the host application around runtime work.
- Read the implementation
The host sits outside these layers. It supplies configuration, binds callers to sessions and handles user-facing selection and confirmation. Chat, direct invocation and the protocol-independent MCP handlers reuse the same runtime contract.
03 / Runtime flow
Separate interpretation from execution.
Model routing produces a proposed call. Orchestration owns the state needed to execute it. The HTTP layer receives a request assembled from the compiled contract.
YAML → Zod + AJV → Compiled registry
Incoming message
Model routing
Lexical candidates · Optional model recall
One validated tool call, or no tool
Conversation
Reply within the current context.
A valid conversational detour can retain the pending input, selection or confirmation.
Orchestration
Resolve what the action needs.
Collect missing input. Resolve read dependencies and choices. Validate the final arguments. Require confirmation for writes.
Execution
Send the prepared HTTP request.
Apply transport policy and credentials. Return the API result through the configured validation and presentation path.
Read the architecture · Read the router
04 / Engineering decisions
Give each decision a place to be checked.
Compile once; validate at each boundary.
Zod and AJV serve different contracts: application configuration and arbitrary tool JSON Schema. Compiling those schemas at startup avoids rebuilding validators for every message. Returned tool choices and final execution arguments still have their own checks.
Read the implementationKeep API identifiers out of guesswork.
A selected record supplies the identifier needed by a later call. Dependency mappings carry those values into execution, and dependency-owned top-level fields are removed from the model-facing input schema. The execution schema still requires them.
Read the implementationMake provider differences explicit.
Five adapters use native fetch behind a shared capability contract. This avoids separate provider SDK dependency trees while keeping wire-format differences in the adapters. Model behavior still needs evaluation for the chosen provider and catalog.
Read the implementation
05 / Across turns
Keep the operation coherent across turns.
These three situations show why a pending action needs its own state, separate from the conversation history.
Illustrated flows reconstructed from the implementation. This is not a live agent or a recorded customer conversation.
06 / Confirmation
Bind approval to the request it approves.
A confirmation stores the prepared request, its preview and an expiry. A hash binds it to the session, configuration, arguments, dependency data and host context. If those inputs change, the old approval is no longer valid.
The host calls confirm() after explicit approval. The runtime validates the confirmation and consumes it before sending HTTP. A typed “yes” in the core chat flow returns the pending confirmation; it does not independently authorize the write.
// Persist consumption before HTTP.
delete s.confirmation;
transition(s, "EXECUTING");
await this.#store.set(s.id, s);
return this.#execute(t, f, c.prepared);
The approval is consumed before transport. An interrupted operation is not implicitly replayed.
Confirmation implementation07 / Authentication ownership
Let the API remain the authority.
AGENTO forwards an opaque session token at the HTTP boundary. The downstream API decides whether it is valid and whether the action is allowed. The host binds sessions to callers; the runtime keeps credential transport out of model tool arguments.
- Host application
- Bind the caller to the session
- AGENTO
- Store and transport opaque credentials
- Downstream API
- Validate identity, expiry and permission
08 / When execution fails
A failed reply and a failed action need different handling.
Bound the HTTP work.
Requests have timeouts, response-size limits and circuit-breaker policies. The executor checks the configured origin and blocks redirects. Retries are restricted by the declared read-only or idempotency policy.
Read the implementationPreserve a completed action.
If a write succeeds and the optional AI presentation fails, the runtime retains the completed API result. A failed explanation must not turn into another attempt to perform the action.
Read the implementationKeep the delivery boundary honest.
Consuming an approval prevents replay of that approval. A network timeout can still leave the business outcome uncertain. Backend idempotency and reconciliation are needed where ambiguous delivery matters.
Read the implementation
09 / Recent implementation milestones
The work moved deeper into the conversation lifecycle.
20 SEP 2026
The foundation
The initial repository snapshot contains the compiled configuration, runtime state, HTTP transport, provider adapters and integration boundaries.
Commit e7b4bf8 ↗21 SEP 2026
Routing and continuation
Subsequent changes add multilingual recall and strengthen selection, confirmation and navigation across turns.
Commit 9d0b464 ↗22 SEP 2026
Selection lifecycle
The latest reviewed change carries permitted option facts through side questions, preserves expiry and tightens reference handling.
Commit 9cde905 ↗10 / What the implementation delivers
A reusable execution layer around existing APIs.
The result is an alpha library with explicit contracts for routing, input collection, dependencies, selection, approval and HTTP execution. Applications supply the domain contracts; AGENTO supplies the state and execution rules that carry an operation across turns.
- One runtime contract
- Chat, direct invocation and host-controlled continuation share theexecution model. The package root and /v2 entry point expose AgentRuntime.
- Host integration examples
- Console and Discord examples show how applications embed the runtime. Their domain behavior is declared in configuration.
- Five provider adapters
- OpenAI, Anthropic, Mistral, Cohere and Ollama adapters use native HTTP transport behind a capability-aware model interface.
- An MCP integration foundation
- tools/list and tools/call handlers reuse runtime validation. Selection and confirmation remain host-controlled; a standalone MCP transport is not shipped.
11 / The current boundary
What still needs to be established.
- Live routing quality. The current release is alpha. Semantic selection still needs evaluation against the chosen live model, languages and actual catalog. No live accuracy percentage is claimed.
- Multiple application instances. The supplied session store, rate limiter and circuit breaker operate in memory. Horizontal scale needs a distributed implementation of the session transaction contract and shared operational controls.
- Catalog size and configuration trust. Lightweight recall is bounded to small catalogs. Configuration remains trusted application code; accepting third-party configs requires additional network and resource controls.
A useful agent keeps track of what the user chose, what the API confirmed and what still needs permission.
Implementation references / pinned to the reviewed commit
- Project contract and scope ↗README.md
- Architecture and design decisions ↗docs/v2/ARCHITECTURE.md
- Configuration compiler ↗src/v2/config/compiler.ts
- Lexical retrieval ↗src/v2/tools/retriever.ts
- Model recall ↗src/v2/tools/semantic-recall.ts
- Final tool routing ↗src/v2/tools/router.ts
- State, selection and confirmation ↗src/v2/runtime/agent-runtime.ts
- Session transaction contract ↗src/v2/session/store.ts
- HTTP execution ↗src/v2/http/executor.ts
- Provider adapters ↗src/v2/models/providers.ts
- MCP boundary ↗src/v2/mcp/adapter.ts
- Conversation responder ↗src/v2/conversation/responder.ts
- Authentication and operations ↗docs/v2/SECURITY-OPERATIONS.md
- Alpha scope and known limits ↗docs/v2/VERIFICATION.md