@elfenlabs/cog 0.1.0
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/LICENSE +21 -0
- package/README.md +295 -0
- package/dist/agent.d.ts +38 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +183 -0
- package/dist/agent.js.map +1 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +38 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/openai.d.ts +30 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +196 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/tool.d.ts +24 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +31 -0
- package/dist/tool.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elfenlabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# 🧠 Cog
|
|
2
|
+
|
|
3
|
+
A minimal agent SDK for TypeScript. Three primitives, zero opinions on your LLM provider.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm install @elfenlabs/cog
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { createContext, createTool, createOpenAIProvider, runAgent } from '@elfenlabs/cog'
|
|
13
|
+
|
|
14
|
+
// Define a tool
|
|
15
|
+
const getWeather = createTool({
|
|
16
|
+
id: 'get_weather',
|
|
17
|
+
description: 'Get the current weather for a city',
|
|
18
|
+
schema: {
|
|
19
|
+
city: { type: 'string', description: 'The city name' },
|
|
20
|
+
},
|
|
21
|
+
execute: async (args) => {
|
|
22
|
+
const { city } = args as { city: string }
|
|
23
|
+
return { city, temp: 22, condition: 'sunny' }
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// Create context and provider
|
|
28
|
+
const ctx = createContext()
|
|
29
|
+
ctx.push("What's the weather in Tokyo?")
|
|
30
|
+
|
|
31
|
+
const provider = createOpenAIProvider('https://api.openai.com', 'gpt-4o', {
|
|
32
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Run the agent
|
|
36
|
+
const result = await runAgent({
|
|
37
|
+
ctx,
|
|
38
|
+
provider,
|
|
39
|
+
instruction: 'You are a helpful assistant. Use tools when needed.',
|
|
40
|
+
tools: [getWeather],
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
console.log(result.response) // "The weather in Tokyo is 22°C and sunny."
|
|
44
|
+
console.log(result.steps) // 2
|
|
45
|
+
console.log(result.usage) // { promptTokens, completionTokens, totalTokens }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Primitives
|
|
49
|
+
|
|
50
|
+
| Primitive | What it is |
|
|
51
|
+
|---|---|
|
|
52
|
+
| **Context** | Append-only message chain. You push messages in, the agent loop reads them out. |
|
|
53
|
+
| **Tool** | Schema + execute function. The agent calls tools automatically based on model output. |
|
|
54
|
+
| **Agent** | The loop. Calls the provider, executes tool calls, repeats until the model responds with text. |
|
|
55
|
+
|
|
56
|
+
## Context
|
|
57
|
+
|
|
58
|
+
An ordered `Message[]` chain. Push strings (become `user` messages) or full `Message` objects.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { createContext } from '@elfenlabs/cog'
|
|
62
|
+
|
|
63
|
+
const ctx = createContext()
|
|
64
|
+
|
|
65
|
+
// Strings become user messages
|
|
66
|
+
ctx.push('What is 2 + 2?')
|
|
67
|
+
|
|
68
|
+
// Full messages for other roles
|
|
69
|
+
ctx.push({ role: 'system', content: 'You are a math tutor.' })
|
|
70
|
+
|
|
71
|
+
// Read messages
|
|
72
|
+
ctx.messages // readonly Message[]
|
|
73
|
+
|
|
74
|
+
// Serialize / restore
|
|
75
|
+
const snapshot = ctx.serialize()
|
|
76
|
+
const restored = createContext({ from: snapshot })
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Message Shape
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
type Message = {
|
|
83
|
+
role: 'system' | 'user' | 'assistant' | 'tool'
|
|
84
|
+
content: string
|
|
85
|
+
reasoning?: string // chain-of-thought from reasoning models
|
|
86
|
+
toolCallId?: string // links tool results back to the call
|
|
87
|
+
toolCalls?: ToolCallRequest[] // tool calls requested by the model
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Tool
|
|
92
|
+
|
|
93
|
+
A tool is an `id`, a `description`, a `schema`, and an `execute` function.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { createTool } from '@elfenlabs/cog'
|
|
97
|
+
|
|
98
|
+
const calculator = createTool({
|
|
99
|
+
id: 'calculator',
|
|
100
|
+
description: 'Evaluate a math expression',
|
|
101
|
+
schema: {
|
|
102
|
+
expression: { type: 'string', description: 'The expression to evaluate', required: true },
|
|
103
|
+
},
|
|
104
|
+
execute: async (args) => {
|
|
105
|
+
const { expression } = args as { expression: string }
|
|
106
|
+
return { result: eval(expression) }
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// The .spec property gives you the wire format for provider APIs
|
|
111
|
+
calculator.spec // { name, description, parameters }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Parameter Types
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
type ToolParameter = {
|
|
118
|
+
type: 'string' | 'number' | 'boolean'
|
|
119
|
+
description: string
|
|
120
|
+
required?: boolean // default: true
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Agent Loop
|
|
125
|
+
|
|
126
|
+
`runAgent` calls the provider in a loop, executing tool calls until the model responds with text only.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { runAgent } from '@elfenlabs/cog'
|
|
130
|
+
|
|
131
|
+
const result = await runAgent({
|
|
132
|
+
ctx, // Context — the conversation so far
|
|
133
|
+
provider, // Provider — any LLM backend
|
|
134
|
+
instruction: '...', // system prompt (prepended to every call)
|
|
135
|
+
tools: [tool1, tool2], // available tools
|
|
136
|
+
|
|
137
|
+
// Limits
|
|
138
|
+
maxSteps: 50, // default: 50
|
|
139
|
+
signal: abortController.signal,
|
|
140
|
+
|
|
141
|
+
// Streaming callbacks
|
|
142
|
+
onThinkingStart: () => {},
|
|
143
|
+
onThinking: (chunk) => {}, // reasoning tokens (dim/hidden)
|
|
144
|
+
onThinkingEnd: () => {},
|
|
145
|
+
onOutputStart: () => {},
|
|
146
|
+
onOutput: (chunk) => {}, // content tokens (visible)
|
|
147
|
+
onOutputEnd: () => {},
|
|
148
|
+
|
|
149
|
+
// Tool lifecycle hooks
|
|
150
|
+
onBeforeToolCall: async (tool, args) => {
|
|
151
|
+
// return false to block the call
|
|
152
|
+
},
|
|
153
|
+
onAfterToolCall: (tool, args, result) => {},
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
result.response // final text response
|
|
157
|
+
result.steps // number of provider calls made
|
|
158
|
+
result.usage // { promptTokens, completionTokens, totalTokens }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### How the Loop Works
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
┌─────────────────────────────────────────────┐
|
|
165
|
+
│ system prompt + ctx.messages → provider │
|
|
166
|
+
│ ↓ │
|
|
167
|
+
│ ┌─ tool calls? ──────────────────────────┐ │
|
|
168
|
+
│ │ YES → execute tools → push results │ │
|
|
169
|
+
│ │ → loop back to provider │ │
|
|
170
|
+
│ ├─ text content? ────────────────────────┤ │
|
|
171
|
+
│ │ YES → push assistant message → return │ │
|
|
172
|
+
│ ├─ reasoning only? ─────────────────────┤ │
|
|
173
|
+
│ │ YES → push reasoning → loop │ │
|
|
174
|
+
│ └────────────────────────────────────────┘ │
|
|
175
|
+
└─────────────────────────────────────────────┘
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Provider
|
|
179
|
+
|
|
180
|
+
The `Provider` interface is a single method. Implement it for any LLM backend.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
interface Provider {
|
|
184
|
+
generate(params: {
|
|
185
|
+
messages: Message[]
|
|
186
|
+
tools?: ToolSpec[]
|
|
187
|
+
signal?: AbortSignal
|
|
188
|
+
stream?: StreamCallbacks
|
|
189
|
+
}): Promise<GenerateResult>
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
type GenerateResult = {
|
|
193
|
+
content?: string
|
|
194
|
+
reasoning?: string
|
|
195
|
+
toolCalls?: ToolCallRequest[]
|
|
196
|
+
usage?: Usage
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
type StreamCallbacks = {
|
|
200
|
+
onReasoning?: (chunk: string) => void
|
|
201
|
+
onContent?: (chunk: string) => void
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Built-in: OpenAI-Compatible Provider
|
|
206
|
+
|
|
207
|
+
Works with OpenAI, vLLM, OpenRouter, Ollama, LiteLLM, and any OpenAI-compatible API. Supports streaming (SSE) with reasoning model support (`reasoning_content`).
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { createOpenAIProvider } from '@elfenlabs/cog'
|
|
211
|
+
|
|
212
|
+
// OpenAI
|
|
213
|
+
const openai = createOpenAIProvider('https://api.openai.com', 'gpt-4o', {
|
|
214
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
// Local vLLM
|
|
218
|
+
const vllm = createOpenAIProvider('http://localhost:8000', 'my-model')
|
|
219
|
+
|
|
220
|
+
// OpenRouter
|
|
221
|
+
const openrouter = createOpenAIProvider('https://openrouter.ai/api', 'anthropic/claude-sonnet-4.5', {
|
|
222
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
223
|
+
temperature: 0.2,
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Sub-Agent Composition
|
|
228
|
+
|
|
229
|
+
Agents are just functions. Wrap `runAgent` inside a tool to create sub-agents with isolated context.
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
const searchOrders = createTool({
|
|
233
|
+
id: 'search_orders',
|
|
234
|
+
description: 'Search through paginated orders to find a match',
|
|
235
|
+
schema: {
|
|
236
|
+
query: { type: 'string', description: 'What to search for' },
|
|
237
|
+
},
|
|
238
|
+
execute: async (args) => {
|
|
239
|
+
const { query } = args as { query: string }
|
|
240
|
+
|
|
241
|
+
// Sub-agent gets its own isolated context
|
|
242
|
+
const subCtx = createContext()
|
|
243
|
+
subCtx.push(`Find: ${query}`)
|
|
244
|
+
|
|
245
|
+
const fetchPage = createTool({
|
|
246
|
+
id: 'fetch_page',
|
|
247
|
+
description: 'Fetch a page of orders',
|
|
248
|
+
schema: { page: { type: 'number', description: 'Page number' } },
|
|
249
|
+
execute: async (a) => api.getOrders((a as { page: number }).page),
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
const result = await runAgent({
|
|
253
|
+
ctx: subCtx,
|
|
254
|
+
provider,
|
|
255
|
+
instruction: 'Search through pages until you find the item or exhaust all pages.',
|
|
256
|
+
tools: [fetchPage],
|
|
257
|
+
maxSteps: 20,
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
// Only the final answer bubbles up — no pagination noise in parent context
|
|
261
|
+
return result.response
|
|
262
|
+
},
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
// Parent agent uses the sub-agent as a regular tool
|
|
266
|
+
const result = await runAgent({
|
|
267
|
+
ctx: createContext(),
|
|
268
|
+
provider,
|
|
269
|
+
instruction: 'Use search_orders to look up order information.',
|
|
270
|
+
tools: [searchOrders],
|
|
271
|
+
})
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Error Handling
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { MaxStepsError, AgentAbortError } from '@elfenlabs/cog'
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
await runAgent({ ctx, provider, instruction: '...', tools, maxSteps: 10 })
|
|
281
|
+
} catch (err) {
|
|
282
|
+
if (err instanceof MaxStepsError) {
|
|
283
|
+
// Agent exceeded step limit
|
|
284
|
+
}
|
|
285
|
+
if (err instanceof AgentAbortError) {
|
|
286
|
+
// AbortSignal was triggered
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Unknown tool calls and tool execution errors are automatically caught and fed back to the model as `tool` messages, letting it recover gracefully.
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
MIT
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Agent Loop
|
|
3
|
+
*
|
|
4
|
+
* The heart of the library. Calls the model in a loop,
|
|
5
|
+
* executing tool calls until the model responds with text only.
|
|
6
|
+
*/
|
|
7
|
+
import type { Context } from './context.js';
|
|
8
|
+
import type { Tool } from './tool.js';
|
|
9
|
+
import type { Provider, Usage } from './types.js';
|
|
10
|
+
export type AgentConfig = {
|
|
11
|
+
ctx: Context;
|
|
12
|
+
provider: Provider;
|
|
13
|
+
instruction: string;
|
|
14
|
+
tools: Tool<any>[];
|
|
15
|
+
maxSteps?: number;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
onThinkingStart?: () => void;
|
|
18
|
+
onThinking?: (chunk: string) => void;
|
|
19
|
+
onThinkingEnd?: () => void;
|
|
20
|
+
onOutputStart?: () => void;
|
|
21
|
+
onOutput?: (chunk: string) => void;
|
|
22
|
+
onOutputEnd?: () => void;
|
|
23
|
+
onBeforeToolCall?: (tool: Tool<any>, args: Record<string, unknown>) => Promise<boolean | void> | boolean | void;
|
|
24
|
+
onAfterToolCall?: (tool: Tool<any>, args: Record<string, unknown>, result: unknown) => void;
|
|
25
|
+
};
|
|
26
|
+
export type AgentResult = {
|
|
27
|
+
response: string;
|
|
28
|
+
steps: number;
|
|
29
|
+
usage: Usage;
|
|
30
|
+
};
|
|
31
|
+
export declare class MaxStepsError extends Error {
|
|
32
|
+
constructor(maxSteps: number);
|
|
33
|
+
}
|
|
34
|
+
export declare class AgentAbortError extends Error {
|
|
35
|
+
constructor();
|
|
36
|
+
}
|
|
37
|
+
export declare function runAgent(config: AgentConfig): Promise<AgentResult>;
|
|
38
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,KAAK,EAAW,QAAQ,EAAmB,KAAK,EAAE,MAAM,YAAY,CAAA;AAI3E,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,OAAO,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,gBAAgB,CAAC,EAAE,CACjB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAA;IAC7C,eAAe,CAAC,EAAE,CAChB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,OAAO,KACZ,IAAI,CAAA;CACV,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,KAAK,CAAA;CACb,CAAA;AAID,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,QAAQ,EAAE,MAAM;CAI7B;AAED,qBAAa,eAAgB,SAAQ,KAAK;;CAKzC;AAID,wBAAsB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAwMxE"}
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Agent Loop
|
|
3
|
+
*
|
|
4
|
+
* The heart of the library. Calls the model in a loop,
|
|
5
|
+
* executing tool calls until the model responds with text only.
|
|
6
|
+
*/
|
|
7
|
+
// ── Errors ──────────────────────────────────────────────────────────────────
|
|
8
|
+
export class MaxStepsError extends Error {
|
|
9
|
+
constructor(maxSteps) {
|
|
10
|
+
super(`Agent exceeded maximum steps (${maxSteps})`);
|
|
11
|
+
this.name = 'MaxStepsError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class AgentAbortError extends Error {
|
|
15
|
+
constructor() {
|
|
16
|
+
super('Agent was aborted');
|
|
17
|
+
this.name = 'AgentAbortError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// ── Agent Loop ──────────────────────────────────────────────────────────────
|
|
21
|
+
export async function runAgent(config) {
|
|
22
|
+
const { ctx, provider, instruction, tools, maxSteps = 50, signal, onThinkingStart, onThinking, onThinkingEnd, onOutputStart, onOutput, onOutputEnd, onBeforeToolCall, onAfterToolCall, } = config;
|
|
23
|
+
const toolMap = new Map(tools.map(t => [t.id, t]));
|
|
24
|
+
const toolSpecs = tools.map(t => t.spec);
|
|
25
|
+
let steps = 0;
|
|
26
|
+
let isThinking = false;
|
|
27
|
+
let isOutputting = false;
|
|
28
|
+
const totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
29
|
+
/** End reasoning block if one is active */
|
|
30
|
+
const endThinking = () => {
|
|
31
|
+
if (isThinking) {
|
|
32
|
+
isThinking = false;
|
|
33
|
+
onThinkingEnd?.();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/** End output block if one is active */
|
|
37
|
+
const endOutput = () => {
|
|
38
|
+
if (isOutputting) {
|
|
39
|
+
isOutputting = false;
|
|
40
|
+
onOutputEnd?.();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
while (true) {
|
|
44
|
+
// Check abort
|
|
45
|
+
if (signal?.aborted) {
|
|
46
|
+
throw new AgentAbortError();
|
|
47
|
+
}
|
|
48
|
+
// Check step limit
|
|
49
|
+
if (steps >= maxSteps) {
|
|
50
|
+
throw new MaxStepsError(maxSteps);
|
|
51
|
+
}
|
|
52
|
+
// Build messages: instruction as system prompt + context messages
|
|
53
|
+
const messages = [
|
|
54
|
+
{ role: 'system', content: instruction },
|
|
55
|
+
...ctx.messages,
|
|
56
|
+
];
|
|
57
|
+
// Build stream callbacks for the provider
|
|
58
|
+
// Wrap onThinking to manage start/end lifecycle
|
|
59
|
+
const wrappedOnThinking = onThinking
|
|
60
|
+
? (chunk) => {
|
|
61
|
+
if (!isThinking) {
|
|
62
|
+
isThinking = true;
|
|
63
|
+
onThinkingStart?.();
|
|
64
|
+
}
|
|
65
|
+
onThinking(chunk);
|
|
66
|
+
}
|
|
67
|
+
: undefined;
|
|
68
|
+
const wrappedOnOutput = onOutput
|
|
69
|
+
? (chunk) => {
|
|
70
|
+
if (!isOutputting) {
|
|
71
|
+
isOutputting = true;
|
|
72
|
+
onOutputStart?.();
|
|
73
|
+
}
|
|
74
|
+
onOutput(chunk);
|
|
75
|
+
}
|
|
76
|
+
: undefined;
|
|
77
|
+
const stream = wrappedOnThinking || wrappedOnOutput
|
|
78
|
+
? {
|
|
79
|
+
onReasoning: wrappedOnThinking,
|
|
80
|
+
onContent: wrappedOnOutput,
|
|
81
|
+
}
|
|
82
|
+
: undefined;
|
|
83
|
+
// Call the provider
|
|
84
|
+
const result = await provider.generate({
|
|
85
|
+
messages,
|
|
86
|
+
tools: toolSpecs.length > 0 ? toolSpecs : undefined,
|
|
87
|
+
signal,
|
|
88
|
+
stream,
|
|
89
|
+
});
|
|
90
|
+
steps++;
|
|
91
|
+
// Accumulate token usage
|
|
92
|
+
if (result.usage) {
|
|
93
|
+
totalUsage.promptTokens += result.usage.promptTokens;
|
|
94
|
+
totalUsage.completionTokens += result.usage.completionTokens;
|
|
95
|
+
totalUsage.totalTokens += result.usage.totalTokens;
|
|
96
|
+
}
|
|
97
|
+
// Case 1: Model returned tool calls → execute and loop
|
|
98
|
+
if (result.toolCalls && result.toolCalls.length > 0) {
|
|
99
|
+
endThinking();
|
|
100
|
+
// Append the assistant message with tool calls to context
|
|
101
|
+
ctx.push({
|
|
102
|
+
role: 'assistant',
|
|
103
|
+
content: result.content ?? '',
|
|
104
|
+
reasoning: result.reasoning,
|
|
105
|
+
toolCalls: result.toolCalls,
|
|
106
|
+
});
|
|
107
|
+
for (const call of result.toolCalls) {
|
|
108
|
+
const tool = toolMap.get(call.name);
|
|
109
|
+
if (!tool) {
|
|
110
|
+
// Unknown tool — append error as tool result so model can recover
|
|
111
|
+
ctx.push({
|
|
112
|
+
role: 'tool',
|
|
113
|
+
content: `Error: unknown tool "${call.name}"`,
|
|
114
|
+
toolCallId: call.id,
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// Hook: before
|
|
119
|
+
if (onBeforeToolCall) {
|
|
120
|
+
const allowed = await onBeforeToolCall(tool, call.arguments);
|
|
121
|
+
if (allowed === false) {
|
|
122
|
+
ctx.push({
|
|
123
|
+
role: 'tool',
|
|
124
|
+
content: 'Error: tool call was blocked',
|
|
125
|
+
toolCallId: call.id,
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Execute the tool
|
|
131
|
+
try {
|
|
132
|
+
const toolResult = await tool.execute(call.arguments, ctx);
|
|
133
|
+
const content = typeof toolResult === 'string'
|
|
134
|
+
? toolResult
|
|
135
|
+
: JSON.stringify(toolResult);
|
|
136
|
+
ctx.push({
|
|
137
|
+
role: 'tool',
|
|
138
|
+
content,
|
|
139
|
+
toolCallId: call.id,
|
|
140
|
+
});
|
|
141
|
+
// Hook: after
|
|
142
|
+
if (onAfterToolCall) {
|
|
143
|
+
onAfterToolCall(tool, call.arguments, toolResult);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
148
|
+
ctx.push({
|
|
149
|
+
role: 'tool',
|
|
150
|
+
content: `Error: ${message}`,
|
|
151
|
+
toolCallId: call.id,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Continue the loop
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
// Case 2: Model returned text only → done
|
|
159
|
+
if (result.content) {
|
|
160
|
+
endThinking();
|
|
161
|
+
endOutput();
|
|
162
|
+
ctx.push({
|
|
163
|
+
role: 'assistant',
|
|
164
|
+
content: result.content,
|
|
165
|
+
reasoning: result.reasoning,
|
|
166
|
+
});
|
|
167
|
+
return { response: result.content, steps, usage: totalUsage };
|
|
168
|
+
}
|
|
169
|
+
// Case 3: Reasoning only (no content, no tool calls) — continue loop
|
|
170
|
+
// Reasoning models sometimes produce a think step before acting.
|
|
171
|
+
if (result.reasoning) {
|
|
172
|
+
ctx.push({
|
|
173
|
+
role: 'assistant',
|
|
174
|
+
content: '',
|
|
175
|
+
reasoning: result.reasoning,
|
|
176
|
+
});
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
// Case 4: Nothing at all — error
|
|
180
|
+
throw new Error('Provider returned neither content nor tool calls');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Context
|
|
3
|
+
*
|
|
4
|
+
* Append-only message chain. Push messages in, serialize out.
|
|
5
|
+
*/
|
|
6
|
+
import type { Message } from './types.js';
|
|
7
|
+
export type SerializedContext = {
|
|
8
|
+
messages: Message[];
|
|
9
|
+
};
|
|
10
|
+
export type ContextOptions = {
|
|
11
|
+
/** Restore from a serialized snapshot */
|
|
12
|
+
from?: SerializedContext;
|
|
13
|
+
};
|
|
14
|
+
export declare class Context {
|
|
15
|
+
private _messages;
|
|
16
|
+
constructor(opts?: ContextOptions);
|
|
17
|
+
/** All messages in the chain (readonly copy) */
|
|
18
|
+
get messages(): readonly Message[];
|
|
19
|
+
/**
|
|
20
|
+
* Push a message onto the chain.
|
|
21
|
+
* - String → user message
|
|
22
|
+
* - Message object → stored as-is
|
|
23
|
+
*/
|
|
24
|
+
push(content: string | Message): void;
|
|
25
|
+
/** Serialize to a JSON-safe snapshot */
|
|
26
|
+
serialize(): SerializedContext;
|
|
27
|
+
}
|
|
28
|
+
export declare function createContext(opts?: ContextOptions): Context;
|
|
29
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAIzC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,OAAO,EAAE,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,yCAAyC;IACzC,IAAI,CAAC,EAAE,iBAAiB,CAAA;CACzB,CAAA;AAID,qBAAa,OAAO;IAClB,OAAO,CAAC,SAAS,CAAW;gBAEhB,IAAI,CAAC,EAAE,cAAc;IAIjC,gDAAgD;IAChD,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAEjC;IAED;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAQrC,wCAAwC;IACxC,SAAS,IAAI,iBAAiB;CAG/B;AAID,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAE5D"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Context
|
|
3
|
+
*
|
|
4
|
+
* Append-only message chain. Push messages in, serialize out.
|
|
5
|
+
*/
|
|
6
|
+
// ── Context ─────────────────────────────────────────────────────────────────
|
|
7
|
+
export class Context {
|
|
8
|
+
_messages;
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
this._messages = opts?.from ? structuredClone(opts.from.messages) : [];
|
|
11
|
+
}
|
|
12
|
+
/** All messages in the chain (readonly copy) */
|
|
13
|
+
get messages() {
|
|
14
|
+
return this._messages;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Push a message onto the chain.
|
|
18
|
+
* - String → user message
|
|
19
|
+
* - Message object → stored as-is
|
|
20
|
+
*/
|
|
21
|
+
push(content) {
|
|
22
|
+
if (typeof content === 'string') {
|
|
23
|
+
this._messages.push({ role: 'user', content });
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this._messages.push(content);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Serialize to a JSON-safe snapshot */
|
|
30
|
+
serialize() {
|
|
31
|
+
return { messages: structuredClone(this._messages) };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ── Factory ─────────────────────────────────────────────────────────────────
|
|
35
|
+
export function createContext(opts) {
|
|
36
|
+
return new Context(opts);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,+EAA+E;AAE/E,MAAM,OAAO,OAAO;IACV,SAAS,CAAW;IAE5B,YAAY,IAAqB;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACxE,CAAC;IAED,gDAAgD;IAChD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,OAAyB;QAC5B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;QAChD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,SAAS;QACP,OAAO,EAAE,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAA;IACtD,CAAC;CACF;AAED,+EAA+E;AAE/E,MAAM,UAAU,aAAa,CAAC,IAAqB;IACjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — A minimal agent SDK for TypeScript
|
|
3
|
+
*
|
|
4
|
+
* Three primitives, infinite composition.
|
|
5
|
+
*/
|
|
6
|
+
export { createContext, Context } from './context.js';
|
|
7
|
+
export type { ContextOptions, SerializedContext } from './context.js';
|
|
8
|
+
export { createTool, Tool } from './tool.js';
|
|
9
|
+
export type { ToolConfig } from './tool.js';
|
|
10
|
+
export { runAgent, MaxStepsError, AgentAbortError } from './agent.js';
|
|
11
|
+
export type { AgentConfig, AgentResult } from './agent.js';
|
|
12
|
+
export { createOpenAIProvider } from './providers/openai.js';
|
|
13
|
+
export type { OpenAIProviderOptions } from './providers/openai.js';
|
|
14
|
+
export type { Message, ToolCallRequest, ToolParameter, ToolSpec, GenerateResult, StreamCallbacks, Provider, Usage, } from './types.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACrD,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAErE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACrE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC5D,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAElE,YAAY,EACV,OAAO,EACP,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,eAAe,EACf,QAAQ,EACR,KAAK,GACN,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — A minimal agent SDK for TypeScript
|
|
3
|
+
*
|
|
4
|
+
* Three primitives, infinite composition.
|
|
5
|
+
*/
|
|
6
|
+
export { createContext, Context } from './context.js';
|
|
7
|
+
export { createTool, Tool } from './tool.js';
|
|
8
|
+
export { runAgent, MaxStepsError, AgentAbortError } from './agent.js';
|
|
9
|
+
export { createOpenAIProvider } from './providers/openai.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGrD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAG5C,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAGrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog — OpenAI-compatible Provider
|
|
3
|
+
*
|
|
4
|
+
* Works with OpenAI, vLLM, OpenRouter, and any OpenAI-compatible API.
|
|
5
|
+
* Supports streaming (SSE) with reasoning_content extraction.
|
|
6
|
+
*/
|
|
7
|
+
import type { Provider } from '../types.js';
|
|
8
|
+
export type OpenAIProviderOptions = {
|
|
9
|
+
/** API key for authentication (sent as Bearer token) */
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
/** Temperature for generation (default: 0.7) */
|
|
12
|
+
temperature?: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Create a provider for any OpenAI-compatible API.
|
|
16
|
+
*
|
|
17
|
+
* Works with: OpenAI, vLLM, OpenRouter, Ollama, LiteLLM, etc.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const provider = createOpenAIProvider('https://api.openai.com', 'gpt-4o')
|
|
22
|
+
* const provider = createOpenAIProvider('http://localhost:8000', 'my-model')
|
|
23
|
+
* const provider = createOpenAIProvider('https://openrouter.ai/api', 'anthropic/claude-sonnet-4.5', {
|
|
24
|
+
* apiKey: 'sk-or-...',
|
|
25
|
+
* temperature: 0.2,
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function createOpenAIProvider(baseUrl: string, model: string, opts?: OpenAIProviderOptions): Provider;
|
|
30
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAA8D,MAAM,aAAa,CAAA;AAIvG,MAAM,MAAM,qBAAqB,GAAG;IAClC,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAwID;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,qBAAqB,GAC3B,QAAQ,CA2DV"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog — OpenAI-compatible Provider
|
|
3
|
+
*
|
|
4
|
+
* Works with OpenAI, vLLM, OpenRouter, and any OpenAI-compatible API.
|
|
5
|
+
* Supports streaming (SSE) with reasoning_content extraction.
|
|
6
|
+
*/
|
|
7
|
+
// ── Message Conversion ──────────────────────────────────────────────────────
|
|
8
|
+
/** Convert internal Cog messages to OpenAI API wire format */
|
|
9
|
+
function toAPIMessages(messages) {
|
|
10
|
+
return messages.map(m => {
|
|
11
|
+
const msg = { role: m.role, content: m.content };
|
|
12
|
+
if (m.toolCallId)
|
|
13
|
+
msg.tool_call_id = m.toolCallId;
|
|
14
|
+
if (m.toolCalls) {
|
|
15
|
+
msg.tool_calls = m.toolCalls.map(tc => ({
|
|
16
|
+
id: tc.id,
|
|
17
|
+
type: 'function',
|
|
18
|
+
function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
return msg;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** Convert internal Cog tool specs to OpenAI function-calling format */
|
|
25
|
+
function toAPITools(tools) {
|
|
26
|
+
return tools.map(t => ({
|
|
27
|
+
type: 'function',
|
|
28
|
+
function: {
|
|
29
|
+
name: t.name,
|
|
30
|
+
description: t.description,
|
|
31
|
+
parameters: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: Object.fromEntries(Object.entries(t.parameters).map(([k, v]) => [
|
|
34
|
+
k,
|
|
35
|
+
{ type: v.type, description: v.description },
|
|
36
|
+
])),
|
|
37
|
+
required: Object.entries(t.parameters)
|
|
38
|
+
.filter(([_, v]) => v.required !== false)
|
|
39
|
+
.map(([k]) => k),
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
/** Parse tool calls from a non-streaming response message */
|
|
45
|
+
function parseToolCalls(toolCalls) {
|
|
46
|
+
if (!toolCalls)
|
|
47
|
+
return undefined;
|
|
48
|
+
return toolCalls.map((tc) => ({
|
|
49
|
+
id: tc.id,
|
|
50
|
+
name: tc.function.name,
|
|
51
|
+
arguments: JSON.parse(tc.function.arguments),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
// ── SSE Streaming ───────────────────────────────────────────────────────────
|
|
55
|
+
async function readSSEStream(response, stream) {
|
|
56
|
+
let content = '';
|
|
57
|
+
let reasoning = '';
|
|
58
|
+
let usage;
|
|
59
|
+
const toolCallsMap = new Map();
|
|
60
|
+
const reader = response.body.getReader();
|
|
61
|
+
const decoder = new TextDecoder();
|
|
62
|
+
let buffer = '';
|
|
63
|
+
while (true) {
|
|
64
|
+
const { done, value } = await reader.read();
|
|
65
|
+
if (done)
|
|
66
|
+
break;
|
|
67
|
+
buffer += decoder.decode(value, { stream: true });
|
|
68
|
+
const lines = buffer.split('\n');
|
|
69
|
+
buffer = lines.pop();
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
if (!line.startsWith('data: '))
|
|
72
|
+
continue;
|
|
73
|
+
const payload = line.slice(6).trim();
|
|
74
|
+
if (payload === '[DONE]')
|
|
75
|
+
continue;
|
|
76
|
+
const chunk = JSON.parse(payload);
|
|
77
|
+
// Usage arrives in the final chunk (when stream_options.include_usage is set)
|
|
78
|
+
if (chunk.usage) {
|
|
79
|
+
usage = {
|
|
80
|
+
promptTokens: chunk.usage.prompt_tokens ?? 0,
|
|
81
|
+
completionTokens: chunk.usage.completion_tokens ?? 0,
|
|
82
|
+
totalTokens: chunk.usage.total_tokens ?? 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
86
|
+
if (!delta)
|
|
87
|
+
continue;
|
|
88
|
+
if (delta.reasoning_content) {
|
|
89
|
+
reasoning += delta.reasoning_content;
|
|
90
|
+
stream?.onReasoning?.(delta.reasoning_content);
|
|
91
|
+
}
|
|
92
|
+
if (delta.content) {
|
|
93
|
+
content += delta.content;
|
|
94
|
+
stream?.onContent?.(delta.content);
|
|
95
|
+
}
|
|
96
|
+
if (delta.tool_calls) {
|
|
97
|
+
for (const tc of delta.tool_calls) {
|
|
98
|
+
const idx = tc.index ?? 0;
|
|
99
|
+
if (!toolCallsMap.has(idx)) {
|
|
100
|
+
toolCallsMap.set(idx, { id: tc.id ?? '', name: '', args: '' });
|
|
101
|
+
}
|
|
102
|
+
const entry = toolCallsMap.get(idx);
|
|
103
|
+
if (tc.id)
|
|
104
|
+
entry.id = tc.id;
|
|
105
|
+
if (tc.function?.name)
|
|
106
|
+
entry.name += tc.function.name;
|
|
107
|
+
if (tc.function?.arguments)
|
|
108
|
+
entry.args += tc.function.arguments;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const toolCalls = toolCallsMap.size > 0
|
|
114
|
+
? Array.from(toolCallsMap.values()).map(tc => ({
|
|
115
|
+
id: tc.id,
|
|
116
|
+
name: tc.name,
|
|
117
|
+
arguments: JSON.parse(tc.args || '{}'),
|
|
118
|
+
}))
|
|
119
|
+
: undefined;
|
|
120
|
+
return {
|
|
121
|
+
content: content || undefined,
|
|
122
|
+
reasoning: reasoning || undefined,
|
|
123
|
+
toolCalls,
|
|
124
|
+
usage,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ── Provider Factory ────────────────────────────────────────────────────────
|
|
128
|
+
/**
|
|
129
|
+
* Create a provider for any OpenAI-compatible API.
|
|
130
|
+
*
|
|
131
|
+
* Works with: OpenAI, vLLM, OpenRouter, Ollama, LiteLLM, etc.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* const provider = createOpenAIProvider('https://api.openai.com', 'gpt-4o')
|
|
136
|
+
* const provider = createOpenAIProvider('http://localhost:8000', 'my-model')
|
|
137
|
+
* const provider = createOpenAIProvider('https://openrouter.ai/api', 'anthropic/claude-sonnet-4.5', {
|
|
138
|
+
* apiKey: 'sk-or-...',
|
|
139
|
+
* temperature: 0.2,
|
|
140
|
+
* })
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export function createOpenAIProvider(baseUrl, model, opts) {
|
|
144
|
+
const temperature = opts?.temperature ?? 0.7;
|
|
145
|
+
return {
|
|
146
|
+
async generate(params) {
|
|
147
|
+
const shouldStream = !!(params.stream?.onReasoning || params.stream?.onContent);
|
|
148
|
+
const body = {
|
|
149
|
+
model,
|
|
150
|
+
messages: toAPIMessages(params.messages),
|
|
151
|
+
temperature,
|
|
152
|
+
stream: shouldStream,
|
|
153
|
+
...(shouldStream ? { stream_options: { include_usage: true } } : {}),
|
|
154
|
+
};
|
|
155
|
+
const tools = params.tools && params.tools.length > 0 ? toAPITools(params.tools) : undefined;
|
|
156
|
+
if (tools) {
|
|
157
|
+
body.tools = tools;
|
|
158
|
+
body.tool_choice = 'auto';
|
|
159
|
+
}
|
|
160
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
161
|
+
if (opts?.apiKey)
|
|
162
|
+
headers['Authorization'] = `Bearer ${opts.apiKey}`;
|
|
163
|
+
const response = await fetch(`${baseUrl}/v1/chat/completions`, {
|
|
164
|
+
method: 'POST',
|
|
165
|
+
headers,
|
|
166
|
+
body: JSON.stringify(body),
|
|
167
|
+
signal: params.signal,
|
|
168
|
+
});
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
const text = await response.text();
|
|
171
|
+
throw new Error(`LLM request failed (${response.status}): ${text}`);
|
|
172
|
+
}
|
|
173
|
+
// Non-streaming path
|
|
174
|
+
if (!shouldStream) {
|
|
175
|
+
const data = (await response.json());
|
|
176
|
+
const message = data.choices[0].message;
|
|
177
|
+
const usage = data.usage
|
|
178
|
+
? {
|
|
179
|
+
promptTokens: data.usage.prompt_tokens ?? 0,
|
|
180
|
+
completionTokens: data.usage.completion_tokens ?? 0,
|
|
181
|
+
totalTokens: data.usage.total_tokens ?? 0,
|
|
182
|
+
}
|
|
183
|
+
: undefined;
|
|
184
|
+
return {
|
|
185
|
+
content: message.content ?? undefined,
|
|
186
|
+
reasoning: message.reasoning_content ?? undefined,
|
|
187
|
+
toolCalls: parseToolCalls(message.tool_calls),
|
|
188
|
+
usage,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// Streaming path (SSE)
|
|
192
|
+
return readSSEStream(response, params.stream);
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
|
package/dist/tool.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Tool
|
|
3
|
+
*
|
|
4
|
+
* A tool is a schema + execute function. Everything is a tool.
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from './context.js';
|
|
7
|
+
import type { ToolParameter, ToolSpec } from './types.js';
|
|
8
|
+
export type ToolConfig<TArgs = Record<string, unknown>> = {
|
|
9
|
+
id: string;
|
|
10
|
+
description: string;
|
|
11
|
+
schema?: Record<string, ToolParameter>;
|
|
12
|
+
execute: (args: TArgs, ctx: Context) => Promise<unknown>;
|
|
13
|
+
};
|
|
14
|
+
export declare class Tool<TArgs = Record<string, unknown>> {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly description: string;
|
|
17
|
+
readonly schema: Record<string, ToolParameter>;
|
|
18
|
+
readonly execute: (args: TArgs, ctx: Context) => Promise<unknown>;
|
|
19
|
+
constructor(config: ToolConfig<TArgs>);
|
|
20
|
+
/** Tool specification for the provider (OpenAI-compatible format) */
|
|
21
|
+
get spec(): ToolSpec;
|
|
22
|
+
}
|
|
23
|
+
export declare function createTool<TArgs = Record<string, unknown>>(config: ToolConfig<TArgs>): Tool<TArgs>;
|
|
24
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAIzD,MAAM,MAAM,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACxD,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IACtC,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACzD,CAAA;AAID,qBAAa,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC9C,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;gBAErD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC;IAOrC,qEAAqE;IACrE,IAAI,IAAI,IAAI,QAAQ,CAMnB;CACF;AAID,wBAAgB,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,IAAI,CAAC,KAAK,CAAC,CAEb"}
|
package/dist/tool.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Tool
|
|
3
|
+
*
|
|
4
|
+
* A tool is a schema + execute function. Everything is a tool.
|
|
5
|
+
*/
|
|
6
|
+
// ── Tool ────────────────────────────────────────────────────────────────────
|
|
7
|
+
export class Tool {
|
|
8
|
+
id;
|
|
9
|
+
description;
|
|
10
|
+
schema;
|
|
11
|
+
execute;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.id = config.id;
|
|
14
|
+
this.description = config.description;
|
|
15
|
+
this.schema = config.schema ?? {};
|
|
16
|
+
this.execute = config.execute;
|
|
17
|
+
}
|
|
18
|
+
/** Tool specification for the provider (OpenAI-compatible format) */
|
|
19
|
+
get spec() {
|
|
20
|
+
return {
|
|
21
|
+
name: this.id,
|
|
22
|
+
description: this.description,
|
|
23
|
+
parameters: this.schema,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// ── Factory ─────────────────────────────────────────────────────────────────
|
|
28
|
+
export function createTool(config) {
|
|
29
|
+
return new Tool(config);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=tool.js.map
|
package/dist/tool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,+EAA+E;AAE/E,MAAM,OAAO,IAAI;IACN,EAAE,CAAQ;IACV,WAAW,CAAQ;IACnB,MAAM,CAA+B;IACrC,OAAO,CAAiD;IAEjE,YAAY,MAAyB;QACnC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAA;QACnB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAA;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAA;QACjC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;IAC/B,CAAC;IAED,qEAAqE;IACrE,IAAI,IAAI;QACN,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,EAAE;YACb,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,MAAM;SACxB,CAAA;IACH,CAAC;CACF;AAED,+EAA+E;AAE/E,MAAM,UAAU,UAAU,CACxB,MAAyB;IAEzB,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,CAAA;AACzB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cog v2 — Core Types
|
|
3
|
+
*/
|
|
4
|
+
/** A tool call request from the model */
|
|
5
|
+
export type ToolCallRequest = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
arguments: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
/** A message in the context chain */
|
|
11
|
+
export type Message = {
|
|
12
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
13
|
+
content: string;
|
|
14
|
+
reasoning?: string;
|
|
15
|
+
toolCallId?: string;
|
|
16
|
+
toolCalls?: ToolCallRequest[];
|
|
17
|
+
};
|
|
18
|
+
/** Parameter definition for a tool */
|
|
19
|
+
export type ToolParameter = {
|
|
20
|
+
type: 'string' | 'number' | 'boolean';
|
|
21
|
+
description: string;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Tool specification sent to the provider */
|
|
25
|
+
export type ToolSpec = {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
parameters: Record<string, ToolParameter>;
|
|
29
|
+
};
|
|
30
|
+
/** Token usage statistics from a provider call */
|
|
31
|
+
export type Usage = {
|
|
32
|
+
promptTokens: number;
|
|
33
|
+
completionTokens: number;
|
|
34
|
+
totalTokens: number;
|
|
35
|
+
};
|
|
36
|
+
/** Result from a provider generate call */
|
|
37
|
+
export type GenerateResult = {
|
|
38
|
+
content?: string;
|
|
39
|
+
reasoning?: string;
|
|
40
|
+
toolCalls?: ToolCallRequest[];
|
|
41
|
+
usage?: Usage;
|
|
42
|
+
};
|
|
43
|
+
/** Streaming callbacks passed to the provider */
|
|
44
|
+
export type StreamCallbacks = {
|
|
45
|
+
onReasoning?: (chunk: string) => void;
|
|
46
|
+
onContent?: (chunk: string) => void;
|
|
47
|
+
};
|
|
48
|
+
/** LLM provider interface — user-supplied */
|
|
49
|
+
export interface Provider {
|
|
50
|
+
generate(params: {
|
|
51
|
+
messages: Message[];
|
|
52
|
+
tools?: ToolSpec[];
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
stream?: StreamCallbacks;
|
|
55
|
+
}): Promise<GenerateResult>;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,yCAAyC;AACzC,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC,CAAA;AAED,qCAAqC;AACrC,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAA;CAC9B,CAAA;AAID,sCAAsC;AACtC,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,8CAA8C;AAC9C,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CAC1C,CAAA;AAID,kDAAkD;AAClD,MAAM,MAAM,KAAK,GAAG;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,2CAA2C;AAC3C,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAA;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,CAAA;AAED,iDAAiD;AACjD,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,CAAA;AAED,6CAA6C;AAC7C,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,EAAE,OAAO,EAAE,CAAA;QACnB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAA;QAClB,MAAM,CAAC,EAAE,WAAW,CAAA;QACpB,MAAM,CAAC,EAAE,eAAe,CAAA;KACzB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;CAC5B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elfenlabs/cog",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A minimal agent SDK for TypeScript — three primitives, infinite composition",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "tsc",
|
|
22
|
+
"test": "bun test"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"agent",
|
|
26
|
+
"sdk",
|
|
27
|
+
"llm",
|
|
28
|
+
"context",
|
|
29
|
+
"state-machine",
|
|
30
|
+
"ai",
|
|
31
|
+
"typescript"
|
|
32
|
+
],
|
|
33
|
+
"author": "Elfenlabs",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/elfenlabs/cog.git"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/elfenlabs/cog#readme",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/elfenlabs/cog/issues"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/bun": "^1.3.9",
|
|
45
|
+
"tsx": "^4.21.0",
|
|
46
|
+
"typescript": "^5.9.3"
|
|
47
|
+
}
|
|
48
|
+
}
|