@siftd/connect-agent 0.2.38 → 0.2.40
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 +3 -7
- package/dist/agent.js +69 -127
- package/dist/api.d.ts +0 -1
- package/dist/cli.js +1 -1
- package/dist/core/task-queue.d.ts +124 -0
- package/dist/core/task-queue.js +248 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/orchestrator.d.ts +81 -3
- package/dist/orchestrator.js +349 -10
- package/dist/websocket.d.ts +5 -2
- package/dist/websocket.js +10 -0
- package/package.json +1 -1
package/dist/orchestrator.js
CHANGED
|
@@ -20,6 +20,7 @@ import { SharedState } from './workers/shared-state.js';
|
|
|
20
20
|
import { getKnowledgeForPrompt } from './genesis/index.js';
|
|
21
21
|
import { loadHubContext, formatHubContext, logAction, logWorker } from './core/hub.js';
|
|
22
22
|
import { buildWorkerPrompt } from './prompts/worker-system.js';
|
|
23
|
+
import { LiaTaskQueue } from './core/task-queue.js';
|
|
23
24
|
/**
|
|
24
25
|
* Extract file paths from worker output
|
|
25
26
|
* Workers naturally mention files they create: "Created /tmp/foo.html", "Saved to /path/file"
|
|
@@ -74,6 +75,21 @@ YOUR IDENTITY:
|
|
|
74
75
|
HOW YOU WORK:
|
|
75
76
|
You are the orchestrator, not the executor. You coordinate and remember while workers do the hands-on work.
|
|
76
77
|
|
|
78
|
+
CRITICAL - DATE AWARENESS:
|
|
79
|
+
ALWAYS run \`date\` via bash FIRST before referencing ANY temporal context from memory.
|
|
80
|
+
- Before mentioning meetings, deadlines, or scheduled items: check today's date
|
|
81
|
+
- Cross-reference memory timestamps with current date
|
|
82
|
+
- Only surface RELEVANT, CURRENT information - never reference past events as if they're upcoming
|
|
83
|
+
- A personal assistant that gives outdated information is worse than useless - it's actively misleading
|
|
84
|
+
|
|
85
|
+
TASK QUEUE (Always-Listening):
|
|
86
|
+
You have an internal task queue. Users can keep sending messages while you work - you're interruptible.
|
|
87
|
+
- Use lia_plan to break down complex goals into steps
|
|
88
|
+
- Use lia_add_task to queue follow-up work or new requests that come in
|
|
89
|
+
- Use lia_get_queue to see what's pending
|
|
90
|
+
- When you receive multiple requests, acknowledge them and queue them: "Got it, adding to my queue..."
|
|
91
|
+
- You can work on one task while others wait - always stay responsive
|
|
92
|
+
|
|
77
93
|
TOOL RULES:
|
|
78
94
|
|
|
79
95
|
✅ bash - READ-ONLY operations only:
|
|
@@ -141,6 +157,23 @@ CALENDAR + TODO (Lia-managed data):
|
|
|
141
157
|
- calendar.json: { "version": 1, "calendars": [...], "events": [...] }
|
|
142
158
|
- todos.json: { "version": 1, "items": [...] }
|
|
143
159
|
|
|
160
|
+
COMPLEX TODO/CALENDAR OPERATIONS:
|
|
161
|
+
When users ask to "break down", "split", or "parse" a todo item:
|
|
162
|
+
1. READ THE NOTES FIELD - the TODO SNAPSHOT includes notes with full content
|
|
163
|
+
2. Parse the notes into distinct actionable items (grants, meetings, tasks, etc.)
|
|
164
|
+
3. Call todo_upsert_items with MULTIPLE new items extracted from the notes
|
|
165
|
+
4. Mark the original item as done: true OR delete by not including it in upsert
|
|
166
|
+
5. Each new item should have: id (unique), title, priority, notes (if details needed), due (if deadline mentioned)
|
|
167
|
+
|
|
168
|
+
Example: If a todo has notes listing "NIH R01 deadline Jan 25, AASLD pilot Feb, ADA Mar":
|
|
169
|
+
→ Create 3 separate todos: one for NIH R01 (due: 2026-01-25), one for AASLD, one for ADA
|
|
170
|
+
→ Extract deadlines, descriptions, requirements from the original notes
|
|
171
|
+
|
|
172
|
+
When users reference a todo by number (e.g., "#3", "item 3", "the third one"):
|
|
173
|
+
- Match it to the items in the TODO SNAPSHOT (which is ordered)
|
|
174
|
+
- READ its notes field carefully - that's where the real content lives
|
|
175
|
+
- Don't guess what it contains - the snapshot shows you exactly what's there
|
|
176
|
+
|
|
144
177
|
WORKFLOW:
|
|
145
178
|
Before complex work: Check CLAUDE.md → Read LANDMARKS.md → Search memory
|
|
146
179
|
After completing work: Update LANDMARKS.md → Remember learnings
|
|
@@ -179,9 +212,16 @@ export class MasterOrchestrator {
|
|
|
179
212
|
calendarTools;
|
|
180
213
|
sharedState;
|
|
181
214
|
verboseMode = new Map(); // per-user verbose mode
|
|
215
|
+
// Lia's internal task queue - allows async message processing
|
|
216
|
+
taskQueue;
|
|
217
|
+
taskUpdateCallback;
|
|
218
|
+
planUpdateCallback;
|
|
219
|
+
// Lia's visible todo list (displayed inline in chat)
|
|
220
|
+
currentTodos = [];
|
|
221
|
+
todoUpdateCallback;
|
|
182
222
|
constructor(options) {
|
|
183
223
|
this.client = new Anthropic({ apiKey: options.apiKey });
|
|
184
|
-
this.model = options.model || 'claude-sonnet-4-20250514';
|
|
224
|
+
this.model = options.model || process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-20250514';
|
|
185
225
|
this.maxTokens = options.maxTokens || 4096;
|
|
186
226
|
this.userId = options.userId;
|
|
187
227
|
this.orgId = options.orgId;
|
|
@@ -261,6 +301,12 @@ export class MasterOrchestrator {
|
|
|
261
301
|
this.workerLogCallback(workerId, line, stream);
|
|
262
302
|
}
|
|
263
303
|
});
|
|
304
|
+
// Initialize Lia's internal task queue
|
|
305
|
+
this.taskQueue = new LiaTaskQueue({
|
|
306
|
+
onTaskUpdate: (task) => this.taskUpdateCallback?.(task),
|
|
307
|
+
onPlanUpdate: (plan) => this.planUpdateCallback?.(plan),
|
|
308
|
+
processTask: async (task) => this.processQueuedTask(task),
|
|
309
|
+
});
|
|
264
310
|
}
|
|
265
311
|
/**
|
|
266
312
|
* Initialize the orchestrator - indexes filesystem on first call
|
|
@@ -318,6 +364,80 @@ export class MasterOrchestrator {
|
|
|
318
364
|
this.broadcastGalleryUpdate();
|
|
319
365
|
} : null);
|
|
320
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Set callback for task queue updates (for real-time UI updates)
|
|
369
|
+
*/
|
|
370
|
+
setTaskUpdateCallback(callback) {
|
|
371
|
+
this.taskUpdateCallback = callback || undefined;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Set callback for plan updates (for real-time UI updates)
|
|
375
|
+
*/
|
|
376
|
+
setPlanUpdateCallback(callback) {
|
|
377
|
+
this.planUpdateCallback = callback || undefined;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Set callback for visible todo list updates (displayed inline in chat)
|
|
381
|
+
*/
|
|
382
|
+
setTodoUpdateCallback(callback) {
|
|
383
|
+
this.todoUpdateCallback = callback || undefined;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Queue a message for async processing (non-blocking)
|
|
387
|
+
* Returns immediately with task ID - use callbacks or getTaskQueueStatus for results
|
|
388
|
+
*/
|
|
389
|
+
queueMessage(message, options) {
|
|
390
|
+
return this.taskQueue.addTask({
|
|
391
|
+
type: 'user_message',
|
|
392
|
+
content: message,
|
|
393
|
+
priority: options?.priority || 'normal',
|
|
394
|
+
metadata: {
|
|
395
|
+
userId: this.userId,
|
|
396
|
+
messageId: options?.messageId,
|
|
397
|
+
context: this.instanceMode,
|
|
398
|
+
orgId: this.orgId,
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Process a task from the queue (called by LiaTaskQueue)
|
|
404
|
+
*/
|
|
405
|
+
async processQueuedTask(task) {
|
|
406
|
+
// This is where the actual work happens
|
|
407
|
+
return this.processMessage(task.content, [], // Fresh conversation for each task
|
|
408
|
+
undefined // No sendMessage callback for queued tasks
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Get task queue status (for UI)
|
|
413
|
+
*/
|
|
414
|
+
getTaskQueueStatus() {
|
|
415
|
+
return this.taskQueue.getStatus();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Get pending tasks
|
|
419
|
+
*/
|
|
420
|
+
getPendingTasks() {
|
|
421
|
+
return this.taskQueue.getPendingTasks();
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Get task by ID
|
|
425
|
+
*/
|
|
426
|
+
getTask(taskId) {
|
|
427
|
+
return this.taskQueue.getTask(taskId);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Cancel a pending task
|
|
431
|
+
*/
|
|
432
|
+
cancelTask(taskId) {
|
|
433
|
+
return this.taskQueue.cancelTask(taskId);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Get Lia's internal todo list formatted for context
|
|
437
|
+
*/
|
|
438
|
+
getTaskQueueContext() {
|
|
439
|
+
return this.taskQueue.formatAsTodoList();
|
|
440
|
+
}
|
|
321
441
|
/**
|
|
322
442
|
* Get gallery workers with their assets
|
|
323
443
|
*/
|
|
@@ -429,6 +549,22 @@ export class MasterOrchestrator {
|
|
|
429
549
|
if (hasRunning || workers.length > 0) {
|
|
430
550
|
this.workerStatusCallback(workers);
|
|
431
551
|
}
|
|
552
|
+
// Update linked todos with worker progress
|
|
553
|
+
if (this.currentTodos.length > 0 && this.todoUpdateCallback) {
|
|
554
|
+
let todoUpdated = false;
|
|
555
|
+
for (const todo of this.currentTodos) {
|
|
556
|
+
if (todo.workerId && todo.status === 'in_progress') {
|
|
557
|
+
const worker = workers.find(w => w.id === todo.workerId);
|
|
558
|
+
if (worker && todo.progress !== worker.progress) {
|
|
559
|
+
todo.progress = worker.progress;
|
|
560
|
+
todoUpdated = true;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (todoUpdated) {
|
|
565
|
+
this.todoUpdateCallback(this.currentTodos);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
432
568
|
// Clean up completed jobs after 3 seconds
|
|
433
569
|
const now = Date.now();
|
|
434
570
|
for (const [id, job] of this.jobs) {
|
|
@@ -548,9 +684,8 @@ export class MasterOrchestrator {
|
|
|
548
684
|
}
|
|
549
685
|
/**
|
|
550
686
|
* Process a user message
|
|
551
|
-
* @param apiKey Optional per-request API key (overrides default)
|
|
552
687
|
*/
|
|
553
|
-
async processMessage(message, conversationHistory = [], sendMessage
|
|
688
|
+
async processMessage(message, conversationHistory = [], sendMessage) {
|
|
554
689
|
// Handle slash commands first
|
|
555
690
|
const slashResponse = this.handleSlashCommand(message);
|
|
556
691
|
if (slashResponse) {
|
|
@@ -598,7 +733,7 @@ ${hubContextStr}
|
|
|
598
733
|
{ role: 'user', content: message }
|
|
599
734
|
];
|
|
600
735
|
try {
|
|
601
|
-
const response = await this.runAgentLoop(messages, systemWithContext, sendMessage
|
|
736
|
+
const response = await this.runAgentLoop(messages, systemWithContext, sendMessage);
|
|
602
737
|
// Auto-remember important things from the conversation
|
|
603
738
|
await this.autoRemember(message, response);
|
|
604
739
|
void this.autoCaptureContext(message);
|
|
@@ -999,22 +1134,19 @@ ${hubContextStr}
|
|
|
999
1134
|
}
|
|
1000
1135
|
/**
|
|
1001
1136
|
* Run the agentic loop
|
|
1002
|
-
* @param apiKey Optional per-request API key (creates temporary client)
|
|
1003
1137
|
*/
|
|
1004
|
-
async runAgentLoop(messages, system, sendMessage
|
|
1138
|
+
async runAgentLoop(messages, system, sendMessage) {
|
|
1005
1139
|
const tools = this.getToolDefinitions();
|
|
1006
1140
|
let currentMessages = [...messages];
|
|
1007
1141
|
let iterations = 0;
|
|
1008
1142
|
const maxIterations = 30; // Increased for complex multi-tool tasks
|
|
1009
1143
|
const requestTimeoutMs = 60000;
|
|
1010
|
-
// Use per-request client if apiKey provided, otherwise use default
|
|
1011
|
-
const client = apiKey ? new Anthropic({ apiKey }) : this.client;
|
|
1012
1144
|
while (iterations < maxIterations) {
|
|
1013
1145
|
iterations++;
|
|
1014
1146
|
const requestStart = Date.now();
|
|
1015
1147
|
console.log(`[ORCHESTRATOR] Anthropic request ${iterations}/${maxIterations} (model: ${this.model})`);
|
|
1016
1148
|
const response = await Promise.race([
|
|
1017
|
-
client.messages.create({
|
|
1149
|
+
this.client.messages.create({
|
|
1018
1150
|
model: this.model,
|
|
1019
1151
|
max_tokens: this.maxTokens,
|
|
1020
1152
|
system,
|
|
@@ -1117,7 +1249,18 @@ Writes ONLY to ~/Lia-Hub/shared/outputs/.lia/calendar.json (creates the director
|
|
|
1117
1249
|
name: 'todo_upsert_items',
|
|
1118
1250
|
description: `Create or update todo items for /todo.
|
|
1119
1251
|
|
|
1120
|
-
Writes ONLY to ~/Lia-Hub/shared/outputs/.lia/todos.json (creates the directory/file if missing)
|
|
1252
|
+
Writes ONLY to ~/Lia-Hub/shared/outputs/.lia/todos.json (creates the directory/file if missing).
|
|
1253
|
+
|
|
1254
|
+
UPSERT BEHAVIOR:
|
|
1255
|
+
- Items with matching 'id' are REPLACED (use this to update or mark done)
|
|
1256
|
+
- Items with new 'id' are ADDED
|
|
1257
|
+
- To "delete" an item, set done: true or exclude it when replacing
|
|
1258
|
+
|
|
1259
|
+
BREAKING DOWN A TODO:
|
|
1260
|
+
When asked to split/parse a todo into multiple items:
|
|
1261
|
+
1. Include the original item with done: true (marks it complete)
|
|
1262
|
+
2. Add the new parsed items with unique ids
|
|
1263
|
+
3. Extract deadlines, priorities, and notes from the original content`,
|
|
1121
1264
|
input_schema: {
|
|
1122
1265
|
type: 'object',
|
|
1123
1266
|
properties: {
|
|
@@ -1540,6 +1683,85 @@ Be specific about what you want done.`,
|
|
|
1540
1683
|
},
|
|
1541
1684
|
required: ['port']
|
|
1542
1685
|
}
|
|
1686
|
+
},
|
|
1687
|
+
// Lia's internal task management tools
|
|
1688
|
+
{
|
|
1689
|
+
name: 'lia_plan',
|
|
1690
|
+
description: `Create a plan to break down a complex goal into steps. Use this when you receive multiple requests or need to organize work. The plan becomes your internal todo list.`,
|
|
1691
|
+
input_schema: {
|
|
1692
|
+
type: 'object',
|
|
1693
|
+
properties: {
|
|
1694
|
+
goal: {
|
|
1695
|
+
type: 'string',
|
|
1696
|
+
description: 'The overall goal you are trying to accomplish'
|
|
1697
|
+
},
|
|
1698
|
+
steps: {
|
|
1699
|
+
type: 'array',
|
|
1700
|
+
items: { type: 'string' },
|
|
1701
|
+
description: 'List of steps to accomplish the goal'
|
|
1702
|
+
}
|
|
1703
|
+
},
|
|
1704
|
+
required: ['goal', 'steps']
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
name: 'lia_add_task',
|
|
1709
|
+
description: `Add a task to your internal queue. Use when the user sends a new request while you are busy, or when you identify follow-up work. Tasks are processed in priority order.`,
|
|
1710
|
+
input_schema: {
|
|
1711
|
+
type: 'object',
|
|
1712
|
+
properties: {
|
|
1713
|
+
task: {
|
|
1714
|
+
type: 'string',
|
|
1715
|
+
description: 'The task description'
|
|
1716
|
+
},
|
|
1717
|
+
priority: {
|
|
1718
|
+
type: 'string',
|
|
1719
|
+
enum: ['urgent', 'high', 'normal', 'low'],
|
|
1720
|
+
description: 'Task priority (default: normal)'
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1723
|
+
required: ['task']
|
|
1724
|
+
}
|
|
1725
|
+
},
|
|
1726
|
+
{
|
|
1727
|
+
name: 'lia_get_queue',
|
|
1728
|
+
description: 'Get your current task queue status. Shows what you are working on and what is pending.',
|
|
1729
|
+
input_schema: {
|
|
1730
|
+
type: 'object',
|
|
1731
|
+
properties: {},
|
|
1732
|
+
required: []
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
{
|
|
1736
|
+
name: 'lia_todo_write',
|
|
1737
|
+
description: `Update your visible todo list displayed inline in the chat. Use this to show the user what you're working on.
|
|
1738
|
+
|
|
1739
|
+
Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears in the chat conversation.
|
|
1740
|
+
- Use for multi-step tasks to show real-time progress
|
|
1741
|
+
- Update status as you complete each item
|
|
1742
|
+
- Only have ONE item as in_progress at a time
|
|
1743
|
+
- Link workerId to show actual worker progress percentage`,
|
|
1744
|
+
input_schema: {
|
|
1745
|
+
type: 'object',
|
|
1746
|
+
properties: {
|
|
1747
|
+
todos: {
|
|
1748
|
+
type: 'array',
|
|
1749
|
+
items: {
|
|
1750
|
+
type: 'object',
|
|
1751
|
+
properties: {
|
|
1752
|
+
id: { type: 'string', description: 'Unique identifier for the todo (optional, auto-generated if not provided)' },
|
|
1753
|
+
content: { type: 'string', description: 'Imperative form: "Run tests", "Build component"' },
|
|
1754
|
+
activeForm: { type: 'string', description: 'Present continuous: "Running tests", "Building component"' },
|
|
1755
|
+
status: { type: 'string', enum: ['pending', 'in_progress', 'completed'] },
|
|
1756
|
+
workerId: { type: 'string', description: 'Optional: link to a spawned worker ID for real progress tracking' }
|
|
1757
|
+
},
|
|
1758
|
+
required: ['content', 'activeForm', 'status']
|
|
1759
|
+
},
|
|
1760
|
+
description: 'The full todo list (replaces existing list)'
|
|
1761
|
+
}
|
|
1762
|
+
},
|
|
1763
|
+
required: ['todos']
|
|
1764
|
+
}
|
|
1543
1765
|
}
|
|
1544
1766
|
];
|
|
1545
1767
|
}
|
|
@@ -1683,6 +1905,19 @@ Be specific about what you want done.`,
|
|
|
1683
1905
|
case 'stop_local_server':
|
|
1684
1906
|
result = await this.executeStopServer(input.port);
|
|
1685
1907
|
break;
|
|
1908
|
+
// Lia's internal task management tools
|
|
1909
|
+
case 'lia_plan':
|
|
1910
|
+
result = this.executeLiaPlan(input.goal, input.steps);
|
|
1911
|
+
break;
|
|
1912
|
+
case 'lia_add_task':
|
|
1913
|
+
result = this.executeLiaAddTask(input.task, input.priority);
|
|
1914
|
+
break;
|
|
1915
|
+
case 'lia_get_queue':
|
|
1916
|
+
result = this.executeLiaGetQueue();
|
|
1917
|
+
break;
|
|
1918
|
+
case 'lia_todo_write':
|
|
1919
|
+
result = this.executeLiaTodoWrite(input.todos);
|
|
1920
|
+
break;
|
|
1686
1921
|
default:
|
|
1687
1922
|
result = { success: false, output: `Unknown tool: ${toolUse.name}` };
|
|
1688
1923
|
}
|
|
@@ -2186,6 +2421,102 @@ Be specific about what you want done.`,
|
|
|
2186
2421
|
return { success: false, output: `No server running on port ${port}` };
|
|
2187
2422
|
}
|
|
2188
2423
|
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Create a plan with steps (Lia's internal planning)
|
|
2426
|
+
*/
|
|
2427
|
+
executeLiaPlan(goal, steps) {
|
|
2428
|
+
try {
|
|
2429
|
+
const plan = this.taskQueue.createPlan(goal, steps);
|
|
2430
|
+
console.log(`[ORCHESTRATOR] Created plan: ${plan.id} with ${steps.length} steps`);
|
|
2431
|
+
const stepsFormatted = steps.map((s, i) => `${i + 1}. ${s}`).join('\n');
|
|
2432
|
+
return {
|
|
2433
|
+
success: true,
|
|
2434
|
+
output: `Created plan "${goal}" with ${steps.length} steps:\n${stepsFormatted}\n\nPlan ID: ${plan.id}`
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
catch (error) {
|
|
2438
|
+
return { success: false, output: `Failed to create plan: ${error}` };
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
/**
|
|
2442
|
+
* Add a task to Lia's internal queue
|
|
2443
|
+
*/
|
|
2444
|
+
executeLiaAddTask(task, priority) {
|
|
2445
|
+
try {
|
|
2446
|
+
const newTask = this.taskQueue.addTask({
|
|
2447
|
+
type: 'follow_up',
|
|
2448
|
+
content: task,
|
|
2449
|
+
priority: priority || 'normal',
|
|
2450
|
+
metadata: {
|
|
2451
|
+
userId: this.userId,
|
|
2452
|
+
context: this.instanceMode,
|
|
2453
|
+
orgId: this.orgId,
|
|
2454
|
+
},
|
|
2455
|
+
});
|
|
2456
|
+
console.log(`[ORCHESTRATOR] Added task to queue: ${newTask.id}`);
|
|
2457
|
+
const status = this.taskQueue.getStatus();
|
|
2458
|
+
return {
|
|
2459
|
+
success: true,
|
|
2460
|
+
output: `Added to my queue: "${task}" (priority: ${priority || 'normal'}). ${status.pendingCount} tasks pending.`
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
catch (error) {
|
|
2464
|
+
return { success: false, output: `Failed to add task: ${error}` };
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
/**
|
|
2468
|
+
* Get Lia's task queue status
|
|
2469
|
+
*/
|
|
2470
|
+
executeLiaGetQueue() {
|
|
2471
|
+
try {
|
|
2472
|
+
const status = this.taskQueue.getStatus();
|
|
2473
|
+
const todoList = this.taskQueue.formatAsTodoList();
|
|
2474
|
+
let output = todoList;
|
|
2475
|
+
if (!status.isProcessing && status.pendingCount === 0) {
|
|
2476
|
+
output = 'My queue is empty - ready for new tasks.';
|
|
2477
|
+
}
|
|
2478
|
+
return { success: true, output };
|
|
2479
|
+
}
|
|
2480
|
+
catch (error) {
|
|
2481
|
+
return { success: false, output: `Failed to get queue: ${error}` };
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
/**
|
|
2485
|
+
* Update visible todo list (displayed inline in chat)
|
|
2486
|
+
*/
|
|
2487
|
+
executeLiaTodoWrite(todos) {
|
|
2488
|
+
try {
|
|
2489
|
+
// Assign IDs if missing
|
|
2490
|
+
this.currentTodos = todos.map((todo, i) => ({
|
|
2491
|
+
...todo,
|
|
2492
|
+
id: todo.id || `todo_${Date.now()}_${i}`,
|
|
2493
|
+
}));
|
|
2494
|
+
// Update progress from linked workers
|
|
2495
|
+
const allWorkers = this.getWorkerStatus();
|
|
2496
|
+
for (const todo of this.currentTodos) {
|
|
2497
|
+
if (todo.workerId && todo.status === 'in_progress') {
|
|
2498
|
+
const workerStatus = allWorkers.find(w => w.id === todo.workerId);
|
|
2499
|
+
if (workerStatus) {
|
|
2500
|
+
todo.progress = workerStatus.progress;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
// Broadcast to UI
|
|
2505
|
+
this.todoUpdateCallback?.(this.currentTodos);
|
|
2506
|
+
const counts = {
|
|
2507
|
+
pending: this.currentTodos.filter(t => t.status === 'pending').length,
|
|
2508
|
+
inProgress: this.currentTodos.filter(t => t.status === 'in_progress').length,
|
|
2509
|
+
completed: this.currentTodos.filter(t => t.status === 'completed').length,
|
|
2510
|
+
};
|
|
2511
|
+
return {
|
|
2512
|
+
success: true,
|
|
2513
|
+
output: `Todo list updated: ${counts.completed}/${this.currentTodos.length} completed, ${counts.inProgress} in progress`
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
catch (error) {
|
|
2517
|
+
return { success: false, output: `Failed to update todo list: ${error}` };
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2189
2520
|
/**
|
|
2190
2521
|
* Format tool preview for user
|
|
2191
2522
|
*/
|
|
@@ -2235,6 +2566,14 @@ Be specific about what you want done.`,
|
|
|
2235
2566
|
return `Starting server on port ${input.port || 8080}...`;
|
|
2236
2567
|
case 'stop_local_server':
|
|
2237
2568
|
return `Stopping server on port ${input.port}...`;
|
|
2569
|
+
case 'lia_plan':
|
|
2570
|
+
return `Planning: ${input.goal}`;
|
|
2571
|
+
case 'lia_add_task':
|
|
2572
|
+
return `Queuing task: ${input.task.slice(0, 50)}...`;
|
|
2573
|
+
case 'lia_get_queue':
|
|
2574
|
+
return 'Checking my task queue...';
|
|
2575
|
+
case 'lia_todo_write':
|
|
2576
|
+
return null; // Don't show preview - the todo list itself is the UI
|
|
2238
2577
|
default:
|
|
2239
2578
|
return null;
|
|
2240
2579
|
}
|
package/dist/websocket.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - Streams responses as they're generated
|
|
7
7
|
* - Supports interruption and progress updates
|
|
8
8
|
*/
|
|
9
|
-
import type { WorkerStatus } from './orchestrator.js';
|
|
9
|
+
import type { WorkerStatus, LiaTodoItem } from './orchestrator.js';
|
|
10
10
|
import { AssetResponse } from './core/asset-api.js';
|
|
11
11
|
export type MessageHandler = (message: WebSocketMessage) => Promise<void>;
|
|
12
12
|
export type StreamHandler = (chunk: string) => void;
|
|
@@ -15,7 +15,6 @@ export interface WebSocketMessage {
|
|
|
15
15
|
id?: string;
|
|
16
16
|
content?: string;
|
|
17
17
|
timestamp?: number;
|
|
18
|
-
apiKey?: string;
|
|
19
18
|
requestId?: string;
|
|
20
19
|
assetId?: string;
|
|
21
20
|
groupId?: string;
|
|
@@ -67,6 +66,10 @@ export declare class AgentWebSocket {
|
|
|
67
66
|
* Send workers status update for progress bars
|
|
68
67
|
*/
|
|
69
68
|
sendWorkersUpdate(workers: WorkerStatus[]): void;
|
|
69
|
+
/**
|
|
70
|
+
* Send todo list update for inline display in chat
|
|
71
|
+
*/
|
|
72
|
+
sendTodoUpdate(todos: LiaTodoItem[]): void;
|
|
70
73
|
/**
|
|
71
74
|
* Send gallery command (AI controls the gallery)
|
|
72
75
|
*/
|
package/dist/websocket.js
CHANGED
|
@@ -169,6 +169,16 @@ export class AgentWebSocket {
|
|
|
169
169
|
workers
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Send todo list update for inline display in chat
|
|
174
|
+
*/
|
|
175
|
+
sendTodoUpdate(todos) {
|
|
176
|
+
this.sendToServer({
|
|
177
|
+
type: 'lia_todo_update',
|
|
178
|
+
todos,
|
|
179
|
+
timestamp: Date.now()
|
|
180
|
+
});
|
|
181
|
+
}
|
|
172
182
|
/**
|
|
173
183
|
* Send gallery command (AI controls the gallery)
|
|
174
184
|
*/
|