Agent building: 150 lines of TypeScript code
Building a working AI agent requires just 150 lines of TypeScript code, not complex frameworks. While the GitHub repository "awesome-ai-agents-2026" curates over 300 tools, true understanding comes from stripping away the bloat to reveal the core mechanics. Type-safe architectures are the single most critical component for preventing bugs in modern AI agent development; simplicity often outperforms bloated ecosystems.
You will learn how strong typing enforces reliability when defining tool interfaces and managing conversation memory systems. We will structure a Message interface that keeps history intact without crashing the application.
Finally, we implement a functional research assistant using Node.js 18 and the @anthropic-ai/sdk. You will see how to replace mock data with real API calls from providers like SerpAPI or Brave Search while maintaining a clean error-handling strategy. By the end, you will possess a fully operational script that handles multi-step tasks, demonstrating that the barrier to entry for building intelligent systems is lower than the industry claims.
The Role of Type-Safe Architectures in Modern AI Agent Development
Defining AI Agent Message and Tool Interfaces in TypeScript
Clear communication boundaries between an AI model and its execution environment start with strict TypeScript interfaces. Create a `src/types.ts` file containing two specific interfaces: Message and Tool. The Message interface holds a `role` (either 'user' or 'assistant') plus `content` as a string, guaranteeing the LLM API receives properly formatted conversation history. Changes to tool functionality break existing code paths immediately, notifying developers before deployment. This agent accepts user questions, invokes tools like web search on demand, retains conversation history, and manages errors without crashing.
The Tool interface mandates `name`, `description`, `input_schema`, and an `execute` function returning a `Promise`. Such a schema forces a contract where the agent maps tool definitions directly to API requests. Flexible languages permit flexible argument passing, yet this rigidity removes a category of runtime errors where missing parameters trigger silent failures. Increased initial verbosity represents the cost; developers must define JSON schemas for every capability beforehand. Immediate feedback during refactoring emerges from this upfront effort, offering a distinct advantage when orchestrating complex multi-step tasks across diverse domains or enterprise workflows. Explicit types guarantee the agent processes structured data matching the set schema.
Building a 150-Line Research Assistant Without Frameworks
Orchestrating tool use and memory without heavy frameworks requires approximately 150 lines of TypeScript to construct a functional research assistant. Architecture depends on a Tool interface defining an `execute` function that returns a `Promise`, allowing safe handling of asynchronous web search operations. Enforcing strict types on the `input_schema` stops runtime errors when the LLM generates malformed arguments for external APIs. This method contrasts with the trend toward complex team-based orchestration found in multi-agent systems, favoring a single, verifiable control loop instead.
Implementation manages conversation history by appending user queries and assistant responses to a local array before each API call. This pattern ensures the model retains context across multi-step tasks while keeping state management explicit. Relying on a single process for state introduces a limitation: the agent loses memory if the Node.js process restarts, unlike distributed systems that persist state to external databases. Builders asking if they should use TypeScript for AI agents find the answer in the need for type safety when integrating flexible tools. Specialized niches like Web3 or enterprise often demand distinct frameworks, yet a lightweight TypeScript implementation offers sufficient rigor for custom research tasks. Manual verbosity exchanges for total control over the execution flow.
Preventing Runtime Errors Through Strong Typing Validation
Type safety in TypeScript halts runtime crashes by flagging interface mismatches during compilation rather than execution. Modifying a tool's `input_schema` causes the compiler to immediately identify broken references across the codebase. This mechanism prevents unpredictable failures common in untyped JavaScript implementations where malformed arguments reach the LLM API unchecked. Tool signatures remain consistent with their callers throughout development thanks to strong typing.
Over 300 distinct frameworks and tools now populate the system, creating significant integration complexity for builders. Strong typing acts as a guardrail against this fragmentation, enforcing contract stability between the agent logic and external utilities. Developers asking whether to adopt TypeScript for AI agents should consider that static analysis provides immediate feedback on structural changes. Skipping this safety net incurs a cost measurable in debugging time spent tracing data corruption through conversation history.
Internal Mechanics of Tool-Calling and Conversation Memory Systems
Agent Runner Logic and Tool Use Stop Reasons
The `chat` method initiates requests with a `max_tokens` limit of 4096 to constrain output generation. A response bearing the `stop_reason` of `tool_use` triggers the `handleToolUse` method to process external function calls. This conditional branch parses the response content for tool blocks, executes the mapped logic, and returns results to the model for final synthesis.
Such a loop enables flexible tool-augmented chatbots by deferring logic execution to the model's discretion. Relying on `stop_reason` parsing introduces latency because every tool call requires a round-trip API interaction before the user receives an answer. The drawback is a measurable response delay compared to direct function invocation patterns.
TypeScript interfaces enforce strict schema validation on tool inputs, preventing runtime errors during parameter passing. Strong typing governs the boundary between the LLM and external systems. The compiler notifies the developer wherever a change in tool functionality breaks the code.
Maintaining State with Conversation History Arrays
The `conversationHistory` array preserves context by storing every `user` and `assistant` message sequentially. This stateful mechanism allows the agent to reference prior turns when formulating responses. When the model requests external data, the `handleToolUse` method filters content for `tool_use` blocks and executes the corresponding logic. The system then appends these results back into the history before requesting a final synthesis. Flexible tool-augmented chatbots act on current information while retaining conversational continuity through this process.
Meanwhile, the TypeScript implementation enforces strict typing on the `Message` interface, preventing schema drift during complex multi-turn exchanges. Unbounded array growth eventually exceeds the context window of the underlying model. Builders must implement truncation policies or summarization strategies to maintain performance over long sessions. Latency increases as the token count rises with each interaction if such limits remain absent.
Memory management becomes a primary constraint on agent complexity as a direct operational consequence. The industry shifts toward LLM-powered backend services. Storing full history for thousands of concurrent users requires careful architectural planning due to the associated costs.
Security Risks of Eval in Calculator Tool Implementation
The guide demonstrates adding a `calculatorTool` in `src/tools/calculator.ts` which uses `eval` to perform mathematical calculations. Using JavaScript's `eval` function for mathematical operations introduces a remote code execution vector in production agents. The reference architecture demonstrates a `searchTool` in `src/tools/search.ts` that currently returns mock data, noting that for production, users should integrate with APIs like SerpAPI, Brave Search, or Tavily. Deployed systems relying on mock data or unsanitized inputs allow arbitrary command injection if user input is not strictly sanitized. Developers should replace mock implementations with dedicated, safe API integrations to enforce secure arithmetic and data evaluation. The source warns that in production, a safe math library like `mathjs` should be used instead of `eval`.
In practice, the `handleToolUse` method mitigates total system failure by catching exceptions and returning error strings rather than crashing the runtime. When the agent requests a tool that the registry cannot find, the logic returns a specific "Tool not found" message to the model. This error handling strategy prevents the agent from entering infinite retry loops when facing missing dependencies or typos in tool names.
Runtime validation alone leaves the application exposed to prompt injection attacks targeting the tool inputs.
Implementing a Functional Research Agent with Web Search Integration
Defining the search_web Tool Schema and Mock Execution
Construct the `src/tools/search.ts` module to export a `searchTool` object enforcing a strict input_schema requiring a `query` string. This definition moves the implementation beyond simple text generation toward action execution by standardizing how the agent requests external data.
- Declare the tool name as `search_web` with a description instructing usage for facts or recent events.
- Define the input_schema properties to accept only a single string argument, preventing malformed requests.
- Implement the `execute` function to return mock data simulating a successful search result.
- Log the search query to the console before returning the static response array.
Production environments demand integration with external search providers while maintaining the same interface signature. The rigid schema ensures that even as backend providers change, the agent's tool-calling interfaces remain stable and type-safe.
Assembling the Agent Runner with System Prompts and History
The `src/agent.ts` file aggregates the system prompt and conversation history to initialize the agent runner. This file imports the `searchTool` and configures the `Agent` class. The set prompt acts as a behavioral constraint, ensuring the LLM prioritizes tool usage for factual queries over internal parametric memory.
- Import the `searchTool` from the local tools module to enable external data retrieval.
- Instantiate the `Agent` with a system prompt and the available tools list.
- Execute the main loop using `npx tsx src/index.ts` to start the interactive session.
This assembly pattern supports tool registration and invocation within the runtime. The execution flow forces a decision at every turn: the model must either answer directly or invoke the search_web tool, creating an auditable trace of reasoning. A significant limitation arises here; without persistent storage backends, the conversation history remains volatile and resets upon process termination. The class maintains a `conversationHistory` array to preserve context only for the duration of the session.
Prerequisites Checklist: Node.js Version, API Keys, and Dependencies
Establishing a functional research agent requires Node.js 18 as the minimum runtime to support modern TypeScript features used in async tool execution.
- Install the core SDK `@anthropic-ai/sdk` alongside `dotenv` for secure environment variable management.
- Add development dependencies including `typescript`, `@types/node`, and `tsx` to enable rapid iteration.
- Configure an `.env` file with your `ANTHROPIC_API_KEY` before initializing the TypeScript compiler.
| Dependency Type | Package Name | Function |
|---|---|---|
| Runtime | @anthropic-ai/sdk | LLM API client |
| Runtime | dotenv | Secret injection |
| Dev | tsx | TS execution |
The required dependencies are `@anthropic-ai/sdk` and `dotenv`, while dev dependencies include `typescript`, `@types/node`, and `tsx`, with the entire setup estimated to take approximately five minutes. Relying on static responses during early prototyping isolates logic errors from network latency issues. Implementing strong error handling in the `execute` function prevents the entire agent from crashing if a single tool call fails.
Resolving Common Configuration Errors and Deployment Limitations
Diagnosing Missing API Key and Module Resolution Errors
The error `ANTHROPIC_API_KEY not found` surfaces when the `.env` file sits outside the project root, blocking the `dotenv` library from loading secrets before the TypeScript runtime initializes. Credentials must reside in the root directory so the agent constructor validates them immediately upon startup. A missing module error signals that Node.js cannot resolve dependencies because the local `node_modules` directory lacks the required packages. Running `npm install` populates this directory, satisfying import statements for `@anthropic-ai/sdk` and linked libraries.
Misconfiguration prevents the system from authenticating requests or locating tool implementations like `search_web`. Skipping dependency management breaks the execution chain entirely. Operational stability depends on strict adherence to file placement and package installation protocols.
Configuration oversights incur specific penalties:
- Debugging sessions expand due to silent environment variable failures.
- Agent downtime occurs when dependency trees remain unresolved.
- Context vanishes when initialization halts mid-conversation.
Validating file paths and dependency locks is necessary before deploying to platforms like Vercel or Railway.
Implementing Conversation History Limits to Prevent Context Overflow
Unbounded message arrays trigger runtime failures once the accumulated token count exceeds the model's context window. Conversation history grows too large, forcing developers to implement a limit, such as slicing the array if length exceeds 20. This mechanical truncation prevents memory exhaustion but introduces a specific failure mode where the agent loses access to earlier tool definitions. The stateful nature of these agents means that discarding old context breaks the continuity required for complex, multi-step reasoning tasks. Operators face a tension between preserving long-term context and maintaining system stability within fixed resource limits. Blindly appending messages without a slicing strategy guarantees eventual crashes in long-running sessions. Aggressive truncation risks losing critical instructions or user preferences set at the start of a session.
Silent loss of early context cues degrades performance. Hallucination rates increase due to missing constraints. The agent fails to recognize previously set tools. Extended dialogues exhibit unpredictable behavior. Re-processing large payloads drives higher latency.
Implementing circular buffers or vector storage is often suggested for production systems requiring deep history. The cost of this safeguard is the permanent loss of early conversation turns unless external logging captures them separately. Ignoring this constraint renders the agent unusable after extended interaction periods.
Production Gaps: Missing Budget Limits and Observability Features
The guide explicitly states what is missing for production readiness: budget limits for token usage. Operational blindness compounds this financial risk when basic implementations omit logging and error tracking.
Unbounded token consumption drains budgets during infinite tool loops. Missing summarization strategies cause context windows to overflow. Silent failures occur without structured error tracking systems.
Developers relying on simple array slicing for memory management face a hard constraint: truncating history to fit context windows often discards critical tool definitions, causing the agent to lose capability mid-conversation. Frameworks like LangGraph offer checkpoints for stateful agents, yet basic TypeScript runners do not include these safeguards by default.
Teams must address the lack of built-in safeguards for token usage and context management. Studying Anthropic's tool use guide helps understand valid safety guardrails before deploying agents that interact with external systems. Without these layers, the agent remains a fragile experiment rather than a reliable service.
About
Sofia Berg serves as Research Editor at AI Agents News, where she specializes in translating complex multi-agent research into actionable insights for engineers. Her daily work involves rigorously evaluating agentic frameworks and dissecting benchmark results from arXiv papers, giving her a unique perspective on what actually works in production versus what remains theoretical. This specific expertise makes her uniquely qualified to author a guide on building AI agents, as she constantly assesses the gap between academic concepts and practical implementation. At AI Agents News, an independent hub dedicated to autonomous systems and coding agents, Sofia focuses on stripping away hype to reveal core mechanics. By using her deep familiarity with tool use, planning algorithms, and evaluation metrics, she crafts this tutorial to demonstrate that constructing a functional agent requires understanding fundamental orchestration rather than relying on opaque, heavy frameworks.
Conclusion
Scaling AI agents exposes a brutal reality where unbounded token consumption silently drains budgets while context truncation destroys functional memory. The operational cost is not merely financial; it is the complete loss of user intent when early constraints vanish from the window. Relying on basic array slicing for memory management is a temporary fix that guarantees eventual failure in long-running sessions. Teams must stop treating context limits as a minor configuration detail and start viewing them as a primary architectural constraint that dictates agent reliability.
You should mandate the implementation of circular buffers or vector storage for any agent expected to handle extended dialogues before the next deployment cycle. This shift moves the system from a fragile experiment to a reliable service capable of sustaining deep interaction histories without crashing. Do not wait for a budget crisis or a user complaint about lost instructions to act on.
Start this week by auditing your current context window strategy to identify exactly where tool definitions get discarded during truncation. Replace simple slicing logic with a checkpoint mechanism that preserves critical system instructions regardless of conversation length. This immediate adjustment prevents the agent from becoming incompetent mid-session and ensures that safety guardrails remain active throughout the entire interaction lifecycle.
Frequently Asked Questions
You need Node.js 18, basic TypeScript knowledge, and an Anthropic API key. These prerequisites allow you to run the 150 lines of code without needing complex frameworks or prior AI experience.
Strong typing flags interface mismatches during compilation rather than execution. This immediate feedback stops malformed arguments from reaching the LLM API, preventing unpredictable crashes common in untyped JavaScript implementations.
The agent loses all conversation history because state is managed locally in memory. Unlike distributed systems, this lightweight approach does not persist data to external databases when the process stops.
Yes, you can integrate real providers like SerpAPI or Brave Search while keeping the same structure. The current mock data simply returns three static result lines for demonstration purposes.
No, this script is designed for learning core mechanics rather than production deployment. It demonstrates functional research capabilities but lacks the robust error handling required for critical enterprise workflows.