@datalayer/agent-runtimes 1.3.83 → 1.3.85
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/lib/chat/ChatFloating.d.ts +5 -4
- package/lib/chat/ChatFloating.js +8 -6
- package/lib/chat/ChatLanguage.d.ts +17 -0
- package/lib/chat/ChatLanguage.js +29 -0
- package/lib/chat/assistant/AssistantStage.d.ts +4 -4
- package/lib/chat/assistant/AssistantStage.js +4 -2
- package/lib/chat/assistant/BalloonParts.d.ts +2 -1
- package/lib/chat/assistant/BalloonParts.js +12 -5
- package/lib/chat/assistant/BalloonVisual.js +3 -1
- package/lib/chat/assistant/ConversationBalloon.d.ts +1 -1
- package/lib/chat/assistant/ConversationBalloon.js +3 -2
- package/lib/chat/assistant/SpeechBalloon.d.ts +1 -1
- package/lib/chat/assistant/SpeechBalloon.js +10 -7
- package/lib/chat/assistant/toolLine.d.ts +8 -4
- package/lib/chat/assistant/toolLine.js +13 -9
- package/lib/chat/base/ChatBase.js +30 -11
- package/lib/chat/base/loopElement.d.ts +53 -0
- package/lib/chat/base/loopElement.js +78 -0
- package/lib/chat/base/loopWindow.d.ts +31 -0
- package/lib/chat/base/loopWindow.js +74 -0
- package/lib/chat/display/EmptyState.js +3 -1
- package/lib/chat/index.d.ts +2 -0
- package/lib/chat/index.js +3 -0
- package/lib/chat/messages/ChatMessages.js +3 -1
- package/lib/chat/messages/TurnFooter.js +3 -1
- package/lib/chat/prompt/InputPrompt.js +3 -1
- package/lib/chat/prompt/InputPromptLexical.js +3 -1
- package/lib/chat/prompt/footer/InPromptFooter.js +3 -1
- package/lib/chat/tools/ToolApprovalBanner.js +5 -3
- package/lib/chat/tools/ToolApprovalDialog.js +5 -3
- package/lib/chat/tools/ToolCallDisplay.js +29 -25
- package/lib/chat/words.d.ts +102 -0
- package/lib/chat/words.js +460 -0
- package/lib/components/a2ui/custom/index.d.ts +39 -0
- package/lib/components/a2ui/custom/index.js +95 -0
- package/lib/components/a2ui/custom/sandbox.d.ts +73 -0
- package/lib/components/a2ui/custom/sandbox.js +188 -0
- package/lib/components/a2ui/datalayer/FileUpload.d.ts +10 -2
- package/lib/components/a2ui/datalayer/FileUpload.js +10 -7
- package/lib/components/a2ui/datalayer/Form.d.ts +2 -0
- package/lib/components/a2ui/datalayer/Form.js +9 -2
- package/lib/components/a2ui/datalayer/formWidgets.d.ts +19 -0
- package/lib/components/a2ui/datalayer/formWidgets.js +51 -0
- package/lib/components/a2ui/datalayer/index.d.ts +1 -1
- package/lib/components/a2ui/datalayer/index.js +1 -1
- package/lib/components/a2ui/datalayer/schema.d.ts +10 -0
- package/lib/components/a2ui/datalayer/schema.js +12 -1
- package/lib/components/a2ui/index.d.ts +1 -0
- package/lib/components/a2ui/index.js +1 -0
- package/lib/components/a2ui/visibleWhen.d.ts +12 -1
- package/lib/components/a2ui/visibleWhen.js +24 -3
- package/lib/components/inspector/AgentInspector.d.ts +25 -44
- package/lib/components/inspector/AgentInspector.js +27 -215
- package/lib/components/inspector/AgentInspectorDialog.d.ts +6 -6
- package/lib/components/inspector/AgentInspectorDialog.js +2 -2
- package/lib/components/inspector/a2aSpans.d.ts +51 -0
- package/lib/components/inspector/a2aSpans.js +373 -0
- package/lib/components/inspector/agentSpans.d.ts +120 -0
- package/lib/components/inspector/agentSpans.js +253 -0
- package/lib/components/inspector/chatSpans.d.ts +36 -0
- package/lib/components/inspector/chatSpans.js +50 -0
- package/lib/components/inspector/classify.d.ts +11 -8
- package/lib/components/inspector/classify.js +23 -24
- package/lib/components/inspector/index.d.ts +7 -7
- package/lib/components/inspector/index.js +7 -7
- package/lib/components/teams/A2ATeamGraph.d.ts +4 -4
- package/lib/components/teams/SceneTranscript.d.ts +29 -0
- package/lib/components/teams/SceneTranscript.js +54 -0
- package/lib/components/teams/SceneView.d.ts +41 -0
- package/lib/components/teams/SceneView.js +28 -0
- package/lib/components/teams/index.d.ts +3 -0
- package/lib/components/teams/index.js +3 -0
- package/lib/components/teams/sceneTranscript.d.ts +74 -0
- package/lib/components/teams/sceneTranscript.js +294 -0
- package/lib/components/teams/teamConnections.d.ts +2 -2
- package/lib/components/teams/teamConnections.js +3 -3
- package/lib/components/teams/useA2ATeam.d.ts +4 -4
- package/lib/components/teams/useA2ATeam.js +50 -46
- package/lib/examples/AgentA2ATeamExample.d.ts +10 -9
- package/lib/examples/AgentA2ATeamExample.js +70 -60
- package/lib/examples/AssistantExample.js +2 -2
- package/lib/loop/apps/AppComposer.d.ts +40 -4
- package/lib/loop/apps/AppComposer.js +194 -19
- package/lib/loop/apps/AppRenderer.d.ts +21 -3
- package/lib/loop/apps/AppRenderer.js +88 -48
- package/lib/loop/apps/appspec.d.ts +13 -1
- package/lib/loop/apps/appspec.js +305 -12
- package/lib/loop/apps/checks.d.ts +14 -0
- package/lib/loop/apps/checks.js +276 -5
- package/lib/loop/apps/composer.d.ts +21 -10
- package/lib/loop/apps/composer.js +41 -8
- package/lib/loop/apps/customComponents.d.ts +41 -0
- package/lib/loop/apps/customComponents.js +260 -0
- package/lib/loop/apps/hostTools.d.ts +8 -1
- package/lib/loop/apps/hostTools.js +9 -0
- package/lib/loop/apps/index.d.ts +1 -0
- package/lib/loop/apps/index.js +1 -0
- package/lib/loop/apps/language.d.ts +68 -0
- package/lib/loop/apps/language.js +275 -0
- package/lib/loop/apps/settingsInputs.d.ts +29 -0
- package/lib/loop/apps/settingsInputs.js +147 -0
- package/lib/loop/apps/uploads.d.ts +43 -0
- package/lib/loop/apps/uploads.js +66 -0
- package/lib/loop/core/a2uiComponents.d.ts +10 -0
- package/lib/loop/core/a2uiComponents.js +15 -0
- package/lib/loop/core/index.d.ts +15 -1
- package/lib/loop/core/index.js +3 -0
- package/lib/loop/embed/AppEmbed.d.ts +25 -3
- package/lib/loop/embed/AppEmbed.js +106 -18
- package/lib/loop/embed/element.d.ts +5 -0
- package/lib/loop/embed/element.js +84 -5
- package/lib/loop/embed/embedConfig.d.ts +8 -0
- package/lib/loop/embed/embedConfig.js +18 -0
- package/lib/loop/embed/embedSession.d.ts +14 -0
- package/lib/loop/embed/embedSession.js +34 -0
- package/lib/loop/embed/hostBridge.d.ts +50 -3
- package/lib/loop/embed/hostBridge.js +22 -2
- package/lib/loop/index.d.ts +4 -3
- package/lib/loop/index.js +4 -3
- package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +7 -1
- package/lib/loop/plugins/a2ui-surface/InlineSurface.js +7 -2
- package/lib/loop/plugins/a2ui-surface/SurfaceToolResult.js +4 -1
- package/lib/loop/plugins/a2ui-surface/ownComponents.d.ts +6 -0
- package/lib/loop/plugins/a2ui-surface/ownComponents.js +30 -0
- package/lib/loop/plugins/app-components/index.d.ts +26 -0
- package/lib/loop/plugins/app-components/index.js +56 -0
- package/lib/loop/plugins/app-elements/AppElements.d.ts +27 -0
- package/lib/loop/plugins/app-elements/AppElements.js +79 -0
- package/lib/loop/plugins/app-elements/index.d.ts +20 -0
- package/lib/loop/plugins/app-elements/index.js +43 -0
- package/lib/loop/plugins/app-page/AppPage.d.ts +9 -0
- package/lib/loop/plugins/app-page/AppPage.js +106 -8
- package/lib/loop/plugins/app-page/appPageModel.d.ts +17 -1
- package/lib/loop/plugins/app-page/appPageModel.js +122 -4
- package/lib/loop/plugins/app-page/index.d.ts +1 -0
- package/lib/loop/plugins/app-page/index.js +1 -0
- package/lib/loop/plugins/app-page/pageRun.d.ts +46 -0
- package/lib/loop/plugins/app-page/pageRun.js +111 -0
- package/lib/loop/plugins/assistant/index.js +8 -6
- package/lib/loop/plugins/chat/ChatView.js +16 -6
- package/lib/loop/plugins/chat/index.d.ts +1 -1
- package/lib/loop/plugins/chat/index.js +2 -1
- package/lib/models/PageTag.d.ts +1 -1
- package/lib/protocols/BrowserAgentAdapter.d.ts +8 -6
- package/lib/protocols/BrowserAgentAdapter.js +13 -10
- package/lib/runtimes/browser/a2aPeer.d.ts +2 -1
- package/lib/runtimes/browser/protocol.d.ts +1 -1
- package/lib/specs/actions.js +78 -1
- package/lib/specs/apps.d.ts +5 -0
- package/lib/specs/apps.js +1518 -216
- package/lib/specs/appspecSchema.js +630 -3
- package/lib/specs/teams/teams.d.ts +3 -0
- package/lib/specs/teams/teams.js +249 -0
- package/lib/specs/uiPlugins.js +6 -1
- package/lib/types/agentspecs.d.ts +200 -1
- package/lib/types/chat.d.ts +6 -5
- package/lib/types/teams.d.ts +13 -2
- package/package.json +2 -2
- package/scripts/codegen/generate_apps.py +20 -2
- package/scripts/codegen/generate_teams.py +15 -2
- package/lib/components/inspector/JsonTree.d.ts +0 -24
- package/lib/components/inspector/JsonTree.js +0 -89
- package/lib/components/inspector/a2aInspect.d.ts +0 -56
- package/lib/components/inspector/a2aInspect.js +0 -478
- package/lib/components/inspector/agentInspector.d.ts +0 -179
- package/lib/components/inspector/agentInspector.js +0 -267
- package/lib/components/inspector/chatInspect.d.ts +0 -38
- package/lib/components/inspector/chatInspect.js +0 -65
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A widget's page written in its code, run on its inputs (LOOP P-05).
|
|
3
|
+
*
|
|
4
|
+
* The page opens a session of the application's agent on its runtime
|
|
5
|
+
* (`POST /api/v1/apps/sessions`), then, each time an input changes, sends
|
|
6
|
+
* them all as the session's `page` action (`POST …/sessions/{uid}/actions`,
|
|
7
|
+
* `{name: "page", payload: {inputs}}`). The runtime checks them against the
|
|
8
|
+
* page's form — refused with 422 and a sentence — runs its code's
|
|
9
|
+
* `@app.page` on them, and answers its outputs as a `CUSTOM` event named
|
|
10
|
+
* `loop.page`, `{inputs, outputs}`, which the page shows in place. Nothing is
|
|
11
|
+
* said in the conversation.
|
|
12
|
+
*
|
|
13
|
+
* @module loop/plugins/app-page/pageRun
|
|
14
|
+
*/
|
|
15
|
+
/** The `CUSTOM` event that says what a page shows. */
|
|
16
|
+
export declare const LOOP_PAGE = "loop.page";
|
|
17
|
+
/** Where the page reaches the application's session API, and as whom. */
|
|
18
|
+
export type PageRunContext = {
|
|
19
|
+
/** The agent-runtimes server that runs the application. */
|
|
20
|
+
serverUrl: string;
|
|
21
|
+
/** The application's agent there. */
|
|
22
|
+
agentId: string;
|
|
23
|
+
/** The person's token; none on the machine itself. */
|
|
24
|
+
token?: string;
|
|
25
|
+
fetcher?: typeof fetch;
|
|
26
|
+
};
|
|
27
|
+
/** What a turn of the session API said: the events of its stream, parsed. */
|
|
28
|
+
export declare function streamEvents(stream: string): Array<Record<string, unknown>>;
|
|
29
|
+
/** What a run of the page answered: its outputs, by name, or why there are none. */
|
|
30
|
+
export type PageTurn = {
|
|
31
|
+
outputs: Record<string, unknown>;
|
|
32
|
+
inputs: Record<string, unknown>;
|
|
33
|
+
} | {
|
|
34
|
+
refused: string;
|
|
35
|
+
};
|
|
36
|
+
/** The page's turn, read from the stream the runtime answered. */
|
|
37
|
+
export declare function pageTurnOf(stream: string): PageTurn;
|
|
38
|
+
/** Open the session its page runs in; its uid, as the runtime says it. */
|
|
39
|
+
export declare function openPageSession(context: PageRunContext): Promise<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Run the page on its inputs in a session: its outputs, or the runtime's
|
|
42
|
+
* sentence — its form refusing an input, its code failing.
|
|
43
|
+
*/
|
|
44
|
+
export declare function runPageIn(context: PageRunContext, uid: string, inputs: Record<string, unknown>): Promise<PageTurn>;
|
|
45
|
+
/** Each output as the page's data holds it, by path. */
|
|
46
|
+
export declare function outputsData(outputs: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A widget's page written in its code, run on its inputs (LOOP P-05).
|
|
7
|
+
*
|
|
8
|
+
* The page opens a session of the application's agent on its runtime
|
|
9
|
+
* (`POST /api/v1/apps/sessions`), then, each time an input changes, sends
|
|
10
|
+
* them all as the session's `page` action (`POST …/sessions/{uid}/actions`,
|
|
11
|
+
* `{name: "page", payload: {inputs}}`). The runtime checks them against the
|
|
12
|
+
* page's form — refused with 422 and a sentence — runs its code's
|
|
13
|
+
* `@app.page` on them, and answers its outputs as a `CUSTOM` event named
|
|
14
|
+
* `loop.page`, `{inputs, outputs}`, which the page shows in place. Nothing is
|
|
15
|
+
* said in the conversation.
|
|
16
|
+
*
|
|
17
|
+
* @module loop/plugins/app-page/pageRun
|
|
18
|
+
*/
|
|
19
|
+
/** The `CUSTOM` event that says what a page shows. */
|
|
20
|
+
export const LOOP_PAGE = 'loop.page';
|
|
21
|
+
/** What a turn of the session API said: the events of its stream, parsed. */
|
|
22
|
+
export function streamEvents(stream) {
|
|
23
|
+
const events = [];
|
|
24
|
+
for (const block of stream.split('\n\n')) {
|
|
25
|
+
const data = block
|
|
26
|
+
.split('\n')
|
|
27
|
+
.filter(line => line.startsWith('data:'))
|
|
28
|
+
.map(line => line.slice('data:'.length).trim())
|
|
29
|
+
.join('');
|
|
30
|
+
if (!data)
|
|
31
|
+
continue;
|
|
32
|
+
try {
|
|
33
|
+
events.push(JSON.parse(data));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Not an event: skipped, as a reader of the stream skips it.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return events;
|
|
40
|
+
}
|
|
41
|
+
/** The page's turn, read from the stream the runtime answered. */
|
|
42
|
+
export function pageTurnOf(stream) {
|
|
43
|
+
let shown = null;
|
|
44
|
+
for (const event of streamEvents(stream)) {
|
|
45
|
+
if (event.type === 'RUN_ERROR') {
|
|
46
|
+
return { refused: String(event.message ?? 'Its page could not run.') };
|
|
47
|
+
}
|
|
48
|
+
if (event.type === 'CUSTOM' && event.name === LOOP_PAGE) {
|
|
49
|
+
const value = (event.value ?? {});
|
|
50
|
+
shown = { outputs: value.outputs ?? {}, inputs: value.inputs ?? {} };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return (shown ?? {
|
|
54
|
+
refused: 'Its page showed nothing: its code answered no outputs.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const base = (context) => `${context.serverUrl.replace(/\/+$/, '')}/api/v1/apps/sessions`;
|
|
58
|
+
async function posted(context, url, body) {
|
|
59
|
+
const response = await (context.fetcher ?? fetch)(url, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'content-type': 'application/json',
|
|
63
|
+
...(context.token ? { Authorization: `Bearer ${context.token}` } : {}),
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify(body),
|
|
66
|
+
});
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
let detail = '';
|
|
69
|
+
try {
|
|
70
|
+
const said = (await response.json());
|
|
71
|
+
detail = typeof said.detail === 'string' ? said.detail : '';
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// No sentence: the status says it.
|
|
75
|
+
}
|
|
76
|
+
throw new Error(detail || `Its page was refused (${response.status}).`);
|
|
77
|
+
}
|
|
78
|
+
return response.text();
|
|
79
|
+
}
|
|
80
|
+
/** Open the session its page runs in; its uid, as the runtime says it. */
|
|
81
|
+
export async function openPageSession(context) {
|
|
82
|
+
const stream = await posted(context, base(context), {
|
|
83
|
+
agent: context.agentId,
|
|
84
|
+
});
|
|
85
|
+
for (const event of streamEvents(stream)) {
|
|
86
|
+
if (event.type === 'CUSTOM' && event.name === 'loop.session') {
|
|
87
|
+
const uid = event.value?.uid;
|
|
88
|
+
if (typeof uid === 'string' && uid) {
|
|
89
|
+
return uid;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
throw new Error('The runtime opened no session for its page.');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Run the page on its inputs in a session: its outputs, or the runtime's
|
|
97
|
+
* sentence — its form refusing an input, its code failing.
|
|
98
|
+
*/
|
|
99
|
+
export async function runPageIn(context, uid, inputs) {
|
|
100
|
+
try {
|
|
101
|
+
const stream = await posted(context, `${base(context)}/${encodeURIComponent(uid)}/actions`, { name: 'page', payload: { inputs } });
|
|
102
|
+
return pageTurnOf(stream);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return { refused: error instanceof Error ? error.message : String(error) };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Each output as the page's data holds it, by path. */
|
|
109
|
+
export function outputsData(outputs) {
|
|
110
|
+
return Object.fromEntries(Object.entries(outputs).map(([name, value]) => [`/outputs/${name}`, value]));
|
|
111
|
+
}
|
|
@@ -9,7 +9,7 @@ import { pageLayoutPanelOpen, togglePagePanel, } from '@datalayer/primer-addons/
|
|
|
9
9
|
import { AssistantStage } from '../../../chat/assistant/AssistantStage';
|
|
10
10
|
import { decisionsAskerAt } from '../../../chat/assistant/decisions';
|
|
11
11
|
import { peekLine } from '../../../chat/assistant/ConversationBalloon';
|
|
12
|
-
import {
|
|
12
|
+
import { assistantStateOf, keepAway, keptAway, latestSaying, } from '../../../chat/assistant/state';
|
|
13
13
|
import { useApproveToolRequest, useRejectToolRequest, useToolApprovalsQuery, } from '../../../hooks/useToolApprovals';
|
|
14
14
|
import { approvalsOfApp, ruleOfApproval } from '../app-rules/AppRulesCard';
|
|
15
15
|
import { useViewportDrag } from '../../../chat/useViewportDrag';
|
|
@@ -17,6 +17,7 @@ import { LoopAssistantCharacter, LoopAssistantMenu, LoopChatLayout, LoopChatTurn
|
|
|
17
17
|
import { assistantCharacterFor } from '../assistant-characters';
|
|
18
18
|
import { useOptionalSandboxService } from '../agents/useSandboxService';
|
|
19
19
|
import { TARGET_SPECS } from '../agents/switchable';
|
|
20
|
+
import { useChatWords } from '../../../chat/ChatLanguage';
|
|
20
21
|
export const LOOP_ASSISTANT_PLUGIN_NAME = '@datalayer/loop-plugin-assistant';
|
|
21
22
|
/** The character's size, in pixels, as the chat's own assistant. */
|
|
22
23
|
const SIZE = 88;
|
|
@@ -72,6 +73,7 @@ function focusComposer() {
|
|
|
72
73
|
composer?.focus();
|
|
73
74
|
}
|
|
74
75
|
export function LoopAssistant({ app, person, appId, decisions, balloon: displayGiven = 'history', workspace, }) {
|
|
76
|
+
const chatText = useChatWords();
|
|
75
77
|
// The balloon's display, as its menu chose it; the Appspec's until then.
|
|
76
78
|
const [chosenDisplay, setChosenDisplay] = useState();
|
|
77
79
|
const display = chosenDisplay ?? displayGiven;
|
|
@@ -203,18 +205,18 @@ export function LoopAssistant({ app, person, appId, decisions, balloon: displayG
|
|
|
203
205
|
const atWork = turn.status === 'streaming' || turn.status === 'thinking';
|
|
204
206
|
const current = display === 'current';
|
|
205
207
|
const balloon = state === 'paused'
|
|
206
|
-
? { text:
|
|
208
|
+
? { text: chatText.paused }
|
|
207
209
|
: approval
|
|
208
|
-
? { text:
|
|
210
|
+
? { text: chatText.waitingForYou, approval }
|
|
209
211
|
: presence === 'waiting'
|
|
210
|
-
? { text:
|
|
212
|
+
? { text: chatText.waitingOpen }
|
|
211
213
|
: tool
|
|
212
214
|
? { text: turn.activity ?? '', tool, busy: true }
|
|
213
215
|
: current && (atWork || unheard)
|
|
214
216
|
? {
|
|
215
217
|
text: turn.status === 'thinking'
|
|
216
|
-
?
|
|
217
|
-
: (saying?.text ??
|
|
218
|
+
? chatText.thinking
|
|
219
|
+
: (saying?.text ?? chatText.thinking),
|
|
218
220
|
more: saying?.more,
|
|
219
221
|
speaking: turn.status === 'streaming',
|
|
220
222
|
busy: atWork,
|
|
@@ -49,6 +49,7 @@ import { NONE_EDITOR, seedEditorChoice, setEditorOptions, } from '../shell/edito
|
|
|
49
49
|
import { FaceDrawing, PresenceFace, PresenceLine, } from '../../../chat/presence/Presence';
|
|
50
50
|
import { presenceState, presenceToolOf, } from '../../../chat/presence/presenceStatus';
|
|
51
51
|
import { latestSaying, newestIsAnswer, } from '../../../chat/assistant/state';
|
|
52
|
+
import { useChatWords } from '../../../chat/ChatLanguage';
|
|
52
53
|
/** No editor: the conversation on its own. */
|
|
53
54
|
const NO_SURFACE = '';
|
|
54
55
|
/**
|
|
@@ -64,6 +65,7 @@ const FULLSCREEN_HINT_PERIOD_MS = 1400;
|
|
|
64
65
|
*/
|
|
65
66
|
const FACE_LARGE = parseInt(loopShapeVars['--loop-face-large'], 10);
|
|
66
67
|
export default function ChatView({ workspace }) {
|
|
68
|
+
const chatText = useChatWords();
|
|
67
69
|
/* The active theme's own colours. Read from the store rather than a
|
|
68
70
|
provider, so a workspace mounted without the addons theme still gets the
|
|
69
71
|
default palette instead of throwing. */
|
|
@@ -76,7 +78,7 @@ export default function ChatView({ workspace }) {
|
|
|
76
78
|
// where it sets anything else about this plugin.
|
|
77
79
|
const reactor = useReactorPlatform();
|
|
78
80
|
const config = reactor.getConfig(CHAT_PLUGIN_NAME);
|
|
79
|
-
const placeholder = config?.placeholder
|
|
81
|
+
const placeholder = config?.placeholder || chatText.placeholder;
|
|
80
82
|
const defaultSurface = config?.defaultSurface ?? 'notebook';
|
|
81
83
|
/*
|
|
82
84
|
* The input-prompt plugin's own configuration, read from here rather than
|
|
@@ -372,11 +374,12 @@ export default function ChatView({ workspace }) {
|
|
|
372
374
|
* itself (`modeEffect`, `BrowserAgentAdapter`).
|
|
373
375
|
*/
|
|
374
376
|
const sendNow = useCallback((message, given) => {
|
|
375
|
-
const
|
|
377
|
+
const forwardedProps = runForwardedProps(runPropsRef.current.map(entry => entry.value), given);
|
|
378
|
+
// The page's files, or those attached in the composer (LOOP P-21).
|
|
379
|
+
const loop = forwardedProps?.loop;
|
|
376
380
|
if (inPageRef.current && loop?.files && loop.files.length > 0) {
|
|
377
381
|
return 'A file is given to an application running on a runtime: run it on Datalayer or on your machine to give it one.';
|
|
378
382
|
}
|
|
379
|
-
const forwardedProps = runForwardedProps(runPropsRef.current.map(entry => entry.value), given);
|
|
380
383
|
// A new turn: whatever the panel showed is gone, this message is it.
|
|
381
384
|
turnFeedRef.current?.begin(message, controlsRef.current?.thread());
|
|
382
385
|
const send = controlsRef.current?.send;
|
|
@@ -752,6 +755,7 @@ export default function ChatView({ workspace }) {
|
|
|
752
755
|
const suggestionEntries = useContributions(LoopChatSuggestion);
|
|
753
756
|
const hiddenOpeners = chatExtras.hiddenOpeners;
|
|
754
757
|
const hideOpeners = chatExtras.hideOpeners;
|
|
758
|
+
const liveOpeners = chatExtras.openers;
|
|
755
759
|
const suggestions = useMemo(() => {
|
|
756
760
|
if (hideOpeners) {
|
|
757
761
|
return [];
|
|
@@ -760,6 +764,11 @@ export default function ChatView({ workspace }) {
|
|
|
760
764
|
// the two-group merge below uses to tell openers apart.
|
|
761
765
|
const hidden = new Set(hiddenOpeners ?? []);
|
|
762
766
|
const offered = (items) => hidden.size === 0 ? items : items.filter(item => !hidden.has(item.text));
|
|
767
|
+
// What a plugin offers live (an application's profile's starters,
|
|
768
|
+
// LOOP P-20) wins over what was contributed when the reactor was built.
|
|
769
|
+
if (liveOpeners) {
|
|
770
|
+
return offered(liveOpeners);
|
|
771
|
+
}
|
|
763
772
|
const contributed = suggestionEntries.flatMap(entry => entry.value.suggestions);
|
|
764
773
|
if (contributed.length > 0) {
|
|
765
774
|
return offered(contributed);
|
|
@@ -788,6 +797,7 @@ export default function ChatView({ workspace }) {
|
|
|
788
797
|
agentId,
|
|
789
798
|
hiddenOpeners,
|
|
790
799
|
hideOpeners,
|
|
800
|
+
liveOpeners,
|
|
791
801
|
]);
|
|
792
802
|
/*
|
|
793
803
|
* The same openers in the shape the chat's empty state asks for.
|
|
@@ -1032,8 +1042,8 @@ export default function ChatView({ workspace }) {
|
|
|
1032
1042
|
const chatDisabled = gateBlocked || keyExpired || Boolean(inPageRefusal) || ambient.disabled;
|
|
1033
1043
|
const disabledReason = keyExpired
|
|
1034
1044
|
? expiredKeyIsTemporary
|
|
1035
|
-
?
|
|
1036
|
-
:
|
|
1045
|
+
? chatText.demoKeyExpired
|
|
1046
|
+
: chatText.keyExpired
|
|
1037
1047
|
: (inPageRefusal ??
|
|
1038
1048
|
gateReason ??
|
|
1039
1049
|
(ambient.disabled ? ambient.disableReason : undefined));
|
|
@@ -1765,7 +1775,7 @@ export default function ChatView({ workspace }) {
|
|
|
1765
1775
|
renderToolResult: chatExtras.renderToolResult, showTurnFooter: chatExtras.showTokenUsage ?? config?.showTokenUsage ?? true, onContextSnapshot: handleContextSnapshot, onLoadingChange: handleLoadingChange, onItemsChange: handleMessagesChange, onDisplayItemsChange: handleDisplayItemsChange, enableStreaming: true }) }), besideChat && !promptHidden ? prompt : null] }) }));
|
|
1766
1776
|
// Off when the host asked for the menu alone: the composer's suggestions
|
|
1767
1777
|
// control carries the same openers (`suggestions` above).
|
|
1768
|
-
const chipsEl = config?.suggestionLabels !== false && chatSuggestions.length > 0 ? (_jsx(Box, { "aria-label":
|
|
1778
|
+
const chipsEl = config?.suggestionLabels !== false && chatSuggestions.length > 0 ? (_jsx(Box, { "aria-label": chatText.suggestedPrompts, sx: { display: 'flex', flexWrap: 'wrap', gap: 2, px: 2, pb: '6px' }, children: chatSuggestions.map(item => (_jsx(Box, { as: "button", type: "button",
|
|
1769
1779
|
// The whole request, where the chip shows only its summary.
|
|
1770
1780
|
title: item.message, disabled: busy || chatDisabled, onClick: () => void handleSend(item.message), sx: {
|
|
1771
1781
|
appearance: 'none',
|
|
@@ -78,7 +78,7 @@ export type ChatPluginConfig = {
|
|
|
78
78
|
* Configured on the plugin rather than passed to the workspace: the prompt
|
|
79
79
|
* belongs to the chat, and a shell that has no chat plugin has no prompt to
|
|
80
80
|
* put a placeholder in. A host that wants different words says so where the
|
|
81
|
-
* words are.
|
|
81
|
+
* words are. Empty, the chat's own, in the person's language (LOOP P-26).
|
|
82
82
|
*/
|
|
83
83
|
placeholder: string;
|
|
84
84
|
/**
|
|
@@ -38,7 +38,8 @@ export const CHAT_PLUGIN_NAME = '@datalayer/loop-plugin-chat';
|
|
|
38
38
|
export const ChatPlugin = definePlugin({
|
|
39
39
|
name: CHAT_PLUGIN_NAME,
|
|
40
40
|
config: {
|
|
41
|
-
|
|
41
|
+
// The chat's own words, in the person's language (`chat/words`).
|
|
42
|
+
placeholder: '',
|
|
42
43
|
// The notebook: it is what most of these agents work on, and a workspace
|
|
43
44
|
// that opens on an empty chat hides the half of itself that does the work.
|
|
44
45
|
defaultSurface: 'notebook',
|
package/lib/models/PageTag.d.ts
CHANGED
|
@@ -15,5 +15,5 @@ export type PageTag = {
|
|
|
15
15
|
export declare const PAGE_TAGE_NONE: PageTag;
|
|
16
16
|
export declare const PAGE_TAGS: PageTag[];
|
|
17
17
|
export declare const PAGE_TAGS_BY_NAME_MAP: Map<PageTagName | undefined, PageTag>;
|
|
18
|
-
export declare const PAGE_TAGS_BY_COLOR_MAP: Map<"default" | "
|
|
18
|
+
export declare const PAGE_TAGS_BY_COLOR_MAP: Map<"default" | "green" | "lime" | "blue" | "coral" | "gray" | "indigo" | "orange" | "pink" | "purple" | "red" | "teal" | "yellow" | "lemon", PageTag>;
|
|
19
19
|
export {};
|
|
@@ -70,7 +70,7 @@ export interface BrowserAgentAdapterConfig extends ProtocolAdapterConfig, Fronte
|
|
|
70
70
|
* rules. Unsaid for an agent with no modes, which refuses a run sent in
|
|
71
71
|
* some.
|
|
72
72
|
*/
|
|
73
|
-
modeEffect?: (chosen: Record<string, string
|
|
73
|
+
modeEffect?: (chosen: Record<string, string>, profile?: string) => AppModeEffect;
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* An agent loop running in the page, speaking the protocol adapter interface.
|
|
@@ -120,12 +120,14 @@ export declare class BrowserAgentAdapter extends BaseProtocolAdapter {
|
|
|
120
120
|
*/
|
|
121
121
|
private resolveModel;
|
|
122
122
|
/**
|
|
123
|
-
* What the modes a run is sent in
|
|
124
|
-
*
|
|
123
|
+
* What the modes a run is sent in, and the profile its conversation is
|
|
124
|
+
* with, tell it, and the model it runs on (LOOP P-19, P-20) — the
|
|
125
|
+
* runtime's session API applies the same, for that run only.
|
|
125
126
|
*
|
|
126
|
-
* Refused, in a sentence, rather than run without them: modes
|
|
127
|
-
* agent that has none, modes that are not the
|
|
128
|
-
*
|
|
127
|
+
* Refused, in a sentence, rather than run without them: modes or a profile
|
|
128
|
+
* sent to an agent that has none, modes or a profile that are not the
|
|
129
|
+
* application's, and a model chosen for an agent whose model is the host's
|
|
130
|
+
* own.
|
|
129
131
|
*/
|
|
130
132
|
private runModes;
|
|
131
133
|
/**
|
|
@@ -141,26 +141,29 @@ export class BrowserAgentAdapter extends BaseProtocolAdapter {
|
|
|
141
141
|
return createBrowserModel({ ...inference, model: requested || model });
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
144
|
-
* What the modes a run is sent in
|
|
145
|
-
*
|
|
144
|
+
* What the modes a run is sent in, and the profile its conversation is
|
|
145
|
+
* with, tell it, and the model it runs on (LOOP P-19, P-20) — the
|
|
146
|
+
* runtime's session API applies the same, for that run only.
|
|
146
147
|
*
|
|
147
|
-
* Refused, in a sentence, rather than run without them: modes
|
|
148
|
-
* agent that has none, modes that are not the
|
|
149
|
-
*
|
|
148
|
+
* Refused, in a sentence, rather than run without them: modes or a profile
|
|
149
|
+
* sent to an agent that has none, modes or a profile that are not the
|
|
150
|
+
* application's, and a model chosen for an agent whose model is the host's
|
|
151
|
+
* own.
|
|
150
152
|
*/
|
|
151
153
|
runModes(forwardedProps) {
|
|
152
154
|
const loop = forwardedProps?.loop;
|
|
153
|
-
const chosen = loop?.modes;
|
|
154
|
-
|
|
155
|
+
const chosen = loop?.modes ?? {};
|
|
156
|
+
const profile = loop?.profile || undefined;
|
|
157
|
+
if (Object.keys(chosen).length === 0 && !profile) {
|
|
155
158
|
return undefined;
|
|
156
159
|
}
|
|
157
160
|
const { modeEffect, languageModel } = this.browserConfig;
|
|
158
161
|
if (!modeEffect) {
|
|
159
|
-
throw new Error('This agent has no modes:
|
|
162
|
+
throw new Error('This agent has no modes or profiles: what was chosen in the composer cannot be applied to it.');
|
|
160
163
|
}
|
|
161
|
-
const effect = modeEffect(chosen);
|
|
164
|
+
const effect = modeEffect(chosen, profile);
|
|
162
165
|
if (effect.model && languageModel) {
|
|
163
|
-
throw new Error(`The mode chosen runs on ${effect.model}, and this agent's model is its host's own: it cannot run on another.`);
|
|
166
|
+
throw new Error(`The mode or profile chosen runs on ${effect.model}, and this agent's model is its host's own: it cannot run on another.`);
|
|
164
167
|
}
|
|
165
168
|
return effect;
|
|
166
169
|
}
|
|
@@ -56,7 +56,8 @@ export type ConnectA2APeerOptions = {
|
|
|
56
56
|
key?: string;
|
|
57
57
|
/**
|
|
58
58
|
* The fetch to use, for tests and hosts that wrap the network — such as
|
|
59
|
-
* the Agent Inspector's `
|
|
59
|
+
* the Agent Inspector's `traceA2AFetch`, which records the traffic as
|
|
60
|
+
* OpenTelemetry spans.
|
|
60
61
|
*/
|
|
61
62
|
fetch?: typeof globalThis.fetch;
|
|
62
63
|
};
|
|
@@ -39,7 +39,7 @@ export type BrowserProtocolOptions = {
|
|
|
39
39
|
/** Told what a delegated run does, as it does it — see `subagentTools`. */
|
|
40
40
|
onSubagentEvent?: (event: AgentStreamSubagentPayload) => void;
|
|
41
41
|
/** What the modes a run is sent in tell it (LOOP P-19); none when unsaid. */
|
|
42
|
-
modeEffect?: (chosen: Record<string, string
|
|
42
|
+
modeEffect?: (chosen: Record<string, string>, profile?: string) => AppModeEffect;
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
45
|
* The protocol config for an agent whose loop runs in this page.
|
package/lib/specs/actions.js
CHANGED
|
@@ -229,8 +229,13 @@ export const SERVER_ACTIONS = {
|
|
|
229
229
|
conditions: {},
|
|
230
230
|
},
|
|
231
231
|
earthdata: {
|
|
232
|
+
checked: '2026-10-07',
|
|
232
233
|
default: [],
|
|
233
|
-
tools: {
|
|
234
|
+
tools: {
|
|
235
|
+
search_earth_datasets: ['read'],
|
|
236
|
+
search_earth_datagranules: ['read'],
|
|
237
|
+
download_earth_data_granules: ['write'],
|
|
238
|
+
},
|
|
234
239
|
conditions: {},
|
|
235
240
|
},
|
|
236
241
|
eurus: {
|
|
@@ -693,9 +698,25 @@ export const APP_BEHAVIOURS = {
|
|
|
693
698
|
'odoo-accounting.odoo_accounting_trial_balance': 'do_it',
|
|
694
699
|
'odoo-accounting.odoo_accounting_unreconcile_lines': 'leave_to_me',
|
|
695
700
|
},
|
|
701
|
+
'change-detection': {
|
|
702
|
+
'earthdata.download_earth_data_granules': 'leave_to_me',
|
|
703
|
+
'earthdata.search_earth_datagranules': 'do_it',
|
|
704
|
+
'earthdata.search_earth_datasets': 'do_it',
|
|
705
|
+
},
|
|
706
|
+
'crop-monitoring': {
|
|
707
|
+
'earthdata.download_earth_data_granules': 'leave_to_me',
|
|
708
|
+
'earthdata.search_earth_datagranules': 'do_it',
|
|
709
|
+
'earthdata.search_earth_datasets': 'do_it',
|
|
710
|
+
},
|
|
696
711
|
'customer-interview': {},
|
|
697
712
|
'data-quality': {},
|
|
698
713
|
decide: {},
|
|
714
|
+
'disaster-assessment': {
|
|
715
|
+
'earthdata.download_earth_data_granules': 'leave_to_me',
|
|
716
|
+
'earthdata.search_earth_datagranules': 'do_it',
|
|
717
|
+
'earthdata.search_earth_datasets': 'do_it',
|
|
718
|
+
},
|
|
719
|
+
'event-response': {},
|
|
699
720
|
'inbox-triage': {
|
|
700
721
|
'google-workspace.append_table_rows': 'leave_to_me',
|
|
701
722
|
'google-workspace.batch_modify_gmail_message_labels': 'do_it',
|
|
@@ -819,6 +840,57 @@ export const APP_BEHAVIOURS = {
|
|
|
819
840
|
'google-workspace.update_paragraph_style': 'leave_to_me',
|
|
820
841
|
},
|
|
821
842
|
'model-choice': {},
|
|
843
|
+
'month-end-close': {
|
|
844
|
+
'odoo-accounting.odoo_accounting_aged_balance': 'do_it',
|
|
845
|
+
'odoo-accounting.odoo_accounting_bank_status': 'do_it',
|
|
846
|
+
'odoo-accounting.odoo_accounting_book_bank_line': 'leave_to_me',
|
|
847
|
+
'odoo-accounting.odoo_accounting_check_tax_period': 'do_it',
|
|
848
|
+
'odoo-accounting.odoo_accounting_create_customer_invoice': 'leave_to_me',
|
|
849
|
+
'odoo-accounting.odoo_accounting_create_draft_invoice': 'leave_to_me',
|
|
850
|
+
'odoo-accounting.odoo_accounting_create_draft_journal_entry': 'leave_to_me',
|
|
851
|
+
'odoo-accounting.odoo_accounting_create_matching_model': 'leave_to_me',
|
|
852
|
+
'odoo-accounting.odoo_accounting_create_vendor_bill': 'leave_to_me',
|
|
853
|
+
'odoo-accounting.odoo_accounting_explain_account_balance': 'do_it',
|
|
854
|
+
'odoo-accounting.odoo_accounting_general_ledger': 'do_it',
|
|
855
|
+
'odoo-accounting.odoo_accounting_get_asset': 'do_it',
|
|
856
|
+
'odoo-accounting.odoo_accounting_get_bank_line': 'do_it',
|
|
857
|
+
'odoo-accounting.odoo_accounting_get_invoice': 'do_it',
|
|
858
|
+
'odoo-accounting.odoo_accounting_get_journal_entry': 'do_it',
|
|
859
|
+
'odoo-accounting.odoo_accounting_get_lock_dates': 'do_it',
|
|
860
|
+
'odoo-accounting.odoo_accounting_get_tax_return': 'do_it',
|
|
861
|
+
'odoo-accounting.odoo_accounting_get_tax_settings': 'do_it',
|
|
862
|
+
'odoo-accounting.odoo_accounting_link_bank_feed': 'leave_to_me',
|
|
863
|
+
'odoo-accounting.odoo_accounting_list_accounts': 'do_it',
|
|
864
|
+
'odoo-accounting.odoo_accounting_list_assets': 'do_it',
|
|
865
|
+
'odoo-accounting.odoo_accounting_list_bank_feeds': 'do_it',
|
|
866
|
+
'odoo-accounting.odoo_accounting_list_bank_lines': 'do_it',
|
|
867
|
+
'odoo-accounting.odoo_accounting_list_currency_rates': 'do_it',
|
|
868
|
+
'odoo-accounting.odoo_accounting_list_invoices': 'do_it',
|
|
869
|
+
'odoo-accounting.odoo_accounting_list_journal_entries': 'do_it',
|
|
870
|
+
'odoo-accounting.odoo_accounting_list_journals': 'do_it',
|
|
871
|
+
'odoo-accounting.odoo_accounting_list_open_balances': 'do_it',
|
|
872
|
+
'odoo-accounting.odoo_accounting_list_partners': 'do_it',
|
|
873
|
+
'odoo-accounting.odoo_accounting_list_tax_grid_lines': 'do_it',
|
|
874
|
+
'odoo-accounting.odoo_accounting_list_tax_returns': 'do_it',
|
|
875
|
+
'odoo-accounting.odoo_accounting_list_taxes': 'do_it',
|
|
876
|
+
'odoo-accounting.odoo_accounting_list_untagged_tax_lines': 'do_it',
|
|
877
|
+
'odoo-accounting.odoo_accounting_match_bank_line': 'leave_to_me',
|
|
878
|
+
'odoo-accounting.odoo_accounting_partner_ledger': 'do_it',
|
|
879
|
+
'odoo-accounting.odoo_accounting_post_invoice': 'leave_to_me',
|
|
880
|
+
'odoo-accounting.odoo_accounting_post_journal_entry': 'leave_to_me',
|
|
881
|
+
'odoo-accounting.odoo_accounting_reconcile_lines': 'leave_to_me',
|
|
882
|
+
'odoo-accounting.odoo_accounting_remove_duplicate_bank_lines': 'leave_to_me',
|
|
883
|
+
'odoo-accounting.odoo_accounting_reset_bank_line': 'leave_to_me',
|
|
884
|
+
'odoo-accounting.odoo_accounting_set_currency_rates': 'leave_to_me',
|
|
885
|
+
'odoo-accounting.odoo_accounting_set_lock_date': 'leave_to_me',
|
|
886
|
+
'odoo-accounting.odoo_accounting_set_tax_grids': 'leave_to_me',
|
|
887
|
+
'odoo-accounting.odoo_accounting_set_tax_periodicity': 'leave_to_me',
|
|
888
|
+
'odoo-accounting.odoo_accounting_suggest_bank_matches': 'do_it',
|
|
889
|
+
'odoo-accounting.odoo_accounting_suggest_reconciliations': 'do_it',
|
|
890
|
+
'odoo-accounting.odoo_accounting_tax_grids': 'do_it',
|
|
891
|
+
'odoo-accounting.odoo_accounting_trial_balance': 'do_it',
|
|
892
|
+
'odoo-accounting.odoo_accounting_unreconcile_lines': 'leave_to_me',
|
|
893
|
+
},
|
|
822
894
|
'pipeline-report': {},
|
|
823
895
|
'quote-calculator': {},
|
|
824
896
|
'report-from-a-file': {},
|
|
@@ -840,9 +912,13 @@ export const APP_BEHAVIOURS = {
|
|
|
840
912
|
*/
|
|
841
913
|
export const APP_ESCALATIONS = {
|
|
842
914
|
accounting: {},
|
|
915
|
+
'change-detection': {},
|
|
916
|
+
'crop-monitoring': {},
|
|
843
917
|
'customer-interview': {},
|
|
844
918
|
'data-quality': {},
|
|
845
919
|
decide: {},
|
|
920
|
+
'disaster-assessment': {},
|
|
921
|
+
'event-response': {},
|
|
846
922
|
'inbox-triage': {
|
|
847
923
|
'google-workspace.batch_modify_gmail_message_labels': [
|
|
848
924
|
{
|
|
@@ -878,6 +954,7 @@ export const APP_ESCALATIONS = {
|
|
|
878
954
|
],
|
|
879
955
|
},
|
|
880
956
|
'model-choice': {},
|
|
957
|
+
'month-end-close': {},
|
|
881
958
|
'pipeline-report': {},
|
|
882
959
|
'quote-calculator': {},
|
|
883
960
|
'report-from-a-file': {},
|
package/lib/specs/apps.d.ts
CHANGED
|
@@ -9,11 +9,16 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { AppBuilt, AppKind, AppSpec } from '../types/agentspecs';
|
|
11
11
|
export declare const ACCOUNTING_APP_0_0_1: AppSpec;
|
|
12
|
+
export declare const CHANGE_DETECTION_APP_0_0_1: AppSpec;
|
|
13
|
+
export declare const CROP_MONITORING_APP_0_0_1: AppSpec;
|
|
12
14
|
export declare const CUSTOMER_INTERVIEW_APP_0_0_1: AppSpec;
|
|
13
15
|
export declare const DATA_QUALITY_APP_0_0_1: AppSpec;
|
|
14
16
|
export declare const DECIDE_APP_0_0_1: AppSpec;
|
|
17
|
+
export declare const DISASTER_ASSESSMENT_APP_0_0_1: AppSpec;
|
|
18
|
+
export declare const EVENT_RESPONSE_APP_0_0_1: AppSpec;
|
|
15
19
|
export declare const INBOX_TRIAGE_APP_0_0_1: AppSpec;
|
|
16
20
|
export declare const MODEL_CHOICE_APP_0_0_1: AppSpec;
|
|
21
|
+
export declare const MONTH_END_CLOSE_APP_0_0_1: AppSpec;
|
|
17
22
|
export declare const PIPELINE_REPORT_APP_0_0_1: AppSpec;
|
|
18
23
|
export declare const QUOTE_CALCULATOR_APP_0_0_1: AppSpec;
|
|
19
24
|
export declare const REPORT_FROM_A_FILE_APP_0_0_1: AppSpec;
|