@siftd/connect-agent 0.2.59 → 0.2.60
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/agent.js +65 -10
- package/dist/orchestrator.js +2 -2
- package/dist/workers/manager.js +1 -1
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -9,7 +9,7 @@ import { getUserId, getOrgId, getAnthropicApiKey, isCloudMode, getDeploymentInfo
|
|
|
9
9
|
import { MasterOrchestrator } from './orchestrator.js';
|
|
10
10
|
import { AgentWebSocket } from './websocket.js';
|
|
11
11
|
import { startHeartbeat, stopHeartbeat, getHeartbeatState } from './heartbeat.js';
|
|
12
|
-
import { loadHubContext, readScratchpad } from './core/hub.js';
|
|
12
|
+
import { getSharedOutputPath, loadHubContext, readScratchpad } from './core/hub.js';
|
|
13
13
|
import { PRODUCT_FULL_NAME } from './branding.js';
|
|
14
14
|
import { startPreviewWorker, stopPreviewWorker } from './core/preview-worker.js';
|
|
15
15
|
function parseAttachments(content) {
|
|
@@ -38,6 +38,53 @@ function stripAttachmentBlock(content) {
|
|
|
38
38
|
return content;
|
|
39
39
|
return content.slice(0, index).trim();
|
|
40
40
|
}
|
|
41
|
+
function normalizeAttachmentSubdir(raw, allowRoot) {
|
|
42
|
+
if (!raw)
|
|
43
|
+
return null;
|
|
44
|
+
let value = raw.trim();
|
|
45
|
+
value = value.replace(/^["'`]+|["'`]+$/g, '');
|
|
46
|
+
value = value.replace(/[),.;:!?]+$/g, '');
|
|
47
|
+
value = value.replace(/\\+/g, '/');
|
|
48
|
+
const filesPrefix = /^\/?files\b/i;
|
|
49
|
+
if (filesPrefix.test(value)) {
|
|
50
|
+
value = value.replace(filesPrefix, '');
|
|
51
|
+
}
|
|
52
|
+
value = value.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
53
|
+
if (!value)
|
|
54
|
+
return allowRoot ? '' : null;
|
|
55
|
+
const segments = value
|
|
56
|
+
.split('/')
|
|
57
|
+
.map((segment) => segment.trim())
|
|
58
|
+
.filter((segment) => segment && segment !== '.' && segment !== '..');
|
|
59
|
+
const sanitized = segments
|
|
60
|
+
.map((segment) => segment.replace(/[^\w.-]+/g, '_'))
|
|
61
|
+
.filter(Boolean);
|
|
62
|
+
if (sanitized.length === 0)
|
|
63
|
+
return allowRoot ? '' : null;
|
|
64
|
+
return sanitized.join('/');
|
|
65
|
+
}
|
|
66
|
+
function extractAttachmentSubdir(text) {
|
|
67
|
+
const cleaned = text.trim();
|
|
68
|
+
if (!cleaned)
|
|
69
|
+
return null;
|
|
70
|
+
const filesMatch = cleaned.match(/\/files(?:\/[^\s"'`)\]]+)?/i);
|
|
71
|
+
if (filesMatch) {
|
|
72
|
+
return normalizeAttachmentSubdir(filesMatch[0], true);
|
|
73
|
+
}
|
|
74
|
+
const folderMatch = cleaned.match(/\b(?:folder|directory)\b[^a-zA-Z0-9]*(?:called|named)?\s*["'`]?([A-Za-z0-9][\w./-]+)\/?/i);
|
|
75
|
+
if (folderMatch) {
|
|
76
|
+
return normalizeAttachmentSubdir(folderMatch[1], false);
|
|
77
|
+
}
|
|
78
|
+
const inFolderMatch = cleaned.match(/\bin\s+([A-Za-z0-9][\w./-]+)\s*(?:folder|directory)\b/i);
|
|
79
|
+
if (inFolderMatch) {
|
|
80
|
+
return normalizeAttachmentSubdir(inFolderMatch[1], false);
|
|
81
|
+
}
|
|
82
|
+
const inPathMatch = cleaned.match(/\bin\s+([A-Za-z0-9][\w./-]+\/)\b/i);
|
|
83
|
+
if (inPathMatch) {
|
|
84
|
+
return normalizeAttachmentSubdir(inPathMatch[1], false);
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
41
88
|
function isSaveIntent(text) {
|
|
42
89
|
const lower = text.toLowerCase();
|
|
43
90
|
if (!lower)
|
|
@@ -74,14 +121,17 @@ function humanizePath(path) {
|
|
|
74
121
|
}
|
|
75
122
|
return path;
|
|
76
123
|
}
|
|
77
|
-
async function saveAttachments(attachments,
|
|
78
|
-
const
|
|
79
|
-
const
|
|
124
|
+
async function saveAttachments(attachments, options = {}) {
|
|
125
|
+
const baseDir = getSharedOutputPath();
|
|
126
|
+
const requestedSubdir = options.subdir;
|
|
127
|
+
const targetDir = typeof requestedSubdir === 'string'
|
|
128
|
+
? join(baseDir, requestedSubdir)
|
|
129
|
+
: join(baseDir, 'safe-files');
|
|
80
130
|
await mkdir(targetDir, { recursive: true });
|
|
81
131
|
const results = [];
|
|
82
132
|
for (const attachment of attachments) {
|
|
83
133
|
const targetPath = await getUniquePath(targetDir, attachment.name);
|
|
84
|
-
onProgress?.(`Saving ${attachment.name}...`);
|
|
134
|
+
options.onProgress?.(`Saving ${attachment.name}...`);
|
|
85
135
|
try {
|
|
86
136
|
const response = await fetch(attachment.url);
|
|
87
137
|
if (!response.ok) {
|
|
@@ -93,12 +143,12 @@ async function saveAttachments(attachments, onProgress) {
|
|
|
93
143
|
const stream = Readable.fromWeb(response.body);
|
|
94
144
|
await pipeline(stream, createWriteStream(targetPath));
|
|
95
145
|
results.push({ name: attachment.name, path: targetPath });
|
|
96
|
-
onProgress?.(`Saved ${attachment.name} → ${humanizePath(targetPath)}`);
|
|
146
|
+
options.onProgress?.(`Saved ${attachment.name} → ${humanizePath(targetPath)}`);
|
|
97
147
|
}
|
|
98
148
|
catch (error) {
|
|
99
149
|
const message = error instanceof Error ? error.message : String(error);
|
|
100
150
|
results.push({ name: attachment.name, path: targetPath, error: message });
|
|
101
|
-
onProgress?.(`Failed ${attachment.name}: ${message}`);
|
|
151
|
+
options.onProgress?.(`Failed ${attachment.name}: ${message}`);
|
|
102
152
|
}
|
|
103
153
|
}
|
|
104
154
|
return results;
|
|
@@ -233,7 +283,11 @@ async function sendToOrchestrator(input, orch, messageId) {
|
|
|
233
283
|
if (wsClient?.connected()) {
|
|
234
284
|
wsClient.sendTyping(false);
|
|
235
285
|
}
|
|
236
|
-
|
|
286
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
287
|
+
if (/request timed out after \d+ms/i.test(message)) {
|
|
288
|
+
return 'Still working on it — I’ll respond as soon as I have results.';
|
|
289
|
+
}
|
|
290
|
+
return `Error: ${message}`;
|
|
237
291
|
}
|
|
238
292
|
finally {
|
|
239
293
|
orch.setWorkerLogCallback(null);
|
|
@@ -270,14 +324,15 @@ export async function processMessage(message) {
|
|
|
270
324
|
wsClient.sendProgress(message.id, msgText);
|
|
271
325
|
}
|
|
272
326
|
};
|
|
273
|
-
const
|
|
327
|
+
const baseText = stripAttachmentBlock(message.content);
|
|
328
|
+
const requestedSubdir = extractAttachmentSubdir(baseText);
|
|
329
|
+
const results = await saveAttachments(attachments, { subdir: requestedSubdir, onProgress: progress });
|
|
274
330
|
const saved = results.filter((entry) => !entry.error);
|
|
275
331
|
const failed = results.filter((entry) => entry.error);
|
|
276
332
|
const savedLines = saved.map((entry) => `- ${humanizePath(entry.path)}`).join('\n');
|
|
277
333
|
const failedLines = failed
|
|
278
334
|
.map((entry) => `- ${entry.name}: ${entry.error}`)
|
|
279
335
|
.join('\n');
|
|
280
|
-
const baseText = stripAttachmentBlock(message.content);
|
|
281
336
|
if (isSaveIntent(baseText)) {
|
|
282
337
|
const responseLines = [
|
|
283
338
|
saved.length > 0 ? `Saved ${saved.length} file${saved.length === 1 ? '' : 's'}:` : 'No files saved.',
|
package/dist/orchestrator.js
CHANGED
|
@@ -22,7 +22,7 @@ import { getKnowledgeForPrompt } from './genesis/index.js';
|
|
|
22
22
|
import { loadHubContext, formatHubContext, logAction, logWorker, getSharedOutputPath } from './core/hub.js';
|
|
23
23
|
import { buildWorkerPrompt } from './prompts/worker-system.js';
|
|
24
24
|
import { LiaTaskQueue } from './core/task-queue.js';
|
|
25
|
-
const DEFAULT_CLAUDE_MODEL = 'claude-opus-4-
|
|
25
|
+
const DEFAULT_CLAUDE_MODEL = 'claude-opus-4-6';
|
|
26
26
|
const DEFAULT_TOOL_MAX_TOKENS = 1024;
|
|
27
27
|
function readBooleanEnv(value, fallback) {
|
|
28
28
|
if (value === undefined)
|
|
@@ -1605,7 +1605,7 @@ ${hubContextStr}
|
|
|
1605
1605
|
let currentMessages = [...messages];
|
|
1606
1606
|
let iterations = 0;
|
|
1607
1607
|
const maxIterations = 30; // Increased for complex multi-tool tasks
|
|
1608
|
-
const requestTimeoutMs =
|
|
1608
|
+
const requestTimeoutMs = 180000;
|
|
1609
1609
|
const forcedToolChoice = this.getToolChoice(currentMessages);
|
|
1610
1610
|
let retriedForcedTool = false;
|
|
1611
1611
|
let retriedTodoCal = false;
|
package/dist/workers/manager.js
CHANGED
|
@@ -48,7 +48,7 @@ function getFileType(ext) {
|
|
|
48
48
|
return 'text';
|
|
49
49
|
return 'other';
|
|
50
50
|
}
|
|
51
|
-
const DEFAULT_CLAUDE_MODEL = 'claude-opus-4-
|
|
51
|
+
const DEFAULT_CLAUDE_MODEL = 'claude-opus-4-6';
|
|
52
52
|
function readBooleanEnv(value, fallback) {
|
|
53
53
|
if (value === undefined)
|
|
54
54
|
return fallback;
|