@siftd/connect-agent 0.2.50 → 0.2.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.js +62 -25
- package/package.json +1 -1
package/dist/orchestrator.d.ts
CHANGED
|
@@ -207,6 +207,7 @@ export declare class MasterOrchestrator {
|
|
|
207
207
|
private getTeamFilesDir;
|
|
208
208
|
private getFileScopeOverrides;
|
|
209
209
|
private rewriteFilesAlias;
|
|
210
|
+
private resolveFilesWritePath;
|
|
210
211
|
private getFileScopeSystemNote;
|
|
211
212
|
/**
|
|
212
213
|
* Check if verbose mode is enabled
|
package/dist/orchestrator.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import Anthropic from '@anthropic-ai/sdk';
|
|
8
8
|
import { spawn, execSync } from 'child_process';
|
|
9
|
-
import { existsSync, readFileSync } from 'fs';
|
|
10
|
-
import { join } from 'path';
|
|
9
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
10
|
+
import { join, resolve, dirname, sep } from 'path';
|
|
11
11
|
import { AdvancedMemoryStore } from './core/memory-advanced.js';
|
|
12
12
|
import { PostgresMemoryStore, isPostgresConfigured } from './core/memory-postgres.js';
|
|
13
13
|
import { TaskScheduler } from './core/scheduler.js';
|
|
@@ -103,7 +103,8 @@ TOOL RULES:
|
|
|
103
103
|
- Installing packages
|
|
104
104
|
- Running builds or tests
|
|
105
105
|
|
|
106
|
-
✅
|
|
106
|
+
✅ files_write for simple /files writes
|
|
107
|
+
✅ delegate_to_worker / spawn_worker - complex file operations:
|
|
107
108
|
- Creating, editing, deleting files
|
|
108
109
|
- Running npm/pip/cargo install
|
|
109
110
|
- Building, testing, deploying
|
|
@@ -142,6 +143,7 @@ FILES BROWSER:
|
|
|
142
143
|
Users can type /files to open the Finder UI (cloud mode).
|
|
143
144
|
When asked to browse or locate files, point them to /files.
|
|
144
145
|
Refer to /files instead of internal Lia-Hub paths in responses.
|
|
146
|
+
When users ask you to create or update a file in /files, use files_write.
|
|
145
147
|
|
|
146
148
|
FILES SCOPES:
|
|
147
149
|
- "My Files" are private to the user (default /files view)
|
|
@@ -186,7 +188,7 @@ WORKFLOW:
|
|
|
186
188
|
Before complex work: Check CLAUDE.md → Read LANDMARKS.md → Search memory
|
|
187
189
|
After completing work: Update LANDMARKS.md → Remember learnings
|
|
188
190
|
|
|
189
|
-
You orchestrate through workers. You remember through memory. You never do arbitrary file operations directly (calendar_upsert_events and
|
|
191
|
+
You orchestrate through workers. You remember through memory. You never do arbitrary file operations directly (calendar_upsert_events, todo_upsert_items, and files_write are the safe exceptions).`;
|
|
190
192
|
const TODO_CAL_SYSTEM_PROMPT_BASE = `You are Lia. Your ONLY job is to update /todo and /cal using tools.
|
|
191
193
|
|
|
192
194
|
Rules:
|
|
@@ -783,7 +785,7 @@ export class MasterOrchestrator {
|
|
|
783
785
|
return { type: 'tool', name: 'calendar_upsert_events' };
|
|
784
786
|
}
|
|
785
787
|
if (wantsFiles) {
|
|
786
|
-
return { type: 'tool', name: '
|
|
788
|
+
return { type: 'tool', name: 'files_write' };
|
|
787
789
|
}
|
|
788
790
|
return undefined;
|
|
789
791
|
}
|
|
@@ -849,6 +851,22 @@ export class MasterOrchestrator {
|
|
|
849
851
|
return `${targetDir}${suffix}`;
|
|
850
852
|
});
|
|
851
853
|
}
|
|
854
|
+
resolveFilesWritePath(rawPath) {
|
|
855
|
+
const trimmed = rawPath.trim();
|
|
856
|
+
if (!trimmed)
|
|
857
|
+
throw new Error('File path is required');
|
|
858
|
+
const teamDir = this.currentFileScope === 'team' ? this.getTeamFilesDir() : null;
|
|
859
|
+
const baseDir = teamDir || getSharedOutputPath();
|
|
860
|
+
const normalized = this.rewriteFilesAlias(trimmed);
|
|
861
|
+
const relative = normalized.replace(/^\/+/, '');
|
|
862
|
+
const candidate = normalized.startsWith(baseDir) ? normalized : join(baseDir, relative);
|
|
863
|
+
const resolved = resolve(candidate);
|
|
864
|
+
const baseResolved = resolve(baseDir);
|
|
865
|
+
if (resolved !== baseResolved && !resolved.startsWith(`${baseResolved}${sep}`)) {
|
|
866
|
+
throw new Error('Invalid file path');
|
|
867
|
+
}
|
|
868
|
+
return resolved;
|
|
869
|
+
}
|
|
852
870
|
getFileScopeSystemNote() {
|
|
853
871
|
if (this.currentFileScope !== 'team')
|
|
854
872
|
return null;
|
|
@@ -889,25 +907,6 @@ export class MasterOrchestrator {
|
|
|
889
907
|
this.attachmentContext = null;
|
|
890
908
|
}
|
|
891
909
|
}
|
|
892
|
-
const wantsFiles = this.hasFileMutation(message);
|
|
893
|
-
if (wantsFiles) {
|
|
894
|
-
this.attachmentContext = this.extractAttachmentContext(message);
|
|
895
|
-
const { task } = this.withAttachments(message);
|
|
896
|
-
const normalizedTask = this.rewriteFilesAlias(task);
|
|
897
|
-
const fileScope = this.getFileScopeOverrides();
|
|
898
|
-
const scopedTask = fileScope.instructions ? `${fileScope.instructions}\n\n${normalizedTask}` : normalizedTask;
|
|
899
|
-
try {
|
|
900
|
-
await this.delegateToWorker(scopedTask, undefined, fileScope.workingDir, fileScope.instructions);
|
|
901
|
-
return 'Working on it. Check /files shortly.';
|
|
902
|
-
}
|
|
903
|
-
catch (error) {
|
|
904
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
905
|
-
return `Error: ${errorMessage}`;
|
|
906
|
-
}
|
|
907
|
-
finally {
|
|
908
|
-
this.attachmentContext = null;
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
910
|
// DISABLED: Dumb regex extraction was creating garbage todos
|
|
912
911
|
// Let the AI use calendar_upsert_events and todo_upsert_items tools properly
|
|
913
912
|
// const quickWrite = this.tryHandleCalendarTodo(message);
|
|
@@ -1412,7 +1411,9 @@ ${hubContextStr}
|
|
|
1412
1411
|
const needsNoWorkers = toolName === 'todo_upsert_items' || toolName === 'calendar_upsert_events';
|
|
1413
1412
|
const followup = needsNoWorkers
|
|
1414
1413
|
? `You must call the ${toolName} tool now. Use the exact task/event titles and any bracketed tags exactly as provided. Do not spawn workers.`
|
|
1415
|
-
:
|
|
1414
|
+
: toolName === 'files_write'
|
|
1415
|
+
? 'You must call the files_write tool now. Provide the file path under /files and the full content.'
|
|
1416
|
+
: `You must call the ${toolName} tool now. Use the user's request as the task details.`;
|
|
1416
1417
|
currentMessages = [
|
|
1417
1418
|
...currentMessages,
|
|
1418
1419
|
{ role: 'assistant', content: response.content },
|
|
@@ -1573,6 +1574,26 @@ and preserve explicit due dates and priority from the user.`,
|
|
|
1573
1574
|
required: ['items']
|
|
1574
1575
|
}
|
|
1575
1576
|
},
|
|
1577
|
+
{
|
|
1578
|
+
name: 'files_write',
|
|
1579
|
+
description: `Create or overwrite a file in /files.
|
|
1580
|
+
|
|
1581
|
+
Only write to /files (shared outputs). Use a filename or /files/path/to/file.ext.`,
|
|
1582
|
+
input_schema: {
|
|
1583
|
+
type: 'object',
|
|
1584
|
+
properties: {
|
|
1585
|
+
path: {
|
|
1586
|
+
type: 'string',
|
|
1587
|
+
description: 'Target file path (e.g. /files/report.txt or report.txt)'
|
|
1588
|
+
},
|
|
1589
|
+
content: {
|
|
1590
|
+
type: 'string',
|
|
1591
|
+
description: 'File contents to write'
|
|
1592
|
+
}
|
|
1593
|
+
},
|
|
1594
|
+
required: ['path', 'content']
|
|
1595
|
+
}
|
|
1596
|
+
},
|
|
1576
1597
|
// Web tools
|
|
1577
1598
|
{
|
|
1578
1599
|
name: 'web_search',
|
|
@@ -2115,6 +2136,22 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
|
|
|
2115
2136
|
result = this.calendarTools.upsertTodoItems(taggedItems);
|
|
2116
2137
|
}
|
|
2117
2138
|
break;
|
|
2139
|
+
case 'files_write':
|
|
2140
|
+
{
|
|
2141
|
+
try {
|
|
2142
|
+
const pathValue = String(input.path || '').trim();
|
|
2143
|
+
const content = String(input.content || '');
|
|
2144
|
+
const targetPath = this.resolveFilesWritePath(pathValue);
|
|
2145
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
2146
|
+
writeFileSync(targetPath, content, 'utf8');
|
|
2147
|
+
result = { success: true, output: 'Saved file to /files.' };
|
|
2148
|
+
}
|
|
2149
|
+
catch (error) {
|
|
2150
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2151
|
+
result = { success: false, output: '', error: message };
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
break;
|
|
2118
2155
|
case 'web_search':
|
|
2119
2156
|
result = await this.webTools.webSearch(input.query, { numResults: input.num_results });
|
|
2120
2157
|
break;
|