tiny-agent-ai 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -0
- package/package.json +32 -0
- package/src/index.ts +21 -0
- package/tsconfig.json +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# tiny-agent
|
|
2
|
+
|
|
3
|
+
Minimal, extension-based AI agent. The core is ~200 lines — just the loop and types. Everything else is an extension.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add tiny-agent-ai
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Agent, OpenAIProvider, toolsExtension, loopDetectionExtension } from 'tiny-agent-ai'
|
|
13
|
+
import type { Tool } from 'tiny-agent-ai'
|
|
14
|
+
|
|
15
|
+
// Define a custom tool
|
|
16
|
+
const weatherTool: Tool = {
|
|
17
|
+
definition: {
|
|
18
|
+
name: 'get_weather',
|
|
19
|
+
description: 'Get current weather for a city',
|
|
20
|
+
parameters: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: { city: { type: 'string', description: 'City name' } },
|
|
23
|
+
required: ['city'],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
async execute(input) {
|
|
27
|
+
const res = await fetch(`https://wttr.in/${input.city}?format=j1`)
|
|
28
|
+
const data = await res.json()
|
|
29
|
+
return { output: JSON.stringify(data.current_condition[0]) }
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const provider = new OpenAIProvider(process.env.OPENAI_API_KEY!, 'gpt-4o')
|
|
34
|
+
|
|
35
|
+
const agent = new Agent({
|
|
36
|
+
provider,
|
|
37
|
+
systemPrompt: 'You are a helpful assistant with access to weather data.',
|
|
38
|
+
extensions: [
|
|
39
|
+
{ name: 'weather', tools: [weatherTool] },
|
|
40
|
+
toolsExtension(),
|
|
41
|
+
loopDetectionExtension(),
|
|
42
|
+
],
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
for await (const event of agent.run('What is the weather in Berlin?')) {
|
|
46
|
+
if (event.type === 'text_delta') process.stdout.write(event.text)
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The `Agent` class takes a provider, a system prompt, and an array of extensions. No config files, no env var conventions, no DI — you wire it however you want.
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
The core (`packages/core/`) has three files:
|
|
55
|
+
|
|
56
|
+
- **`types.ts`** — `Message`, `Tool`, `Provider`, `Extension`, `MessageStore` interfaces
|
|
57
|
+
- **`agent.ts`** — The loop: stream LLM → parse tool calls → run hooks → execute tools → repeat
|
|
58
|
+
- **`index.ts`** — Barrel exports
|
|
59
|
+
|
|
60
|
+
The loop:
|
|
61
|
+
|
|
62
|
+
1. Push user message, call `beforeSend` hooks, stream from provider
|
|
63
|
+
2. Collect text deltas and tool call chunks into a complete assistant message
|
|
64
|
+
3. If no tool calls → `onTurnDone`, yield `turn_done`, return
|
|
65
|
+
4. For each tool call → `beforeToolCall` (can block/inject) → execute → `afterToolCall` (can transform result)
|
|
66
|
+
5. Append tool results, go to step 1
|
|
67
|
+
|
|
68
|
+
## Extension API
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface Extension {
|
|
72
|
+
name: string
|
|
73
|
+
tools?: Tool[]
|
|
74
|
+
beforeSend?(messages: Message[]): Message[] | Promise<Message[]>
|
|
75
|
+
beforeToolCall?(toolCall: ToolCall): boolean | { inject: Message } | Promise<...>
|
|
76
|
+
afterToolCall?(toolCall: ToolCall, result: ToolResult): ToolResult | Promise<ToolResult>
|
|
77
|
+
onTurnDone?(messages: Message[]): void | Promise<void>
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Extensions run in array order. Put safety extensions before tool extensions.
|
|
82
|
+
|
|
83
|
+
Built-in:
|
|
84
|
+
- **toolsExtension** — read, write, edit, glob, grep, bash
|
|
85
|
+
- **loopDetectionExtension** — breaks infinite tool-call loops
|
|
86
|
+
- **compactionExtension** — summarizes old messages when context fills up
|
|
87
|
+
- **taskExtension** — delegates subtasks to isolated sub-agents
|
|
88
|
+
|
|
89
|
+
See [`packages/core/README.md`](packages/core/README.md) for detailed extension docs.
|
|
90
|
+
|
|
91
|
+
## Providers
|
|
92
|
+
|
|
93
|
+
The core defines a `Provider` interface — anything that implements `stream()` works:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
interface Provider {
|
|
97
|
+
name: string
|
|
98
|
+
stream(messages, tools, systemPrompt, maxTokens): AsyncIterable<ProviderChunk>
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Included: `OpenAIProvider` (works with any OpenAI-compatible API) and `AnthropicProvider`. Write your own for Gemini, Ollama, or anything else.
|
|
103
|
+
|
|
104
|
+
## Message Persistence
|
|
105
|
+
|
|
106
|
+
The `Agent` accepts an optional `store: MessageStore` for persistence. The interface is minimal:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
interface MessageStore {
|
|
110
|
+
getMessages(): Message[]
|
|
111
|
+
append(message: Message): void
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The included `Session` class (`packages/session/`) is a JSONL-based implementation. You can swap it for Redis, SQLite, a database — whatever fits your use case.
|
|
116
|
+
|
|
117
|
+
## Packages
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
packages/core/ Agent loop + types (zero deps)
|
|
121
|
+
packages/tiny-agent/ Barrel — single import (`tiny-agent-ai` on npm)
|
|
122
|
+
packages/providers/openai/ OpenAI-compatible provider (included)
|
|
123
|
+
packages/providers/anthropic/ Native Anthropic provider (included)
|
|
124
|
+
packages/extensions/tools/ Filesystem + bash tools
|
|
125
|
+
packages/extensions/loop-detection/ Breaks infinite loops
|
|
126
|
+
packages/extensions/compaction/ Context window management
|
|
127
|
+
packages/extensions/task/ Sub-agent delegation
|
|
128
|
+
packages/session/ JSONL MessageStore implementation (example)
|
|
129
|
+
packages/examples/cli/ Interactive REPL with slash commands
|
|
130
|
+
packages/examples/web/ SSE server + chat UI
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Running the Examples
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
bun install
|
|
137
|
+
cd packages/examples/cli # or web
|
|
138
|
+
cp agent.config.example.json agent.config.json
|
|
139
|
+
# Add your API key and model
|
|
140
|
+
|
|
141
|
+
bun run dev
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
See each example's README for details.
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
bun run typecheck # Type-check all packages
|
|
150
|
+
bun run format # Prettier
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tiny-agent-ai",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Minimal, extension-based AI agent. ~200 lines core, everything else is an extension.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/xy69/tiny-agent"
|
|
10
|
+
},
|
|
11
|
+
"keywords": ["ai", "agent", "llm", "coding-agent", "openai", "anthropic", "tools"],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"typecheck": "tsc --noEmit"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@tiny-agent/core": "workspace:*",
|
|
20
|
+
"@tiny-agent/ext-tools": "workspace:*",
|
|
21
|
+
"@tiny-agent/ext-compaction": "workspace:*",
|
|
22
|
+
"@tiny-agent/ext-loop-detection": "workspace:*",
|
|
23
|
+
"@tiny-agent/ext-task": "workspace:*",
|
|
24
|
+
"@tiny-agent/provider-openai": "workspace:*",
|
|
25
|
+
"@tiny-agent/provider-anthropic": "workspace:*",
|
|
26
|
+
"@tiny-agent/session": "workspace:*"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"typescript": "catalog:",
|
|
30
|
+
"@types/bun": "catalog:"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { Agent } from '@tiny-agent/core'
|
|
2
|
+
export type { AgentOptions } from '@tiny-agent/core'
|
|
3
|
+
export type {
|
|
4
|
+
Extension,
|
|
5
|
+
Tool,
|
|
6
|
+
ToolDefinition,
|
|
7
|
+
ToolResult,
|
|
8
|
+
MessageStore,
|
|
9
|
+
Provider,
|
|
10
|
+
StreamEvent,
|
|
11
|
+
Message,
|
|
12
|
+
ProviderChunk,
|
|
13
|
+
ToolCall,
|
|
14
|
+
} from '@tiny-agent/core'
|
|
15
|
+
export { Session } from '@tiny-agent/session'
|
|
16
|
+
export { OpenAIProvider } from '@tiny-agent/provider-openai'
|
|
17
|
+
export { AnthropicProvider } from '@tiny-agent/provider-anthropic'
|
|
18
|
+
export { toolsExtension } from '@tiny-agent/ext-tools'
|
|
19
|
+
export { compactionExtension } from '@tiny-agent/ext-compaction'
|
|
20
|
+
export { loopDetectionExtension } from '@tiny-agent/ext-loop-detection'
|
|
21
|
+
export { taskExtension } from '@tiny-agent/ext-task'
|
package/tsconfig.json
ADDED