@ugm/desiagent 0.1.37 → 0.2.1

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.
Files changed (115) hide show
  1. package/README.md +298 -156
  2. package/dist/core/execution/agents.d.ts.map +1 -1
  3. package/dist/core/execution/agents.js +18 -4
  4. package/dist/core/execution/agents.js.map +1 -1
  5. package/dist/core/execution/dagExecutor.d.ts +15 -2
  6. package/dist/core/execution/dagExecutor.d.ts.map +1 -1
  7. package/dist/core/execution/dagExecutor.js +164 -30
  8. package/dist/core/execution/dagExecutor.js.map +1 -1
  9. package/dist/core/execution/dags.d.ts +19 -1
  10. package/dist/core/execution/dags.d.ts.map +1 -1
  11. package/dist/core/execution/dags.js +171 -92
  12. package/dist/core/execution/dags.js.map +1 -1
  13. package/dist/core/execution/inference.d.ts +20 -16
  14. package/dist/core/execution/inference.d.ts.map +1 -1
  15. package/dist/core/execution/inference.js +2 -1
  16. package/dist/core/execution/inference.js.map +1 -1
  17. package/dist/core/providers/factory.d.ts +1 -0
  18. package/dist/core/providers/factory.d.ts.map +1 -1
  19. package/dist/core/providers/factory.js +5 -4
  20. package/dist/core/providers/factory.js.map +1 -1
  21. package/dist/core/providers/openrouter.d.ts +9 -2
  22. package/dist/core/providers/openrouter.d.ts.map +1 -1
  23. package/dist/core/providers/openrouter.js +66 -9
  24. package/dist/core/providers/openrouter.js.map +1 -1
  25. package/dist/core/providers/types.d.ts +9 -0
  26. package/dist/core/providers/types.d.ts.map +1 -1
  27. package/dist/core/skills/detector.d.ts +8 -0
  28. package/dist/core/skills/detector.d.ts.map +1 -0
  29. package/dist/core/skills/detector.js +60 -0
  30. package/dist/core/skills/detector.js.map +1 -0
  31. package/dist/core/skills/registry.d.ts +44 -0
  32. package/dist/core/skills/registry.d.ts.map +1 -0
  33. package/dist/core/skills/registry.js +149 -0
  34. package/dist/core/skills/registry.js.map +1 -0
  35. package/dist/core/tools/base.d.ts +14 -1
  36. package/dist/core/tools/base.d.ts.map +1 -1
  37. package/dist/core/tools/base.js.map +1 -1
  38. package/dist/core/tools/bash.js +1 -1
  39. package/dist/core/tools/bash.js.map +1 -1
  40. package/dist/core/tools/edit.js +1 -1
  41. package/dist/core/tools/edit.js.map +1 -1
  42. package/dist/core/tools/executor.d.ts +4 -1
  43. package/dist/core/tools/executor.d.ts.map +1 -1
  44. package/dist/core/tools/executor.js +8 -2
  45. package/dist/core/tools/executor.js.map +1 -1
  46. package/dist/core/tools/fetchPage.d.ts +1 -1
  47. package/dist/core/tools/fetchPage.d.ts.map +1 -1
  48. package/dist/core/tools/fetchPage.js +20 -4
  49. package/dist/core/tools/fetchPage.js.map +1 -1
  50. package/dist/core/tools/glob.js +1 -1
  51. package/dist/core/tools/glob.js.map +1 -1
  52. package/dist/core/tools/grep.js +1 -1
  53. package/dist/core/tools/grep.js.map +1 -1
  54. package/dist/core/tools/llmExecute.d.ts +41 -32
  55. package/dist/core/tools/llmExecute.d.ts.map +1 -1
  56. package/dist/core/tools/llmExecute.js +13 -0
  57. package/dist/core/tools/llmExecute.js.map +1 -1
  58. package/dist/core/tools/readEmail.d.ts +1 -1
  59. package/dist/core/tools/readEmail.d.ts.map +1 -1
  60. package/dist/core/tools/readEmail.js +6 -9
  61. package/dist/core/tools/readEmail.js.map +1 -1
  62. package/dist/core/tools/readFile.js +1 -1
  63. package/dist/core/tools/readFile.js.map +1 -1
  64. package/dist/core/tools/sendEmail.d.ts +7 -7
  65. package/dist/core/tools/sendEmail.d.ts.map +1 -1
  66. package/dist/core/tools/sendEmail.js +12 -17
  67. package/dist/core/tools/sendEmail.js.map +1 -1
  68. package/dist/core/tools/writeFile.d.ts +1 -1
  69. package/dist/core/tools/writeFile.js +1 -1
  70. package/dist/core/tools/writeFile.js.map +1 -1
  71. package/dist/core/workers/statsQueue.d.ts +69 -0
  72. package/dist/core/workers/statsQueue.d.ts.map +1 -0
  73. package/dist/core/workers/statsQueue.js +106 -0
  74. package/dist/core/workers/statsQueue.js.map +1 -0
  75. package/dist/core/workers/statsWorker.d.ts +11 -0
  76. package/dist/core/workers/statsWorker.d.ts.map +1 -0
  77. package/dist/core/workers/statsWorker.js +235 -0
  78. package/dist/core/workers/statsWorker.js.map +1 -0
  79. package/dist/db/client.d.ts +1 -1
  80. package/dist/db/client.d.ts.map +1 -1
  81. package/dist/db/client.js +21 -86
  82. package/dist/db/client.js.map +1 -1
  83. package/dist/index.d.ts +6 -3
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +71 -33
  86. package/dist/index.js.map +1 -1
  87. package/dist/services/agentsSeedData.d.ts.map +1 -1
  88. package/dist/services/agentsSeedData.js +14 -0
  89. package/dist/services/agentsSeedData.js.map +1 -1
  90. package/dist/services/initDB.d.ts +6 -0
  91. package/dist/services/initDB.d.ts.map +1 -1
  92. package/dist/services/initDB.js +2 -2
  93. package/dist/services/initDB.js.map +1 -1
  94. package/dist/test/setup.d.ts +1 -0
  95. package/dist/test/setup.d.ts.map +1 -0
  96. package/dist/test/setup.js +3 -0
  97. package/dist/test/setup.js.map +1 -0
  98. package/dist/types/client.d.ts +1 -0
  99. package/dist/types/client.d.ts.map +1 -1
  100. package/dist/types/config.d.ts +40 -7
  101. package/dist/types/config.d.ts.map +1 -1
  102. package/dist/types/config.js +69 -7
  103. package/dist/types/config.js.map +1 -1
  104. package/dist/types/dag.d.ts +44 -44
  105. package/dist/types/dag.js +7 -7
  106. package/dist/types/dag.js.map +1 -1
  107. package/dist/util/logger.d.ts +1 -8
  108. package/dist/util/logger.d.ts.map +1 -1
  109. package/dist/util/logger.js +11 -60
  110. package/dist/util/logger.js.map +1 -1
  111. package/dist/util/sendEmailTool.d.ts +7 -7
  112. package/dist/util/sendEmailTool.d.ts.map +1 -1
  113. package/dist/util/sendEmailTool.js +8 -0
  114. package/dist/util/sendEmailTool.js.map +1 -1
  115. package/package.json +2 -1
package/README.md CHANGED
@@ -1,278 +1,420 @@
1
1
  # desiAgent
2
2
 
3
- A library-first async agent system for building autonomous workflows with TypeScript.
3
+ A library-first async agent system for building autonomous workflows with TypeScript. Give it a goal in plain English and it decomposes it into a DAG of tasks, executes them with built-in tools, and streams results back — all in a few lines of code.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Multiple LLM Providers**: OpenAI, OpenRouter, and Ollama support
8
- - **Autonomous Execution**: Let agents execute objectives autonomously
9
- - **DAG Workflows**: Decompose complex objectives into directed acyclic graphs
10
- - **Built-in Tools**: Web scraping, file operations, bash commands, and more
11
- - **Event Streaming**: Track execution progress in real-time
12
- - **SQLite Storage**: Persistent storage using bun:sqlite
7
+ - **Goal DAG Execution** — Describe what you want; desiAgent plans a directed acyclic graph (DAG) of sub-tasks and executes them autonomously.
8
+ - **Multiple LLM Providers** OpenAI, OpenRouter, and Ollama (local) out of the box.
9
+ - **Built-in Tools** Web scraping, file I/O, bash commands, email (SMTP/IMAP), PDF parsing, and more.
10
+ - **Event Streaming** `for await` over execution events to track progress in real-time.
11
+ - **Clarification Flow** If the goal is ambiguous the agent asks for clarification before proceeding.
12
+ - **In-Memory or Persistent Storage** Use `:memory:` for quick experiments or a SQLite file for production.
13
+ - **Cron Scheduling** — Schedule DAGs to run on a cron expression with timezone support.
14
+ - **Artifacts** — Tools can write output files (reports, code, images) that are automatically stored and retrievable.
15
+ - **Cost Tracking** — Token usage and USD cost are recorded per execution step.
16
+ - **Skills** — Drop a `SKILL.md` file into your workspace or global config and the agent discovers it automatically. Skills can be injected as context into LLM prompts or executed as sub-tasks in a DAG.
17
+ - **Experiments API** — Compare models and temperatures on the same goal in one call.
13
18
 
14
19
  ## Installation
15
20
 
16
21
  ### Prerequisites
17
22
 
18
- - [Bun](https://bun.sh) 1.3.5 or higher
23
+ - [Bun](https://bun.sh) 1.3.5
19
24
 
20
25
  ### Install
21
26
 
22
27
  ```bash
23
- bun add desiagent
28
+ bun add @ugm/desiagent
24
29
  ```
25
30
 
26
- Or with npm/pnpm:
31
+ Or with npm / pnpm:
27
32
 
28
33
  ```bash
29
- npm install desiagent
34
+ npm install @ugm/desiagent
30
35
  # or
31
- pnpm add desiagent
36
+ pnpm add @ugm/desiagent
32
37
  ```
33
38
 
34
- ## Environment Variables
39
+ ### Environment Variables
35
40
 
36
- Create a `.env` file in your project root with the appropriate API keys for your chosen provider:
37
-
38
- ### OpenAI
41
+ Create a `.env` file with your provider's API key:
39
42
 
40
43
  ```bash
41
- OPENAI_API_KEY=sk-...
42
- ```
44
+ # OpenRouter (recommended — access to many models via one key)
45
+ OPENROUTER_API_KEY=sk-or-...
43
46
 
44
- ### OpenRouter
47
+ # OpenAI
48
+ OPENAI_API_KEY=sk-...
45
49
 
46
- ```bash
47
- OPENROUTER_API_KEY=sk-or-...
50
+ # Ollama (local, no key needed)
51
+ OLLAMA_BASE_URL=http://localhost:11434 # optional, this is the default
48
52
  ```
49
53
 
50
- ### Ollama (Local)
54
+ ## Examples
51
55
 
52
- ```bash
53
- OLLAMA_BASE_URL=http://localhost:11434 # Optional, this is the default
54
- ```
56
+ > All examples below use OpenRouter and an in-memory database (`:memory:`) so you can run them without any local SQLite file.
55
57
 
56
- ## Quick Start
58
+ ### 1. Goal → Execute in One Call
57
59
 
58
- ### Basic Example (OpenAI)
60
+ The fastest way to go from idea to result. `createAndExecuteFromGoal` plans the DAG **and** executes it in a single call.
59
61
 
60
62
  ```typescript
61
- import { setupDesiAgent } from 'desiagent';
63
+ import { setupDesiAgent } from '@ugm/desiagent';
62
64
 
63
65
  const client = await setupDesiAgent({
64
- llmProvider: 'openai',
65
- openaiApiKey: process.env.OPENAI_API_KEY,
66
- modelName: 'gpt-4o',
66
+ llmProvider: 'openrouter',
67
+ openrouterApiKey: process.env.OPENROUTER_API_KEY,
68
+ modelName: 'google/gemini-2.5-flash-lite-preview-09-2025',
69
+ databasePath: ':memory:',
70
+ skipGenerationStats: true,
67
71
  });
68
72
 
69
- // Create and execute a DAG
70
- const execution = await client.dags.createAndExecute('Summarize the latest tech news');
71
- console.log(`Execution: ${execution.id}, Status: ${execution.status}`);
73
+ const result = await client.dags.createAndExecuteFromGoal({
74
+ goalText: 'Research the top 5 trends in AI agents for 2025 and write a concise briefing document to ai-trends.md',
75
+ agentName: 'DecomposerV9',
76
+ temperature: 0.7,
77
+ });
78
+
79
+ if (result.status === 'clarification_required') {
80
+ console.log('Agent needs more info:', result.clarificationQuery);
81
+ } else {
82
+ console.log('Execution started:', result.executionId);
83
+
84
+ // Stream events until completion
85
+ for await (const event of client.executions.streamEvents(result.executionId)) {
86
+ console.log(event.type, event.data);
87
+ }
88
+
89
+ // Retrieve final result
90
+ const details = await client.executions.getWithSubSteps(result.executionId);
91
+ console.log('Final result:\n', details.finalResult);
92
+ }
72
93
 
73
94
  await client.shutdown();
74
95
  ```
75
96
 
76
- ### Using OpenRouter
97
+ ### 2. Plan First, Execute Later
98
+
99
+ Separate planning from execution so you can inspect or modify the DAG before running it.
77
100
 
78
101
  ```typescript
79
- import { setupDesiAgent } from 'desiagent';
102
+ import { setupDesiAgent } from '@ugm/desiagent';
80
103
 
81
104
  const client = await setupDesiAgent({
82
105
  llmProvider: 'openrouter',
83
106
  openrouterApiKey: process.env.OPENROUTER_API_KEY,
84
- modelName: 'google/gemini-2.5-flash-lite-preview-06-2025',
107
+ modelName: 'google/gemini-2.5-flash-lite-preview-09-2025',
108
+ databasePath: ':memory:',
109
+ skipGenerationStats: true,
85
110
  });
86
111
 
87
- const execution = await client.dags.createAndExecute('Research best practices for API design');
112
+ // Step 1 Plan
113
+ const plan = await client.dags.createFromGoal({
114
+ goalText: 'Create a tutorial on processing driftwood into handicrafts — cover cleaning, tools, finishes — and write it to driftwood.md',
115
+ agentName: 'DecomposerV9',
116
+ temperature: 0.7,
117
+ });
118
+
119
+ if (plan.status !== 'success') {
120
+ console.log('Planning issue:', plan.status);
121
+ await client.shutdown();
122
+ process.exit(1);
123
+ }
124
+
125
+ console.log('DAG created:', plan.dagId);
126
+
127
+ // Step 2 — Execute
128
+ const execution = await client.dags.execute(plan.dagId);
129
+ console.log('Execution ID:', execution.id);
130
+
131
+ for await (const event of client.executions.streamEvents(execution.id)) {
132
+ console.log(event.type, event.data);
133
+ }
134
+
135
+ const details = await client.executions.getWithSubSteps(execution.id);
136
+ console.log('Final result:\n', details.finalResult);
137
+
88
138
  await client.shutdown();
89
139
  ```
90
140
 
91
- ### Using Ollama (Local LLM)
141
+ ### 3. List Agents and Tools
142
+
143
+ Explore what's available in the system.
92
144
 
93
145
  ```typescript
94
- import { setupDesiAgent } from 'desiagent';
146
+ import { setupDesiAgent } from '@ugm/desiagent';
95
147
 
96
148
  const client = await setupDesiAgent({
97
- llmProvider: 'ollama',
98
- ollamaBaseUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434',
99
- modelName: 'llama3.2',
149
+ llmProvider: 'openrouter',
150
+ openrouterApiKey: process.env.OPENROUTER_API_KEY,
151
+ modelName: 'openai/gpt-4o',
152
+ databasePath: ':memory:',
153
+ skipGenerationStats: true,
154
+ logLevel: 'warn',
100
155
  });
101
156
 
102
- const execution = await client.dags.createAndExecute('Explain quantum computing in simple terms');
157
+ // List seeded agents
158
+ const agents = await client.agents.list();
159
+ for (const a of agents) {
160
+ console.log(`${a.name} (${a.provider}/${a.model}) — ${a.description}`);
161
+ }
162
+
163
+ // List available tools
164
+ const tools = await client.tools.list();
165
+ for (const t of tools) {
166
+ console.log(t.function.name);
167
+ }
168
+
103
169
  await client.shutdown();
104
170
  ```
105
171
 
106
- ## Configuration Options
172
+ ### 4. Handle Clarifications
107
173
 
108
- ```typescript
109
- interface DesiAgentConfig {
110
- // LLM Provider (required)
111
- llmProvider: 'openai' | 'openrouter' | 'ollama';
112
- modelName: string;
174
+ When the agent decides the goal is ambiguous, it returns a clarification query instead of creating a DAG.
113
175
 
114
- // Provider-specific API keys
115
- openaiApiKey?: string; // Required for 'openai' provider
116
- openrouterApiKey?: string; // Required for 'openrouter' provider
117
- ollamaBaseUrl?: string; // Optional for 'ollama', defaults to http://localhost:11434
176
+ ```typescript
177
+ import { setupDesiAgent } from '@ugm/desiagent';
118
178
 
119
- // Database (optional)
120
- databasePath?: string; // Default: ~/.desiAgent/data/agent.db
179
+ const client = await setupDesiAgent({
180
+ llmProvider: 'openrouter',
181
+ openrouterApiKey: process.env.OPENROUTER_API_KEY,
182
+ modelName: 'google/gemini-2.5-flash-lite-preview-09-2025',
183
+ databasePath: ':memory:',
184
+ skipGenerationStats: true,
185
+ });
121
186
 
122
- // Agent definitions (optional)
123
- agentDefinitionsPath?: string; // Default: ~/.desiAgent/agents
187
+ const plan = await client.dags.createFromGoal({
188
+ goalText: 'Build the app',
189
+ agentName: 'DecomposerV9',
190
+ });
124
191
 
125
- // Logging (optional)
126
- logLevel?: 'debug' | 'info' | 'warn' | 'error'; // Default: 'info'
192
+ if (plan.status === 'clarification_required') {
193
+ console.log('Agent asks:', plan.clarificationQuery);
127
194
 
128
- // Callbacks (optional)
129
- onExecutionStart?: (executionId: string) => void;
130
- onExecutionEnd?: (executionId: string, result: any) => void;
195
+ // Provide the answer and retry
196
+ const resumed = await client.dags.resumeFromClarification(
197
+ plan.dagId,
198
+ 'A Pomodoro timer web app using HTML, CSS, and vanilla JS',
199
+ );
200
+ console.log('Resumed status:', resumed.status);
131
201
  }
202
+
203
+ await client.shutdown();
132
204
  ```
133
205
 
134
- ## API Reference
206
+ ### 5. Custom Inference (No DAG)
135
207
 
136
- ### Agents
208
+ Use a named agent directly for a single LLM call — useful for summarisation, translation, or any one-shot task.
137
209
 
138
210
  ```typescript
139
- // Create a new agent
140
- const agent = await client.agents.create(name, version, prompt, params?);
211
+ import { setupDesiAgent } from '@ugm/desiagent';
141
212
 
142
- // List all agents
143
- const agents = await client.agents.list(filter?);
213
+ const client = await setupDesiAgent({
214
+ llmProvider: 'openrouter',
215
+ openrouterApiKey: process.env.OPENROUTER_API_KEY,
216
+ modelName: 'openai/gpt-4o',
217
+ databasePath: ':memory:',
218
+ skipGenerationStats: true,
219
+ });
220
+
221
+ // Resolve an agent by name and call it directly
222
+ const agent = await client.agents.resolve('Summarizer');
223
+ // ... or use the lower-level inference API in scripts/infer.ts
224
+
225
+ await client.shutdown();
226
+ ```
227
+
228
+ ### Running the Bundled Examples
144
229
 
145
- // Get a specific agent
146
- const agent = await client.agents.get(id);
230
+ The [`examples/`](./examples/) directory contains runnable scripts:
147
231
 
148
- // Update an agent
149
- await client.agents.update(id, updates);
232
+ ```bash
233
+ # Execute a goal from a file
234
+ bun run examples/execute-goal.ts -f examples/goals/pomodoro-timer.txt
235
+
236
+ # In-memory database smoke test
237
+ bun run examples/init_6_memory_db.ts
150
238
 
151
- // Activate/Delete an agent
152
- await client.agents.activate(id);
153
- await client.agents.delete(id);
239
+ # List all agents
240
+ bun run examples/list-agents.ts
154
241
 
155
- // Resolve agent by name
156
- const agent = await client.agents.resolve(name);
242
+ # List all tools
243
+ bun run examples/list-tools.ts --names
157
244
  ```
158
245
 
159
- ### DAGs (Directed Acyclic Graphs)
246
+ ## Skills
160
247
 
161
- ```typescript
162
- // Create a DAG from an objective
163
- const dag = await client.dags.create(objective, params?);
248
+ Skills are reusable instruction files (`SKILL.md`) that extend what the agent can do. Each skill is a Markdown file with YAML frontmatter describing its name, description, and type. When a goal is submitted, desiAgent automatically discovers skills, detects which ones are relevant, and either injects their content into the LLM prompt or executes them as sub-tasks inside a DAG.
164
249
 
165
- // Create and immediately execute
166
- const execution = await client.dags.createAndExecute(objective, params?);
250
+ ### Skill Types
167
251
 
168
- // Execute an existing DAG
169
- const execution = await client.dags.execute(dagId, params?);
252
+ | Type | Behaviour |
253
+ |---|---|
254
+ | `context` | The skill's Markdown body is loaded and injected as instructions into an LLM inference call during DAG execution. |
255
+ | `executable` | A sibling `handler.ts` file is imported and its default export is called with the task parameters. |
170
256
 
171
- // List DAGs
172
- const dags = await client.dags.list(filter?);
173
- const scheduled = await client.dags.listScheduled();
257
+ ### SKILL.md Format
174
258
 
175
- // Get/Update/Delete
176
- const dag = await client.dags.get(id);
177
- await client.dags.update(id, updates);
178
- await client.dags.delete(id);
259
+ ```markdown
260
+ ---
261
+ name: my-skill
262
+ description: A short sentence describing what this skill does (min 10 chars).
263
+ type: context # or "executable"
264
+ model: openai/gpt-4o # optional — override model for this skill
265
+ provider: openrouter # optional — override provider
266
+ ---
179
267
 
180
- // Resume a paused execution
181
- await client.dags.resume(executionId);
268
+ Your skill instructions in Markdown go here.
269
+ The agent receives this content when the skill is used.
182
270
  ```
183
271
 
184
- ### Executions
272
+ > The `name` field **must** match the enclosing directory name (e.g., `my-skill/SKILL.md` must have `name: my-skill`).
185
273
 
186
- ```typescript
187
- // List executions
188
- const executions = await client.executions.list(filter?);
274
+ ### Discovery
189
275
 
190
- // Get execution details
191
- const execution = await client.executions.get(id);
192
- const subSteps = await client.executions.getSubSteps(id);
276
+ On startup, `SkillRegistry.discover()` scans the following locations **in order**. The first skill registered for a given name wins — later duplicates are silently skipped.
193
277
 
194
- // Delete an execution
195
- await client.executions.delete(id);
278
+ | Priority | Location | Scope |
279
+ |---|---|---|
280
+ | 1 | `<workspace>/.agents/skills/<name>/SKILL.md` | Local (workspace) |
281
+ | 2 | `<workspace>/skills/<name>/SKILL.md` | Local (workspace) |
282
+ | 3 | `<workspace>/SKILL.md` | Local (workspace root) |
283
+ | 4 | `~/.config/agents/skills/<name>/SKILL.md` | Global |
284
+ | 5 | `~/.desiAgent/skills/<name>/SKILL.md` | Global |
196
285
 
197
- // Stream execution events (AsyncIterable)
198
- for await (const event of client.executions.streamEvents(id)) {
199
- console.log(event.type, event.data);
286
+ **Local wins over global.** If a workspace defines a skill named `summarizer` in `.agents/skills/summarizer/SKILL.md` and a global skill with the same name exists in `~/.desiAgent/skills/summarizer/SKILL.md`, the workspace version is used.
287
+
288
+ ### How Skills Are Selected
289
+
290
+ When you submit a goal, a `MinimalSkillDetector` checks for:
291
+
292
+ 1. **Explicit triggers** — phrases like `use skill <name>` or `use <name> skill` in the goal text.
293
+ 2. **Keyword matching** — if no explicit trigger is found, skill descriptions are matched against keywords in the goal.
294
+
295
+ Matched skills are listed in the agent's system prompt so the LLM can plan DAG tasks with `action_type: 'skill'`.
296
+
297
+ ### Using Skills Programmatically
298
+
299
+ ```typescript
300
+ import { SkillRegistry } from '@ugm/desiagent';
301
+
302
+ const registry = new SkillRegistry(process.cwd());
303
+ await registry.discover();
304
+
305
+ // List all discovered skills
306
+ for (const skill of registry.getAll()) {
307
+ console.log(`${skill.name} (${skill.type}) — ${skill.description}`);
200
308
  }
309
+
310
+ // Load a skill's content
311
+ const content = await registry.loadContent('my-skill');
312
+ console.log(content);
201
313
  ```
202
314
 
203
- ## CLI
315
+ ## Configuration Reference
204
316
 
205
- The `desi` CLI ships with the standalone `desiCLI` package. Command groups support default subcommands for convenience:
317
+ ```typescript
318
+ interface DesiAgentConfig {
319
+ llmProvider: 'openai' | 'openrouter' | 'ollama';
320
+ modelName: string;
206
321
 
207
- ```bash
208
- # Artifacts
209
- desi artifacts # Same as: desi artifacts list
210
- desi artifacts report.json # Same as: desi artifacts get report.json
322
+ // Provider keys
323
+ openaiApiKey?: string;
324
+ openrouterApiKey?: string;
325
+ ollamaBaseUrl?: string; // default: http://localhost:11434
326
+
327
+ // Storage
328
+ databasePath?: string; // default: ~/.desiAgent/data/agent.db
329
+ // use ':memory:' for ephemeral experiments
330
+ artifactsDir?: string; // default: sibling of database file
211
331
 
212
- # Agents
213
- desi agents # Same as: desi agents list
332
+ // Agent definitions
333
+ agentDefinitionsPath?: string; // default: ~/.desiAgent/agents
214
334
 
215
- # Results
216
- desi results exec_123 # Same as: desi results view exec_123
335
+ // Logging
336
+ logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
337
+
338
+ // Lifecycle hooks
339
+ onExecutionStart?: (executionId: string) => void;
340
+ onExecutionEnd?: (executionId: string, result: Record<string, any>) => void;
341
+
342
+ // Workspace root for skill discovery
343
+ workspaceRoot?: string; // default: process.cwd()
344
+
345
+ // Feature flags
346
+ autoStartScheduler?: boolean; // default: true
347
+ enableToolValidation?: boolean; // default: true
348
+ skipGenerationStats?: boolean; // default: false
349
+ }
217
350
  ```
218
351
 
219
- ## Examples
352
+ ## Contributing
220
353
 
221
- ### News Bulletin Generator
354
+ We welcome contributions of all kinds — bug fixes, new tools, documentation improvements, and feature ideas.
222
355
 
223
- See [`examples/news-bulletin.ts`](./examples/news-bulletin.ts) for a complete example that creates a news bulletin with multiple categories.
356
+ ### Getting Started
224
357
 
225
- ```bash
226
- # Run with Ollama
227
- bun run examples/news-bulletin.ts
358
+ 1. **Fork & clone** the repository.
228
359
 
229
- # Run with OpenRouter
230
- OPENROUTER_API_KEY=your-key bun run examples/news-bulletin-openrouter.ts
231
- ```
360
+ ```bash
361
+ git clone https://github.com/<your-username>/desiAgent.git
362
+ cd desiAgent
363
+ ```
232
364
 
233
- ## Manual Abort Tests
365
+ 2. **Install dependencies** (requires Bun ≥ 1.3.5).
234
366
 
235
- Use these scripts to manually verify that abort signals cancel in-flight LLM calls.
367
+ ```bash
368
+ bun install
369
+ ```
236
370
 
237
- ```bash
238
- # OpenRouter abort test
239
- OPENROUTER_API_KEY=sk-or-... ABORT_AFTER_MS=2000 bun run test:abort:openrouter
371
+ 3. **Create a branch** for your change.
240
372
 
241
- # Ollama abort test
242
- OLLAMA_BASE_URL=http://localhost:11434 OLLAMA_MODEL=mistral ABORT_AFTER_MS=2000 bun run test:abort:ollama
243
- ```
373
+ ```bash
374
+ git checkout -b feat/my-awesome-feature
375
+ ```
244
376
 
245
- ## Development
377
+ 4. **Make your changes**, then verify:
246
378
 
247
- ### Setup
379
+ ```bash
380
+ bun run type-check # TypeScript must compile cleanly
381
+ bun test # All tests must pass
382
+ ```
248
383
 
249
- ```bash
250
- # Install dependencies
251
- pnpm install
384
+ ### Code Guidelines
385
+
386
+ - **TypeScript only** — no plain JS files.
387
+ - **Follow existing patterns** — look at neighbouring files before writing new code. Match naming conventions, imports, and error handling style.
388
+ - **Keep PRs focused** — one logical change per pull request. Small, reviewable diffs are merged faster.
389
+ - **Write tests** — if you add a feature or fix a bug, add or update a test in the corresponding `*.test.ts` file. Run `bun test` to verify.
390
+ - **No secrets** — never commit API keys, tokens, or credentials. Use environment variables and `.env` files (already in `.gitignore`).
252
391
 
253
- # Run in development mode
254
- bun run dev
392
+ ### Commit Messages
393
+
394
+ Follow the [Conventional Commits](https://www.conventionalcommits.org/) format:
395
+
396
+ ```
397
+ feat: add PDF attachment support to inference
398
+ fix: handle empty goal text in DAG creation
399
+ docs: update README examples
400
+ chore: bump drizzle-orm to 0.46
255
401
  ```
256
402
 
257
- ### Commands
403
+ ### Pull Request Process
258
404
 
259
- ```bash
260
- # Build
261
- pnpm build
405
+ 1. Ensure your branch is up to date with `main`.
406
+ 2. Open a PR against `main` with a clear title and description of **what** and **why**.
407
+ 3. Link any related issues (e.g., `Closes #42`).
408
+ 4. A maintainer will review your PR. Address feedback promptly — we aim to merge within a few days.
262
409
 
263
- # Type check
264
- pnpm type-check
410
+ ### Reporting Issues
265
411
 
266
- # Run tests
267
- pnpm test
268
- pnpm test:watch
269
- pnpm test:coverage
412
+ - Use [GitHub Issues](https://github.com/ugmurthy/desiAgent/issues) to report bugs or request features.
413
+ - Include steps to reproduce, expected vs. actual behaviour, and your environment (OS, Bun version, provider used).
270
414
 
271
- # Database commands
272
- pnpm db:generate
273
- pnpm db:push
274
- pnpm db:studio
275
- ```
415
+ ### Code of Conduct
416
+
417
+ Be respectful and constructive. We follow the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct.
276
418
 
277
419
  ## License
278
420
 
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/core/execution/agents.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAIlD;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAUD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,MAAM,CAAe;IAG7B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkC;IAC3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAU;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAM;gBAEhC,EAAE,EAAE,SAAS;IAIzB;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ3C;;OAEG;IACG,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,OAAO,CAAC,KAAK,CAAC;IA2CjB;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAYrC;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAmB1D;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IAoEjE;;OAEG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAiC1C;;;OAGG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IA+BlD;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBvC;;OAEG;IACH,OAAO,CAAC,QAAQ;CAgBjB"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/core/execution/agents.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAIlD;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAUD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,MAAM,CAAe;IAG7B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkC;IAC3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAU;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAM;gBAEhC,EAAE,EAAE,SAAS;IAIzB;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ3C;;OAEG;IACG,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,OAAO,CAAC,KAAK,CAAC;IA2CjB;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAYrC;;OAEG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAmB1D;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IAkFjE;;OAEG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAiC1C;;;OAGG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IA+BlD;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBvC;;OAEG;IACH,OAAO,CAAC,QAAQ;CAgBjB"}
@@ -133,11 +133,25 @@ export class AgentsService {
133
133
  if (updates.systemPrompt !== undefined) {
134
134
  updateData.promptTemplate = updates.systemPrompt;
135
135
  }
136
- if (updates.constraints?.maxTokens !== undefined) {
137
- updateData.model = updates.constraints.maxTokens;
136
+ if (updates.provider !== undefined) {
137
+ updateData.provider = updates.provider;
138
138
  }
139
- if (updates.metadata !== undefined) {
140
- updateData.metadata = updates.metadata;
139
+ if (updates.model !== undefined) {
140
+ updateData.model = updates.model;
141
+ }
142
+ // Build metadata: if metadata is explicitly provided, it replaces existing;
143
+ // description and constraints are merged on top of existing metadata
144
+ if (updates.metadata !== undefined || updates.description !== undefined || updates.constraints !== undefined) {
145
+ const currentMetadata = existing.metadata || {};
146
+ const baseMetadata = updates.metadata !== undefined ? updates.metadata : currentMetadata;
147
+ updateData.metadata = {
148
+ ...baseMetadata,
149
+ ...(updates.constraints !== undefined ? { constraints: updates.constraints } : {}),
150
+ ...(updates.description !== undefined ? { description: updates.description } : {}),
151
+ };
152
+ }
153
+ if (updates.isActive !== undefined) {
154
+ updateData.active = updates.isActive;
141
155
  }
142
156
  await this.db.update(agents).set(updateData).where(eq(agents.id, id));
143
157
  // Invalidate cache for this agent