@datalayer/agent-runtimes 1.5.15 → 1.5.16
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.
|
@@ -32,6 +32,8 @@ import { useCoreStore } from '@datalayer/core';
|
|
|
32
32
|
import { DEFAULT_SERVICE_URLS } from '@datalayer/core/lib/api/constants';
|
|
33
33
|
import { useChatStore } from '../../stores/chatStore';
|
|
34
34
|
import { useConversationStore } from '../../stores/conversationStore';
|
|
35
|
+
import { askedOf } from '../../apps/apps/records';
|
|
36
|
+
import { extractChatMessagesFromFullContext } from './fullContextMessages';
|
|
35
37
|
import { generateMessageId, createUserMessage, createAssistantMessage, } from '../../types/messages';
|
|
36
38
|
import { AI_MODEL_CATALOGUE, DEFAULT_MODEL, isChatModel, } from '../../specs/models';
|
|
37
39
|
import { internalQueryClient, isToolCallMessage, convertHistoryToDisplayItems, createProtocolAdapter, getApiBaseFromConfig, sanitizeAssistantContent, } from '../../utils';
|
|
@@ -315,99 +317,6 @@ function formatToolResultFallback(result) {
|
|
|
315
317
|
return 'Tool completed successfully.';
|
|
316
318
|
}
|
|
317
319
|
}
|
|
318
|
-
function extractChatMessagesFromFullContext(fullContext) {
|
|
319
|
-
if (!fullContext) {
|
|
320
|
-
return [];
|
|
321
|
-
}
|
|
322
|
-
const rawMessages = Array.isArray(fullContext.messages)
|
|
323
|
-
? fullContext.messages
|
|
324
|
-
: [];
|
|
325
|
-
return rawMessages
|
|
326
|
-
.map((msg, index) => {
|
|
327
|
-
const role = String(msg.role || '').toLowerCase();
|
|
328
|
-
const timestampValue = typeof msg.timestamp === 'string' && msg.timestamp.length > 0
|
|
329
|
-
? msg.timestamp
|
|
330
|
-
: new Date().toISOString();
|
|
331
|
-
const createdAtRaw = new Date(timestampValue);
|
|
332
|
-
const createdAt = Number.isNaN(createdAtRaw.getTime())
|
|
333
|
-
? new Date()
|
|
334
|
-
: createdAtRaw;
|
|
335
|
-
const rawContent = typeof msg.content === 'string'
|
|
336
|
-
? msg.content
|
|
337
|
-
: JSON.stringify(msg.content ?? '');
|
|
338
|
-
const isToolCall = Boolean(msg.isToolCall);
|
|
339
|
-
const isToolResult = Boolean(msg.isToolResult);
|
|
340
|
-
const toolCallId = typeof msg.toolCallId === 'string' && msg.toolCallId.length > 0
|
|
341
|
-
? msg.toolCallId
|
|
342
|
-
: undefined;
|
|
343
|
-
const toolName = typeof msg.toolName === 'string' && msg.toolName.length > 0
|
|
344
|
-
? msg.toolName
|
|
345
|
-
: undefined;
|
|
346
|
-
// Tool-call turns arrive as assistant messages whose `content` is the
|
|
347
|
-
// JSON-encoded tool arguments. Reconstruct a structured `toolCalls`
|
|
348
|
-
// entry so it renders as a tool card (matching the live stream) instead
|
|
349
|
-
// of leaking raw JSON into the transcript.
|
|
350
|
-
if (isToolCall) {
|
|
351
|
-
let args = {};
|
|
352
|
-
if (rawContent) {
|
|
353
|
-
try {
|
|
354
|
-
const parsed = JSON.parse(rawContent);
|
|
355
|
-
if (parsed &&
|
|
356
|
-
typeof parsed === 'object' &&
|
|
357
|
-
!Array.isArray(parsed)) {
|
|
358
|
-
args = parsed;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
catch {
|
|
362
|
-
args = {};
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
const resolvedToolCallId = toolCallId || `history-tc-${index}`;
|
|
366
|
-
return {
|
|
367
|
-
id: `history-toolcall-${index}-${timestampValue}`,
|
|
368
|
-
role: 'assistant',
|
|
369
|
-
content: '',
|
|
370
|
-
createdAt,
|
|
371
|
-
toolCalls: [
|
|
372
|
-
{
|
|
373
|
-
type: 'tool-call',
|
|
374
|
-
toolCallId: resolvedToolCallId,
|
|
375
|
-
toolName: toolName || 'tool',
|
|
376
|
-
args,
|
|
377
|
-
status: 'completed',
|
|
378
|
-
},
|
|
379
|
-
],
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
// Tool results arrive as `role: 'tool'` messages; keep them (with the
|
|
383
|
-
// matching toolCallId) so `convertHistoryToDisplayItems` can merge the
|
|
384
|
-
// result into its tool card.
|
|
385
|
-
if (isToolResult || role === 'tool') {
|
|
386
|
-
return {
|
|
387
|
-
id: `history-toolresult-${index}-${timestampValue}`,
|
|
388
|
-
role: 'tool',
|
|
389
|
-
content: rawContent,
|
|
390
|
-
createdAt,
|
|
391
|
-
metadata: {
|
|
392
|
-
toolCallId,
|
|
393
|
-
toolName,
|
|
394
|
-
},
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
// Only hydrate conversational turns in the visible history.
|
|
398
|
-
// System messages may contain internal prompts and metadata.
|
|
399
|
-
if (role !== 'user' && role !== 'assistant') {
|
|
400
|
-
return null;
|
|
401
|
-
}
|
|
402
|
-
return {
|
|
403
|
-
id: `history-${role}-${index}-${timestampValue}`,
|
|
404
|
-
role,
|
|
405
|
-
content: rawContent,
|
|
406
|
-
createdAt,
|
|
407
|
-
};
|
|
408
|
-
})
|
|
409
|
-
.filter((m) => m !== null);
|
|
410
|
-
}
|
|
411
320
|
function parseEnabledMcpToolsByServer(mcpStatusData) {
|
|
412
321
|
if (!mcpStatusData || typeof mcpStatusData !== 'object') {
|
|
413
322
|
return null;
|
|
@@ -3867,7 +3776,9 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
|
|
|
3867
3776
|
typingSuggestions: resolvedSuggestions?.map(item => item.message || item.title), autoFocus: autoFocus, focusTrigger: focusTrigger, padding: padding, onSend: () => handleSend(), onStop: handleStop, disableInputPrompt: disableInputPrompt || disabled || !!overlay || launching, promptVariant: promptVariant, mentionableAgents: mentionableAgents, promptCommands: promptCommands,
|
|
3868
3777
|
// The runtime's memory of what was sent to this agent, for the arrow
|
|
3869
3778
|
// keys — part of the same initial state as the models and tools.
|
|
3870
|
-
|
|
3779
|
+
// Without what the runtime told the application before a personal
|
|
3780
|
+
// agent's request (`askedOf`): the person never wrote it.
|
|
3781
|
+
promptHistory: configQuery.data?.promptHistory?.map(askedOf), showTokenUsage: showTokenUsage, showContextRing: showContextRing, agentUsage: agentUsage, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, isA2AProtocol: isA2AProtocol, showAgentsMenu: showAgentsMenu, agents: footerAgents, selectedAgentId: selectedAgentId ?? footerAgents[0]?.id, onSelectAgent: onSelectAgent, hasConfigData: !!configQuery.data, hasSkillsData: !!skillsQuery.data,
|
|
3871
3782
|
// So the bar can tell "not here yet" from "not coming": a chat whose
|
|
3872
3783
|
// agent has no config endpoint waits for ever otherwise.
|
|
3873
3784
|
configLoading: configQuery.isLoading, models: offeredModels,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A chat's conversation as the runtime's agent holds it (`fullContext`, from
|
|
7
|
+
* the `agent.snapshot` it sends), drawn as messages — kept out of `ChatBase`
|
|
8
|
+
* so it can be read and tested without rendering a chat.
|
|
9
|
+
*
|
|
10
|
+
* A shipped application's page opens on this conversation, so a turn a
|
|
11
|
+
* personal agent asked over PAP or PACT is drawn through `askedOf`: the
|
|
12
|
+
* preamble the runtime told the application (`<asked-for>…</asked-for>`) is
|
|
13
|
+
* kept in the record for the builder and never shown to the person.
|
|
14
|
+
*/
|
|
15
|
+
import { askedOf } from '../../apps/apps/records';
|
|
16
|
+
export function extractChatMessagesFromFullContext(fullContext) {
|
|
17
|
+
if (!fullContext) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const rawMessages = Array.isArray(fullContext.messages)
|
|
21
|
+
? fullContext.messages
|
|
22
|
+
: [];
|
|
23
|
+
return rawMessages
|
|
24
|
+
.map((msg, index) => {
|
|
25
|
+
const role = String(msg.role || '').toLowerCase();
|
|
26
|
+
const timestampValue = typeof msg.timestamp === 'string' && msg.timestamp.length > 0
|
|
27
|
+
? msg.timestamp
|
|
28
|
+
: new Date().toISOString();
|
|
29
|
+
const createdAtRaw = new Date(timestampValue);
|
|
30
|
+
const createdAt = Number.isNaN(createdAtRaw.getTime())
|
|
31
|
+
? new Date()
|
|
32
|
+
: createdAtRaw;
|
|
33
|
+
const rawContent = typeof msg.content === 'string'
|
|
34
|
+
? msg.content
|
|
35
|
+
: JSON.stringify(msg.content ?? '');
|
|
36
|
+
const isToolCall = Boolean(msg.isToolCall);
|
|
37
|
+
const isToolResult = Boolean(msg.isToolResult);
|
|
38
|
+
const toolCallId = typeof msg.toolCallId === 'string' && msg.toolCallId.length > 0
|
|
39
|
+
? msg.toolCallId
|
|
40
|
+
: undefined;
|
|
41
|
+
const toolName = typeof msg.toolName === 'string' && msg.toolName.length > 0
|
|
42
|
+
? msg.toolName
|
|
43
|
+
: undefined;
|
|
44
|
+
// Tool-call turns arrive as assistant messages whose `content` is the
|
|
45
|
+
// JSON-encoded tool arguments. Reconstruct a structured `toolCalls`
|
|
46
|
+
// entry so it renders as a tool card (matching the live stream) instead
|
|
47
|
+
// of leaking raw JSON into the transcript.
|
|
48
|
+
if (isToolCall) {
|
|
49
|
+
let args = {};
|
|
50
|
+
if (rawContent) {
|
|
51
|
+
try {
|
|
52
|
+
const parsed = JSON.parse(rawContent);
|
|
53
|
+
if (parsed &&
|
|
54
|
+
typeof parsed === 'object' &&
|
|
55
|
+
!Array.isArray(parsed)) {
|
|
56
|
+
args = parsed;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
args = {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const resolvedToolCallId = toolCallId || `history-tc-${index}`;
|
|
64
|
+
return {
|
|
65
|
+
id: `history-toolcall-${index}-${timestampValue}`,
|
|
66
|
+
role: 'assistant',
|
|
67
|
+
content: '',
|
|
68
|
+
createdAt,
|
|
69
|
+
toolCalls: [
|
|
70
|
+
{
|
|
71
|
+
type: 'tool-call',
|
|
72
|
+
toolCallId: resolvedToolCallId,
|
|
73
|
+
toolName: toolName || 'tool',
|
|
74
|
+
args,
|
|
75
|
+
status: 'completed',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// Tool results arrive as `role: 'tool'` messages; keep them (with the
|
|
81
|
+
// matching toolCallId) so `convertHistoryToDisplayItems` can merge the
|
|
82
|
+
// result into its tool card.
|
|
83
|
+
if (isToolResult || role === 'tool') {
|
|
84
|
+
return {
|
|
85
|
+
id: `history-toolresult-${index}-${timestampValue}`,
|
|
86
|
+
role: 'tool',
|
|
87
|
+
content: rawContent,
|
|
88
|
+
createdAt,
|
|
89
|
+
metadata: {
|
|
90
|
+
toolCallId,
|
|
91
|
+
toolName,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// Only hydrate conversational turns in the visible history.
|
|
96
|
+
// System messages may contain internal prompts and metadata.
|
|
97
|
+
if (role !== 'user' && role !== 'assistant') {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
// A turn a personal agent asked: what the runtime told the application
|
|
101
|
+
// before the person's words is never shown to them (decided 2026-10-14).
|
|
102
|
+
return {
|
|
103
|
+
id: `history-${role}-${index}-${timestampValue}`,
|
|
104
|
+
role,
|
|
105
|
+
content: role === 'user' ? askedOf(rawContent) : rawContent,
|
|
106
|
+
createdAt,
|
|
107
|
+
};
|
|
108
|
+
})
|
|
109
|
+
.filter((m) => m !== null);
|
|
110
|
+
}
|