@datalayer/agent-runtimes 1.3.86 → 1.3.88
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/components/a2ui/datalayer/Download.d.ts +21 -0
- package/lib/components/a2ui/datalayer/Download.js +66 -0
- package/lib/components/a2ui/datalayer/drawn.d.ts +1 -1
- package/lib/components/a2ui/datalayer/drawn.js +1 -0
- package/lib/components/a2ui/datalayer/index.d.ts +2 -1
- package/lib/components/a2ui/datalayer/index.js +3 -0
- package/lib/components/inspector/a2aSpans.d.ts +9 -0
- package/lib/components/inspector/a2aSpans.js +11 -1
- package/lib/components/teams/A2ATeamGraph.d.ts +2 -2
- package/lib/components/teams/A2ATeamGraph.js +39 -22
- package/lib/components/teams/AnswerSurfaces.d.ts +56 -0
- package/lib/components/teams/AnswerSurfaces.js +27 -0
- package/lib/components/teams/AnswerSurfacesView.d.ts +14 -0
- package/lib/components/teams/AnswerSurfacesView.js +30 -0
- package/lib/components/teams/index.d.ts +1 -0
- package/lib/components/teams/index.js +1 -0
- package/lib/components/teams/useA2ATeam.d.ts +56 -2
- package/lib/components/teams/useA2ATeam.js +122 -3
- package/lib/hooks/useAgentRuntimes.d.ts +13 -0
- package/lib/hooks/useAgentRuntimes.js +11 -1
- package/lib/loop/apps/AppFeedback.js +11 -2
- package/lib/loop/apps/AppRenderer.d.ts +13 -1
- package/lib/loop/apps/AppRenderer.js +34 -1
- package/lib/loop/apps/AppRuntimePlugins.d.ts +8 -0
- package/lib/loop/apps/AppRuntimePlugins.js +87 -0
- package/lib/loop/apps/feedback.d.ts +7 -0
- package/lib/loop/apps/feedback.js +3 -0
- package/lib/loop/apps/pluginPair.d.ts +60 -0
- package/lib/loop/apps/pluginPair.js +44 -0
- package/lib/loop/apps/threads.d.ts +35 -0
- package/lib/loop/apps/threads.js +79 -0
- package/lib/loop/embed/LoopEmbed.d.ts +4 -3
- package/lib/loop/embed/hostBridge.d.ts +27 -0
- package/lib/loop/embed/hostBridge.js +47 -0
- package/lib/loop/index.d.ts +1 -1
- package/lib/loop/index.js +1 -1
- package/lib/loop/plugins/agent-capacity/index.d.ts +7 -0
- package/lib/loop/plugins/agent-capacity/index.js +3 -2
- package/lib/loop/plugins/agents/DatalayerAgentBridge.js +11 -0
- package/lib/loop/plugins/agents/appLaunch.d.ts +15 -0
- package/lib/loop/plugins/agents/appLaunch.js +28 -0
- package/lib/loop/plugins/chat/ChatView.js +177 -109
- package/lib/loop/shell/LoopWorkspace.d.ts +3 -3
- package/lib/loop/shell/LoopWorkspace.js +1 -1
- package/lib/runtimes/__tests__/fixtures/accounting-agent-card.json +10 -2
- package/lib/runtimes/actions.js +23 -0
- package/lib/runtimes/apis.d.ts +18 -0
- package/lib/runtimes/browser/a2aPeer.d.ts +19 -2
- package/lib/runtimes/browser/a2aPeer.js +13 -7
- package/lib/specs/apps.js +102 -30
- package/lib/specs/envvars.d.ts +2 -0
- package/lib/specs/envvars.js +22 -0
- package/lib/specs/outputs.d.ts +1 -0
- package/lib/specs/outputs.js +12 -0
- package/lib/specs/sceneSchema.d.ts +8 -0
- package/lib/specs/sceneSchema.js +863 -0
- package/lib/specs/scenes.js +238 -121
- package/lib/specs/teams/teams.js +23 -7
- package/lib/specs/uiPlugins.js +55 -0
- package/lib/stores/agentRuntimeStore.js +4 -0
- package/lib/types/chat.d.ts +6 -0
- package/lib/types/scenes.d.ts +7 -1
- package/package.json +1 -1
- package/scripts/codegen/generate_envvars.py +1 -1
- package/scripts/codegen/generate_mcp_servers.py +11 -7
- package/scripts/codegen/generate_scenes.py +43 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A thread opened from a person's history, to go on with it (LOOP P-24).
|
|
3
|
+
*
|
|
4
|
+
* A thread is a session of an application: its uid is the conversation's
|
|
5
|
+
* AG-UI thread. Opened again, its conversation is read from the runtime the
|
|
6
|
+
* chat runs on — the session's messages while the runtime holds it
|
|
7
|
+
* (`GET …/sessions/{uid}/messages`, D-13), else the session resumed from its
|
|
8
|
+
* record (`POST …/sessions/{uid}/resume` with the agent, R-04), whose
|
|
9
|
+
* stream's `MESSAGES_SNAPSHOT` says what it holds — and the chat draws it
|
|
10
|
+
* and goes on with it on the same thread.
|
|
11
|
+
*
|
|
12
|
+
* Pure: the network is the `fetch` it is handed.
|
|
13
|
+
*
|
|
14
|
+
* @module loop/apps/threads
|
|
15
|
+
*/
|
|
16
|
+
import type { ChatMessage } from '../../types/messages';
|
|
17
|
+
/** What opening a thread says, in a person's words. */
|
|
18
|
+
export declare const THREAD_WORDS: {
|
|
19
|
+
readonly opening: "Opening your conversation…";
|
|
20
|
+
readonly notOpened: (detail: string) => string;
|
|
21
|
+
};
|
|
22
|
+
/** The AG-UI messages a session-API stream's `MESSAGES_SNAPSHOT` carries, if one does. */
|
|
23
|
+
export declare function snapshotOfStream(text: string): unknown[] | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* A thread's conversation, read from the runtime its application runs on:
|
|
26
|
+
* held there, or resumed from its record. Throws the runtime's sentence when
|
|
27
|
+
* neither answers.
|
|
28
|
+
*/
|
|
29
|
+
export declare function openThread({ agentBaseUrl, agentId, uid, token, fetcher, }: {
|
|
30
|
+
agentBaseUrl: string;
|
|
31
|
+
agentId: string;
|
|
32
|
+
uid: string;
|
|
33
|
+
token?: string | null;
|
|
34
|
+
fetcher?: typeof fetch;
|
|
35
|
+
}): Promise<ChatMessage[]>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { messagesOfThread } from '../embed/embedSession';
|
|
6
|
+
/** What opening a thread says, in a person's words. */
|
|
7
|
+
export const THREAD_WORDS = {
|
|
8
|
+
opening: 'Opening your conversation…',
|
|
9
|
+
notOpened: (detail) => `Your conversation could not be opened, so this is a new one: ${detail}`,
|
|
10
|
+
};
|
|
11
|
+
/** The AG-UI messages a session-API stream's `MESSAGES_SNAPSHOT` carries, if one does. */
|
|
12
|
+
export function snapshotOfStream(text) {
|
|
13
|
+
let found;
|
|
14
|
+
for (const block of text.split(/\r?\n\r?\n/)) {
|
|
15
|
+
const data = block
|
|
16
|
+
.split(/\r?\n/)
|
|
17
|
+
.filter(line => line.startsWith('data:'))
|
|
18
|
+
.map(line => line.slice('data:'.length).trim())
|
|
19
|
+
.join('');
|
|
20
|
+
if (!data) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const event = JSON.parse(data);
|
|
25
|
+
if (event.type === 'MESSAGES_SNAPSHOT' && Array.isArray(event.messages)) {
|
|
26
|
+
found = event.messages;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Not an event: skipped.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return found;
|
|
34
|
+
}
|
|
35
|
+
async function detailOf(response) {
|
|
36
|
+
try {
|
|
37
|
+
const body = (await response.json());
|
|
38
|
+
if (typeof body.detail === 'string' && body.detail) {
|
|
39
|
+
return body.detail;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// No sentence: the status says it.
|
|
44
|
+
}
|
|
45
|
+
return `${response.status}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A thread's conversation, read from the runtime its application runs on:
|
|
49
|
+
* held there, or resumed from its record. Throws the runtime's sentence when
|
|
50
|
+
* neither answers.
|
|
51
|
+
*/
|
|
52
|
+
export async function openThread({ agentBaseUrl, agentId, uid, token, fetcher = fetch, }) {
|
|
53
|
+
const base = `${agentBaseUrl.replace(/\/+$/, '')}/api/v1/apps/sessions/${encodeURIComponent(uid)}`;
|
|
54
|
+
const authorization = token
|
|
55
|
+
? { Authorization: `Bearer ${token}` }
|
|
56
|
+
: {};
|
|
57
|
+
const held = await fetcher(`${base}/messages`, { headers: authorization });
|
|
58
|
+
if (held.ok) {
|
|
59
|
+
const body = (await held.json());
|
|
60
|
+
return messagesOfThread(body.messages);
|
|
61
|
+
}
|
|
62
|
+
if (held.status !== 404) {
|
|
63
|
+
throw new Error(await detailOf(held));
|
|
64
|
+
}
|
|
65
|
+
// Not held here: resumed from its record, under the same uid.
|
|
66
|
+
const resumed = await fetcher(`${base}/resume`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: { 'Content-Type': 'application/json', ...authorization },
|
|
69
|
+
body: JSON.stringify({ agent: agentId }),
|
|
70
|
+
});
|
|
71
|
+
if (!resumed.ok) {
|
|
72
|
+
throw new Error(await detailOf(resumed));
|
|
73
|
+
}
|
|
74
|
+
const snapshot = snapshotOfStream(await resumed.text());
|
|
75
|
+
if (!snapshot) {
|
|
76
|
+
throw new Error(`The runtime said nothing of session ${uid}.`);
|
|
77
|
+
}
|
|
78
|
+
return messagesOfThread(snapshot);
|
|
79
|
+
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* @module loop/embed/LoopEmbed
|
|
19
19
|
*/
|
|
20
20
|
import { type ReactNode } from 'react';
|
|
21
|
-
import type {
|
|
21
|
+
import type { PlatformInput } from '@datalayer/reactor';
|
|
22
22
|
import { type LoopPresetOptions } from '../presets';
|
|
23
23
|
export type LoopEmbedProps = LoopPresetOptions & {
|
|
24
24
|
/** Which agent the conversation is with. */
|
|
@@ -59,9 +59,10 @@ export type LoopEmbedProps = LoopPresetOptions & {
|
|
|
59
59
|
* How a page adds something to Loop rather than around it — a button in the
|
|
60
60
|
* window's title bar, a panel of its own, a command. Without this a host
|
|
61
61
|
* would have to rebuild the plugin list to add one thing to it, which is the
|
|
62
|
-
* assembly this component exists to save.
|
|
62
|
+
* assembly this component exists to save. An extension groups some of
|
|
63
|
+
* them, as an application's own plugins are (`AppRenderer`, LOOP F-15).
|
|
63
64
|
*/
|
|
64
|
-
plugins?:
|
|
65
|
+
plugins?: PlatformInput[];
|
|
65
66
|
};
|
|
66
67
|
export declare function LoopEmbed({ agentId, showHeader, chatHeaderActions, headerActions, headerContainer, frameTitle, frameHeight, sidebarRail, plugins, ...preset }: LoopEmbedProps): React.JSX.Element;
|
|
67
68
|
export default LoopEmbed;
|
|
@@ -124,3 +124,30 @@ export declare function hostFrontendTools(app: Pick<AppSpec, 'connections' | 'ru
|
|
|
124
124
|
* the page says.
|
|
125
125
|
*/
|
|
126
126
|
export declare function hostUserRunProps(app: Pick<AppSpec, 'deployment'>, host: () => AppEmbedHost): RunPropsContribution | undefined;
|
|
127
|
+
/** A user token ai-agents signed, and when it ends (seconds since the epoch). */
|
|
128
|
+
export type SignedUserToken = {
|
|
129
|
+
token: string;
|
|
130
|
+
exp: number;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Asks ai-agents to sign the person signed in to Datalayer as a deployment's
|
|
134
|
+
* user (LOOP D-21; STUDIO A-18 to A-20), with their own token: what a
|
|
135
|
+
* surface that has no host server holding the deployment's secret — the
|
|
136
|
+
* VS Code extension, Jupyter AI Agents, Datalayer Desktop — sends as
|
|
137
|
+
* `forwardedProps.loop.user_token` with the runs of an application that
|
|
138
|
+
* says `user: signed`. HS256 with the deployment's secret, `sub` the
|
|
139
|
+
* person's uid, `name` theirs, fifteen minutes; refused (`403`) for an
|
|
140
|
+
* application's principal or a narrowed token, and for a person the
|
|
141
|
+
* deployment does not let in. Those surfaces share no code, so they copy
|
|
142
|
+
* it.
|
|
143
|
+
*
|
|
144
|
+
* @param aiAgentsUrl - The ai-agents service's base URL.
|
|
145
|
+
* @param deploymentUid - The deployment talked to.
|
|
146
|
+
* @param token - The person's Datalayer token.
|
|
147
|
+
* @param fetcher - What asks; `fetch` unless given.
|
|
148
|
+
*
|
|
149
|
+
* @returns The user token and when it ends.
|
|
150
|
+
*
|
|
151
|
+
* @throws With ai-agents' sentence when it refuses.
|
|
152
|
+
*/
|
|
153
|
+
export declare function fetchUserToken(aiAgentsUrl: string, deploymentUid: string, token: string, fetcher?: (url: string, init: RequestInit) => Promise<Response>): Promise<SignedUserToken>;
|
|
@@ -122,3 +122,50 @@ export function hostUserRunProps(app, host) {
|
|
|
122
122
|
},
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Asks ai-agents to sign the person signed in to Datalayer as a deployment's
|
|
127
|
+
* user (LOOP D-21; STUDIO A-18 to A-20), with their own token: what a
|
|
128
|
+
* surface that has no host server holding the deployment's secret — the
|
|
129
|
+
* VS Code extension, Jupyter AI Agents, Datalayer Desktop — sends as
|
|
130
|
+
* `forwardedProps.loop.user_token` with the runs of an application that
|
|
131
|
+
* says `user: signed`. HS256 with the deployment's secret, `sub` the
|
|
132
|
+
* person's uid, `name` theirs, fifteen minutes; refused (`403`) for an
|
|
133
|
+
* application's principal or a narrowed token, and for a person the
|
|
134
|
+
* deployment does not let in. Those surfaces share no code, so they copy
|
|
135
|
+
* it.
|
|
136
|
+
*
|
|
137
|
+
* @param aiAgentsUrl - The ai-agents service's base URL.
|
|
138
|
+
* @param deploymentUid - The deployment talked to.
|
|
139
|
+
* @param token - The person's Datalayer token.
|
|
140
|
+
* @param fetcher - What asks; `fetch` unless given.
|
|
141
|
+
*
|
|
142
|
+
* @returns The user token and when it ends.
|
|
143
|
+
*
|
|
144
|
+
* @throws With ai-agents' sentence when it refuses.
|
|
145
|
+
*/
|
|
146
|
+
export async function fetchUserToken(aiAgentsUrl, deploymentUid, token, fetcher = fetch) {
|
|
147
|
+
const url = `${aiAgentsUrl.replace(/\/+$/, '')}/api/ai-agents/v1/apps/deployments/${encodeURIComponent(deploymentUid)}/user-token`;
|
|
148
|
+
const response = await fetcher(url, {
|
|
149
|
+
method: 'POST',
|
|
150
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
151
|
+
});
|
|
152
|
+
let body = {};
|
|
153
|
+
try {
|
|
154
|
+
const read = await response.json();
|
|
155
|
+
body =
|
|
156
|
+
read && typeof read === 'object' ? read : {};
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// The status says it.
|
|
160
|
+
}
|
|
161
|
+
if (!response.ok) {
|
|
162
|
+
const detail = typeof body.detail === 'string' ? body.detail : '';
|
|
163
|
+
throw new Error(detail || `ai-agents refused to sign you (${response.status}).`);
|
|
164
|
+
}
|
|
165
|
+
const signed = typeof body.user_token === 'string' ? body.user_token : '';
|
|
166
|
+
const exp = Number(body.exp);
|
|
167
|
+
if (!signed || !Number.isFinite(exp)) {
|
|
168
|
+
throw new Error('ai-agents answered no user token.');
|
|
169
|
+
}
|
|
170
|
+
return { token: signed, exp };
|
|
171
|
+
}
|
package/lib/loop/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export { PromptPlugin, PROMPT_PLUGIN_NAME } from './plugins/prompt';
|
|
|
70
70
|
export { LoopEmbed, type LoopEmbedProps } from './embed/LoopEmbed';
|
|
71
71
|
export { AppEmbed, AppFloating, embedAssistantCharacter, type AppEmbedProps, type AppFloatingProps, type EmbedSession, useEmbedSession, useHostBridge, } from './embed/AppEmbed';
|
|
72
72
|
export { EMBED_SESSION_KEY_PREFIX, embedSessionKey, visitOfToken, } from './embed/embedSession';
|
|
73
|
-
export { HOST_CONTEXT_TOOL, hostFrontendTools, hostNotAllowed, hostRefused, hostTool, hostToolsOf, hostUserRunProps, signedUser, type AppEmbedHost, type HostEvent, type HostFunction, type HostQuestion, } from './embed/hostBridge';
|
|
73
|
+
export { HOST_CONTEXT_TOOL, hostFrontendTools, hostNotAllowed, hostRefused, hostTool, hostToolsOf, hostUserRunProps, fetchUserToken, signedUser, type SignedUserToken, type AppEmbedHost, type HostEvent, type HostFunction, type HostQuestion, } from './embed/hostBridge';
|
|
74
74
|
export { defineDatalayerAppElement, type DatalayerAppElementOptions, } from './embed/element';
|
|
75
75
|
export { EMBED_ATTRIBUTES, EMBED_HOST_VARIABLES, EMBED_TAG, embedLookOf, embedSnippetOf, floatingViewOf, languageOf, resumeOf, type EmbedLook, type EmbedSnippetOptions, } from './embed/embedConfig';
|
|
76
76
|
export { SubagentActivityPlugin, SubagentPulse, SUBAGENT_ACTIVITY_PLUGIN_NAME, } from './plugins/subagent-activity';
|
package/lib/loop/index.js
CHANGED
|
@@ -91,7 +91,7 @@ export { LoopEmbed } from './embed/LoopEmbed';
|
|
|
91
91
|
export { AppEmbed, AppFloating, embedAssistantCharacter, useEmbedSession, useHostBridge, } from './embed/AppEmbed';
|
|
92
92
|
export { EMBED_SESSION_KEY_PREFIX, embedSessionKey, visitOfToken, } from './embed/embedSession';
|
|
93
93
|
// The host page and an embedded application, talking (LOOP D-10).
|
|
94
|
-
export { HOST_CONTEXT_TOOL, hostFrontendTools, hostNotAllowed, hostRefused, hostTool, hostToolsOf, hostUserRunProps, signedUser, } from './embed/hostBridge';
|
|
94
|
+
export { HOST_CONTEXT_TOOL, hostFrontendTools, hostNotAllowed, hostRefused, hostTool, hostToolsOf, hostUserRunProps, fetchUserToken, signedUser, } from './embed/hostBridge';
|
|
95
95
|
export { defineDatalayerAppElement, } from './embed/element';
|
|
96
96
|
export { EMBED_ATTRIBUTES, EMBED_HOST_VARIABLES, EMBED_TAG, embedLookOf, embedSnippetOf, floatingViewOf, languageOf, resumeOf, } from './embed/embedConfig';
|
|
97
97
|
export { SubagentActivityPlugin, SubagentPulse, SUBAGENT_ACTIVITY_PLUGIN_NAME, } from './plugins/subagent-activity';
|
|
@@ -40,6 +40,13 @@ export type AgentCapacityOptions = {
|
|
|
40
40
|
model?: string;
|
|
41
41
|
/** What its modes tell a run turned in the page (LOOP P-19). */
|
|
42
42
|
modeEffect?: AgentBlueprintContribution['modeEffect'];
|
|
43
|
+
/**
|
|
44
|
+
* Its own name in place of `@datalayer/loop-plugin-agent-<key>`: an
|
|
45
|
+
* application's, the name its runtime's plugin has too (LOOP F-15).
|
|
46
|
+
*/
|
|
47
|
+
name?: string;
|
|
48
|
+
/** The runtime plugins it cannot work without (Reactor's cross-tier declaration). */
|
|
49
|
+
requiredBackendPlugins?: string[];
|
|
43
50
|
};
|
|
44
51
|
export declare function defineAgentCapacityPlugin(options: AgentCapacityOptions): ReactorPlugin<Record<string, never>, unknown, unknown>;
|
|
45
52
|
export default defineAgentCapacityPlugin;
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
import { contribution, definePlugin, } from '@datalayer/reactor';
|
|
24
24
|
import { LoopAgentBlueprint, LoopChatSuggestion, } from '../../core';
|
|
25
25
|
export function defineAgentCapacityPlugin(options) {
|
|
26
|
-
const { key, displayName, description, specId, octicon, emoji, codemode, createPayload, suggestions, instructions, model, modeEffect, } = options;
|
|
26
|
+
const { key, displayName, description, specId, octicon, emoji, codemode, createPayload, suggestions, instructions, model, modeEffect, name, requiredBackendPlugins, } = options;
|
|
27
27
|
return definePlugin({
|
|
28
|
-
name: `@datalayer/loop-plugin-agent-${key}`,
|
|
28
|
+
name: name ?? `@datalayer/loop-plugin-agent-${key}`,
|
|
29
|
+
...(requiredBackendPlugins ? { requiredBackendPlugins } : {}),
|
|
29
30
|
displayName,
|
|
30
31
|
description,
|
|
31
32
|
octicon: octicon ?? 'dependabot',
|
|
@@ -7,6 +7,7 @@ import { useReactorPlatform, useSignalValue } from '@datalayer/reactor/react';
|
|
|
7
7
|
import { useAgentRuntimes } from '../../../hooks/useAgentRuntimes';
|
|
8
8
|
import { AGENTSPECS } from '../../../specs/agents/agents';
|
|
9
9
|
import { IDLE_SANDBOX_TARGET_SIGNAL } from '../../core';
|
|
10
|
+
import { appLaunchOf } from './appLaunch';
|
|
10
11
|
import { AGENTS_PLUGIN_NAME } from './plugin';
|
|
11
12
|
import { useOptionalSandboxService } from './useSandboxService';
|
|
12
13
|
/**
|
|
@@ -69,9 +70,19 @@ export function DatalayerAgentBridge() {
|
|
|
69
70
|
// An application's spec, when the workspace runs one.
|
|
70
71
|
...(createPayload ? { createPayload } : {}),
|
|
71
72
|
}), [agentSpecId, agentName, protocol, createPayload]);
|
|
73
|
+
/*
|
|
74
|
+
* The application the runtime is launched for (STUDIO R-19): its Appspec
|
|
75
|
+
* and where it runs, read from the payload its agent is created with — the
|
|
76
|
+
* Studio's Preview, the hosted page signed in. Sent with the launch, so the
|
|
77
|
+
* runtime is given the secrets its connections declare before its agent is
|
|
78
|
+
* made; without it, a connection needing a secret is refused on the
|
|
79
|
+
* runtime. A bare spec launches none.
|
|
80
|
+
*/
|
|
81
|
+
const appLaunch = useMemo(() => appLaunchOf(createPayload), [createPayload]);
|
|
72
82
|
const { runtime, status, error } = useAgentRuntimes({
|
|
73
83
|
agentSpecId,
|
|
74
84
|
agentConfig,
|
|
85
|
+
...(appLaunch ? { appLaunch } : {}),
|
|
75
86
|
variant: 'cloud-pydanticai',
|
|
76
87
|
autoStart: onDatalayer && !already,
|
|
77
88
|
autoCreateAgent: onDatalayer && !already,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an application's runtime is launched with (STUDIO R-19).
|
|
3
|
+
*
|
|
4
|
+
* Pure, so it is read without the agent hook's runtime stack.
|
|
5
|
+
*
|
|
6
|
+
* @module loop/plugins/agents/appLaunch
|
|
7
|
+
*/
|
|
8
|
+
import type { AppLaunch } from '../../../hooks/useAgentRuntimes';
|
|
9
|
+
/**
|
|
10
|
+
* The launch of the application an agent is created with, or none.
|
|
11
|
+
*
|
|
12
|
+
* `app_spec` and `app_instance` are what `appDatalayerCreatePayload` writes;
|
|
13
|
+
* the launch sends them as `RuntimesClient.create` does in Python.
|
|
14
|
+
*/
|
|
15
|
+
export declare function appLaunchOf(createPayload: Record<string, unknown> | undefined): AppLaunch | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The launch of the application an agent is created with, or none.
|
|
7
|
+
*
|
|
8
|
+
* `app_spec` and `app_instance` are what `appDatalayerCreatePayload` writes;
|
|
9
|
+
* the launch sends them as `RuntimesClient.create` does in Python.
|
|
10
|
+
*/
|
|
11
|
+
export function appLaunchOf(createPayload) {
|
|
12
|
+
const appSpec = createPayload?.app_spec;
|
|
13
|
+
if (!appSpec || typeof appSpec !== 'object') {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const instance = (createPayload?.app_instance ?? {});
|
|
17
|
+
const appUid = typeof instance.app_uid === 'string' && instance.app_uid
|
|
18
|
+
? instance.app_uid
|
|
19
|
+
: undefined;
|
|
20
|
+
const deploymentUid = typeof instance.deployment_uid === 'string' && instance.deployment_uid
|
|
21
|
+
? instance.deployment_uid
|
|
22
|
+
: undefined;
|
|
23
|
+
return {
|
|
24
|
+
appSpec: appSpec,
|
|
25
|
+
...(appUid ? { appUid } : {}),
|
|
26
|
+
...(deploymentUid ? { deploymentUid } : {}),
|
|
27
|
+
};
|
|
28
|
+
}
|