@clawchatsai/connector 0.0.46 → 0.0.47
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/package.json +1 -1
- package/server.js +4 -68
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -3969,7 +3969,6 @@ export function createApp(config = {}) {
|
|
|
3969
3969
|
this._externalBroadcastTargets = [];
|
|
3970
3970
|
this.streamState = new Map();
|
|
3971
3971
|
this.activityLogs = new Map();
|
|
3972
|
-
this._pendingMediaUrls = new Map(); // sessionKey → string[] of MEDIA: paths captured during streaming
|
|
3973
3972
|
setInterval(() => {
|
|
3974
3973
|
const cutoff = Date.now() - 10 * 60 * 1000;
|
|
3975
3974
|
for (const [runId, log] of this.activityLogs) {
|
|
@@ -4066,43 +4065,6 @@ export function createApp(config = {}) {
|
|
|
4066
4065
|
if (!content || !content.trim()) { console.log(`Skipping empty assistant response for thread ${parsed.threadId}`); return; }
|
|
4067
4066
|
const now = Date.now();
|
|
4068
4067
|
|
|
4069
|
-
// Check if the final assembled message content contains MEDIA: lines
|
|
4070
|
-
console.log('[ClawChats] saveAssistantMessage rawContent:', JSON.stringify(content.slice(0, 300)), 'rawMsgContent:', JSON.stringify(JSON.stringify(message?.content)?.slice(0, 300)));
|
|
4071
|
-
console.log('[ClawChats] saveAssistantMessage msgKeys:', Object.keys(message||{}), 'msgMediaUrls:', JSON.stringify(message?.mediaUrls), 'msgMediaUrl:', message?.mediaUrl);
|
|
4072
|
-
|
|
4073
|
-
// Extract MEDIA: paths from the final complete message content (if gateway preserves them here)
|
|
4074
|
-
let attachments = null;
|
|
4075
|
-
const mediaMatches = [...content.matchAll(/^MEDIA:\s*(\S+)/gm)].map(m => m[1].trim()).filter(p => /\.\w{1,10}$/.test(p));
|
|
4076
|
-
if (mediaMatches.length > 0) {
|
|
4077
|
-
console.log('[ClawChats] MEDIA paths from final content:', JSON.stringify(mediaMatches));
|
|
4078
|
-
attachments = mediaMatches.map(filePath => {
|
|
4079
|
-
const name = path.basename(filePath);
|
|
4080
|
-
const ext = (name.split('.').pop() || '').toLowerCase();
|
|
4081
|
-
const type = ['jpg','jpeg','png','gif','webp','svg','bmp','ico'].includes(ext) ? 'image'
|
|
4082
|
-
: ['mp3','wav','ogg','aac','m4a','flac','opus'].includes(ext) ? 'audio'
|
|
4083
|
-
: ['mp4','webm','mov','avi','mkv'].includes(ext) ? 'video' : 'file';
|
|
4084
|
-
return { path: filePath, name, type };
|
|
4085
|
-
});
|
|
4086
|
-
}
|
|
4087
|
-
|
|
4088
|
-
// Fallback: use MEDIA: paths captured from delta stream
|
|
4089
|
-
if (!attachments) {
|
|
4090
|
-
const paths = this._pendingMediaUrls.get(sessionKey);
|
|
4091
|
-
this._pendingMediaUrls.delete(sessionKey);
|
|
4092
|
-
if (paths?.length) {
|
|
4093
|
-
attachments = paths.map(filePath => {
|
|
4094
|
-
const name = path.basename(filePath);
|
|
4095
|
-
const ext = (name.split('.').pop() || '').toLowerCase();
|
|
4096
|
-
const type = ['jpg','jpeg','png','gif','webp','svg','bmp','ico'].includes(ext) ? 'image'
|
|
4097
|
-
: ['mp3','wav','ogg','aac','m4a','flac','opus'].includes(ext) ? 'audio'
|
|
4098
|
-
: ['mp4','webm','mov','avi','mkv'].includes(ext) ? 'video' : 'file';
|
|
4099
|
-
return { path: filePath, name, type };
|
|
4100
|
-
});
|
|
4101
|
-
}
|
|
4102
|
-
} else {
|
|
4103
|
-
this._pendingMediaUrls.delete(sessionKey); // clean up either way
|
|
4104
|
-
}
|
|
4105
|
-
|
|
4106
4068
|
// Check for pending activity message
|
|
4107
4069
|
const pendingMsg = db.prepare(`
|
|
4108
4070
|
SELECT id, metadata FROM messages
|
|
@@ -4122,15 +4084,13 @@ export function createApp(config = {}) {
|
|
|
4122
4084
|
if (lastAssistantIdx >= 0) metadata.activityLog.splice(lastAssistantIdx, 1);
|
|
4123
4085
|
metadata.activitySummary = this.generateActivitySummary(metadata.activityLog);
|
|
4124
4086
|
}
|
|
4125
|
-
if (attachments) metadata.attachments = attachments;
|
|
4126
4087
|
db.prepare('UPDATE messages SET content = ?, metadata = ?, timestamp = ? WHERE id = ?')
|
|
4127
4088
|
.run(content, JSON.stringify(metadata), now, pendingMsg.id);
|
|
4128
4089
|
messageId = pendingMsg.id;
|
|
4129
4090
|
} else {
|
|
4130
4091
|
// No pending activity — normal INSERT (simple responses, no tools)
|
|
4131
4092
|
messageId = seq != null ? `gw-${parsed.threadId}-${seq}` : `gw-${parsed.threadId}-${now}`;
|
|
4132
|
-
|
|
4133
|
-
db.prepare(`INSERT INTO messages (id, thread_id, role, content, status, metadata, timestamp, created_at) VALUES (?, ?, 'assistant', ?, 'sent', ?, ?, ?) ON CONFLICT(id) DO UPDATE SET content = excluded.content, metadata = COALESCE(excluded.metadata, metadata), timestamp = excluded.timestamp`).run(messageId, parsed.threadId, content, metaStr, now, now);
|
|
4093
|
+
db.prepare(`INSERT INTO messages (id, thread_id, role, content, status, timestamp, created_at) VALUES (?, ?, 'assistant', ?, 'sent', ?, ?) ON CONFLICT(id) DO UPDATE SET content = excluded.content, timestamp = excluded.timestamp`).run(messageId, parsed.threadId, content, now, now);
|
|
4134
4094
|
}
|
|
4135
4095
|
|
|
4136
4096
|
try {
|
|
@@ -4172,8 +4132,6 @@ export function createApp(config = {}) {
|
|
|
4172
4132
|
} catch (e) { console.error(`Failed to save error marker:`, e.message); }
|
|
4173
4133
|
}
|
|
4174
4134
|
|
|
4175
|
-
// _scanRecentWorkspaceFiles removed — MEDIA: paths captured from delta stream instead
|
|
4176
|
-
|
|
4177
4135
|
generateThreadTitle(db, threadId, workspace, skipHeuristic = false) {
|
|
4178
4136
|
const thread = db.prepare('SELECT title FROM threads WHERE id = ?').get(threadId);
|
|
4179
4137
|
if (!thread) return;
|
|
@@ -4224,25 +4182,7 @@ export function createApp(config = {}) {
|
|
|
4224
4182
|
if (!this.activityLogs.has(runId)) this.activityLogs.set(runId, { sessionKey, steps: [], startTime: Date.now() });
|
|
4225
4183
|
const log = this.activityLogs.get(runId);
|
|
4226
4184
|
if (stream === 'assistant') {
|
|
4227
|
-
// Check data.mediaUrls — gateway populates this via splitMediaFromOutput on each streaming event.
|
|
4228
|
-
// Partial path events (e.g. ["/"]) fail the extension filter; complete-path events pass.
|
|
4229
|
-
const incomingUrls = Array.isArray(data?.mediaUrls) ? data.mediaUrls : (data?.mediaUrl ? [data.mediaUrl] : []);
|
|
4230
|
-
for (const p of incomingUrls) {
|
|
4231
|
-
if (typeof p === 'string' && /\.\w{1,10}$/.test(p)) {
|
|
4232
|
-
if (!log._seenMediaPaths) log._seenMediaPaths = new Set();
|
|
4233
|
-
if (!log._seenMediaPaths.has(p)) {
|
|
4234
|
-
log._seenMediaPaths.add(p);
|
|
4235
|
-
if (!this._pendingMediaUrls.has(sessionKey)) this._pendingMediaUrls.set(sessionKey, []);
|
|
4236
|
-
this._pendingMediaUrls.get(sessionKey).push(p);
|
|
4237
|
-
console.log('[ClawChats] MEDIA path captured from mediaUrls:', p);
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
}
|
|
4241
|
-
if (incomingUrls.length > 0) console.log('[ClawChats] mediaUrls on event:', JSON.stringify(incomingUrls));
|
|
4242
4185
|
const text = data?.text || '';
|
|
4243
|
-
const delta = data?.delta || '';
|
|
4244
|
-
// Log if a MEDIA: directive appears in text or delta (must look like an actual path, not just the word)
|
|
4245
|
-
if (/MEDIA:\s*[./~a-zA-Z]/.test(text.slice(-80)) || /MEDIA:\s*[./~a-zA-Z]/.test(delta)) console.log('[ClawChats] MEDIA in stream! text tail:', JSON.stringify(text.slice(-80)), 'delta:', JSON.stringify(delta));
|
|
4246
4186
|
if (text) {
|
|
4247
4187
|
let currentSegment = log._currentAssistantSegment;
|
|
4248
4188
|
if (!currentSegment || currentSegment._sealed) {
|
|
@@ -4269,7 +4209,6 @@ export function createApp(config = {}) {
|
|
|
4269
4209
|
if (log._currentAssistantSegment && !log._currentAssistantSegment._sealed) { log._currentAssistantSegment._sealed = true; }
|
|
4270
4210
|
const step = { type: 'tool', timestamp: Date.now(), name: data?.name || 'unknown', phase: data?.phase || 'start', toolCallId: data?.toolCallId, meta: data?.meta, isError: data?.isError || false };
|
|
4271
4211
|
if (data?.phase === 'result') {
|
|
4272
|
-
if (data?.name === 'exec') console.log('[ClawChats] exec tool result meta:', JSON.stringify(data?.meta));
|
|
4273
4212
|
const existing = log.steps.findLast(s => s.toolCallId === data.toolCallId && (s.phase === 'start' || s.phase === 'running'));
|
|
4274
4213
|
if (existing) { existing.phase = 'done'; existing.resultMeta = data?.meta; existing.isError = data?.isError || false; existing.durationMs = Date.now() - existing.timestamp; }
|
|
4275
4214
|
else { step.phase = 'done'; log.steps.push(step); }
|
|
@@ -4282,7 +4221,6 @@ export function createApp(config = {}) {
|
|
|
4282
4221
|
}
|
|
4283
4222
|
if (stream === 'lifecycle') {
|
|
4284
4223
|
if (data?.phase === 'end' || data?.phase === 'error') {
|
|
4285
|
-
// MEDIA: paths already captured during delta streaming — nothing to do here
|
|
4286
4224
|
if (log._currentAssistantSegment && !log._currentAssistantSegment._sealed) log._currentAssistantSegment._sealed = true;
|
|
4287
4225
|
const lastAssistantIdx = log.steps.findLastIndex(s => s.type === 'assistant');
|
|
4288
4226
|
if (lastAssistantIdx >= 0) log.steps.splice(lastAssistantIdx, 1);
|
|
@@ -4609,7 +4547,7 @@ export function createApp(config = {}) {
|
|
|
4609
4547
|
}
|
|
4610
4548
|
|
|
4611
4549
|
// ── Browser WebSocket setup (shared logic for standalone and plugin) ────────
|
|
4612
|
-
|
|
4550
|
+
function _setupBrowserWs(wssInstance) {
|
|
4613
4551
|
wssInstance.on('connection', (ws) => {
|
|
4614
4552
|
console.log('Browser client connected');
|
|
4615
4553
|
_gatewayClient.addBrowserClient(ws);
|
|
@@ -4619,7 +4557,6 @@ export function createApp(config = {}) {
|
|
|
4619
4557
|
ws.on('message', (data) => {
|
|
4620
4558
|
const msgStr = data.toString();
|
|
4621
4559
|
_debugLogger.logFrame('BR→SRV', msgStr);
|
|
4622
|
-
let forwardStr = msgStr;
|
|
4623
4560
|
try {
|
|
4624
4561
|
const msg = JSON.parse(msgStr);
|
|
4625
4562
|
if (msg.type === 'req' && msg.method === 'connect') {
|
|
@@ -4639,9 +4576,8 @@ export function createApp(config = {}) {
|
|
|
4639
4576
|
if (msg.action === 'debug-start') { const result = _debugLogger.start(msg.ts, ws); if (result.error === 'already-active') ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-error', error: 'Recording already active in another tab', sessionId: result.sessionId })); else ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-started', sessionId: result.sessionId })); return; }
|
|
4640
4577
|
if (msg.action === 'debug-dump') { const { sessionId, files } = _debugLogger.saveDump(msg); ws.send(JSON.stringify({ type: 'clawchats', event: 'debug-saved', sessionId, files })); return; }
|
|
4641
4578
|
}
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
_gatewayClient.sendToGateway(forwardStr);
|
|
4579
|
+
} catch { /* Not JSON or not a ClawChats message, forward to gateway */ }
|
|
4580
|
+
_gatewayClient.sendToGateway(msgStr);
|
|
4645
4581
|
});
|
|
4646
4582
|
|
|
4647
4583
|
ws.on('close', () => { console.log('Browser client disconnected'); _debugLogger.handleClientDisconnect(ws); _gatewayClient.removeBrowserClient(ws); });
|