A local AI agent built with TypeScript, Ollama, and Qwen 3.5 9B.
AgentLab is a learning project focused on understanding how AI agents work internally, exploring task planning, prompt engineering, structured outputs, tool calling, conversation memory, and local language models.
Instead of relying on a high-level agent framework, AgentLab implements its core orchestration logic from scratch using TypeScript.
- Features
- Architecture
- Execution Flow
- Project Structure
- Technology Stack
- Language Model
- How It Works
- Getting Started
- Running AgentLab
- Testing
- Current Limitations
- Learning Goals
- Local LLM inference: Runs with Ollama and Qwen 3.5 9B.
- Task planning: Generates structured plans containing a goal, execution steps, and a decision about tool usage.
- Tool selection: Determines whether a registered tool should be executed.
- Controlled tool execution: Executes tools through explicit TypeScript implementations.
- Conversation memory: Maintains message history during an interactive session.
- Structured outputs: Uses JSON schemas and Zod to validate model-generated plans and tool decisions.
- Interactive CLI: Provides a terminal interface for conversations.
- Automated testing: Includes unit tests and integration tests against the local model.
AgentLab separates LLM reasoning from application logic and tool execution.
flowchart TD
User([User])
CLI["index.ts<br/>Interactive CLI"]
Session["agentSession.ts<br/>Conversation Memory"]
Runner["runToolAgent.ts<br/>Agent Orchestrator"]
Planner["agent.ts<br/>Task Planner"]
Selector["toolAgent.ts<br/>Tool Selection"]
Registry["tools.ts<br/>Tool Registry and Execution"]
LLM["llm.ts<br/>Ollama Client"]
Model["Qwen 3.5 9B<br/>Local LLM"]
User --> CLI
CLI --> Session
Session --> Runner
Runner --> Planner
Runner --> Selector
Selector --> Registry
Planner --> LLM
Selector --> LLM
Runner --> Registry
Runner --> LLM
LLM <--> Model
Runner --> Session
Session --> CLI
CLI --> User
| Component | Responsibility |
|---|---|
index.ts |
Reads user input and displays responses in the terminal. |
agentSession.ts |
Maintains conversation history and supports resetting the session. |
runToolAgent.ts |
Coordinates planning, tool execution, and final response generation. |
agent.ts |
Generates and validates a structured task plan. |
toolAgent.ts |
Selects a registered tool or decides that no tool is needed. |
tools.ts |
Defines available tools and executes their implementations. |
llm.ts |
Sends chat requests to the local Ollama API. |
models.ts |
Defines Zod schemas and TypeScript types for structured outputs. |
When a user submits a request, AgentLab follows this sequence:
sequenceDiagram
actor User
participant CLI as index.ts
participant Session as AgentSession
participant Runner as runToolAgent
participant Planner as createPlan
participant Selector as proposeToolCall
participant Tools as Tool Registry
participant LLM as Ollama / Qwen
User->>CLI: Submit a request
CLI->>Session: send(task)
Session->>Runner: runToolAgent(task, history)
Runner->>Planner: Create a plan
Planner->>LLM: Generate structured plan
LLM-->>Planner: Plan JSON
Planner-->>Runner: Validated AgentPlan
opt Plan requires tools
Runner->>Selector: Propose a tool call
Selector->>LLM: Select tool or no tool
LLM-->>Selector: Structured ToolCall
Selector-->>Runner: Validated decision
opt A tool is selected
Runner->>Tools: Execute registered tool
Tools-->>Runner: Tool result
Runner->>Selector: Evaluate next tool decision
end
end
Runner->>LLM: Generate final answer
LLM-->>Runner: Final response
Runner-->>Session: ToolAgentResult
Session->>Session: Store user message and response
Session-->>CLI: Return result
CLI-->>User: Display plan and answer
The language model proposes decisions, but TypeScript controls execution.
- The model generates plans and proposes tool calls.
- Zod validates structured outputs.
- The application validates tool names against the registered catalog.
- TypeScript executes the actual tool implementations.
- Tool results are added to the model context.
- The model generates the final response.
The model does not execute arbitrary code or gain access to system resources simply by requesting a tool.
tslab/
├── src/
│ ├── index.ts # Interactive CLI
│ ├── agentSession.ts # Conversation history
│ ├── runToolAgent.ts # Agent orchestration
│ ├── agent.ts # Task planning
│ ├── toolAgent.ts # Tool selection and validation
│ ├── tools.ts # Tool registry and implementations
│ ├── llm.ts # Ollama API client
│ └── models.ts # Zod schemas and TypeScript types
├── tests/
│ ├── tools.test.ts
│ ├── agentSession.unit.test.ts
│ ├── agentSession.test.ts
│ ├── toolAgent.test.ts
│ ├── runToolAgent.test.ts
│ ├── agent.test.ts
│ └── llm.test.ts
├── package.json
├── tsconfig.json
├── vitest.config.ts
├── .gitignore
└── README.md
| Technology | Purpose |
|---|---|
| TypeScript | Application logic, types, and tool execution |
| Node.js | Runtime environment |
| Ollama | Local model inference and API |
| Qwen 3.5 | Language model for planning, tool selection, and responses |
| Zod | Runtime validation of structured outputs |
| Vitest | Unit and integration testing |
| tsx | Running TypeScript directly during development |
| Yarn | Dependency management and scripts |
| Mermaid | Architecture and sequence diagrams |
AgentLab currently uses Qwen 3.5 9B through Ollama.
| Property | Value |
|---|---|
| Model identifier | qwen3.5:9b |
| Runtime | Ollama |
| Inference | Local |
| API endpoint | http://localhost:11434/api/chat |
| Output formats | Plain text and schema-constrained JSON |
A 9-billion-parameter model provides a practical balance between model capability and local resource requirements for experimentation.
Running locally makes it possible to experiment with prompts, structured outputs, and tool-calling workflows without sending ordinary inference requests to a hosted LLM API.
Performance depends on hardware, quantization, context size, and the task being performed. Local execution does not guarantee that model outputs are correct.
The model handles three main tasks:
- Planning: Converts a natural-language request into a structured plan.
- Tool selection: Decides whether a registered tool is appropriate and explains why.
- Response generation: Produces the final answer using the request, conversation history, plan, and available tool results.
The planner generates an AgentPlan:
type AgentPlan = {
goal: string;
steps: string[];
requires_tools: boolean;
};The generated plan is parsed and validated against a Zod schema before orchestration continues.
The tool selector generates a ToolCall:
type ToolCall = {
use_tool: boolean;
tool: string | null;
reason: string;
};A requested tool must exist in the registered tool catalog. Unknown tools and inconsistent decisions are rejected by application validation.
Tools are implemented as ordinary TypeScript functions and registered in tools.ts.
The initial tool is:
| Tool | Description |
|---|---|
get_current_time |
Returns the current date and time in ISO 8601 format, plus a UTC representation. |
The registry makes available capabilities explicit. The model can propose using a tool, but it cannot create new registered capabilities merely by mentioning them in its response.
AgentSession stores user and assistant messages in memory during the current process.
Previous messages are supplied to the planner, tool selector, and final response generation.
Use reset in the CLI to clear the current conversation history. This memory is in-process only and is not persisted between application restarts.
After planning and optional tool execution, the orchestrator calls the model to generate the final response.
The result contains the plan, last tool decision, last tool result, and final answer.
Install the following:
git clone https://github.com/skantus/agent-lab.git
cd agent-labIf your local working directory is still named tslab, that is fine. The local folder name does not determine the GitHub repository name.
yarn installollama pull qwen3.5:9bThe model download requires several gigabytes of storage.
Ensure the Ollama service is running:
ollama serveIf Ollama is already running as a background service, you do not need to start it again.
ollama listConfirm that qwen3.5:9b is available.
Start the interactive CLI:
yarn devExample interaction:
AgentLab ready. Type 'exit' to quit or 'reset' to clear memory.
You: Hi, my name is Alex.
Plan:
Goal: Respond to the user's greeting and acknowledge their name.
1. Understand the user's introduction
2. Respond naturally
Requires tools: false
AgentLab: Nice to meet you, Alex!
You: What is my name?
Plan:
Goal: Retrieve the user's name from conversation history.
1. Review the conversation history
2. Answer using the stored conversation context
Requires tools: false
AgentLab: Your name is Alex.
The exact plan and wording are generated by the model and may differ between runs.
| Command | Behavior |
|---|---|
reset |
Clears the conversation history |
exit |
Exits AgentLab |
yarn testThe unit test suite covers tool execution, tool selection and validation, agent orchestration, and session memory.
yarn test:integrationIntegration tests use the real local Ollama model. They are slower than unit tests and require Ollama and the configured model to be available.
| Command | Description |
|---|---|
yarn dev |
Starts the interactive CLI |
yarn test |
Runs the unit test suite |
yarn test:integration |
Runs tests against the local model |
yarn test:watch |
Runs Vitest in watch mode |
AgentLab is an educational implementation, not yet a production-ready autonomous agent.
- Limited tool catalog: Only the current-time tool is registered.
- Planner-dependent execution: The planner's
requires_toolsdecision controls whether tool selection runs. An incorrect plan can prevent a needed tool from being considered. - Bounded tool loop: Tool selection is limited to three attempts per request.
- No persistent memory: Conversation history is lost when the process exits.
- No general-purpose autonomy: The agent does not independently execute every plan step or verify that every goal has been achieved.
- Model variability: Plans, tool decisions, and responses can vary between runs.
- Local resource requirements: Model latency and memory usage depend on the machine running Ollama.
These limitations are useful areas for experimentation when learning how agent orchestration works.
AgentLab explores the fundamentals of AI agent engineering:
- Prompt engineering and instruction design.
- Planning and decomposition of natural-language tasks.
- Structured model outputs and schema validation.
- Tool calling and capability boundaries.
- Orchestration of multi-stage LLM workflows.
- Conversation context and memory.
- Unit testing versus model integration testing.
- Local LLM inference and privacy trade-offs.
No license has been specified yet. Until a license is added to the repository, reuse and redistribution are not automatically granted.


