illuma-agents 1.0.45 → 1.0.49

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 (34) hide show
  1. package/dist/cjs/deepagents/DeepAgentBackend.cjs +170 -0
  2. package/dist/cjs/deepagents/DeepAgentBackend.cjs.map +1 -0
  3. package/dist/cjs/deepagents/DeepAgentRuntime.cjs +135 -0
  4. package/dist/cjs/deepagents/DeepAgentRuntime.cjs.map +1 -0
  5. package/dist/cjs/deepagents/types.cjs +29 -0
  6. package/dist/cjs/deepagents/types.cjs.map +1 -0
  7. package/dist/cjs/main.cjs +17 -6
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/esm/deepagents/DeepAgentBackend.mjs +168 -0
  10. package/dist/esm/deepagents/DeepAgentBackend.mjs.map +1 -0
  11. package/dist/esm/deepagents/DeepAgentRuntime.mjs +132 -0
  12. package/dist/esm/deepagents/DeepAgentRuntime.mjs.map +1 -0
  13. package/dist/esm/deepagents/types.mjs +26 -0
  14. package/dist/esm/deepagents/types.mjs.map +1 -0
  15. package/dist/esm/main.mjs +4 -1
  16. package/dist/esm/main.mjs.map +1 -1
  17. package/dist/types/deepagents/DeepAgentBackend.d.ts +82 -0
  18. package/dist/types/deepagents/DeepAgentRuntime.d.ts +46 -0
  19. package/dist/types/deepagents/index.d.ts +16 -0
  20. package/dist/types/deepagents/types.d.ts +105 -0
  21. package/dist/types/index.d.ts +1 -1
  22. package/package.json +2 -1
  23. package/src/deepagents/DeepAgentBackend.ts +214 -0
  24. package/src/deepagents/DeepAgentRuntime.ts +187 -0
  25. package/src/deepagents/index.ts +25 -0
  26. package/src/deepagents/types.ts +118 -0
  27. package/src/index.ts +3 -1
  28. package/src/specs/deepagents.test.ts +286 -0
  29. package/dist/cjs/tools/DesktopTools.cjs +0 -363
  30. package/dist/cjs/tools/DesktopTools.cjs.map +0 -1
  31. package/dist/esm/tools/DesktopTools.mjs +0 -357
  32. package/dist/esm/tools/DesktopTools.mjs.map +0 -1
  33. package/dist/types/tools/DesktopTools.d.ts +0 -134
  34. package/src/tools/DesktopTools.ts +0 -574
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Deep Agent Backend
3
+ *
4
+ * A backend implementation that extends deepagents' FilesystemBackend
5
+ * with SSE streaming for real-time updates and integration with
6
+ * external code execution services.
7
+ */
8
+
9
+ import { FilesystemBackend } from 'deepagents';
10
+ import type { ExecuteResponse, SandboxBackendProtocol } from 'deepagents';
11
+ import type { DeepAgentTodo, DeepAgentSubagent } from './types';
12
+
13
+ /** SSE Response interface for streaming */
14
+ export interface SSEResponse {
15
+ write: (data: string) => void;
16
+ headersSent?: boolean;
17
+ }
18
+
19
+ /** Options for Deep Agent Backend */
20
+ export interface DeepAgentBackendOptions {
21
+ /** Root directory for file operations (default: process.cwd()) */
22
+ rootDir?: string;
23
+ /** Whether to use virtual paths (default: true) */
24
+ virtualMode?: boolean;
25
+ /** Timeout for command execution in ms (default: 120000) */
26
+ timeout?: number;
27
+ /** Max output size in bytes (default: 100000) */
28
+ maxOutputBytes?: number;
29
+ /** SSE response for streaming updates */
30
+ sseResponse?: SSEResponse;
31
+ /** Conversation ID for event tracking */
32
+ conversationId?: string;
33
+ /** Code executor API URL (optional - for sandboxed execution) */
34
+ codeExecutorUrl?: string;
35
+ /** Callback for todo changes */
36
+ onTodoUpdate?: (todos: DeepAgentTodo[]) => void;
37
+ /** Callback for subagent changes */
38
+ onSubagentUpdate?: (subagents: DeepAgentSubagent[]) => void;
39
+ }
40
+
41
+ /**
42
+ * Deep Agent Backend
43
+ *
44
+ * Extends FilesystemBackend with:
45
+ * - SSE streaming for real-time updates
46
+ * - Integration with external code executor services
47
+ * - Event emission for todos and subagents
48
+ */
49
+ export class DeepAgentBackend extends FilesystemBackend implements SandboxBackendProtocol {
50
+ readonly id: string;
51
+ private readonly timeout: number;
52
+ private readonly maxOutputBytes: number;
53
+ private readonly conversationId?: string;
54
+ private readonly sseResponse?: SSEResponse;
55
+ private readonly codeExecutorUrl?: string;
56
+ private readonly onTodoUpdate?: (todos: DeepAgentTodo[]) => void;
57
+ private readonly onSubagentUpdate?: (subagents: DeepAgentSubagent[]) => void;
58
+
59
+ constructor(options: DeepAgentBackendOptions = {}) {
60
+ super({
61
+ rootDir: options.rootDir ?? process.cwd(),
62
+ virtualMode: options.virtualMode ?? true,
63
+ maxFileSizeMb: 10,
64
+ });
65
+
66
+ this.id = `deep-agent-backend-${Date.now().toString(36)}`;
67
+ this.timeout = options.timeout ?? 120_000;
68
+ this.maxOutputBytes = options.maxOutputBytes ?? 100_000;
69
+ this.conversationId = options.conversationId;
70
+ this.sseResponse = options.sseResponse;
71
+ this.codeExecutorUrl = options.codeExecutorUrl;
72
+ this.onTodoUpdate = options.onTodoUpdate;
73
+ this.onSubagentUpdate = options.onSubagentUpdate;
74
+ }
75
+
76
+ /**
77
+ * Execute a command
78
+ *
79
+ * If codeExecutorUrl is configured, uses the external sandboxed executor.
80
+ * Otherwise, logs a warning (shell execution may not be available).
81
+ */
82
+ async execute(command: string): Promise<ExecuteResponse> {
83
+ if (!command || typeof command !== 'string') {
84
+ return {
85
+ output: 'Error: Command must be a non-empty string.',
86
+ exitCode: 1,
87
+ truncated: false,
88
+ };
89
+ }
90
+
91
+ // If we have a code executor URL, use that for sandboxed execution
92
+ if (this.codeExecutorUrl) {
93
+ return this.executeViaCodeExecutor(command);
94
+ }
95
+
96
+ // Log warning - direct shell execution may not be available
97
+ console.warn('[DeepAgentBackend] Shell execution requested but no code executor configured');
98
+ return {
99
+ output: 'Shell execution is not available in this environment. Consider using the code executor tool instead.',
100
+ exitCode: 1,
101
+ truncated: false,
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Execute command via external code executor service
107
+ */
108
+ private async executeViaCodeExecutor(command: string): Promise<ExecuteResponse> {
109
+ try {
110
+ const response = await fetch(`${this.codeExecutorUrl}/execute`, {
111
+ method: 'POST',
112
+ headers: { 'Content-Type': 'application/json' },
113
+ body: JSON.stringify({
114
+ code: command,
115
+ language: 'shell',
116
+ timeout: this.timeout,
117
+ }),
118
+ signal: AbortSignal.timeout(this.timeout + 5000),
119
+ });
120
+
121
+ if (!response.ok) {
122
+ return {
123
+ output: `Execution error: ${response.statusText}`,
124
+ exitCode: 1,
125
+ truncated: false,
126
+ };
127
+ }
128
+
129
+ const result = await response.json() as {
130
+ output?: string;
131
+ exitCode?: number;
132
+ error?: string;
133
+ };
134
+
135
+ let output = result.output ?? result.error ?? '';
136
+ let truncated = false;
137
+
138
+ if (output.length > this.maxOutputBytes) {
139
+ output = output.slice(0, this.maxOutputBytes) + '\n... (output truncated)';
140
+ truncated = true;
141
+ }
142
+
143
+ return {
144
+ output,
145
+ exitCode: result.exitCode ?? (result.error ? 1 : 0),
146
+ truncated,
147
+ };
148
+ } catch (error) {
149
+ return {
150
+ output: `Execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
151
+ exitCode: 1,
152
+ truncated: false,
153
+ };
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Send an SSE event to the client
159
+ */
160
+ sendEvent(event: string, data: unknown): void {
161
+ if (this.sseResponse && !this.sseResponse.headersSent) {
162
+ try {
163
+ this.sseResponse.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
164
+ } catch (e) {
165
+ console.warn('[DeepAgentBackend] Failed to send SSE event:', e);
166
+ }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Emit todo update event
172
+ */
173
+ emitTodoUpdate(todos: DeepAgentTodo[]): void {
174
+ // Call callback if provided
175
+ if (this.onTodoUpdate) {
176
+ this.onTodoUpdate(todos);
177
+ }
178
+
179
+ // Send SSE event
180
+ this.sendEvent('deep_research', {
181
+ type: 'todo_update',
182
+ conversationId: this.conversationId,
183
+ todos,
184
+ progress: this.calculateProgress(todos),
185
+ isRunning: todos.some(t => t.status === 'in_progress'),
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Emit subagent update event
191
+ */
192
+ emitSubagentUpdate(subagents: DeepAgentSubagent[]): void {
193
+ // Call callback if provided
194
+ if (this.onSubagentUpdate) {
195
+ this.onSubagentUpdate(subagents);
196
+ }
197
+
198
+ // Send SSE event
199
+ this.sendEvent('deep_research', {
200
+ type: 'subagent_update',
201
+ conversationId: this.conversationId,
202
+ subagents,
203
+ });
204
+ }
205
+
206
+ /**
207
+ * Calculate progress from todos
208
+ */
209
+ private calculateProgress(todos: DeepAgentTodo[]): number {
210
+ if (todos.length === 0) return 0;
211
+ const completed = todos.filter(t => t.status === 'completed').length;
212
+ return Math.round((completed / todos.length) * 100);
213
+ }
214
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Deep Agent Runtime
3
+ *
4
+ * Factory for creating and managing deep agent instances with
5
+ * illuma-agents integration.
6
+ *
7
+ * Uses explicit any types to avoid version conflicts between
8
+ * langchain dependencies in deepagents vs illuma-agents.
9
+ */
10
+
11
+ import { createDeepAgent } from 'deepagents';
12
+ import { DeepAgentBackend } from './DeepAgentBackend';
13
+ import type { DeepAgentRuntimeOptions, DeepAgentTodo, DeepAgentSubagent } from './types';
14
+
15
+ /** Default system prompt for deep research mode */
16
+ const DEFAULT_DEEP_RESEARCH_PROMPT = `You are a deep research agent capable of breaking down complex tasks into manageable steps.
17
+
18
+ ## Todo Management
19
+
20
+ You have a todo tool to track your progress. Use it to:
21
+ 1. Create a plan at the START with all tasks as "pending"
22
+ 2. Mark ONE task as "in_progress" before working on it
23
+ 3. Mark it "completed" IMMEDIATELY after finishing
24
+ 4. Update the FULL list each time (include all todos)
25
+
26
+ ## Best Practices
27
+
28
+ - Break complex tasks into 3-7 discrete steps
29
+ - Work through tasks sequentially
30
+ - Keep the user informed of progress
31
+ - If a task is blocked, mark it and move to the next
32
+ - Summarize findings after completing all tasks
33
+ `;
34
+
35
+ /** Return type for createDeepAgentRuntime */
36
+ export interface DeepAgentRuntimeResult {
37
+ /** The deep agent instance */
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ agent: any;
40
+ /** The backend for execution */
41
+ backend: DeepAgentBackend;
42
+ /** Thread ID for checkpointing */
43
+ threadId: string;
44
+ /** Conversation ID for tracking */
45
+ conversationId: string;
46
+ }
47
+
48
+ /**
49
+ * Create a deep agent runtime with the provided options
50
+ *
51
+ * @param options - Configuration for the deep agent
52
+ * @returns The configured deep agent instance
53
+ */
54
+ export async function createDeepAgentRuntime(
55
+ options: DeepAgentRuntimeOptions
56
+ ): Promise<DeepAgentRuntimeResult> {
57
+ const {
58
+ model,
59
+ threadId,
60
+ conversationId,
61
+ workspacePath,
62
+ systemPrompt,
63
+ checkpointer,
64
+ sseResponse,
65
+ onTodoUpdate,
66
+ onSubagentUpdate,
67
+ requireApproval = false,
68
+ codeExecutorUrl,
69
+ } = options;
70
+
71
+ if (!threadId) {
72
+ throw new Error('Thread ID is required for deep agent checkpointing');
73
+ }
74
+
75
+ // Create the backend with SSE streaming
76
+ const backend = new DeepAgentBackend({
77
+ rootDir: workspacePath,
78
+ virtualMode: !workspacePath, // Use virtual mode if no workspace path
79
+ conversationId,
80
+ sseResponse,
81
+ codeExecutorUrl,
82
+ onTodoUpdate,
83
+ onSubagentUpdate,
84
+ });
85
+
86
+ // Build the full system prompt
87
+ const fullSystemPrompt = systemPrompt
88
+ ? `${systemPrompt}\n\n${DEFAULT_DEEP_RESEARCH_PROMPT}`
89
+ : DEFAULT_DEEP_RESEARCH_PROMPT;
90
+
91
+ // Create the deep agent with explicit any casts to avoid version conflicts
92
+ // between langchain types in deepagents vs illuma-agents
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ const agent = createDeepAgent({
95
+ model: model as any,
96
+ checkpointer: checkpointer as any,
97
+ backend,
98
+ systemPrompt: fullSystemPrompt,
99
+ // Require approval for shell commands if configured
100
+ interruptOn: requireApproval ? { execute: true } : undefined,
101
+ } as any);
102
+
103
+ return {
104
+ agent,
105
+ backend,
106
+ threadId,
107
+ conversationId,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Run a deep agent with the given input
113
+ *
114
+ * @param runtime - The deep agent runtime
115
+ * @param input - User input message
116
+ * @param config - Optional run configuration
117
+ */
118
+ export async function runDeepAgent(
119
+ runtime: DeepAgentRuntimeResult,
120
+ input: string,
121
+ config?: {
122
+ signal?: AbortSignal;
123
+ onToken?: (token: string) => void;
124
+ onTodoUpdate?: (todos: DeepAgentTodo[]) => void;
125
+ onSubagentUpdate?: (subagents: DeepAgentSubagent[]) => void;
126
+ }
127
+ ): Promise<{
128
+ response: string;
129
+ todos: DeepAgentTodo[];
130
+ subagents: DeepAgentSubagent[];
131
+ }> {
132
+ const { agent, threadId, backend } = runtime;
133
+
134
+ // Stream the agent response
135
+ const stream = await agent.stream(
136
+ { messages: [{ role: 'human', content: input }] },
137
+ {
138
+ configurable: { thread_id: threadId },
139
+ signal: config?.signal,
140
+ }
141
+ );
142
+
143
+ let fullResponse = '';
144
+ const todos: DeepAgentTodo[] = [];
145
+ const subagents: DeepAgentSubagent[] = [];
146
+
147
+ for await (const event of stream) {
148
+ // Handle different event types
149
+ if ('messages' in event && Array.isArray(event.messages)) {
150
+ // Extract the latest AI message content
151
+ const lastMessage = event.messages[event.messages.length - 1];
152
+ if (lastMessage?.role === 'ai' && typeof lastMessage.content === 'string') {
153
+ const newContent = lastMessage.content.slice(fullResponse.length);
154
+ if (newContent && config?.onToken) {
155
+ config.onToken(newContent);
156
+ }
157
+ fullResponse = lastMessage.content;
158
+ }
159
+ }
160
+
161
+ // Handle todo updates
162
+ if ('todos' in event && Array.isArray(event.todos)) {
163
+ todos.length = 0;
164
+ todos.push(...(event.todos as DeepAgentTodo[]));
165
+ if (config?.onTodoUpdate) {
166
+ config.onTodoUpdate(todos);
167
+ }
168
+ backend.emitTodoUpdate(todos);
169
+ }
170
+
171
+ // Handle subagent updates
172
+ if ('subagents' in event && Array.isArray(event.subagents)) {
173
+ subagents.length = 0;
174
+ subagents.push(...(event.subagents as DeepAgentSubagent[]));
175
+ if (config?.onSubagentUpdate) {
176
+ config.onSubagentUpdate(subagents);
177
+ }
178
+ backend.emitSubagentUpdate(subagents);
179
+ }
180
+ }
181
+
182
+ return {
183
+ response: fullResponse,
184
+ todos,
185
+ subagents,
186
+ };
187
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Deep Agents Integration
3
+ *
4
+ * This module integrates the deepagentsjs library into illuma-agents,
5
+ * providing deep research capabilities including:
6
+ * - Todo planning and tracking
7
+ * - Subagent delegation
8
+ * - Filesystem operations
9
+ * - Shell execution
10
+ *
11
+ * @module deepagents
12
+ */
13
+
14
+ // Re-export core deepagents functionality
15
+ export {
16
+ createDeepAgent,
17
+ FilesystemBackend,
18
+ type SandboxBackendProtocol,
19
+ type ExecuteResponse,
20
+ } from 'deepagents';
21
+
22
+ // Export our custom integrations
23
+ export * from './types';
24
+ export * from './DeepAgentRuntime';
25
+ export * from './DeepAgentBackend';
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Deep Agents Types
3
+ *
4
+ * Type definitions for deep agent integration
5
+ *
6
+ * Uses generic/unknown types to avoid version conflicts between
7
+ * langchain dependencies in deepagents vs illuma-agents.
8
+ */
9
+
10
+ /** Status of a todo item */
11
+ export type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled';
12
+
13
+ /** A todo item tracked by the deep agent */
14
+ export interface DeepAgentTodo {
15
+ /** Unique identifier */
16
+ id: string;
17
+ /** Task description */
18
+ content: string;
19
+ /** Current status */
20
+ status: TodoStatus;
21
+ /** Order index */
22
+ order?: number;
23
+ /** When created */
24
+ createdAt?: string;
25
+ /** When last updated */
26
+ updatedAt?: string;
27
+ }
28
+
29
+ /** A subagent spawned by the deep agent */
30
+ export interface DeepAgentSubagent {
31
+ /** Unique identifier */
32
+ id: string;
33
+ /** Subagent name/purpose */
34
+ name: string;
35
+ /** Description of what it's doing */
36
+ description?: string;
37
+ /** Current status */
38
+ status: 'pending' | 'running' | 'completed' | 'failed';
39
+ /** When started */
40
+ startedAt?: string;
41
+ /** When completed */
42
+ completedAt?: string;
43
+ }
44
+
45
+ /** State of a deep agent session */
46
+ export interface DeepAgentState {
47
+ /** Whether deep research mode is active */
48
+ enabled: boolean;
49
+ /** Current todos */
50
+ todos: DeepAgentTodo[];
51
+ /** Active subagents */
52
+ subagents: DeepAgentSubagent[];
53
+ /** Overall progress (0-100) */
54
+ progress: number;
55
+ /** Whether currently executing */
56
+ isRunning: boolean;
57
+ /** Workspace path for file operations */
58
+ workspacePath?: string;
59
+ }
60
+
61
+ /** Options for creating a deep agent runtime */
62
+ export interface DeepAgentRuntimeOptions {
63
+ /** The LLM model to use (BaseChatModel or model name string) */
64
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+ model: any;
66
+ /** Thread ID for checkpointing */
67
+ threadId: string;
68
+ /** Conversation ID for event tracking */
69
+ conversationId: string;
70
+ /** Workspace path for file operations (optional) */
71
+ workspacePath?: string;
72
+ /** Custom system prompt to prepend */
73
+ systemPrompt?: string;
74
+ /** Checkpointer for state persistence (BaseCheckpointSaver) */
75
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
+ checkpointer?: any;
77
+ /** SSE response object for streaming updates */
78
+ sseResponse?: {
79
+ write: (data: string) => void;
80
+ headersSent?: boolean;
81
+ };
82
+ /** Callback for todo updates */
83
+ onTodoUpdate?: (todos: DeepAgentTodo[]) => void;
84
+ /** Callback for subagent updates */
85
+ onSubagentUpdate?: (subagents: DeepAgentSubagent[]) => void;
86
+ /** Whether to require human approval for shell commands */
87
+ requireApproval?: boolean;
88
+ /** Code executor URL for sandboxed execution */
89
+ codeExecutorUrl?: string;
90
+ }
91
+
92
+ /** Events emitted by the deep agent */
93
+ export interface DeepAgentEvent {
94
+ type: 'todo_update' | 'subagent_update' | 'file_change' | 'execution';
95
+ conversationId: string;
96
+ data: {
97
+ todos?: DeepAgentTodo[];
98
+ subagents?: DeepAgentSubagent[];
99
+ files?: Array<{ path: string; action: 'read' | 'write' | 'delete' }>;
100
+ execution?: { command: string; output: string; exitCode: number | null };
101
+ };
102
+ }
103
+
104
+ /** Calculate progress from todos */
105
+ export function calculateTodoProgress(todos: DeepAgentTodo[]): number {
106
+ if (todos.length === 0) return 0;
107
+ const completed = todos.filter(t => t.status === 'completed').length;
108
+ return Math.round((completed / todos.length) * 100);
109
+ }
110
+
111
+ /** Default state for deep agent */
112
+ export const defaultDeepAgentState: DeepAgentState = {
113
+ enabled: false,
114
+ todos: [],
115
+ subagents: [],
116
+ progress: 0,
117
+ isRunning: false,
118
+ };
package/src/index.ts CHANGED
@@ -8,11 +8,13 @@ export * from './messages';
8
8
  /* Graphs */
9
9
  export * from './graphs';
10
10
 
11
+ /* Deep Agents */
12
+ export * from './deepagents';
13
+
11
14
  /* Tools */
12
15
  export * from './tools/Calculator';
13
16
  export * from './tools/CodeExecutor';
14
17
  export * from './tools/BrowserTools';
15
- export * from './tools/DesktopTools';
16
18
  export * from './tools/ProgrammaticToolCalling';
17
19
  export * from './tools/ToolSearch';
18
20
  export * from './tools/handlers';