@limo-labs/deity 0.2.1 → 0.2.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/dist/index.cjs +33 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -10
- package/dist/index.d.ts +16 -10
- package/dist/index.js +33 -7
- package/dist/index.js.map +1 -1
- package/dist/{jsx-dev-runtime-Dg782FK5.d.cts → jsx-dev-runtime-1R5Vpr7w.d.cts} +6 -8
- package/dist/{jsx-dev-runtime-Dg782FK5.d.ts → jsx-dev-runtime-1R5Vpr7w.d.ts} +6 -8
- package/dist/jsx-dev-runtime.d.cts +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-runtime.d.cts +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/package.json +1 -1
- package/README.md +0 -681
package/README.md
DELETED
|
@@ -1,681 +0,0 @@
|
|
|
1
|
-
# @limo-labs/deity
|
|
2
|
-
|
|
3
|
-
> **Declarative AI Agent Framework** — Build type-safe AI agents with JSX/TSX syntax for agents and declarative API for workflows
|
|
4
|
-
|
|
5
|
-
Deity is a declarative framework for building AI agents. **Agents** use familiar JSX/TSX syntax like React components. **Workflows** use declarative function composition. Full TypeScript support and zero runtime overhead.
|
|
6
|
-
|
|
7
|
-
**Important Distinction:**
|
|
8
|
-
- **Agent Definition:** Uses true JSX/TSX tags (`<Agent>`, `<Prompt>`) in `.tsx` files
|
|
9
|
-
- **Workflow Definition:** Uses function calls (`Workflow()`, `Sequence()`) in `.ts` files
|
|
10
|
-
|
|
11
|
-
[](https://www.npmjs.com/package/@limo-labs/deity)
|
|
12
|
-
[](https://github.com/Limo-Labs/Limo-Deity/blob/main/LICENSE)
|
|
13
|
-
[](https://www.typescriptlang.org/)
|
|
14
|
-
|
|
15
|
-
## ✨ Features
|
|
16
|
-
|
|
17
|
-
- 🎨 **JSX/TSX Syntax for Agents** - Write agents with familiar React-like JSX tags (`.tsx` files)
|
|
18
|
-
- 📦 **Declarative Workflow API** - Compose workflows with function calls (`.ts` files)
|
|
19
|
-
- 🔒 **Type Safe** - Full TypeScript support with Zod schema validation
|
|
20
|
-
- 🔧 **Declarative** - Compose agents and workflows from reusable components
|
|
21
|
-
- 🚀 **Zero Runtime Overhead** - Compiles to lightweight AST nodes
|
|
22
|
-
- 🎯 **LLM Agnostic** - Works with any LLM adapter
|
|
23
|
-
- 🔁 **Auto Retry** - Built-in retry logic with LLM feedback
|
|
24
|
-
- ✅ **Output Validation** - Declarative validation rules
|
|
25
|
-
- 🛠️ **Tool Support** - Native tool calling integration
|
|
26
|
-
- 📊 **Observability** - Built-in execution tracing
|
|
27
|
-
|
|
28
|
-
## 📦 Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install @limo-labs/deity zod
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
yarn add @limo-labs/deity zod
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
pnpm add @limo-labs/deity zod
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## 🚀 Quick Start
|
|
43
|
-
|
|
44
|
-
### 1. Configure TypeScript (Optional - For JSX/TSX Agent Syntax)
|
|
45
|
-
|
|
46
|
-
If you want to use **JSX/TSX tags** for Agent definitions (`.tsx` files), add JSX support to your `tsconfig.json`:
|
|
47
|
-
|
|
48
|
-
```json
|
|
49
|
-
{
|
|
50
|
-
"compilerOptions": {
|
|
51
|
-
"jsx": "react-jsx",
|
|
52
|
-
"jsxImportSource": "@limo-labs/deity"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Note:** Workflow definitions use function calls and work in regular `.ts` files without JSX configuration.
|
|
58
|
-
|
|
59
|
-
### 2. Create Your First Agent (Using JSX/TSX Tags)
|
|
60
|
-
|
|
61
|
-
**File:** `agent.tsx` (note the `.tsx` extension for JSX support)
|
|
62
|
-
|
|
63
|
-
```tsx
|
|
64
|
-
import { Agent, Prompt, System, User, Result } from '@limo-labs/deity';
|
|
65
|
-
import { z } from 'zod';
|
|
66
|
-
|
|
67
|
-
// Define schemas
|
|
68
|
-
const InputSchema = z.object({
|
|
69
|
-
topic: z.string()
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const OutputSchema = z.object({
|
|
73
|
-
summary: z.string(),
|
|
74
|
-
keyPoints: z.array(z.string())
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Create agent using JSX tags (requires .tsx file)
|
|
78
|
-
const SummarizerAgent = (
|
|
79
|
-
<Agent id="summarizer" input={InputSchema} output={OutputSchema}>
|
|
80
|
-
<Prompt>
|
|
81
|
-
<System>You are a summarization expert.</System>
|
|
82
|
-
<User>{(ctx: any): string => `Summarize this topic: ${ctx.inputs.topic}`}</User>
|
|
83
|
-
</Prompt>
|
|
84
|
-
<Result>
|
|
85
|
-
{(ctx: any, llmResult: any) => {
|
|
86
|
-
// Extract output from LLM response
|
|
87
|
-
const content = llmResult.response.content;
|
|
88
|
-
return JSON.parse(content);
|
|
89
|
-
}}
|
|
90
|
-
</Result>
|
|
91
|
-
</Agent>
|
|
92
|
-
);
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### 3. Execute the Agent
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
import { compileAgent, executeComponent, createEnhancedContext } from '@limo-labs/deity';
|
|
99
|
-
|
|
100
|
-
// Compile JSX to executable component
|
|
101
|
-
const component = compileAgent(SummarizerAgent);
|
|
102
|
-
|
|
103
|
-
// Create execution context
|
|
104
|
-
const ctx = await createEnhancedContext({
|
|
105
|
-
inputs: { topic: 'Climate change' }
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Execute
|
|
109
|
-
const result = await executeComponent(component, ctx, llmAdapter);
|
|
110
|
-
console.log(result.output.summary);
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## 📖 Core Concepts
|
|
114
|
-
|
|
115
|
-
### Components
|
|
116
|
-
|
|
117
|
-
Deity provides declarative components for building agents:
|
|
118
|
-
|
|
119
|
-
- **`<Agent>`** - Root component defining the agent
|
|
120
|
-
- **`<Prompt>`** - Prompt construction
|
|
121
|
-
- **`<System>`** - System message
|
|
122
|
-
- **`<User>`** - User message
|
|
123
|
-
- **`<Result>`** - Output extraction
|
|
124
|
-
- **`<Validate>`** - Output validation
|
|
125
|
-
- **`<Retry>`** - Retry configuration
|
|
126
|
-
- **`<Observe>`** - LLM loop observation
|
|
127
|
-
|
|
128
|
-
### Agent Component
|
|
129
|
-
|
|
130
|
-
The `<Agent>` component is the root of every agent:
|
|
131
|
-
|
|
132
|
-
```tsx
|
|
133
|
-
<Agent
|
|
134
|
-
id="unique-id"
|
|
135
|
-
input={InputSchema}
|
|
136
|
-
output={OutputSchema}
|
|
137
|
-
loopConfig={{ maxToolRounds: 10, timeout: 30000 }}
|
|
138
|
-
tools={[...]}
|
|
139
|
-
>
|
|
140
|
-
{/* Children components */}
|
|
141
|
-
</Agent>
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
**Props:**
|
|
145
|
-
- `id` (required) - Unique agent identifier
|
|
146
|
-
- `input` (required) - Zod schema for input validation
|
|
147
|
-
- `output` (required) - Zod schema for output validation
|
|
148
|
-
- `loopConfig` (optional) - LLM loop configuration
|
|
149
|
-
- `loopValidator` (optional) - Custom loop validator
|
|
150
|
-
- `tools` (optional) - Tool definitions
|
|
151
|
-
|
|
152
|
-
### Prompt Component
|
|
153
|
-
|
|
154
|
-
The `<Prompt>` component defines how to build the LLM prompt:
|
|
155
|
-
|
|
156
|
-
```tsx
|
|
157
|
-
<Prompt>
|
|
158
|
-
<System>
|
|
159
|
-
{async (): Promise<string> => {
|
|
160
|
-
// Load prompt from file or construct dynamically
|
|
161
|
-
return await loadPromptTemplate();
|
|
162
|
-
}}
|
|
163
|
-
</System>
|
|
164
|
-
<User>
|
|
165
|
-
{(ctx: any): string => `Process: ${ctx.inputs.task}`}
|
|
166
|
-
</User>
|
|
167
|
-
</Prompt>
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Result Component
|
|
171
|
-
|
|
172
|
-
The `<Result>` component extracts structured output:
|
|
173
|
-
|
|
174
|
-
```tsx
|
|
175
|
-
<Result>
|
|
176
|
-
{(ctx: any, llmResult: any): OutputType => {
|
|
177
|
-
// Extract from tool calls
|
|
178
|
-
const toolCall = llmResult.response.toolCalls?.find(
|
|
179
|
-
tc => tc.name === 'submit_result'
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
if (toolCall) {
|
|
183
|
-
return JSON.parse(toolCall.arguments);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Or extract from text content
|
|
187
|
-
const match = llmResult.response.content.match(/```json\n(.*?)\n```/s);
|
|
188
|
-
return JSON.parse(match[1]);
|
|
189
|
-
}}
|
|
190
|
-
</Result>
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Validate Component
|
|
194
|
-
|
|
195
|
-
The `<Validate>` component defines validation rules:
|
|
196
|
-
|
|
197
|
-
```tsx
|
|
198
|
-
<Validate>
|
|
199
|
-
{(output: any, ctx: any) => ({
|
|
200
|
-
rules: [
|
|
201
|
-
{
|
|
202
|
-
check: output.summary.length >= 100,
|
|
203
|
-
error: 'Summary must be at least 100 characters'
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
check: output.keyPoints.length >= 3,
|
|
207
|
-
error: 'Must have at least 3 key points'
|
|
208
|
-
}
|
|
209
|
-
]
|
|
210
|
-
})}
|
|
211
|
-
</Validate>
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Retry Component
|
|
215
|
-
|
|
216
|
-
The `<Retry>` component configures retry behavior:
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
<Retry
|
|
220
|
-
maxAttempts={3}
|
|
221
|
-
feedbackOnError={true}
|
|
222
|
-
retryOnToolError={true}
|
|
223
|
-
/>
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## 🎯 Examples
|
|
227
|
-
|
|
228
|
-
### Simple Summarizer
|
|
229
|
-
|
|
230
|
-
```tsx
|
|
231
|
-
const Summarizer = (
|
|
232
|
-
<Agent id="summarizer" input={InputSchema} output={OutputSchema}>
|
|
233
|
-
<Prompt>
|
|
234
|
-
<System>You are a summarization expert.</System>
|
|
235
|
-
<User>{(ctx: any): string => `Summarize: ${ctx.inputs.text}`}</User>
|
|
236
|
-
</Prompt>
|
|
237
|
-
<Result>
|
|
238
|
-
{(ctx: any, llmResult: any) => ({
|
|
239
|
-
summary: llmResult.response.content
|
|
240
|
-
})}
|
|
241
|
-
</Result>
|
|
242
|
-
<Validate>
|
|
243
|
-
{(output: any) => ({
|
|
244
|
-
rules: [
|
|
245
|
-
{
|
|
246
|
-
check: output.summary.length >= 50,
|
|
247
|
-
error: 'Summary too short'
|
|
248
|
-
}
|
|
249
|
-
]
|
|
250
|
-
})}
|
|
251
|
-
</Validate>
|
|
252
|
-
<Retry maxAttempts={2} feedbackOnError={true} />
|
|
253
|
-
</Agent>
|
|
254
|
-
);
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### Code Analyzer with Tools
|
|
258
|
-
|
|
259
|
-
```tsx
|
|
260
|
-
import { createMemoryTools } from '@limo-labs/deity';
|
|
261
|
-
|
|
262
|
-
const CodeAnalyzer = (
|
|
263
|
-
<Agent
|
|
264
|
-
id="analyzer"
|
|
265
|
-
input={z.object({ repoPath: z.string() })}
|
|
266
|
-
output={z.object({ findings: z.array(z.any()) })}
|
|
267
|
-
tools={[
|
|
268
|
-
...createMemoryTools(),
|
|
269
|
-
{
|
|
270
|
-
name: 'read_file',
|
|
271
|
-
description: 'Read file contents',
|
|
272
|
-
inputSchema: z.object({ path: z.string() }),
|
|
273
|
-
async execute(input) {
|
|
274
|
-
return { content: await fs.readFile(input.path, 'utf-8') };
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
]}
|
|
278
|
-
>
|
|
279
|
-
<Prompt>
|
|
280
|
-
<System>
|
|
281
|
-
{async (): Promise<string> => {
|
|
282
|
-
return await fs.readFile('./prompts/analyzer.md', 'utf-8');
|
|
283
|
-
}}
|
|
284
|
-
</System>
|
|
285
|
-
<User>
|
|
286
|
-
{(ctx: any): string => `Analyze repository at: ${ctx.inputs.repoPath}`}
|
|
287
|
-
</User>
|
|
288
|
-
</Prompt>
|
|
289
|
-
<Result>
|
|
290
|
-
{(ctx: any, llmResult: any) => {
|
|
291
|
-
// Count memory_store tool calls to verify analysis
|
|
292
|
-
const findings = llmResult.response.toolCalls
|
|
293
|
-
?.filter((tc: any) => tc.name === 'memory_store')
|
|
294
|
-
.map((tc: any) => JSON.parse(tc.arguments));
|
|
295
|
-
|
|
296
|
-
return { findings };
|
|
297
|
-
}}
|
|
298
|
-
</Result>
|
|
299
|
-
</Agent>
|
|
300
|
-
);
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### Dynamic Tool Factory (NEW in 4.0)
|
|
304
|
-
|
|
305
|
-
**Tool Factory Pattern** - Create tools dynamically based on execution context:
|
|
306
|
-
|
|
307
|
-
```tsx
|
|
308
|
-
import { createMemoryTools } from '@limo-labs/deity';
|
|
309
|
-
|
|
310
|
-
const DynamicAgent = (
|
|
311
|
-
<Agent
|
|
312
|
-
id="dynamic"
|
|
313
|
-
input={z.object({ enableMemory: z.boolean() })}
|
|
314
|
-
output={z.object({ result: z.string() })}
|
|
315
|
-
tools={(ctx) => {
|
|
316
|
-
// Static tools always available
|
|
317
|
-
const staticTools = [
|
|
318
|
-
{
|
|
319
|
-
name: 'read_file',
|
|
320
|
-
description: 'Read file',
|
|
321
|
-
inputSchema: z.object({ path: z.string() }),
|
|
322
|
-
async execute(input) {
|
|
323
|
-
return await fs.readFile(input.path, 'utf-8');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
];
|
|
327
|
-
|
|
328
|
-
// Add memory tools conditionally
|
|
329
|
-
const memoryTools = ctx.memory ? createMemoryTools(ctx) : [];
|
|
330
|
-
|
|
331
|
-
return [...staticTools, ...memoryTools];
|
|
332
|
-
}}
|
|
333
|
-
>
|
|
334
|
-
{/* ... */}
|
|
335
|
-
</Agent>
|
|
336
|
-
);
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
**Key Benefits:**
|
|
340
|
-
- ✅ Tools can access ExecutionContext at creation time
|
|
341
|
-
- ✅ Conditional tool inclusion based on context state
|
|
342
|
-
- ✅ Enables Deity's memory tools in TSX workflows
|
|
343
|
-
- ✅ Backward compatible with static tool arrays
|
|
344
|
-
|
|
345
|
-
### Multi-Step Workflow
|
|
346
|
-
|
|
347
|
-
```tsx
|
|
348
|
-
const MultiStepAgent = (
|
|
349
|
-
<Agent id="multi-step" input={InputSchema} output={OutputSchema}>
|
|
350
|
-
<Prompt>
|
|
351
|
-
<System>
|
|
352
|
-
{async (): Promise<string> => {
|
|
353
|
-
const step = ctx.inputs.currentStep;
|
|
354
|
-
return await loadStepPrompt(step);
|
|
355
|
-
}}
|
|
356
|
-
</System>
|
|
357
|
-
<User>{(ctx: any): string => buildStepMessage(ctx)}</User>
|
|
358
|
-
</Prompt>
|
|
359
|
-
<Observe>
|
|
360
|
-
{(llmResult: any) => ({
|
|
361
|
-
toolCallCount: llmResult.response.toolCalls?.length || 0,
|
|
362
|
-
roundsExecuted: llmResult.rounds
|
|
363
|
-
})}
|
|
364
|
-
</Observe>
|
|
365
|
-
<Result>
|
|
366
|
-
{(ctx: any, llmResult: any, observed: any) => {
|
|
367
|
-
console.log(`Executed ${observed.roundsExecuted} rounds`);
|
|
368
|
-
return extractStepOutput(llmResult);
|
|
369
|
-
}}
|
|
370
|
-
</Result>
|
|
371
|
-
</Agent>
|
|
372
|
-
);
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
## 🔧 Advanced Features
|
|
376
|
-
|
|
377
|
-
### Loop Validation
|
|
378
|
-
|
|
379
|
-
Use `loopValidator` to validate during LLM execution loops:
|
|
380
|
-
|
|
381
|
-
```typescript
|
|
382
|
-
import type { Validator, LLMLoopState, ExecutionContext } from '@limo-labs/deity';
|
|
383
|
-
|
|
384
|
-
class CustomValidator implements Validator {
|
|
385
|
-
async validate(
|
|
386
|
-
ctx: ExecutionContext,
|
|
387
|
-
loopState: LLMLoopState
|
|
388
|
-
): Promise<ValidationResult> {
|
|
389
|
-
// Check if required tool was called
|
|
390
|
-
const requiredTool = loopState.toolCallsThisRound.find(
|
|
391
|
-
tc => tc.name === 'submit_plan'
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
if (!requiredTool) {
|
|
395
|
-
return {
|
|
396
|
-
valid: false,
|
|
397
|
-
feedback: 'You must call submit_plan tool to complete this task'
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return { valid: true };
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const agent = (
|
|
406
|
-
<Agent
|
|
407
|
-
id="planner"
|
|
408
|
-
input={InputSchema}
|
|
409
|
-
output={OutputSchema}
|
|
410
|
-
loopValidator={new CustomValidator()}
|
|
411
|
-
>
|
|
412
|
-
{/* ... */}
|
|
413
|
-
</Agent>
|
|
414
|
-
);
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### Loop Configuration
|
|
418
|
-
|
|
419
|
-
Configure LLM execution loop behavior:
|
|
420
|
-
|
|
421
|
-
```tsx
|
|
422
|
-
<Agent
|
|
423
|
-
id="agent"
|
|
424
|
-
input={InputSchema}
|
|
425
|
-
output={OutputSchema}
|
|
426
|
-
loopConfig={{
|
|
427
|
-
maxToolRounds: 15, // Max tool execution rounds
|
|
428
|
-
timeout: 180000 // 3 minute timeout
|
|
429
|
-
}}
|
|
430
|
-
>
|
|
431
|
-
{/* ... */}
|
|
432
|
-
</Agent>
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Dynamic Prompts
|
|
436
|
-
|
|
437
|
-
Load prompts from files or construct dynamically:
|
|
438
|
-
|
|
439
|
-
```tsx
|
|
440
|
-
<System>
|
|
441
|
-
{async (ctx: any): Promise<string> => {
|
|
442
|
-
// Load from file
|
|
443
|
-
const template = await fs.readFile('./prompts/system.md', 'utf-8');
|
|
444
|
-
|
|
445
|
-
// Inject dynamic content
|
|
446
|
-
return template.replace('{{language}}', ctx.inputs.language);
|
|
447
|
-
}}
|
|
448
|
-
</System>
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
## 🎨 Component Composition
|
|
452
|
-
|
|
453
|
-
Agents can be composed from reusable functions:
|
|
454
|
-
|
|
455
|
-
```typescript
|
|
456
|
-
// Reusable prompt builders
|
|
457
|
-
function buildSystemPrompt(role: string) {
|
|
458
|
-
return async (): Promise<string> => {
|
|
459
|
-
return `You are a ${role}.`;
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function buildUserPrompt(template: string) {
|
|
464
|
-
return (ctx: any): string => {
|
|
465
|
-
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => ctx.inputs[key]);
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// Reusable result extractors
|
|
470
|
-
function extractJSONFromToolCall(toolName: string) {
|
|
471
|
-
return (ctx: any, llmResult: any) => {
|
|
472
|
-
const toolCall = llmResult.response.toolCalls?.find(
|
|
473
|
-
(tc: any) => tc.name === toolName
|
|
474
|
-
);
|
|
475
|
-
return JSON.parse(toolCall.arguments);
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Compose agent
|
|
480
|
-
const agent = (
|
|
481
|
-
<Agent id="composer" input={InputSchema} output={OutputSchema}>
|
|
482
|
-
<Prompt>
|
|
483
|
-
<System>{buildSystemPrompt('expert')}</System>
|
|
484
|
-
<User>{buildUserPrompt('Process {{task}}')}</User>
|
|
485
|
-
</Prompt>
|
|
486
|
-
<Result>{extractJSONFromToolCall('submit')}</Result>
|
|
487
|
-
</Agent>
|
|
488
|
-
);
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
## 📚 Utilities
|
|
492
|
-
|
|
493
|
-
### Tool Result Extraction
|
|
494
|
-
|
|
495
|
-
```typescript
|
|
496
|
-
import { extractLastToolResult, extractAllToolResults, countToolCalls } from '@limo-labs/deity';
|
|
497
|
-
|
|
498
|
-
// Extract single tool result
|
|
499
|
-
const result = extractLastToolResult(llmResult, 'tool_name', {
|
|
500
|
-
unwrap: true,
|
|
501
|
-
required: true
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
// Extract all results from a tool
|
|
505
|
-
const allResults = extractAllToolResults(llmResult, 'memory_store');
|
|
506
|
-
|
|
507
|
-
// Count tool calls
|
|
508
|
-
const count = countToolCalls(llmResult, 'memory_store', (result) => {
|
|
509
|
-
return result?.success === true;
|
|
510
|
-
});
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
### Memory Tools
|
|
514
|
-
|
|
515
|
-
```typescript
|
|
516
|
-
import { createMemoryTools } from '@limo-labs/deity';
|
|
517
|
-
|
|
518
|
-
const agent = (
|
|
519
|
-
<Agent
|
|
520
|
-
id="agent"
|
|
521
|
-
input={InputSchema}
|
|
522
|
-
output={OutputSchema}
|
|
523
|
-
tools={createMemoryTools()}
|
|
524
|
-
>
|
|
525
|
-
{/* Agent can now use memory_store, memory_recall, etc. */}
|
|
526
|
-
</Agent>
|
|
527
|
-
);
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
## 🏗️ Architecture
|
|
531
|
-
|
|
532
|
-
```
|
|
533
|
-
┌─────────────────────────────────────────┐
|
|
534
|
-
│ JSX/TSX Components │
|
|
535
|
-
│ <Agent>, <Prompt>, <Result>, etc. │
|
|
536
|
-
└─────────────────────────────────────────┘
|
|
537
|
-
↓ compileAgent()
|
|
538
|
-
┌─────────────────────────────────────────┐
|
|
539
|
-
│ AST Nodes │
|
|
540
|
-
│ AgentNode, PromptNode, ResultNode │
|
|
541
|
-
└─────────────────────────────────────────┘
|
|
542
|
-
↓ executeComponent()
|
|
543
|
-
┌─────────────────────────────────────────┐
|
|
544
|
-
│ Execution Engine │
|
|
545
|
-
│ - Build Prompt │
|
|
546
|
-
│ - Call LLM Loop │
|
|
547
|
-
│ - Extract Output │
|
|
548
|
-
│ - Validate │
|
|
549
|
-
│ - Retry if needed │
|
|
550
|
-
└─────────────────────────────────────────┘
|
|
551
|
-
```
|
|
552
|
-
|
|
553
|
-
## 🧪 Testing
|
|
554
|
-
|
|
555
|
-
Deity includes utilities for testing agents:
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
import { testFullAgent } from '@limo-labs/deity';
|
|
559
|
-
|
|
560
|
-
const result = await testFullAgent(agent, {
|
|
561
|
-
inputs: { task: 'test' },
|
|
562
|
-
mockLLMResponse: {
|
|
563
|
-
content: '{"result": "success"}',
|
|
564
|
-
toolCalls: []
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
expect(result.output).toEqual({ result: 'success' });
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
## 📖 Documentation
|
|
572
|
-
|
|
573
|
-
- [API Reference](./docs/API.md) - Full API documentation
|
|
574
|
-
- [**Declarative Workflow Guide**](./docs/TSX_WORKFLOW.md) - **NEW: Build workflows with declarative API**
|
|
575
|
-
- [Workflow Quick Reference](./docs/TSX_WORKFLOW_QUICK_REF.md) - Quick syntax reference
|
|
576
|
-
- [Migration Guide](./docs/MIGRATION.md) - Migrating from imperative API
|
|
577
|
-
- [Best Practices](./docs/BEST_PRACTICES.md) - Design patterns and tips
|
|
578
|
-
- [Examples](./docs/EXAMPLES.md) - Real-world examples
|
|
579
|
-
|
|
580
|
-
## 🔀 Declarative Workflows (NEW in 4.0)
|
|
581
|
-
|
|
582
|
-
Deity 4.0 introduces **Declarative Workflow API** - build complex multi-agent workflows with function composition:
|
|
583
|
-
|
|
584
|
-
**Note:** Despite the name "TSX Workflow", these use **function calls** (`.ts` files), not JSX tags. Only Agent definitions support true JSX/TSX syntax.
|
|
585
|
-
|
|
586
|
-
```typescript
|
|
587
|
-
import { Workflow, Sequence, Parallel, Conditional, runTSXWorkflow } from '@limo-labs/deity';
|
|
588
|
-
|
|
589
|
-
const workflow = Workflow({
|
|
590
|
-
name: 'code-analysis',
|
|
591
|
-
defaultModel: { adapter: llmAdapter },
|
|
592
|
-
children: Sequence({
|
|
593
|
-
children: [
|
|
594
|
-
// Step 1: Classify code
|
|
595
|
-
ClassifierAgent,
|
|
596
|
-
|
|
597
|
-
// Step 2: Branch based on complexity
|
|
598
|
-
Conditional({
|
|
599
|
-
condition: (ctx) => ctx.getOutput('classifier').isComplex,
|
|
600
|
-
children: [
|
|
601
|
-
// Complex: parallel deep analysis
|
|
602
|
-
Parallel({
|
|
603
|
-
children: [
|
|
604
|
-
SecurityAnalyzer,
|
|
605
|
-
PerformanceAnalyzer,
|
|
606
|
-
QualityAnalyzer,
|
|
607
|
-
],
|
|
608
|
-
}),
|
|
609
|
-
// Simple: quick summary
|
|
610
|
-
QuickSummary,
|
|
611
|
-
],
|
|
612
|
-
}),
|
|
613
|
-
|
|
614
|
-
// Step 3: Generate report
|
|
615
|
-
ReportGenerator,
|
|
616
|
-
],
|
|
617
|
-
}),
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
// Execute
|
|
621
|
-
const result = await runTSXWorkflow(workflow, { code: '...' });
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
### Workflow Components
|
|
625
|
-
|
|
626
|
-
- **`Sequence`** - Execute children in order (function call)
|
|
627
|
-
- **`Parallel`** - Execute children concurrently (function call)
|
|
628
|
-
- **`Conditional`** - Branch based on condition (function call)
|
|
629
|
-
- **`Loop`** - Execute child N times (function call)
|
|
630
|
-
- **`ForEach`** - Execute child for each item in array (function call)
|
|
631
|
-
|
|
632
|
-
**[➡️ Full TSX Workflow Guide](./docs/TSX_WORKFLOW.md)**
|
|
633
|
-
|
|
634
|
-
## 🔗 Integration
|
|
635
|
-
|
|
636
|
-
### LLM Adapters
|
|
637
|
-
|
|
638
|
-
Deity works with any LLM adapter that implements the `LLMAdapter` interface:
|
|
639
|
-
|
|
640
|
-
```typescript
|
|
641
|
-
interface LLMAdapter {
|
|
642
|
-
generate(
|
|
643
|
-
messages: Message[],
|
|
644
|
-
tools?: Tool[],
|
|
645
|
-
config?: GenerationConfig,
|
|
646
|
-
ctx?: ExecutionContext
|
|
647
|
-
): Promise<LLMResponse>;
|
|
648
|
-
}
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
Example adapters:
|
|
652
|
-
- `@limo-labs/deity-adapter-openai` - OpenAI GPT models
|
|
653
|
-
- `@limo-labs/deity-adapter-anthropic` - Claude models
|
|
654
|
-
- `@limo-labs/deity-adapter-copilot` - GitHub Copilot SDK
|
|
655
|
-
|
|
656
|
-
### Framework Integration
|
|
657
|
-
|
|
658
|
-
- **Express/Fastify** - Use as API handlers
|
|
659
|
-
- **Next.js** - Server actions and API routes
|
|
660
|
-
- **Electron** - Desktop app agents
|
|
661
|
-
- **CLI Tools** - Command-line AI agents
|
|
662
|
-
|
|
663
|
-
## 🤝 Contributing
|
|
664
|
-
|
|
665
|
-
Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
666
|
-
|
|
667
|
-
## 📄 License
|
|
668
|
-
|
|
669
|
-
MIT © [Limo Labs](https://github.com/limo-labs)
|
|
670
|
-
|
|
671
|
-
## 🔗 Links
|
|
672
|
-
|
|
673
|
-
- [GitHub](https://github.com/Limo-Labs/Limo-Deity)
|
|
674
|
-
- [npm](https://www.npmjs.com/package/@limo-labs/deity)
|
|
675
|
-
- [Documentation](https://deity.limo.run)
|
|
676
|
-
- [Issues](https://github.com/Limo-Labs/Limo-Deity/issues)
|
|
677
|
-
- [Changelog](./CHANGELOG.md)
|
|
678
|
-
|
|
679
|
-
---
|
|
680
|
-
|
|
681
|
-
**Built with ❤️ by Limo Labs**
|