@jterrazz/intelligence 1.2.0 → 1.4.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/README.md +116 -239
- package/dist/adapters/agents/{chat-agent.adapter.d.ts → autonomous-agent.adapter.d.ts} +8 -7
- package/dist/adapters/agents/{chat-agent.adapter.js → autonomous-agent.adapter.js} +48 -20
- package/dist/adapters/agents/autonomous-agent.adapter.js.map +1 -0
- package/dist/adapters/agents/{query-agent.adapter.d.ts → basic-agent.adapter.d.ts} +8 -7
- package/dist/adapters/agents/{query-agent.adapter.js → basic-agent.adapter.js} +46 -20
- package/dist/adapters/agents/basic-agent.adapter.js.map +1 -0
- package/dist/index.cjs +88 -44
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/ports/agent.port.d.ts +7 -5
- package/dist/ports/agent.port.js +3 -1
- package/dist/ports/agent.port.js.map +1 -1
- package/package.json +5 -5
- package/dist/adapters/agents/chat-agent.adapter.js.map +0 -1
- package/dist/adapters/agents/query-agent.adapter.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@jterrazz/intelligence)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
|
-
`@jterrazz/intelligence` provides a clean, structured, and extensible foundation for building sophisticated AI agents.
|
|
8
|
+
`@jterrazz/intelligence` provides a clean, structured, and extensible foundation for building sophisticated AI agents. It's designed to help you create reliable and maintainable AI-powered applications by focusing on composability and type safety.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Core Principles
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
14
|
+
- **Composable Prompts**: Instead of monolithic prompts, the library offers a collection of constants. Mix and match them to build a precise system prompt that defines your agent's behavior, personality, and output format.
|
|
15
|
+
|
|
16
|
+
- **Safe, Typed Tools**: A `SafeToolAdapter` provides built-in error handling and Zod-based schema validation for any tool you create. This ensures that tool inputs are valid and that your agent can gracefully handle execution errors.
|
|
17
|
+
|
|
18
|
+
- **Ports & Adapters Architecture**: The library uses a hexagonal architecture to separate core logic from implementation details. This makes it easy to swap out underlying models or services (e.g., switching from OpenAI to Anthropic) without rewriting your application.
|
|
18
19
|
|
|
19
20
|
## Installation
|
|
20
21
|
|
|
@@ -26,11 +27,11 @@ npm install @jterrazz/intelligence
|
|
|
26
27
|
|
|
27
28
|
## Quick Start
|
|
28
29
|
|
|
29
|
-
Get your first agent running in
|
|
30
|
+
Get your first agent running in minutes. This example creates a helpful agent for a Discord community.
|
|
30
31
|
|
|
31
32
|
```typescript
|
|
32
33
|
import {
|
|
33
|
-
|
|
34
|
+
AutonomousAgentAdapter,
|
|
34
35
|
OpenRouterAdapter,
|
|
35
36
|
SystemPromptAdapter,
|
|
36
37
|
PROMPT_LIBRARY,
|
|
@@ -43,7 +44,7 @@ const model = new OpenRouterAdapter({
|
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
// 2. Create an agent using a preset prompt
|
|
46
|
-
const agent = new
|
|
47
|
+
const agent = new AutonomousAgentAdapter('discord-bot', {
|
|
47
48
|
model,
|
|
48
49
|
systemPrompt: new SystemPromptAdapter(PROMPT_LIBRARY.PRESETS.COMMUNITY_ANIMATOR),
|
|
49
50
|
});
|
|
@@ -55,277 +56,153 @@ console.log(response);
|
|
|
55
56
|
// Output might be: "Hello, community! I'm here to help with any questions and keep the good vibes flowing. What's on your mind today?"
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
## Core Concepts
|
|
61
|
-
|
|
62
|
-
### 1. Composable Prompts
|
|
63
|
-
|
|
64
|
-
Instead of writing monolithic prompts, the library provides a collection of composable string constants. Mix and match them to build a precise, fine-grained system prompt that defines your agent's behavior.
|
|
65
|
-
|
|
66
|
-
- **`FOUNDATIONS`**: Core, non-negotiable rules (e.g., `PROMPT_LIBRARY.FOUNDATIONS.ETHICAL_CONDUCT`).
|
|
67
|
-
- **`PERSONAS`**: The agent's identity and purpose (e.g., `PROMPT_LIBRARY.PERSONAS.EXPERT_ADVISOR`).
|
|
68
|
-
- **`DOMAINS`**: The agent's area of expertise (e.g., `PROMPT_LIBRARY.DOMAINS.SOFTWARE_ENGINEERING`).
|
|
69
|
-
- **`TONES`**: The emotional flavor of communication (e.g., `PROMPT_LIBRARY.TONES.PROFESSIONAL`).
|
|
70
|
-
- **`FORMATS`**: The structural format of the output (e.g., `PROMPT_LIBRARY.FORMATS.JSON`).
|
|
71
|
-
- **`LANGUAGES`**: The natural language for the response (e.g., `PROMPT_LIBRARY.LANGUAGES.ENGLISH_NATIVE`).
|
|
72
|
-
- **`VERBOSITY`**: The level of detail in the response (e.g., `PROMPT_LIBRARY.VERBOSITY.DETAILED`).
|
|
73
|
-
- **`RESPONSES`**: The strategic approach to responding (e.g., `PROMPT_LIBRARY.RESPONSES.ALWAYS_ENGAGE`).
|
|
74
|
-
|
|
75
|
-
This approach makes agent behavior more predictable and easier to modify.
|
|
76
|
-
|
|
77
|
-
### 2. Safe Tool Integration
|
|
78
|
-
|
|
79
|
-
The `SafeToolAdapter` is a wrapper for your functions that ensures they are executed safely.
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { SafeToolAdapter } from '@jterrazz/intelligence';
|
|
83
|
-
import { z } from 'zod/v4';
|
|
84
|
-
|
|
85
|
-
const weatherTool = new SafeToolAdapter(
|
|
86
|
-
{
|
|
87
|
-
name: 'get_weather',
|
|
88
|
-
description: 'Get the current weather for a specific city.',
|
|
89
|
-
execute: async ({ city }) => `The weather in ${city} is currently sunny.`,
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
// Zod schema for automatic validation and type-safety
|
|
93
|
-
schema: z.object({
|
|
94
|
-
city: z.string().describe('The city name'),
|
|
95
|
-
}),
|
|
96
|
-
},
|
|
97
|
-
);
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
The adapter handles errors gracefully and integrates seamlessly with the agent, which will automatically provide the Zod schema to the underlying model.
|
|
101
|
-
|
|
102
|
-
### 3. Ports and Adapters Architecture
|
|
103
|
-
|
|
104
|
-
The library is built on a hexagonal architecture.
|
|
105
|
-
|
|
106
|
-
- **Ports (`/ports`)**: Define the contracts (interfaces) for core components like `Agent`, `Model`, and `Tool`.
|
|
107
|
-
- **Adapters (`/adapters`)**: Provide concrete implementations. For example, `ChatAgentAdapter` is an adapter that uses LangChain, and `OpenRouterAdapter` is an adapter for the OpenRouter API.
|
|
108
|
-
|
|
109
|
-
This separation of concerns means you can easily create your own adapters to support different models or services without changing the application's core logic.
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
src/
|
|
113
|
-
├── ports/ # Abstract interfaces (the "what")
|
|
114
|
-
└── adapters/ # Concrete implementations (the "how")
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
59
|
+
## Creating Domain-Specific Agents
|
|
118
60
|
|
|
119
|
-
|
|
61
|
+
The most powerful feature of `@jterrazz/intelligence` is its ability to create specialized, reusable agents. By extending the base adapters, you can encapsulate an agent's logic, prompts, and tools into a clean, type-safe class.
|
|
120
62
|
|
|
121
|
-
###
|
|
63
|
+
### 1. Data Extraction Agent (`BasicAgentAdapter`)
|
|
122
64
|
|
|
123
|
-
|
|
65
|
+
Use `BasicAgentAdapter` for simpler, one-shot tasks where you need a structured response but don't require complex tool use. This example creates a reusable agent to extract contact information.
|
|
124
66
|
|
|
125
67
|
```typescript
|
|
126
68
|
import {
|
|
127
|
-
|
|
69
|
+
BasicAgentAdapter,
|
|
70
|
+
ModelPort,
|
|
128
71
|
OpenRouterAdapter,
|
|
129
72
|
SystemPromptAdapter,
|
|
130
73
|
UserPromptAdapter,
|
|
131
74
|
PROMPT_LIBRARY,
|
|
132
75
|
} from '@jterrazz/intelligence';
|
|
133
|
-
|
|
76
|
+
import { z } from 'zod';
|
|
77
|
+
|
|
78
|
+
// 1. Define the output type for compile-time type-safety
|
|
79
|
+
interface Contact {
|
|
80
|
+
name: string;
|
|
81
|
+
email: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 2. Create a specialized agent by extending BasicAgentAdapter
|
|
85
|
+
class ContactExtractorAgent extends BasicAgentAdapter<Contact> {
|
|
86
|
+
constructor(model: ModelPort) {
|
|
87
|
+
super('contact-extractor', {
|
|
88
|
+
model,
|
|
89
|
+
// Define the schema for runtime validation and type inference
|
|
90
|
+
schema: z.object({
|
|
91
|
+
name: z.string().describe('The full name of the person'),
|
|
92
|
+
email: z.string().email().describe('The email address'),
|
|
93
|
+
}),
|
|
94
|
+
// Compose the system prompt from the library
|
|
95
|
+
systemPrompt: new SystemPromptAdapter(
|
|
96
|
+
PROMPT_LIBRARY.FORMATS.JSON,
|
|
97
|
+
'You are an expert at extracting contact details from text.',
|
|
98
|
+
),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 3. Instantiate and use the agent
|
|
134
104
|
const model = new OpenRouterAdapter({
|
|
135
105
|
apiKey: process.env.OPENROUTER_API_KEY!,
|
|
136
106
|
modelName: 'anthropic/claude-3.5-sonnet',
|
|
137
107
|
});
|
|
108
|
+
const agent = new ContactExtractorAgent(model);
|
|
138
109
|
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
PROMPT_LIBRARY.PERSONAS.EXPERT_ADVISOR,
|
|
142
|
-
PROMPT_LIBRARY.DOMAINS.SOFTWARE_ENGINEERING,
|
|
143
|
-
PROMPT_LIBRARY.TONES.PROFESSIONAL,
|
|
144
|
-
PROMPT_LIBRARY.VERBOSITY.DETAILED,
|
|
145
|
-
PROMPT_LIBRARY.FORMATS.MARKDOWN,
|
|
146
|
-
PROMPT_LIBRARY.FOUNDATIONS.FACTUAL_ACCURACY,
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
// 2. Create the user request (using a single array)
|
|
150
|
-
const userPrompt = new UserPromptAdapter([
|
|
151
|
-
'Please review this TypeScript code for best practices:',
|
|
152
|
-
'const x = (s) => s.trim();',
|
|
153
|
-
]);
|
|
154
|
-
|
|
155
|
-
// 3. Configure and run the agent
|
|
156
|
-
const agent = new ChatAgentAdapter('code-reviewer', {
|
|
157
|
-
model,
|
|
158
|
-
systemPrompt,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const response = await agent.run(userPrompt);
|
|
110
|
+
const text = 'Say hi to John Doe, you can reach him at john.doe@example.com.';
|
|
111
|
+
const contact = await agent.run(new UserPromptAdapter(text));
|
|
162
112
|
|
|
163
|
-
console.log(
|
|
113
|
+
console.log(contact);
|
|
114
|
+
// Output: { name: 'John Doe', email: 'john.doe@example.com' }
|
|
164
115
|
```
|
|
165
116
|
|
|
166
|
-
###
|
|
117
|
+
### 2. Autonomous Agent with a Custom Tool (`AutonomousAgentAdapter`)
|
|
167
118
|
|
|
168
|
-
This example
|
|
119
|
+
Use `AutonomousAgentAdapter` when you need an agent that can reason and use tools to accomplish a task. This example creates a weather assistant that uses a tool and returns a structured JSON response.
|
|
169
120
|
|
|
170
121
|
```typescript
|
|
171
122
|
import {
|
|
172
|
-
|
|
123
|
+
AutonomousAgentAdapter,
|
|
124
|
+
ModelPort,
|
|
173
125
|
OpenRouterAdapter,
|
|
126
|
+
SafeToolAdapter,
|
|
174
127
|
SystemPromptAdapter,
|
|
175
128
|
UserPromptAdapter,
|
|
176
|
-
PROMPT_LIBRARY,
|
|
177
129
|
} from '@jterrazz/intelligence';
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
130
|
+
import { z } from 'zod';
|
|
131
|
+
|
|
132
|
+
// 1. Define the agent's final output type
|
|
133
|
+
interface WeatherReport {
|
|
134
|
+
city: string;
|
|
135
|
+
temperature: number;
|
|
136
|
+
conditions: string;
|
|
137
|
+
forecast: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 2. Define a tool. Its `execute` function should return a string,
|
|
141
|
+
// as the agent will process this output to formulate a final answer.
|
|
142
|
+
const weatherTool = new SafeToolAdapter({
|
|
143
|
+
name: 'get_weather',
|
|
144
|
+
description: 'Gets the current weather for a specified city.',
|
|
145
|
+
schema: z.object({ city: z.string().describe('The name of the city') }),
|
|
146
|
+
execute: async ({ city }) => {
|
|
147
|
+
// In a real app, you would call a weather API here.
|
|
148
|
+
// The tool returns raw data, often as a JSON string.
|
|
149
|
+
if (city.toLowerCase() === 'paris') {
|
|
150
|
+
return JSON.stringify({
|
|
151
|
+
city: 'Paris',
|
|
152
|
+
temperature: 25,
|
|
153
|
+
conditions: 'sunny',
|
|
154
|
+
forecast: 'clear skies for the next 24 hours',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return `Sorry, I don't have weather information for ${city}.`;
|
|
158
|
+
},
|
|
196
159
|
});
|
|
197
160
|
|
|
198
|
-
// 3.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
import { z } from 'zod/v4';
|
|
221
|
-
|
|
161
|
+
// 3. Create a specialized agent that uses the tool and has a structured output
|
|
162
|
+
class WeatherAssistantAgent extends AutonomousAgentAdapter<WeatherReport> {
|
|
163
|
+
constructor(model: ModelPort) {
|
|
164
|
+
super('weather-assistant', {
|
|
165
|
+
model,
|
|
166
|
+
tools: [weatherTool],
|
|
167
|
+
// This schema defines the agent's FINAL output structure
|
|
168
|
+
schema: z.object({
|
|
169
|
+
city: z.string(),
|
|
170
|
+
temperature: z.number(),
|
|
171
|
+
conditions: z.string(),
|
|
172
|
+
forecast: z.string(),
|
|
173
|
+
}),
|
|
174
|
+
systemPrompt: new SystemPromptAdapter(
|
|
175
|
+
'You are a helpful weather assistant.',
|
|
176
|
+
'You must use the provided tools to get weather information and then respond with a structured JSON object.',
|
|
177
|
+
),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 4. Instantiate and use the agent
|
|
222
183
|
const model = new OpenRouterAdapter({
|
|
223
184
|
apiKey: process.env.OPENROUTER_API_KEY!,
|
|
224
185
|
modelName: 'anthropic/claude-3.5-sonnet',
|
|
225
186
|
});
|
|
187
|
+
const agent = new WeatherAssistantAgent(model);
|
|
226
188
|
|
|
227
|
-
|
|
228
|
-
const extractionSchema = z.object({
|
|
229
|
-
name: z.string(),
|
|
230
|
-
email: z.string().email(),
|
|
231
|
-
phone: z.string().optional(),
|
|
232
|
-
company: z.string().optional(),
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// 2. Create a system prompt for data extraction
|
|
236
|
-
const systemPrompt = new SystemPromptAdapter(
|
|
237
|
-
PROMPT_LIBRARY.PERSONAS.EXPERT_ADVISOR,
|
|
238
|
-
PROMPT_LIBRARY.TONES.PROFESSIONAL,
|
|
239
|
-
PROMPT_LIBRARY.FORMATS.JSON,
|
|
240
|
-
'You extract contact information from text and return it as JSON.',
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
// 3. Create a query agent with schema parsing
|
|
244
|
-
const agent = new QueryAgentAdapter('contact-extractor', {
|
|
245
|
-
model,
|
|
246
|
-
schema: extractionSchema,
|
|
247
|
-
systemPrompt,
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
// 4. Run the query
|
|
251
|
-
const userPrompt = new UserPromptAdapter(
|
|
252
|
-
'Extract contact info: "Hi, I\'m John Doe from TechCorp. Email me at john@techcorp.com or call 555-1234"',
|
|
253
|
-
);
|
|
254
|
-
const response = await agent.run(userPrompt);
|
|
255
|
-
|
|
256
|
-
// 5. Get both raw response and parsed data
|
|
257
|
-
console.log('Raw response:', response);
|
|
258
|
-
const parsedData = agent.getLastParsedResult();
|
|
259
|
-
console.log('Parsed data:', parsedData);
|
|
260
|
-
// Expected: { name: "John Doe", email: "john@techcorp.com", phone: "555-1234", company: "TechCorp" }
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Recipe: Weather Bot with Tools
|
|
264
|
-
|
|
265
|
-
This example shows how to give an agent a tool and have it respond to a user query.
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
import {
|
|
269
|
-
ChatAgentAdapter,
|
|
270
|
-
OpenRouterAdapter,
|
|
271
|
-
SafeToolAdapter,
|
|
272
|
-
SystemPromptAdapter,
|
|
273
|
-
UserPromptAdapter,
|
|
274
|
-
PROMPT_LIBRARY,
|
|
275
|
-
} from '@jterrazz/intelligence';
|
|
276
|
-
import { z } from 'zod/v4';
|
|
277
|
-
|
|
278
|
-
// Assume 'model' is already configured
|
|
279
|
-
|
|
280
|
-
// 1. Define the tool
|
|
281
|
-
const weatherTool = new SafeToolAdapter(
|
|
282
|
-
{
|
|
283
|
-
name: 'get_weather',
|
|
284
|
-
description: 'Get the current weather for a location.',
|
|
285
|
-
execute: async ({ city }) => {
|
|
286
|
-
// In a real app, you would fetch from a weather API here
|
|
287
|
-
return `The weather in ${city} is 75°F and sunny.`;
|
|
288
|
-
},
|
|
289
|
-
},
|
|
290
|
-
{ schema: z.object({ city: z.string().describe('City name') }) },
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
// 2. Create an agent that knows how to use tools
|
|
294
|
-
const agent = new ChatAgentAdapter('weather-bot', {
|
|
295
|
-
model,
|
|
296
|
-
systemPrompt: new SystemPromptAdapter(PROMPT_LIBRARY.PRESETS.EMPATHETIC_SUPPORT_AGENT), // A good general-purpose preset
|
|
297
|
-
tools: [weatherTool], // Pass the tool instance directly
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
// 3. Run the agent with a user query that requires the tool
|
|
301
|
-
const response = await agent.run(new UserPromptAdapter("What's the weather like in Boston?"));
|
|
189
|
+
const response = await agent.run(new UserPromptAdapter("What's the weather like in Paris?"));
|
|
302
190
|
|
|
303
191
|
console.log(response);
|
|
304
|
-
//
|
|
192
|
+
// Output: { city: 'Paris', temperature: 25, conditions: 'sunny', forecast: 'clear skies for the next 24 hours' }
|
|
305
193
|
```
|
|
306
194
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
## API Reference
|
|
310
|
-
|
|
311
|
-
### Core Components
|
|
195
|
+
## Development
|
|
312
196
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
| `ChatAgentAdapter` | The main agent implementation. Runs prompts and coordinates tools. |
|
|
316
|
-
| `QueryAgentAdapter` | A simpler agent for one-shot responses without tools or complex logic. |
|
|
317
|
-
| `OpenRouterModelAdapter` | An adapter for connecting to any model on the OpenRouter platform. |
|
|
318
|
-
| `SafeToolAdapter` | A type-safe wrapper for creating tools with validation and error handling. |
|
|
319
|
-
| `SystemPromptAdapter` | A simple adapter to generate a system prompt string from a prompt array. |
|
|
320
|
-
| `UserPromptAdapter` | A simple adapter to generate a user prompt string from a prompt array. |
|
|
321
|
-
| `AIResponseParser` | A utility to parse a model's string output into a typed object using Zod. |
|
|
322
|
-
| `PROMPT_LIBRARY` | A frozen object containing the entire composable prompt library. |
|
|
197
|
+
- **Linting**: `npm run lint`
|
|
198
|
+
- **Testing**: `npm run test`
|
|
323
199
|
|
|
324
200
|
## Contributing
|
|
325
201
|
|
|
326
|
-
Contributions are welcome! Please feel free to submit a
|
|
202
|
+
Contributions are welcome! Please feel free to open an issue or submit a pull request.
|
|
203
|
+
|
|
204
|
+
---
|
|
327
205
|
|
|
328
|
-
##
|
|
206
|
+
## License
|
|
329
207
|
|
|
330
|
-
|
|
331
|
-
- Email: contact@jterrazz.com
|
|
208
|
+
This project is licensed under the [MIT License](./LICENSE).
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { type LoggerPort } from '@jterrazz/logger';
|
|
2
|
-
import {
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
3
|
import { type AgentPort } from '../../ports/agent.port.js';
|
|
4
4
|
import type { ModelPort } from '../../ports/model.port.js';
|
|
5
5
|
import type { PromptPort } from '../../ports/prompt.port.js';
|
|
6
6
|
import type { ToolPort } from '../../ports/tool.port.js';
|
|
7
7
|
import type { SystemPromptAdapter } from '../prompts/system-prompt.adapter.js';
|
|
8
|
-
export interface
|
|
8
|
+
export interface AutonomousAgentOptions<TOutput = string> {
|
|
9
9
|
logger?: LoggerPort;
|
|
10
10
|
model: ModelPort;
|
|
11
|
-
schema?: z.ZodSchema<
|
|
11
|
+
schema?: z.ZodSchema<TOutput>;
|
|
12
12
|
systemPrompt: SystemPromptAdapter;
|
|
13
13
|
tools: ToolPort[];
|
|
14
14
|
verbose?: boolean;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* An
|
|
17
|
+
* An autonomous agent that uses tools and a structured prompt to accomplish tasks.
|
|
18
18
|
* It can decide whether to respond or remain silent and supports schema-validated responses.
|
|
19
|
+
* @template TOutput - The TypeScript type of the output
|
|
19
20
|
*/
|
|
20
|
-
export declare class
|
|
21
|
+
export declare class AutonomousAgentAdapter<TOutput = string> implements AgentPort<PromptPort, TOutput> {
|
|
21
22
|
readonly name: string;
|
|
22
23
|
private readonly options;
|
|
23
|
-
constructor(name: string, options:
|
|
24
|
-
run(
|
|
24
|
+
constructor(name: string, options: AutonomousAgentOptions<TOutput>);
|
|
25
|
+
run(input?: PromptPort): Promise<null | TOutput>;
|
|
25
26
|
private createExecutor;
|
|
26
27
|
private parseAgentOutput;
|
|
27
28
|
private resolveUserInput;
|
|
@@ -159,26 +159,28 @@ function _ts_generator(thisArg, body) {
|
|
|
159
159
|
}
|
|
160
160
|
import { ChatPromptTemplate } from '@langchain/core/prompts';
|
|
161
161
|
import { AgentExecutor, createStructuredChatAgent } from 'langchain/agents';
|
|
162
|
+
import { z } from 'zod/v4';
|
|
162
163
|
import { AIResponseParser } from '../utils/ai-response-parser.js';
|
|
163
|
-
var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
164
|
+
var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<GLOBAL_WRAPPER_OUTPUT_FORMAT>\nCRITICAL: The format instructions in this section are the ONLY valid way to structure your response. Your entire response MUST be a single JSON markdown code block. Any formatting guidelines within the <OBJECTIVE> section apply ONLY to the content inside the "RESPOND:" part of your final "action_input".\n\nREQUIRED: You have two ways to respond:\n\n1. **Call a tool** to gather information. For this, you MUST output a JSON blob with the tool\'s name and its input.\n *Valid tool names are: {tool_names}*\n ```json\n {{\n "action": "tool_name_to_use",\n "action_input": "the input for the tool, or an empty object {{}} if no input is needed"\n }}\n ```\n\n2. **Provide the Final Answer** once you have enough information. For this, you MUST output a JSON blob with the "Final Answer" action.\n The "action_input" for a "Final Answer" MUST be a string that begins with either "RESPOND: " for a message or "SILENT: " for no message. This prefix is a literal part of the output string and MUST NOT be omitted.\n - To send a message:\n ```json\n {{\n "action": "Final Answer",\n "action_input": "RESPOND: <your response message>"\n }}\n ```\n - To stay silent:\n ```json\n {{\n "action": "Final Answer",\n "action_input": "SILENT: <your reason for staying silent>"\n }}\n ```\n\n YOU MUST ALWAYS INCLUDE "RESPOND:" OR "SILENT:" IN YOUR FINAL ANSWER\'S "action_input". FAILURE TO DO SO WILL CAUSE AN ERROR.\n\n{schema_format}\n</OUTPUT_FORMAT>\n\n<EXECUTION_CONTEXT>\nThis is internal data for your reference.\n\n<TOOLS>\n{tools}\n</TOOLS>\n\n<WORKING_MEMORY>\nThis is your internal thought process and previous tool usage.\n{agent_scratchpad}\n</WORKING_MEMORY>\n</EXECUTION_CONTEXT>\n';
|
|
164
165
|
/**
|
|
165
|
-
* An
|
|
166
|
+
* An autonomous agent that uses tools and a structured prompt to accomplish tasks.
|
|
166
167
|
* It can decide whether to respond or remain silent and supports schema-validated responses.
|
|
167
|
-
|
|
168
|
+
* @template TOutput - The TypeScript type of the output
|
|
169
|
+
*/ export var AutonomousAgentAdapter = /*#__PURE__*/ function() {
|
|
168
170
|
"use strict";
|
|
169
|
-
function
|
|
170
|
-
_class_call_check(this,
|
|
171
|
+
function AutonomousAgentAdapter(name, options) {
|
|
172
|
+
_class_call_check(this, AutonomousAgentAdapter);
|
|
171
173
|
_define_property(this, "name", void 0);
|
|
172
174
|
_define_property(this, "options", void 0);
|
|
173
175
|
this.name = name;
|
|
174
176
|
this.options = options;
|
|
175
177
|
}
|
|
176
|
-
_create_class(
|
|
178
|
+
_create_class(AutonomousAgentAdapter, [
|
|
177
179
|
{
|
|
178
180
|
key: "run",
|
|
179
|
-
value: function run(
|
|
181
|
+
value: function run(input) {
|
|
180
182
|
return _async_to_generator(function() {
|
|
181
|
-
var _this_options_logger, _this_options_logger1, executor, userInput, result, agentResponse, _this_options_logger2, _agentResponse_message, message, _this_options_logger3, _this_options_logger4, error, _this_options_logger5;
|
|
183
|
+
var _this_options_logger, _this_options_logger1, executor, userInput, result, agentResponse, _this_options_logger2, _agentResponse_message, message, _this_options_logger3, validatedResponse, _this_options_logger4, error, _this_options_logger5;
|
|
182
184
|
return _ts_generator(this, function(_state) {
|
|
183
185
|
switch(_state.label){
|
|
184
186
|
case 0:
|
|
@@ -197,7 +199,7 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
197
199
|
];
|
|
198
200
|
case 2:
|
|
199
201
|
executor = _state.sent();
|
|
200
|
-
userInput = this.resolveUserInput(
|
|
202
|
+
userInput = this.resolveUserInput(input);
|
|
201
203
|
return [
|
|
202
204
|
4,
|
|
203
205
|
executor.invoke({
|
|
@@ -232,15 +234,24 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
232
234
|
message = (_agentResponse_message = agentResponse.message) !== null && _agentResponse_message !== void 0 ? _agentResponse_message : '';
|
|
233
235
|
if (this.options.schema) {
|
|
234
236
|
;
|
|
235
|
-
this.validateResponseContent(message, this.options.schema);
|
|
237
|
+
validatedResponse = this.validateResponseContent(message, this.options.schema);
|
|
236
238
|
(_this_options_logger3 = this.options.logger) === null || _this_options_logger3 === void 0 ? void 0 : _this_options_logger3.info("[".concat(this.name, "] Execution finished; response content validated."));
|
|
239
|
+
return [
|
|
240
|
+
2,
|
|
241
|
+
validatedResponse
|
|
242
|
+
];
|
|
237
243
|
} else {
|
|
238
244
|
;
|
|
239
245
|
(_this_options_logger4 = this.options.logger) === null || _this_options_logger4 === void 0 ? void 0 : _this_options_logger4.info("[".concat(this.name, "] Execution finished."));
|
|
246
|
+
// When no schema is provided, we assume TOutput is string (default), so message is the result
|
|
247
|
+
return [
|
|
248
|
+
2,
|
|
249
|
+
message
|
|
250
|
+
];
|
|
240
251
|
}
|
|
241
252
|
return [
|
|
242
|
-
|
|
243
|
-
|
|
253
|
+
3,
|
|
254
|
+
5
|
|
244
255
|
];
|
|
245
256
|
case 4:
|
|
246
257
|
error = _state.sent();
|
|
@@ -264,7 +275,7 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
264
275
|
key: "createExecutor",
|
|
265
276
|
value: function createExecutor() {
|
|
266
277
|
return _async_to_generator(function() {
|
|
267
|
-
var model, tools, prompt, agent;
|
|
278
|
+
var model, tools, schemaFormatInstructions, jsonSchema, isPrimitiveType, prompt, agent;
|
|
268
279
|
return _ts_generator(this, function(_state) {
|
|
269
280
|
switch(_state.label){
|
|
270
281
|
case 0:
|
|
@@ -272,10 +283,27 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
272
283
|
tools = this.options.tools.map(function(tool) {
|
|
273
284
|
return tool.getDynamicTool();
|
|
274
285
|
});
|
|
286
|
+
// Add schema format instructions if schema is provided
|
|
287
|
+
schemaFormatInstructions = '';
|
|
288
|
+
if (this.options.schema) {
|
|
289
|
+
jsonSchema = z.toJSONSchema(this.options.schema);
|
|
290
|
+
console.log(jsonSchema.type);
|
|
291
|
+
isPrimitiveType = [
|
|
292
|
+
'boolean',
|
|
293
|
+
'integer',
|
|
294
|
+
'number',
|
|
295
|
+
'string'
|
|
296
|
+
].includes(jsonSchema.type);
|
|
297
|
+
if (isPrimitiveType) {
|
|
298
|
+
schemaFormatInstructions = '\n\nSCHEMA VALIDATION: When providing a "RESPOND:" answer, the content after "RESPOND: " must be a '.concat(jsonSchema.type, " value that matches this schema:\n\n```json\n").concat(JSON.stringify(jsonSchema, null, 2), '\n```\n\nExample format:\n```json\n{{\n "action": "Final Answer",\n "action_input": "RESPOND: your ').concat(jsonSchema.type, ' value here"\n}}\n```\n\nDo not wrap the ').concat(jsonSchema.type, ' value in JSON - just provide the raw value after "RESPOND: ".');
|
|
299
|
+
} else {
|
|
300
|
+
schemaFormatInstructions = '\n\nSCHEMA VALIDATION: When providing a "RESPOND:" answer, the content after "RESPOND: " must be valid JSON that matches this exact schema:\n\n```json\n'.concat(JSON.stringify(jsonSchema, null, 2).replace(/{/g, '{{').replace(/}/g, '}}'), '\n```\n\nExample format:\n```json\n{{\n "action": "Final Answer",\n "action_input": "RESPOND: {{\\"field1\\": \\"value1\\", \\"field2\\": \\"value2\\"}}"\n}}\n```\n');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
275
303
|
prompt = ChatPromptTemplate.fromMessages([
|
|
276
304
|
[
|
|
277
305
|
'system',
|
|
278
|
-
SYSTEM_PROMPT_TEMPLATE.replace('{mission_prompt}', this.options.systemPrompt.generate())
|
|
306
|
+
SYSTEM_PROMPT_TEMPLATE.replace('{mission_prompt}', this.options.systemPrompt.generate()).replace('{schema_format}', schemaFormatInstructions)
|
|
279
307
|
],
|
|
280
308
|
[
|
|
281
309
|
'human',
|
|
@@ -332,9 +360,9 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
332
360
|
},
|
|
333
361
|
{
|
|
334
362
|
key: "resolveUserInput",
|
|
335
|
-
value: function resolveUserInput(
|
|
336
|
-
if (
|
|
337
|
-
return
|
|
363
|
+
value: function resolveUserInput(input) {
|
|
364
|
+
if (input) {
|
|
365
|
+
return input.generate();
|
|
338
366
|
}
|
|
339
367
|
return 'Proceed with your instructions.';
|
|
340
368
|
}
|
|
@@ -343,7 +371,7 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
343
371
|
key: "validateResponseContent",
|
|
344
372
|
value: function validateResponseContent(content, schema) {
|
|
345
373
|
try {
|
|
346
|
-
new AIResponseParser(schema).parse(content);
|
|
374
|
+
return new AIResponseParser(schema).parse(content);
|
|
347
375
|
} catch (error) {
|
|
348
376
|
var _this_options_logger;
|
|
349
377
|
(_this_options_logger = this.options.logger) === null || _this_options_logger === void 0 ? void 0 : _this_options_logger.error("[".concat(this.name, "] Failed to validate response content against schema."), {
|
|
@@ -355,7 +383,7 @@ var SYSTEM_PROMPT_TEMPLATE = '\n<OBJECTIVE>\n{mission_prompt}\n</OBJECTIVE>\n\n<
|
|
|
355
383
|
}
|
|
356
384
|
}
|
|
357
385
|
]);
|
|
358
|
-
return
|
|
386
|
+
return AutonomousAgentAdapter;
|
|
359
387
|
}();
|
|
360
388
|
|
|
361
|
-
//# sourceMappingURL=
|
|
389
|
+
//# sourceMappingURL=autonomous-agent.adapter.js.map
|