@siftd/connect-agent 0.1.0 → 0.2.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 +106 -0
- package/dist/agent.js +97 -12
- package/dist/cli.js +18 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +12 -0
- package/dist/core/memory-advanced.d.ts +91 -0
- package/dist/core/memory-advanced.js +571 -0
- package/dist/core/scheduler.d.ts +101 -0
- package/dist/core/scheduler.js +311 -0
- package/dist/orchestrator.d.ts +85 -0
- package/dist/orchestrator.js +532 -0
- package/package.json +12 -4
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Master Orchestrator Agent
|
|
3
|
+
*
|
|
4
|
+
* This is the BRAIN - it orchestrates, remembers, and delegates.
|
|
5
|
+
* It does NOT do the work itself. Claude Code CLI workers do the work.
|
|
6
|
+
*/
|
|
7
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import { AdvancedMemoryStore } from './core/memory-advanced.js';
|
|
10
|
+
import { TaskScheduler } from './core/scheduler.js';
|
|
11
|
+
const SYSTEM_PROMPT = `You are the MASTER ORCHESTRATOR - the user's intelligent assistant accessed via web browser.
|
|
12
|
+
|
|
13
|
+
CRITICAL IDENTITY:
|
|
14
|
+
You are NOT a coding assistant. You are NOT a worker. You are the ORCHESTRATOR.
|
|
15
|
+
Your job is to UNDERSTAND, REMEMBER, DELEGATE, and SYNTHESIZE.
|
|
16
|
+
|
|
17
|
+
You have a powerful worker at your disposal: Claude Code CLI. It can:
|
|
18
|
+
- Read, write, edit any file on the user's machine
|
|
19
|
+
- Run any shell command
|
|
20
|
+
- Explore codebases
|
|
21
|
+
- Make multi-file changes
|
|
22
|
+
- Run builds, tests, deployments
|
|
23
|
+
- Do complex development work
|
|
24
|
+
|
|
25
|
+
YOUR ROLE vs WORKER ROLE:
|
|
26
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
27
|
+
│ YOU (Master Orchestrator) │ WORKER (Claude Code CLI) │
|
|
28
|
+
├────────────────────────────────────┼────────────────────────────┤
|
|
29
|
+
│ Understand user intent │ Execute file operations │
|
|
30
|
+
│ Remember user preferences │ Run shell commands │
|
|
31
|
+
│ Track ongoing projects │ Make code changes │
|
|
32
|
+
│ Decide what needs to be done │ Explore codebases │
|
|
33
|
+
│ Delegate complex tasks │ Build/test/deploy │
|
|
34
|
+
│ Synthesize results for user │ Handle multi-step tasks │
|
|
35
|
+
│ Schedule future work │ Do the actual work │
|
|
36
|
+
│ Maintain conversation context │ Work autonomously │
|
|
37
|
+
└────────────────────────────────────┴────────────────────────────┘
|
|
38
|
+
|
|
39
|
+
DELEGATION STRATEGY:
|
|
40
|
+
- ALWAYS delegate: file operations, code changes, builds, tests, deployments
|
|
41
|
+
- ALWAYS delegate: multi-step tasks, codebase exploration
|
|
42
|
+
- ALWAYS delegate: anything requiring filesystem or shell access
|
|
43
|
+
- Handle yourself: simple questions, scheduling, memory operations, conversation
|
|
44
|
+
|
|
45
|
+
NEVER TRY TO DO THE WORK YOURSELF. You don't have filesystem access. You don't have shell access.
|
|
46
|
+
Your only tools are: delegate_to_worker, remember, search_memory, schedule_task.
|
|
47
|
+
|
|
48
|
+
WHEN YOU DELEGATE:
|
|
49
|
+
1. Be specific about what you want done
|
|
50
|
+
2. Include context about user preferences from memory
|
|
51
|
+
3. Tell the user you're delegating ("Let me have my worker handle that...")
|
|
52
|
+
4. Wait for results and synthesize them into a clear response
|
|
53
|
+
|
|
54
|
+
MEMORY SYSTEM:
|
|
55
|
+
You have persistent memory. Use it to:
|
|
56
|
+
- Remember user preferences ("I prefer TypeScript", "I use pnpm")
|
|
57
|
+
- Track ongoing projects and their status
|
|
58
|
+
- Note user's communication style
|
|
59
|
+
- Store important facts about the user's system/environment
|
|
60
|
+
- Remember past conversations and decisions
|
|
61
|
+
|
|
62
|
+
COMMUNICATION STYLE:
|
|
63
|
+
- Be concise - this is a chat interface, not documentation
|
|
64
|
+
- Be direct - say what you're doing
|
|
65
|
+
- Be helpful - anticipate needs based on memory
|
|
66
|
+
- Acknowledge the user as someone you know and work with
|
|
67
|
+
|
|
68
|
+
You are the user's intelligent agent - you remember them, understand their projects,
|
|
69
|
+
and orchestrate work on their behalf. You are the persistent layer that makes
|
|
70
|
+
working with AI feel like having a knowledgeable assistant who knows you.`;
|
|
71
|
+
export class MasterOrchestrator {
|
|
72
|
+
client;
|
|
73
|
+
model;
|
|
74
|
+
maxTokens;
|
|
75
|
+
memory;
|
|
76
|
+
scheduler;
|
|
77
|
+
jobs = new Map();
|
|
78
|
+
jobCounter = 0;
|
|
79
|
+
userId;
|
|
80
|
+
workspaceDir;
|
|
81
|
+
constructor(options) {
|
|
82
|
+
this.client = new Anthropic({ apiKey: options.apiKey });
|
|
83
|
+
this.model = options.model || 'claude-sonnet-4-20250514';
|
|
84
|
+
this.maxTokens = options.maxTokens || 4096;
|
|
85
|
+
this.userId = options.userId;
|
|
86
|
+
this.workspaceDir = options.workspaceDir || process.env.HOME || '/tmp';
|
|
87
|
+
// Initialize memory with user-specific paths
|
|
88
|
+
this.memory = new AdvancedMemoryStore({
|
|
89
|
+
dbPath: `memories_${options.userId}.db`,
|
|
90
|
+
vectorPath: `./memory_vectors_${options.userId}`,
|
|
91
|
+
voyageApiKey: options.voyageApiKey
|
|
92
|
+
});
|
|
93
|
+
this.scheduler = new TaskScheduler(`scheduled_${options.userId}.json`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Process a user message
|
|
97
|
+
*/
|
|
98
|
+
async processMessage(message, conversationHistory = [], sendMessage) {
|
|
99
|
+
// Build context from memory
|
|
100
|
+
const memoryContext = await this.getMemoryContext(message);
|
|
101
|
+
// Build system prompt with memory context
|
|
102
|
+
const systemWithMemory = memoryContext
|
|
103
|
+
? `${SYSTEM_PROMPT}\n\nRELEVANT MEMORIES:\n${memoryContext}`
|
|
104
|
+
: SYSTEM_PROMPT;
|
|
105
|
+
// Add user message
|
|
106
|
+
const messages = [
|
|
107
|
+
...conversationHistory,
|
|
108
|
+
{ role: 'user', content: message }
|
|
109
|
+
];
|
|
110
|
+
try {
|
|
111
|
+
const response = await this.runAgentLoop(messages, systemWithMemory, sendMessage);
|
|
112
|
+
// Auto-remember important things from the conversation
|
|
113
|
+
await this.autoRemember(message, response);
|
|
114
|
+
return response;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
118
|
+
return `Error: ${errorMessage}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get relevant memory context for a message
|
|
123
|
+
*/
|
|
124
|
+
async getMemoryContext(message) {
|
|
125
|
+
try {
|
|
126
|
+
const memories = await this.memory.search(message, { limit: 5 });
|
|
127
|
+
if (memories.length === 0)
|
|
128
|
+
return null;
|
|
129
|
+
return memories.map(m => `[${m.type}] ${m.content}`).join('\n');
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Auto-remember important information from conversations
|
|
137
|
+
*/
|
|
138
|
+
async autoRemember(userMessage, response) {
|
|
139
|
+
// Look for preference indicators
|
|
140
|
+
const prefIndicators = ['i prefer', 'i like', 'i always', 'i never', 'i use', 'my favorite'];
|
|
141
|
+
const lower = userMessage.toLowerCase();
|
|
142
|
+
for (const indicator of prefIndicators) {
|
|
143
|
+
if (lower.includes(indicator)) {
|
|
144
|
+
await this.memory.remember(userMessage, {
|
|
145
|
+
type: 'semantic',
|
|
146
|
+
source: 'auto-extract',
|
|
147
|
+
importance: 0.7,
|
|
148
|
+
tags: ['preference', 'user']
|
|
149
|
+
});
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Run the agentic loop
|
|
156
|
+
*/
|
|
157
|
+
async runAgentLoop(messages, system, sendMessage) {
|
|
158
|
+
const tools = this.getToolDefinitions();
|
|
159
|
+
let currentMessages = [...messages];
|
|
160
|
+
let iterations = 0;
|
|
161
|
+
const maxIterations = 15;
|
|
162
|
+
while (iterations < maxIterations) {
|
|
163
|
+
iterations++;
|
|
164
|
+
const response = await this.client.messages.create({
|
|
165
|
+
model: this.model,
|
|
166
|
+
max_tokens: this.maxTokens,
|
|
167
|
+
system,
|
|
168
|
+
tools,
|
|
169
|
+
messages: currentMessages
|
|
170
|
+
});
|
|
171
|
+
// Check if done
|
|
172
|
+
if (response.stop_reason === 'end_turn' || !this.hasToolUse(response.content)) {
|
|
173
|
+
return this.extractText(response.content);
|
|
174
|
+
}
|
|
175
|
+
// Process tool calls
|
|
176
|
+
const toolResults = await this.processToolCalls(response.content, sendMessage);
|
|
177
|
+
// Continue conversation
|
|
178
|
+
currentMessages = [
|
|
179
|
+
...currentMessages,
|
|
180
|
+
{ role: 'assistant', content: response.content },
|
|
181
|
+
{ role: 'user', content: toolResults }
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
return 'Maximum iterations reached.';
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get tool definitions for the orchestrator
|
|
188
|
+
*/
|
|
189
|
+
getToolDefinitions() {
|
|
190
|
+
return [
|
|
191
|
+
{
|
|
192
|
+
name: 'delegate_to_worker',
|
|
193
|
+
description: `Delegate a task to Claude Code CLI worker. This is your PRIMARY tool.
|
|
194
|
+
|
|
195
|
+
Use this for ANY task that involves:
|
|
196
|
+
- Reading, writing, or editing files
|
|
197
|
+
- Running shell commands
|
|
198
|
+
- Exploring codebases
|
|
199
|
+
- Making code changes
|
|
200
|
+
- Building, testing, deploying
|
|
201
|
+
- ANY filesystem or system operation
|
|
202
|
+
|
|
203
|
+
The worker will execute the task autonomously and return results.
|
|
204
|
+
Be specific about what you want done.`,
|
|
205
|
+
input_schema: {
|
|
206
|
+
type: 'object',
|
|
207
|
+
properties: {
|
|
208
|
+
task: {
|
|
209
|
+
type: 'string',
|
|
210
|
+
description: 'Detailed description of what the worker should do'
|
|
211
|
+
},
|
|
212
|
+
context: {
|
|
213
|
+
type: 'string',
|
|
214
|
+
description: 'Additional context (user preferences, project info, etc)'
|
|
215
|
+
},
|
|
216
|
+
working_directory: {
|
|
217
|
+
type: 'string',
|
|
218
|
+
description: 'Directory to work in (defaults to user home)'
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
required: ['task']
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'remember',
|
|
226
|
+
description: 'Store something in persistent memory. Use for user preferences, project info, important facts.',
|
|
227
|
+
input_schema: {
|
|
228
|
+
type: 'object',
|
|
229
|
+
properties: {
|
|
230
|
+
content: {
|
|
231
|
+
type: 'string',
|
|
232
|
+
description: 'What to remember'
|
|
233
|
+
},
|
|
234
|
+
type: {
|
|
235
|
+
type: 'string',
|
|
236
|
+
enum: ['episodic', 'semantic', 'procedural'],
|
|
237
|
+
description: 'Memory type: episodic (events), semantic (facts), procedural (how-to)'
|
|
238
|
+
},
|
|
239
|
+
importance: {
|
|
240
|
+
type: 'number',
|
|
241
|
+
description: 'Importance 0-1 (higher = remembered longer)'
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
required: ['content']
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'search_memory',
|
|
249
|
+
description: 'Search your memory for relevant information. Use before delegating to include user context.',
|
|
250
|
+
input_schema: {
|
|
251
|
+
type: 'object',
|
|
252
|
+
properties: {
|
|
253
|
+
query: {
|
|
254
|
+
type: 'string',
|
|
255
|
+
description: 'What to search for'
|
|
256
|
+
},
|
|
257
|
+
type: {
|
|
258
|
+
type: 'string',
|
|
259
|
+
enum: ['episodic', 'semantic', 'procedural'],
|
|
260
|
+
description: 'Filter by memory type'
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
required: ['query']
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: 'schedule_task',
|
|
268
|
+
description: 'Schedule a task for future execution.',
|
|
269
|
+
input_schema: {
|
|
270
|
+
type: 'object',
|
|
271
|
+
properties: {
|
|
272
|
+
task: {
|
|
273
|
+
type: 'string',
|
|
274
|
+
description: 'The task to execute later'
|
|
275
|
+
},
|
|
276
|
+
when: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
description: 'When to run (e.g., "in 30 minutes", "daily at 9:00", "tomorrow at 14:00")'
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
required: ['task', 'when']
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: 'list_scheduled',
|
|
286
|
+
description: 'List all scheduled tasks.',
|
|
287
|
+
input_schema: {
|
|
288
|
+
type: 'object',
|
|
289
|
+
properties: {},
|
|
290
|
+
required: []
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
name: 'memory_stats',
|
|
295
|
+
description: 'Get statistics about your memory system.',
|
|
296
|
+
input_schema: {
|
|
297
|
+
type: 'object',
|
|
298
|
+
properties: {},
|
|
299
|
+
required: []
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
];
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Process tool calls
|
|
306
|
+
*/
|
|
307
|
+
async processToolCalls(content, sendMessage) {
|
|
308
|
+
const toolUseBlocks = content.filter((block) => block.type === 'tool_use');
|
|
309
|
+
const results = [];
|
|
310
|
+
for (const toolUse of toolUseBlocks) {
|
|
311
|
+
const input = toolUse.input;
|
|
312
|
+
let result;
|
|
313
|
+
// Notify user of action
|
|
314
|
+
if (sendMessage) {
|
|
315
|
+
const preview = this.formatToolPreview(toolUse.name, input);
|
|
316
|
+
if (preview)
|
|
317
|
+
await sendMessage(preview);
|
|
318
|
+
}
|
|
319
|
+
switch (toolUse.name) {
|
|
320
|
+
case 'delegate_to_worker':
|
|
321
|
+
result = await this.delegateToWorker(input.task, input.context, input.working_directory);
|
|
322
|
+
break;
|
|
323
|
+
case 'remember':
|
|
324
|
+
result = await this.executeRemember(input.content, input.type, input.importance);
|
|
325
|
+
break;
|
|
326
|
+
case 'search_memory':
|
|
327
|
+
result = await this.executeSearchMemory(input.query, input.type);
|
|
328
|
+
break;
|
|
329
|
+
case 'schedule_task':
|
|
330
|
+
result = await this.executeScheduleTask(input.task, input.when);
|
|
331
|
+
break;
|
|
332
|
+
case 'list_scheduled':
|
|
333
|
+
result = await this.executeListScheduled();
|
|
334
|
+
break;
|
|
335
|
+
case 'memory_stats':
|
|
336
|
+
result = await this.executeMemoryStats();
|
|
337
|
+
break;
|
|
338
|
+
default:
|
|
339
|
+
result = { success: false, output: `Unknown tool: ${toolUse.name}` };
|
|
340
|
+
}
|
|
341
|
+
results.push({
|
|
342
|
+
type: 'tool_result',
|
|
343
|
+
tool_use_id: toolUse.id,
|
|
344
|
+
content: result.output,
|
|
345
|
+
is_error: !result.success
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return results;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Delegate task to Claude Code CLI worker
|
|
352
|
+
*/
|
|
353
|
+
async delegateToWorker(task, context, workingDir) {
|
|
354
|
+
const id = `worker_${Date.now()}_${++this.jobCounter}`;
|
|
355
|
+
const cwd = workingDir || this.workspaceDir;
|
|
356
|
+
// Build prompt for worker
|
|
357
|
+
let prompt = task;
|
|
358
|
+
if (context) {
|
|
359
|
+
prompt = `Context: ${context}\n\nTask: ${task}`;
|
|
360
|
+
}
|
|
361
|
+
prompt += '\n\nKeep your response concise and focused on results.';
|
|
362
|
+
console.log(`[ORCHESTRATOR] Delegating to worker ${id}: ${task.slice(0, 80)}...`);
|
|
363
|
+
return new Promise((resolve) => {
|
|
364
|
+
const job = {
|
|
365
|
+
id,
|
|
366
|
+
task: task.slice(0, 200),
|
|
367
|
+
status: 'running',
|
|
368
|
+
startTime: Date.now(),
|
|
369
|
+
output: ''
|
|
370
|
+
};
|
|
371
|
+
// Spawn Claude Code CLI - use -p flag and pipe prompt to stdin
|
|
372
|
+
const child = spawn('claude', ['-p'], {
|
|
373
|
+
cwd,
|
|
374
|
+
env: { ...process.env },
|
|
375
|
+
shell: false
|
|
376
|
+
});
|
|
377
|
+
job.process = child;
|
|
378
|
+
this.jobs.set(id, job);
|
|
379
|
+
// Send prompt to stdin
|
|
380
|
+
if (child.stdin) {
|
|
381
|
+
child.stdin.write(prompt);
|
|
382
|
+
child.stdin.end();
|
|
383
|
+
}
|
|
384
|
+
// Timeout after 5 minutes
|
|
385
|
+
const timeout = setTimeout(() => {
|
|
386
|
+
if (job.status === 'running') {
|
|
387
|
+
job.status = 'timeout';
|
|
388
|
+
job.endTime = Date.now();
|
|
389
|
+
child.kill('SIGTERM');
|
|
390
|
+
resolve({
|
|
391
|
+
success: false,
|
|
392
|
+
output: `Worker timed out after 5 minutes.\nPartial output:\n${job.output.slice(-1000)}`
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}, 5 * 60 * 1000);
|
|
396
|
+
child.stdout?.on('data', (data) => {
|
|
397
|
+
job.output += data.toString();
|
|
398
|
+
});
|
|
399
|
+
child.stderr?.on('data', (data) => {
|
|
400
|
+
// Ignore status messages
|
|
401
|
+
const text = data.toString();
|
|
402
|
+
if (!text.includes('Checking') && !text.includes('Connected')) {
|
|
403
|
+
job.output += text;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
child.on('close', (code) => {
|
|
407
|
+
clearTimeout(timeout);
|
|
408
|
+
job.status = code === 0 ? 'completed' : 'failed';
|
|
409
|
+
job.endTime = Date.now();
|
|
410
|
+
const duration = ((job.endTime - job.startTime) / 1000).toFixed(1);
|
|
411
|
+
console.log(`[ORCHESTRATOR] Worker ${id} finished in ${duration}s`);
|
|
412
|
+
resolve({
|
|
413
|
+
success: code === 0,
|
|
414
|
+
output: job.output.trim() || '(No output)'
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
child.on('error', (err) => {
|
|
418
|
+
clearTimeout(timeout);
|
|
419
|
+
job.status = 'failed';
|
|
420
|
+
job.endTime = Date.now();
|
|
421
|
+
resolve({
|
|
422
|
+
success: false,
|
|
423
|
+
output: `Worker error: ${err.message}`
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Execute remember tool
|
|
430
|
+
*/
|
|
431
|
+
async executeRemember(content, type, importance) {
|
|
432
|
+
try {
|
|
433
|
+
const id = await this.memory.remember(content, {
|
|
434
|
+
type: type || undefined,
|
|
435
|
+
importance
|
|
436
|
+
});
|
|
437
|
+
return { success: true, output: `Remembered (${id})` };
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
return { success: false, output: `Failed to remember: ${error}` };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Execute search memory tool
|
|
445
|
+
*/
|
|
446
|
+
async executeSearchMemory(query, type) {
|
|
447
|
+
try {
|
|
448
|
+
const memories = await this.memory.search(query, {
|
|
449
|
+
type: type || undefined,
|
|
450
|
+
limit: 10
|
|
451
|
+
});
|
|
452
|
+
if (memories.length === 0) {
|
|
453
|
+
return { success: true, output: 'No relevant memories found.' };
|
|
454
|
+
}
|
|
455
|
+
const output = memories.map(m => `[${m.type}] (${(m.importance * 100).toFixed(0)}%) ${m.content}`).join('\n\n');
|
|
456
|
+
return { success: true, output };
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
return { success: false, output: `Memory search failed: ${error}` };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Execute schedule task tool
|
|
464
|
+
*/
|
|
465
|
+
async executeScheduleTask(task, when) {
|
|
466
|
+
try {
|
|
467
|
+
const taskId = this.scheduler.schedule(task, when, this.userId);
|
|
468
|
+
const scheduled = this.scheduler.get(taskId);
|
|
469
|
+
return {
|
|
470
|
+
success: true,
|
|
471
|
+
output: `Scheduled: ${taskId}\nWhen: ${scheduled ? this.scheduler.formatSchedule(scheduled.schedule) : when}`
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
return { success: false, output: `Scheduling failed: ${error}` };
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Execute list scheduled tool
|
|
480
|
+
*/
|
|
481
|
+
async executeListScheduled() {
|
|
482
|
+
const tasks = this.scheduler.list();
|
|
483
|
+
if (tasks.length === 0) {
|
|
484
|
+
return { success: true, output: 'No scheduled tasks.' };
|
|
485
|
+
}
|
|
486
|
+
const output = tasks.map(t => `${t.enabled ? '✓' : '⏸'} ${t.id}: ${t.task.slice(0, 50)}... (${this.scheduler.formatSchedule(t.schedule)})`).join('\n');
|
|
487
|
+
return { success: true, output };
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Execute memory stats tool
|
|
491
|
+
*/
|
|
492
|
+
async executeMemoryStats() {
|
|
493
|
+
const stats = this.memory.stats();
|
|
494
|
+
return {
|
|
495
|
+
success: true,
|
|
496
|
+
output: `Memories: ${stats.total} (episodic: ${stats.byType.episodic}, semantic: ${stats.byType.semantic}, procedural: ${stats.byType.procedural})\nAvg importance: ${(stats.avgImportance * 100).toFixed(0)}%\nAssociations: ${stats.totalAssociations}`
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Format tool preview for user
|
|
501
|
+
*/
|
|
502
|
+
formatToolPreview(name, input) {
|
|
503
|
+
switch (name) {
|
|
504
|
+
case 'delegate_to_worker':
|
|
505
|
+
return `Delegating to worker: ${input.task.slice(0, 80)}...`;
|
|
506
|
+
case 'remember':
|
|
507
|
+
return `Remembering: ${input.content.slice(0, 50)}...`;
|
|
508
|
+
case 'search_memory':
|
|
509
|
+
return `Searching memory: ${input.query}`;
|
|
510
|
+
case 'schedule_task':
|
|
511
|
+
return `Scheduling: ${input.task} for ${input.when}`;
|
|
512
|
+
default:
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
hasToolUse(content) {
|
|
517
|
+
return content.some(block => block.type === 'tool_use');
|
|
518
|
+
}
|
|
519
|
+
extractText(content) {
|
|
520
|
+
return content
|
|
521
|
+
.filter(block => block.type === 'text')
|
|
522
|
+
.map(block => block.text)
|
|
523
|
+
.join('\n');
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Shutdown cleanly
|
|
527
|
+
*/
|
|
528
|
+
shutdown() {
|
|
529
|
+
this.scheduler.shutdown();
|
|
530
|
+
this.memory.close();
|
|
531
|
+
}
|
|
532
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siftd/connect-agent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Master orchestrator agent - control Claude Code remotely via web",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"agent",
|
|
21
|
+
"orchestrator",
|
|
21
22
|
"cli",
|
|
22
23
|
"connect",
|
|
23
24
|
"claude",
|
|
24
25
|
"remote",
|
|
25
|
-
"terminal"
|
|
26
|
+
"terminal",
|
|
27
|
+
"memory"
|
|
26
28
|
],
|
|
27
29
|
"repository": {
|
|
28
30
|
"type": "git",
|
|
@@ -35,12 +37,18 @@
|
|
|
35
37
|
"access": "public"
|
|
36
38
|
},
|
|
37
39
|
"dependencies": {
|
|
40
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
41
|
+
"better-sqlite3": "^11.7.0",
|
|
38
42
|
"commander": "^12.1.0",
|
|
39
43
|
"conf": "^13.0.1",
|
|
40
|
-
"
|
|
44
|
+
"node-cron": "^3.0.3",
|
|
45
|
+
"ora": "^8.1.1",
|
|
46
|
+
"vectra": "^0.9.0"
|
|
41
47
|
},
|
|
42
48
|
"devDependencies": {
|
|
49
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
43
50
|
"@types/node": "^22.10.2",
|
|
51
|
+
"@types/node-cron": "^3.0.11",
|
|
44
52
|
"typescript": "^5.7.2"
|
|
45
53
|
}
|
|
46
54
|
}
|