@wingman-ai/gateway 0.2.4 → 0.3.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/.wingman/agents/coding/agent.md +5 -0
- package/.wingman/agents/coding-v2/agent.md +58 -0
- package/.wingman/agents/game-dev/agent.md +94 -0
- package/.wingman/agents/game-dev/art-generation.md +37 -0
- package/.wingman/agents/game-dev/asset-refinement.md +17 -0
- package/.wingman/agents/game-dev/planning-idea.md +17 -0
- package/.wingman/agents/game-dev/ui-specialist.md +17 -0
- package/.wingman/agents/main/agent.md +2 -0
- package/README.md +1 -0
- package/dist/agent/config/agentConfig.d.ts +4 -0
- package/dist/agent/config/mcpClientManager.cjs +44 -10
- package/dist/agent/config/mcpClientManager.d.ts +6 -2
- package/dist/agent/config/mcpClientManager.js +44 -10
- package/dist/agent/config/toolRegistry.cjs +3 -1
- package/dist/agent/config/toolRegistry.js +3 -1
- package/dist/agent/tests/mcpClientManager.test.cjs +124 -0
- package/dist/agent/tests/mcpClientManager.test.d.ts +1 -0
- package/dist/agent/tests/mcpClientManager.test.js +118 -0
- package/dist/agent/tools/command_execute.cjs +1 -1
- package/dist/agent/tools/command_execute.js +1 -1
- package/dist/cli/config/schema.d.ts +2 -0
- package/dist/cli/core/agentInvoker.cjs +55 -66
- package/dist/cli/core/agentInvoker.d.ts +10 -13
- package/dist/cli/core/agentInvoker.js +42 -62
- package/dist/cli/core/imagePersistence.cjs +125 -0
- package/dist/cli/core/imagePersistence.d.ts +24 -0
- package/dist/cli/core/imagePersistence.js +85 -0
- package/dist/cli/core/sessionManager.cjs +297 -40
- package/dist/cli/core/sessionManager.d.ts +9 -0
- package/dist/cli/core/sessionManager.js +297 -40
- package/dist/debug/terminalProbe.cjs +57 -0
- package/dist/debug/terminalProbe.d.ts +10 -0
- package/dist/debug/terminalProbe.js +20 -0
- package/dist/debug/terminalProbeAuth.cjs +140 -0
- package/dist/debug/terminalProbeAuth.d.ts +20 -0
- package/dist/debug/terminalProbeAuth.js +97 -0
- package/dist/gateway/http/fs.cjs +19 -0
- package/dist/gateway/http/fs.js +19 -0
- package/dist/gateway/http/sessions.cjs +25 -5
- package/dist/gateway/http/sessions.js +25 -5
- package/dist/gateway/server.cjs +112 -11
- package/dist/gateway/server.d.ts +2 -0
- package/dist/gateway/server.js +112 -11
- package/dist/providers/codex.cjs +230 -37
- package/dist/providers/codex.d.ts +2 -0
- package/dist/providers/codex.js +231 -38
- package/dist/tests/agentInvokerSummarization.test.cjs +56 -37
- package/dist/tests/agentInvokerSummarization.test.js +58 -39
- package/dist/tests/agentInvokerWorkdir.test.cjs +50 -0
- package/dist/tests/agentInvokerWorkdir.test.js +52 -2
- package/dist/tests/cli-init.test.cjs +36 -0
- package/dist/tests/cli-init.test.js +36 -0
- package/dist/tests/codex-provider.test.cjs +173 -0
- package/dist/tests/codex-provider.test.js +174 -1
- package/dist/tests/falRuntime.test.cjs +78 -0
- package/dist/tests/falRuntime.test.d.ts +1 -0
- package/dist/tests/falRuntime.test.js +72 -0
- package/dist/tests/falSummary.test.cjs +51 -0
- package/dist/tests/falSummary.test.d.ts +1 -0
- package/dist/tests/falSummary.test.js +45 -0
- package/dist/tests/gateway.test.cjs +109 -1
- package/dist/tests/gateway.test.js +109 -1
- package/dist/tests/imagePersistence.test.cjs +143 -0
- package/dist/tests/imagePersistence.test.d.ts +1 -0
- package/dist/tests/imagePersistence.test.js +137 -0
- package/dist/tests/sessionMessageAttachments.test.cjs +30 -0
- package/dist/tests/sessionMessageAttachments.test.js +30 -0
- package/dist/tests/sessionStateMessages.test.cjs +126 -0
- package/dist/tests/sessionStateMessages.test.js +126 -0
- package/dist/tests/sessions-api.test.cjs +117 -3
- package/dist/tests/sessions-api.test.js +118 -4
- package/dist/tests/terminalProbe.test.cjs +45 -0
- package/dist/tests/terminalProbe.test.d.ts +1 -0
- package/dist/tests/terminalProbe.test.js +39 -0
- package/dist/tests/terminalProbeAuth.test.cjs +85 -0
- package/dist/tests/terminalProbeAuth.test.d.ts +1 -0
- package/dist/tests/terminalProbeAuth.test.js +79 -0
- package/dist/tools/fal/runtime.cjs +103 -0
- package/dist/tools/fal/runtime.d.ts +10 -0
- package/dist/tools/fal/runtime.js +60 -0
- package/dist/tools/fal/summary.cjs +78 -0
- package/dist/tools/fal/summary.d.ts +22 -0
- package/dist/tools/fal/summary.js +41 -0
- package/dist/tools/mcp-fal-ai.cjs +1041 -0
- package/dist/tools/mcp-fal-ai.d.ts +1 -0
- package/dist/tools/mcp-fal-ai.js +1025 -0
- package/dist/types/mcp.cjs +2 -0
- package/dist/types/mcp.d.ts +8 -0
- package/dist/types/mcp.js +3 -1
- package/dist/webui/assets/index-0nUBsUUq.js +278 -0
- package/dist/webui/assets/index-kk7OrD-G.css +11 -0
- package/dist/webui/index.html +2 -2
- package/package.json +16 -13
- package/dist/webui/assets/index-DVWQluit.css +0 -11
- package/dist/webui/assets/index-Dlyzwalc.js +0 -270
|
@@ -34,6 +34,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
34
34
|
const langgraph_checkpoint_sqlite_namespaceObject = require("@langchain/langgraph-checkpoint-sqlite");
|
|
35
35
|
const external_deepagents_namespaceObject = require("deepagents");
|
|
36
36
|
const external_uuid_namespaceObject = require("uuid");
|
|
37
|
+
const external_imagePersistence_cjs_namespaceObject = require("./imagePersistence.cjs");
|
|
37
38
|
function _define_property(obj, key, value) {
|
|
38
39
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
39
40
|
value: value,
|
|
@@ -54,9 +55,9 @@ class SessionManager {
|
|
|
54
55
|
await this.checkpointer.setup();
|
|
55
56
|
this.db = adapter.db;
|
|
56
57
|
this.db.run(`
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
59
|
+
id TEXT PRIMARY KEY,
|
|
60
|
+
name TEXT NOT NULL,
|
|
60
61
|
agent_name TEXT NOT NULL,
|
|
61
62
|
created_at INTEGER NOT NULL,
|
|
62
63
|
updated_at INTEGER NOT NULL,
|
|
@@ -66,11 +67,24 @@ class SessionManager {
|
|
|
66
67
|
metadata TEXT
|
|
67
68
|
);
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_agent ON sessions(agent_name);
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_updated ON sessions(status, updated_at DESC);
|
|
73
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_agent_updated ON sessions(status, agent_name, updated_at DESC);
|
|
74
|
+
|
|
75
|
+
CREATE TABLE IF NOT EXISTS session_pending_messages (
|
|
76
|
+
id TEXT PRIMARY KEY,
|
|
77
|
+
session_id TEXT NOT NULL,
|
|
78
|
+
request_id TEXT NOT NULL,
|
|
79
|
+
role TEXT NOT NULL,
|
|
80
|
+
content TEXT NOT NULL,
|
|
81
|
+
attachments TEXT,
|
|
82
|
+
created_at INTEGER NOT NULL
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
CREATE INDEX IF NOT EXISTS idx_pending_messages_session_created ON session_pending_messages(session_id, created_at ASC);
|
|
86
|
+
CREATE INDEX IF NOT EXISTS idx_pending_messages_session_request ON session_pending_messages(session_id, request_id);
|
|
87
|
+
`);
|
|
74
88
|
}
|
|
75
89
|
createSession(agentName, name) {
|
|
76
90
|
if (!this.db) throw new Error("SessionManager not initialized");
|
|
@@ -211,6 +225,8 @@ class SessionManager {
|
|
|
211
225
|
checkpointStmt.run(sessionId);
|
|
212
226
|
const writesStmt = this.db.prepare("DELETE FROM writes WHERE thread_id = ?");
|
|
213
227
|
writesStmt.run(sessionId);
|
|
228
|
+
const pendingStmt = this.db.prepare("DELETE FROM session_pending_messages WHERE session_id = ?");
|
|
229
|
+
pendingStmt.run(sessionId);
|
|
214
230
|
}
|
|
215
231
|
clearSessionMessages(sessionId) {
|
|
216
232
|
if (!this.db || !this.checkpointer) throw new Error("SessionManager not initialized");
|
|
@@ -218,21 +234,52 @@ class SessionManager {
|
|
|
218
234
|
checkpointStmt.run(sessionId);
|
|
219
235
|
const writesStmt = this.db.prepare("DELETE FROM writes WHERE thread_id = ?");
|
|
220
236
|
writesStmt.run(sessionId);
|
|
237
|
+
const pendingStmt = this.db.prepare("DELETE FROM session_pending_messages WHERE session_id = ?");
|
|
238
|
+
pendingStmt.run(sessionId);
|
|
221
239
|
const sessionStmt = this.db.prepare(`
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
240
|
+
UPDATE sessions
|
|
241
|
+
SET message_count = 0, last_message_preview = NULL, updated_at = ?
|
|
242
|
+
WHERE id = ?
|
|
243
|
+
`);
|
|
226
244
|
sessionStmt.run(Date.now(), sessionId);
|
|
227
245
|
}
|
|
246
|
+
persistPendingMessage(input) {
|
|
247
|
+
if (!this.db) throw new Error("SessionManager not initialized");
|
|
248
|
+
const attachments = Array.isArray(input.message.attachments) && input.message.attachments.length > 0 ? JSON.stringify(input.message.attachments) : null;
|
|
249
|
+
const stmt = this.db.prepare(`
|
|
250
|
+
INSERT INTO session_pending_messages (
|
|
251
|
+
id, session_id, request_id, role, content, attachments, created_at
|
|
252
|
+
)
|
|
253
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
254
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
255
|
+
role = excluded.role,
|
|
256
|
+
content = excluded.content,
|
|
257
|
+
attachments = excluded.attachments,
|
|
258
|
+
created_at = excluded.created_at
|
|
259
|
+
`);
|
|
260
|
+
stmt.run(input.message.id, input.sessionId, input.requestId, input.message.role, input.message.content || "", attachments, input.message.createdAt);
|
|
261
|
+
}
|
|
262
|
+
clearPendingMessagesForRequest(sessionId, requestId) {
|
|
263
|
+
if (!this.db) throw new Error("SessionManager not initialized");
|
|
264
|
+
const stmt = this.db.prepare(`
|
|
265
|
+
DELETE FROM session_pending_messages
|
|
266
|
+
WHERE session_id = ? AND request_id = ?
|
|
267
|
+
`);
|
|
268
|
+
stmt.run(sessionId, requestId);
|
|
269
|
+
}
|
|
228
270
|
getCheckpointer() {
|
|
229
271
|
if (!this.checkpointer) throw new Error("SessionManager not initialized");
|
|
230
272
|
return this.checkpointer;
|
|
231
273
|
}
|
|
232
274
|
async listMessages(sessionId) {
|
|
233
275
|
if (!this.checkpointer) throw new Error("SessionManager not initialized");
|
|
276
|
+
const pendingMessages = this.listPendingMessages(sessionId);
|
|
234
277
|
const stateMessages = await this.loadMessagesFromState(sessionId);
|
|
235
|
-
if (null !== stateMessages)
|
|
278
|
+
if (null !== stateMessages) {
|
|
279
|
+
const mergedStateMessages = mergePendingMessages(stateMessages, pendingMessages);
|
|
280
|
+
this.persistAssistantImageAttachments(sessionId, mergedStateMessages);
|
|
281
|
+
return mergedStateMessages;
|
|
282
|
+
}
|
|
236
283
|
const rawCheckpoints = this.loadRecentCheckpoints(sessionId, 25);
|
|
237
284
|
const fallbackTuple = 0 === rawCheckpoints.length ? await this.checkpointer.getTuple({
|
|
238
285
|
configurable: {
|
|
@@ -245,7 +292,10 @@ class SessionManager {
|
|
|
245
292
|
fallbackTuple.checkpoint
|
|
246
293
|
] : []
|
|
247
294
|
];
|
|
248
|
-
if (0 === checkpoints.length)
|
|
295
|
+
if (0 === checkpoints.length) {
|
|
296
|
+
this.persistAssistantImageAttachments(sessionId, pendingMessages);
|
|
297
|
+
return pendingMessages;
|
|
298
|
+
}
|
|
249
299
|
let bestScore = -1;
|
|
250
300
|
let bestMessages = [];
|
|
251
301
|
for (const checkpoint of checkpoints){
|
|
@@ -263,8 +313,14 @@ class SessionManager {
|
|
|
263
313
|
bestMessages = scored[0].messages;
|
|
264
314
|
}
|
|
265
315
|
}
|
|
266
|
-
if (0 === bestMessages.length)
|
|
267
|
-
|
|
316
|
+
if (0 === bestMessages.length) {
|
|
317
|
+
this.persistAssistantImageAttachments(sessionId, pendingMessages);
|
|
318
|
+
return pendingMessages;
|
|
319
|
+
}
|
|
320
|
+
const filteredMessages = filterEmptyAssistantMessages(bestMessages);
|
|
321
|
+
const mergedMessages = mergePendingMessages(filteredMessages, pendingMessages);
|
|
322
|
+
this.persistAssistantImageAttachments(sessionId, mergedMessages);
|
|
323
|
+
return mergedMessages;
|
|
268
324
|
}
|
|
269
325
|
rowToSession(row) {
|
|
270
326
|
return {
|
|
@@ -329,6 +385,36 @@ class SessionManager {
|
|
|
329
385
|
return null;
|
|
330
386
|
}
|
|
331
387
|
}
|
|
388
|
+
persistAssistantImageAttachments(sessionId, messages) {
|
|
389
|
+
try {
|
|
390
|
+
(0, external_imagePersistence_cjs_namespaceObject.persistAssistantImagesToDisk)({
|
|
391
|
+
dbPath: this.dbPath,
|
|
392
|
+
sessionId,
|
|
393
|
+
messages: messages
|
|
394
|
+
});
|
|
395
|
+
} catch {}
|
|
396
|
+
}
|
|
397
|
+
listPendingMessages(sessionId) {
|
|
398
|
+
if (!this.db) return [];
|
|
399
|
+
const stmt = this.db.prepare(`
|
|
400
|
+
SELECT id, role, content, attachments, created_at
|
|
401
|
+
FROM session_pending_messages
|
|
402
|
+
WHERE session_id = ?
|
|
403
|
+
ORDER BY created_at ASC, rowid ASC
|
|
404
|
+
`);
|
|
405
|
+
const rows = stmt.all(sessionId);
|
|
406
|
+
if (!rows.length) return [];
|
|
407
|
+
return rows.map((row)=>{
|
|
408
|
+
const attachments = parseSessionAttachments(row.attachments);
|
|
409
|
+
return {
|
|
410
|
+
id: row.id,
|
|
411
|
+
role: row.role,
|
|
412
|
+
content: row.content || "",
|
|
413
|
+
attachments,
|
|
414
|
+
createdAt: row.created_at || Date.now()
|
|
415
|
+
};
|
|
416
|
+
}).filter((message)=>"user" === message.role || message.content.trim().length > 0 || (message.attachments?.length || 0) > 0);
|
|
417
|
+
}
|
|
332
418
|
constructor(dbPath){
|
|
333
419
|
_define_property(this, "checkpointer", null);
|
|
334
420
|
_define_property(this, "stateReaderAgent", null);
|
|
@@ -337,6 +423,50 @@ class SessionManager {
|
|
|
337
423
|
this.dbPath = dbPath;
|
|
338
424
|
}
|
|
339
425
|
}
|
|
426
|
+
function mergePendingMessages(persisted, pending) {
|
|
427
|
+
if (0 === pending.length) return persisted;
|
|
428
|
+
if (0 === persisted.length) return pending;
|
|
429
|
+
const merged = [
|
|
430
|
+
...persisted
|
|
431
|
+
];
|
|
432
|
+
for (const candidate of pending){
|
|
433
|
+
const duplicate = merged.some((message)=>isLikelyDuplicateMessage(message, candidate));
|
|
434
|
+
if (!duplicate) merged.push(candidate);
|
|
435
|
+
}
|
|
436
|
+
merged.sort((a, b)=>{
|
|
437
|
+
if (a.createdAt === b.createdAt) {
|
|
438
|
+
if (a.role === b.role) return 0;
|
|
439
|
+
return "user" === a.role ? -1 : 1;
|
|
440
|
+
}
|
|
441
|
+
return a.createdAt - b.createdAt;
|
|
442
|
+
});
|
|
443
|
+
return merged;
|
|
444
|
+
}
|
|
445
|
+
function isLikelyDuplicateMessage(left, right) {
|
|
446
|
+
if (left.id && right.id && left.id === right.id) return true;
|
|
447
|
+
if (left.role !== right.role) return false;
|
|
448
|
+
if ((left.content || "").trim() !== (right.content || "").trim()) return false;
|
|
449
|
+
const leftAttachments = left.attachments || [];
|
|
450
|
+
const rightAttachments = right.attachments || [];
|
|
451
|
+
if (leftAttachments.length !== rightAttachments.length) return false;
|
|
452
|
+
for(let index = 0; index < leftAttachments.length; index += 1)if (!isAttachmentEquivalent(leftAttachments[index], rightAttachments[index])) return false;
|
|
453
|
+
return Math.abs((left.createdAt || 0) - (right.createdAt || 0)) < 30000;
|
|
454
|
+
}
|
|
455
|
+
function isAttachmentEquivalent(left, right) {
|
|
456
|
+
if (!left || !right) return left === right;
|
|
457
|
+
return left.kind === right.kind && (left.dataUrl || "") === (right.dataUrl || "") && (left.name || "") === (right.name || "") && (left.mimeType || "") === (right.mimeType || "") && (left.size || 0) === (right.size || 0);
|
|
458
|
+
}
|
|
459
|
+
function parseSessionAttachments(raw) {
|
|
460
|
+
if (!raw) return;
|
|
461
|
+
try {
|
|
462
|
+
const parsed = JSON.parse(raw);
|
|
463
|
+
if (!Array.isArray(parsed)) return;
|
|
464
|
+
const attachments = parsed.filter((item)=>item && "object" == typeof item && "string" == typeof item.kind && "string" == typeof item.dataUrl);
|
|
465
|
+
return attachments.length > 0 ? attachments : void 0;
|
|
466
|
+
} catch {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
340
470
|
function isMessageLike(entry) {
|
|
341
471
|
if (!entry || "object" != typeof entry) return false;
|
|
342
472
|
return "string" == typeof entry.role || "string" == typeof entry.type || "string" == typeof entry?.kwargs?.role || "string" == typeof entry?.additional_kwargs?.role;
|
|
@@ -348,22 +478,30 @@ function toSessionMessage(entry, index, baseTime) {
|
|
|
348
478
|
const role = resolveMessageRole(entry);
|
|
349
479
|
if ("user" !== role && "assistant" !== role) {
|
|
350
480
|
if (isToolMessage(entry)) {
|
|
351
|
-
const
|
|
481
|
+
const blocks = extractContentBlocks(entry);
|
|
482
|
+
const toolContent = extractMessageContent(entry, blocks);
|
|
352
483
|
const ui = extractUiFromPayload(toolContent);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
484
|
+
const attachments = extractAttachments(blocks);
|
|
485
|
+
if (ui?.spec || attachments.length > 0) {
|
|
486
|
+
const content = toolContent || ui?.textFallback || "";
|
|
487
|
+
return {
|
|
488
|
+
id: `msg-${index}`,
|
|
489
|
+
role: "assistant",
|
|
490
|
+
content,
|
|
491
|
+
attachments: attachments.length > 0 ? attachments : void 0,
|
|
492
|
+
createdAt: baseTime + index,
|
|
493
|
+
...ui?.spec ? {
|
|
494
|
+
uiBlocks: [
|
|
495
|
+
{
|
|
496
|
+
spec: ui.spec,
|
|
497
|
+
uiOnly: ui.uiOnly,
|
|
498
|
+
textFallback: ui.textFallback
|
|
499
|
+
}
|
|
500
|
+
],
|
|
501
|
+
uiTextFallback: ui.textFallback
|
|
502
|
+
} : {}
|
|
503
|
+
};
|
|
504
|
+
}
|
|
367
505
|
}
|
|
368
506
|
return null;
|
|
369
507
|
}
|
|
@@ -402,11 +540,59 @@ function extractContentBlocks(entry) {
|
|
|
402
540
|
entry?.content,
|
|
403
541
|
entry?.kwargs?.content,
|
|
404
542
|
entry?.additional_kwargs?.content,
|
|
405
|
-
entry?.data?.content
|
|
543
|
+
entry?.data?.content,
|
|
544
|
+
entry?.artifact,
|
|
545
|
+
entry?.kwargs?.artifact,
|
|
546
|
+
entry?.additional_kwargs?.artifact,
|
|
547
|
+
entry?.data?.artifact
|
|
548
|
+
];
|
|
549
|
+
for (const candidate of candidates){
|
|
550
|
+
const blocks = extractContentBlocksFromValue(candidate);
|
|
551
|
+
if (blocks.length > 0) return blocks;
|
|
552
|
+
}
|
|
553
|
+
return [];
|
|
554
|
+
}
|
|
555
|
+
function extractContentBlocksFromValue(value, depth = 0) {
|
|
556
|
+
if (depth > 5 || null == value) return [];
|
|
557
|
+
if (Array.isArray(value)) {
|
|
558
|
+
const unwrapped = [];
|
|
559
|
+
for (const item of value){
|
|
560
|
+
const parsedBlocks = extractBlocksFromTextLikeItem(item, depth + 1);
|
|
561
|
+
if (parsedBlocks.length > 0) {
|
|
562
|
+
unwrapped.push(...parsedBlocks);
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
unwrapped.push(item);
|
|
566
|
+
}
|
|
567
|
+
return unwrapped;
|
|
568
|
+
}
|
|
569
|
+
if ("string" == typeof value) {
|
|
570
|
+
const parsed = tryParseJsonPayload(value);
|
|
571
|
+
return parsed ? extractContentBlocksFromValue(parsed, depth + 1) : [];
|
|
572
|
+
}
|
|
573
|
+
if ("object" != typeof value) return [];
|
|
574
|
+
const record = value;
|
|
575
|
+
const candidates = [
|
|
576
|
+
record.content,
|
|
577
|
+
record?.kwargs?.content,
|
|
578
|
+
record?.additional_kwargs?.content,
|
|
579
|
+
record?.data?.content
|
|
406
580
|
];
|
|
407
|
-
for (const candidate of candidates)
|
|
581
|
+
for (const candidate of candidates){
|
|
582
|
+
const blocks = extractContentBlocksFromValue(candidate, depth + 1);
|
|
583
|
+
if (blocks.length > 0) return blocks;
|
|
584
|
+
}
|
|
408
585
|
return [];
|
|
409
586
|
}
|
|
587
|
+
function extractBlocksFromTextLikeItem(value, depth = 0) {
|
|
588
|
+
if (!value || "object" != typeof value || Array.isArray(value)) return [];
|
|
589
|
+
const record = value;
|
|
590
|
+
const text = "string" == typeof record.text ? record.text : "string" == typeof record.value && isTextLikeContentType(record.type) ? record.value : "string" == typeof record.output_text ? record.output_text : "string" == typeof record.input_text ? record.input_text : null;
|
|
591
|
+
if (!text) return [];
|
|
592
|
+
const parsed = tryParseJsonPayload(text);
|
|
593
|
+
if (!parsed) return [];
|
|
594
|
+
return extractContentBlocksFromValue(parsed, depth + 1);
|
|
595
|
+
}
|
|
410
596
|
function extractMessageContent(entry, blocks = []) {
|
|
411
597
|
if (!entry || "object" != typeof entry) return "";
|
|
412
598
|
const candidates = [
|
|
@@ -424,18 +610,63 @@ function extractMessageContent(entry, blocks = []) {
|
|
|
424
610
|
}
|
|
425
611
|
function extractTextContent(value, depth = 0) {
|
|
426
612
|
if (depth > 5 || null == value) return "";
|
|
427
|
-
if ("string" == typeof value)
|
|
613
|
+
if ("string" == typeof value) {
|
|
614
|
+
const parsed = tryParseJsonPayload(value);
|
|
615
|
+
if (null !== parsed) {
|
|
616
|
+
const extracted = extractTextContent(parsed, depth + 1).trim();
|
|
617
|
+
if (extracted) return extracted;
|
|
618
|
+
}
|
|
619
|
+
return value;
|
|
620
|
+
}
|
|
428
621
|
if (Array.isArray(value)) return value.map((entry)=>extractTextContent(entry, depth + 1)).filter((entry)=>entry.length > 0).join("");
|
|
429
622
|
if ("object" != typeof value) return "";
|
|
430
623
|
const record = value;
|
|
431
|
-
if ("string" == typeof record.text)
|
|
624
|
+
if ("string" == typeof record.text) {
|
|
625
|
+
const parsed = tryParseJsonPayload(record.text);
|
|
626
|
+
if (null !== parsed) {
|
|
627
|
+
const extracted = extractTextContent(parsed, depth + 1).trim();
|
|
628
|
+
if (extracted) return extracted;
|
|
629
|
+
}
|
|
630
|
+
return record.text;
|
|
631
|
+
}
|
|
432
632
|
if (record.text && "object" == typeof record.text && "string" == typeof record.text.value) return record.text.value;
|
|
433
|
-
if ("string" == typeof record.output_text)
|
|
434
|
-
|
|
435
|
-
|
|
633
|
+
if ("string" == typeof record.output_text) {
|
|
634
|
+
const parsed = tryParseJsonPayload(record.output_text);
|
|
635
|
+
if (null !== parsed) {
|
|
636
|
+
const extracted = extractTextContent(parsed, depth + 1).trim();
|
|
637
|
+
if (extracted) return extracted;
|
|
638
|
+
}
|
|
639
|
+
return record.output_text;
|
|
640
|
+
}
|
|
641
|
+
if ("string" == typeof record.input_text) {
|
|
642
|
+
const parsed = tryParseJsonPayload(record.input_text);
|
|
643
|
+
if (null !== parsed) {
|
|
644
|
+
const extracted = extractTextContent(parsed, depth + 1).trim();
|
|
645
|
+
if (extracted) return extracted;
|
|
646
|
+
}
|
|
647
|
+
return record.input_text;
|
|
648
|
+
}
|
|
649
|
+
if ("string" == typeof record.value && isTextLikeContentType(record.type)) {
|
|
650
|
+
const parsed = tryParseJsonPayload(record.value);
|
|
651
|
+
if (null !== parsed) {
|
|
652
|
+
const extracted = extractTextContent(parsed, depth + 1).trim();
|
|
653
|
+
if (extracted) return extracted;
|
|
654
|
+
}
|
|
655
|
+
return record.value;
|
|
656
|
+
}
|
|
436
657
|
if ("content" in record) return extractTextContent(record.content, depth + 1);
|
|
437
658
|
return "";
|
|
438
659
|
}
|
|
660
|
+
function tryParseJsonPayload(value) {
|
|
661
|
+
const trimmed = value.trim();
|
|
662
|
+
if (!trimmed) return null;
|
|
663
|
+
if (!(trimmed.startsWith("{") || trimmed.startsWith("["))) return null;
|
|
664
|
+
try {
|
|
665
|
+
return JSON.parse(trimmed);
|
|
666
|
+
} catch {
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
439
670
|
function isTextLikeContentType(type) {
|
|
440
671
|
if ("string" != typeof type) return false;
|
|
441
672
|
const normalized = type.toLowerCase();
|
|
@@ -454,10 +685,12 @@ function filterUiOnlyAssistantMessages(messages) {
|
|
|
454
685
|
let pendingFallback = null;
|
|
455
686
|
for (const entry of messages){
|
|
456
687
|
if (isToolMessage(entry)) {
|
|
457
|
-
const
|
|
688
|
+
const blocks = extractContentBlocks(entry);
|
|
689
|
+
const content = extractMessageContent(entry, blocks);
|
|
458
690
|
const ui = extractUiFromPayload(content);
|
|
691
|
+
const attachments = extractAttachments(blocks);
|
|
459
692
|
if (ui?.uiOnly && ui?.textFallback) pendingFallback = ui.textFallback.trim();
|
|
460
|
-
if (ui?.spec) filtered.push(entry);
|
|
693
|
+
if (ui?.spec || attachments.length > 0) filtered.push(entry);
|
|
461
694
|
continue;
|
|
462
695
|
}
|
|
463
696
|
const role = resolveMessageRole(entry);
|
|
@@ -537,6 +770,30 @@ function extractImageUrl(block) {
|
|
|
537
770
|
const data = block.source.data;
|
|
538
771
|
if (mediaType && data) return `data:${mediaType};base64,${data}`;
|
|
539
772
|
}
|
|
773
|
+
if ("image" === block.type) {
|
|
774
|
+
const sourceType = block.source_type || block.sourceType;
|
|
775
|
+
const mimeType = block.mime_type || block.mimeType || block.media_type || block.mediaType || "image/png";
|
|
776
|
+
if ("base64" === sourceType && "string" == typeof block.data) return `data:${mimeType};base64,${block.data}`;
|
|
777
|
+
if ("url" === sourceType && "string" == typeof block.url) return block.url;
|
|
778
|
+
if ("string" == typeof block.data) return `data:${mimeType};base64,${block.data}`;
|
|
779
|
+
}
|
|
780
|
+
if ("output_image" === block.type) {
|
|
781
|
+
if ("string" == typeof block.image_url) return block.image_url;
|
|
782
|
+
if ("string" == typeof block.image_url?.url) return block.image_url.url;
|
|
783
|
+
if ("string" == typeof block.url) return block.url;
|
|
784
|
+
}
|
|
785
|
+
if ("resource_link" === block.type) {
|
|
786
|
+
const mimeType = "string" == typeof block.mimeType ? block.mimeType.trim().toLowerCase() : "";
|
|
787
|
+
const uri = "string" == typeof block.uri ? block.uri.trim() : "";
|
|
788
|
+
if (uri && (!mimeType || mimeType.startsWith("image/"))) return uri;
|
|
789
|
+
}
|
|
790
|
+
if ("resource" === block.type && block.resource) {
|
|
791
|
+
const resource = block.resource;
|
|
792
|
+
const mimeType = "string" == typeof resource.mimeType ? resource.mimeType.trim().toLowerCase() : "";
|
|
793
|
+
if (!mimeType || !mimeType.startsWith("image/")) return null;
|
|
794
|
+
if ("string" == typeof resource.blob && resource.blob.trim()) return `data:${mimeType};base64,${resource.blob.trim()}`;
|
|
795
|
+
if ("string" == typeof resource.uri && resource.uri.trim()) return resource.uri.trim();
|
|
796
|
+
}
|
|
540
797
|
return null;
|
|
541
798
|
}
|
|
542
799
|
function extractAudioUrl(block) {
|
|
@@ -35,6 +35,7 @@ export interface SessionAttachment {
|
|
|
35
35
|
name?: string;
|
|
36
36
|
mimeType?: string;
|
|
37
37
|
size?: number;
|
|
38
|
+
path?: string;
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* SessionManager handles session metadata and provides unified access to
|
|
@@ -90,6 +91,12 @@ export declare class SessionManager {
|
|
|
90
91
|
* Clear session messages while preserving the session record
|
|
91
92
|
*/
|
|
92
93
|
clearSessionMessages(sessionId: string): void;
|
|
94
|
+
persistPendingMessage(input: {
|
|
95
|
+
sessionId: string;
|
|
96
|
+
requestId: string;
|
|
97
|
+
message: SessionMessage;
|
|
98
|
+
}): void;
|
|
99
|
+
clearPendingMessagesForRequest(sessionId: string, requestId: string): void;
|
|
93
100
|
/**
|
|
94
101
|
* Get the checkpointer for use with DeepAgents
|
|
95
102
|
*/
|
|
@@ -109,6 +116,8 @@ export declare class SessionManager {
|
|
|
109
116
|
private loadRecentCheckpoints;
|
|
110
117
|
private getStateReaderAgent;
|
|
111
118
|
private loadMessagesFromState;
|
|
119
|
+
private persistAssistantImageAttachments;
|
|
120
|
+
private listPendingMessages;
|
|
112
121
|
}
|
|
113
122
|
export declare function extractMessagesFromState(state: any): SessionMessage[] | null;
|
|
114
123
|
export declare function extractAttachments(blocks: any[]): SessionAttachment[];
|