@datalayer/agent-runtimes 1.3.81 โ†’ 1.3.83

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.
Files changed (72) hide show
  1. package/lib/chat/assistant/SpeechBalloon.js +16 -1
  2. package/lib/chat/base/ChatBase.js +40 -4
  3. package/lib/chat/indicators/McpStatusIndicator.d.ts +1 -1
  4. package/lib/chat/indicators/McpStatusIndicator.js +13 -6
  5. package/lib/chat/indicators/SkillsStatusIndicator.d.ts +1 -1
  6. package/lib/chat/indicators/SkillsStatusIndicator.js +7 -3
  7. package/lib/chat/prompt/InputPrompt.d.ts +4 -1
  8. package/lib/chat/prompt/InputPrompt.js +2 -2
  9. package/lib/chat/prompt/InputPromptBase.d.ts +4 -1
  10. package/lib/chat/prompt/InputPromptBase.js +2 -2
  11. package/lib/chat/prompt/InputPromptLexical.d.ts +7 -1
  12. package/lib/chat/prompt/InputPromptLexical.js +5 -3
  13. package/lib/components/a2ui/datalayer/Form.js +19 -2
  14. package/lib/components/teams/index.d.ts +1 -0
  15. package/lib/components/teams/index.js +1 -0
  16. package/lib/components/teams/usePeerSandbox.d.ts +13 -0
  17. package/lib/components/teams/usePeerSandbox.js +59 -0
  18. package/lib/examples/AgentA2ATeamExample.js +7 -2
  19. package/lib/loop/apps/AppComposer.d.ts +31 -0
  20. package/lib/loop/apps/AppComposer.js +67 -0
  21. package/lib/loop/apps/AppRenderer.d.ts +16 -5
  22. package/lib/loop/apps/AppRenderer.js +49 -16
  23. package/lib/loop/apps/appspec.d.ts +8 -1
  24. package/lib/loop/apps/appspec.js +88 -23
  25. package/lib/loop/apps/checks.js +125 -8
  26. package/lib/loop/apps/composer.d.ts +37 -0
  27. package/lib/loop/apps/composer.js +61 -0
  28. package/lib/loop/apps/index.d.ts +2 -0
  29. package/lib/loop/apps/index.js +2 -0
  30. package/lib/loop/core/index.d.ts +31 -0
  31. package/lib/loop/core/index.js +22 -0
  32. package/lib/loop/embed/AppEmbed.d.ts +46 -7
  33. package/lib/loop/embed/AppEmbed.js +108 -26
  34. package/lib/loop/embed/LoopEmbed.js +2 -0
  35. package/lib/loop/embed/element.js +19 -5
  36. package/lib/loop/embed/embedConfig.d.ts +10 -1
  37. package/lib/loop/embed/embedConfig.js +12 -1
  38. package/lib/loop/embed/embedSession.d.ts +79 -0
  39. package/lib/loop/embed/embedSession.js +136 -0
  40. package/lib/loop/embed/embedTheme.d.ts +12 -9
  41. package/lib/loop/embed/embedTheme.js +32 -22
  42. package/lib/loop/index.d.ts +4 -3
  43. package/lib/loop/index.js +4 -3
  44. package/lib/loop/plugins/agent-capacity/index.d.ts +3 -1
  45. package/lib/loop/plugins/agent-capacity/index.js +2 -1
  46. package/lib/loop/plugins/app-page/appPageModel.d.ts +14 -5
  47. package/lib/loop/plugins/app-page/appPageModel.js +80 -88
  48. package/lib/loop/plugins/chat/ChatView.js +31 -4
  49. package/lib/loop/plugins/chat/index.d.ts +6 -1
  50. package/lib/loop/presets.d.ts +3 -1
  51. package/lib/loop/presets.js +2 -1
  52. package/lib/loop/shell/LoopWorkspace.js +3 -0
  53. package/lib/protocols/BrowserAgentAdapter.d.ts +18 -0
  54. package/lib/protocols/BrowserAgentAdapter.js +35 -2
  55. package/lib/runtimes/__tests__/fixtures/accounting-agent-card.json +8 -0
  56. package/lib/runtimes/browser/a2aPeer.d.ts +11 -0
  57. package/lib/runtimes/browser/a2aPeer.js +15 -1
  58. package/lib/runtimes/browser/protocol.d.ts +3 -0
  59. package/lib/runtimes/browser/protocol.js +2 -1
  60. package/lib/specs/agents/agents.js +6 -3
  61. package/lib/specs/apps.js +216 -176
  62. package/lib/specs/appspecSchema.js +205 -84
  63. package/lib/specs/cogs.js +3 -2
  64. package/lib/types/agentspecs.d.ts +92 -7
  65. package/lib/types/chat.d.ts +29 -1
  66. package/package.json +1 -1
  67. package/scripts/codegen/generate_agents.py +4 -2
  68. package/scripts/codegen/generate_apps.py +0 -1
  69. package/scripts/codegen/generate_backend_tools.py +4 -12
  70. package/scripts/codegen/generate_cogs.py +3 -1
  71. package/scripts/codegen/generate_ui_plugins.py +22 -9
  72. package/scripts/voice/transcribe.mjs +29 -21
@@ -26,6 +26,7 @@ import { type LanguageModel } from 'ai';
26
26
  import type { ProtocolAdapterConfig } from '../types/protocol';
27
27
  import type { ChatMessage } from '../types/messages';
28
28
  import type { FrontendToolDefinition } from '../types/tools';
29
+ import type { AppModeEffect } from '../types/agentspecs';
29
30
  import type { AgentStreamSubagentPayload } from '../types/stream';
30
31
  import { BaseProtocolAdapter } from './BaseProtocolAdapter';
31
32
  import type { TeamContextSharing } from '../types/teams';
@@ -63,6 +64,13 @@ export interface BrowserAgentAdapterConfig extends ProtocolAdapterConfig, Fronte
63
64
  sharing?: TeamContextSharing;
64
65
  /** Told what a delegated run does, as it does it โ€” see `subagentTools`. */
65
66
  onSubagentEvent?: (event: AgentStreamSubagentPayload) => void;
67
+ /**
68
+ * What the modes a run is sent in (`forwardedProps.loop.modes`, LOOP P-19)
69
+ * tell it, and the model it runs on: an application's, by agentspecs'
70
+ * rules. Unsaid for an agent with no modes, which refuses a run sent in
71
+ * some.
72
+ */
73
+ modeEffect?: (chosen: Record<string, string>) => AppModeEffect;
66
74
  }
67
75
  /**
68
76
  * An agent loop running in the page, speaking the protocol adapter interface.
@@ -111,6 +119,15 @@ export declare class BrowserAgentAdapter extends BaseProtocolAdapter {
111
119
  * `languageModel` is the host's own choice and is not swapped out.
112
120
  */
113
121
  private resolveModel;
122
+ /**
123
+ * What the modes a run is sent in tell it, and the model it runs on (LOOP
124
+ * P-19) โ€” the runtime's session API applies the same, for that run only.
125
+ *
126
+ * Refused, in a sentence, rather than run without them: modes sent to an
127
+ * agent that has none, modes that are not the application's, and a mode
128
+ * naming a model for an agent whose model is the host's own.
129
+ */
130
+ private runModes;
114
131
  /**
115
132
  * Run one turn of the loop and report it as it happens.
116
133
  *
@@ -121,5 +138,6 @@ export declare class BrowserAgentAdapter extends BaseProtocolAdapter {
121
138
  sendMessage(message: ChatMessage, options?: {
122
139
  messages?: ChatMessage[];
123
140
  model?: string;
141
+ forwardedProps?: Record<string, unknown>;
124
142
  }): Promise<void>;
125
143
  }
@@ -140,6 +140,30 @@ export class BrowserAgentAdapter extends BaseProtocolAdapter {
140
140
  }
141
141
  return createBrowserModel({ ...inference, model: requested || model });
142
142
  }
143
+ /**
144
+ * What the modes a run is sent in tell it, and the model it runs on (LOOP
145
+ * P-19) โ€” the runtime's session API applies the same, for that run only.
146
+ *
147
+ * Refused, in a sentence, rather than run without them: modes sent to an
148
+ * agent that has none, modes that are not the application's, and a mode
149
+ * naming a model for an agent whose model is the host's own.
150
+ */
151
+ runModes(forwardedProps) {
152
+ const loop = forwardedProps?.loop;
153
+ const chosen = loop?.modes;
154
+ if (!chosen || Object.keys(chosen).length === 0) {
155
+ return undefined;
156
+ }
157
+ const { modeEffect, languageModel } = this.browserConfig;
158
+ if (!modeEffect) {
159
+ throw new Error('This agent has no modes: the options chosen in the composer cannot be applied to it.');
160
+ }
161
+ const effect = modeEffect(chosen);
162
+ 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.`);
164
+ }
165
+ return effect;
166
+ }
143
167
  /**
144
168
  * Run one turn of the loop and report it as it happens.
145
169
  *
@@ -194,9 +218,18 @@ export class BrowserAgentAdapter extends BaseProtocolAdapter {
194
218
  this.emit({ type: 'message', message: assistant, timestamp: new Date() });
195
219
  };
196
220
  try {
221
+ // The modes the person is in, for this run only: their instructions
222
+ // after the agent's, and the model one names over the chat's.
223
+ const modes = this.runModes(options?.forwardedProps);
224
+ const { instructions } = this.browserConfig;
225
+ const system = modes?.instructions
226
+ ? [instructions?.trim(), modes.instructions]
227
+ .filter(Boolean)
228
+ .join('\n\n')
229
+ : instructions;
197
230
  const result = streamText({
198
- model: this.resolveModel(options?.model),
199
- system: this.browserConfig.instructions,
231
+ model: this.resolveModel(modes?.model || options?.model),
232
+ system,
200
233
  messages: history,
201
234
  tools: this.tools,
202
235
  stopWhen: stepCountIs(this.browserConfig.maxSteps ?? DEFAULT_BROWSER_MAX_STEPS),
@@ -38,6 +38,14 @@
38
38
  "pause": "/api/v1/a2a/pause",
39
39
  "steer": "/api/v1/a2a/steer"
40
40
  }
41
+ },
42
+ {
43
+ "uri": "https://datalayer.ai/extensions/face/v1",
44
+ "description": "Its face: an emoji, and an avatar when it has one.",
45
+ "required": false,
46
+ "params": {
47
+ "emoji": "๐Ÿงพ"
48
+ }
41
49
  }
42
50
  ]
43
51
  },
@@ -37,7 +37,18 @@ export type A2APeer = {
37
37
  client: Client;
38
38
  card: AgentCard;
39
39
  skill: AgentSkill;
40
+ /** Its face, when its card carries one (`A2A_FACE_EXTENSION_URI`). */
41
+ face?: A2APeerFace;
40
42
  };
43
+ /** The extension an agent card carries its face in: its name stays plain. */
44
+ export declare const A2A_FACE_EXTENSION_URI = "https://datalayer.ai/extensions/face/v1";
45
+ /** A peer's face: its emoji and, when it has one, its avatar's name. */
46
+ export type A2APeerFace = {
47
+ emoji: string;
48
+ avatar?: string;
49
+ };
50
+ /** The face an agent card carries, if it carries one. */
51
+ export declare function faceOfCard(card: AgentCard): A2APeerFace | undefined;
41
52
  export type ConnectA2APeerOptions = {
42
53
  /** Where the peer is served: `โ€ฆ/api/v1/a2a/agents/<application id>`. */
43
54
  url: string;
@@ -36,6 +36,19 @@ import { ClientFactory, ClientFactoryOptions, DefaultAgentCardResolver, JsonRpcT
36
36
  import { jsonSchema, tool } from 'ai';
37
37
  /** Where an A2A agent's card is, under the address it is served at. */
38
38
  export const AGENT_CARD_PATH = '.well-known/agent-card.json';
39
+ /** The extension an agent card carries its face in: its name stays plain. */
40
+ export const A2A_FACE_EXTENSION_URI = 'https://datalayer.ai/extensions/face/v1';
41
+ /** The face an agent card carries, if it carries one. */
42
+ export function faceOfCard(card) {
43
+ const extension = card.capabilities?.extensions?.find(candidate => candidate.uri === A2A_FACE_EXTENSION_URI);
44
+ const params = (extension?.params ?? {});
45
+ if (typeof params.emoji !== 'string' || !params.emoji) {
46
+ return undefined;
47
+ }
48
+ return typeof params.avatar === 'string' && params.avatar
49
+ ? { emoji: params.emoji, avatar: params.avatar }
50
+ : { emoji: params.emoji };
51
+ }
39
52
  /** A fetch that sends the key as a bearer token, beside the caller's headers. */
40
53
  function withKey(base, key) {
41
54
  if (!key) {
@@ -69,7 +82,8 @@ export async function connectA2APeer(options) {
69
82
  if (!skill) {
70
83
  throw new Error(`${card.name || root} offers no skill on its agent card: there is nothing to ask it.`);
71
84
  }
72
- return { client, card, skill };
85
+ const face = faceOfCard(card);
86
+ return face ? { client, card, skill, face } : { client, card, skill };
73
87
  }
74
88
  /** The media types an answer in words comes in: the answer itself, never an artifact of its own. */
75
89
  export const TEXT_MEDIA_TYPES = [
@@ -12,6 +12,7 @@ import type { ProtocolConfig } from '../../types/protocol';
12
12
  import type { AgentStreamSubagentPayload } from '../../types/stream';
13
13
  import type { FrontendToolDefinition } from '../../types/tools';
14
14
  import type { TeamContextSharing } from '../../types/teams';
15
+ import type { AppModeEffect } from '../../types/agentspecs';
15
16
  import type { BrowserModelOptions } from './model';
16
17
  import type { BrowserSubagent } from './subagents';
17
18
  export type BrowserProtocolOptions = {
@@ -37,6 +38,8 @@ export type BrowserProtocolOptions = {
37
38
  sharing?: TeamContextSharing;
38
39
  /** Told what a delegated run does, as it does it โ€” see `subagentTools`. */
39
40
  onSubagentEvent?: (event: AgentStreamSubagentPayload) => void;
41
+ /** What the modes a run is sent in tell it (LOOP P-19); none when unsaid. */
42
+ modeEffect?: (chosen: Record<string, string>) => AppModeEffect;
40
43
  };
41
44
  /**
42
45
  * The protocol config for an agent whose loop runs in this page.
@@ -16,7 +16,7 @@
16
16
  * keystroke, so an omitted flag reads as a chat that silently ignores typing.
17
17
  */
18
18
  export function browserProtocolConfig(options) {
19
- const { agentId, instructions, model, frontendTools, inference, subagents, sharing, onSubagentEvent, } = options;
19
+ const { agentId, instructions, model, frontendTools, inference, subagents, sharing, onSubagentEvent, modeEffect, } = options;
20
20
  return {
21
21
  type: 'browser-vercel-ai',
22
22
  endpoint: '',
@@ -30,6 +30,7 @@ export function browserProtocolConfig(options) {
30
30
  subagents,
31
31
  sharing,
32
32
  onSubagentEvent,
33
+ modeEffect,
33
34
  },
34
35
  };
35
36
  }
@@ -4900,8 +4900,9 @@ export const JUPYTER_DATA_ANALYST_AGENTSPEC_0_0_1 = {
4900
4900
  'collaboration',
4901
4901
  ],
4902
4902
  domain: undefined,
4903
- enabled: false,
4903
+ enabled: true,
4904
4904
  model: 'bedrock:us.anthropic.claude-sonnet-4-6',
4905
+ modelAdditionals: ['alibaba:qwen-max'],
4905
4906
  mcpServers: [],
4906
4907
  skills: [].filter(Boolean),
4907
4908
  backendTools: [TOOL_MAP['runtime-echo:0.0.1']],
@@ -7966,8 +7967,9 @@ export const WORKER_CUSTOMER_INTERVIEWER_AGENTSPEC_0_0_1 = {
7966
7967
  description: `Conducts adaptive, AI-led interviews that respond intelligently to each answer. It asks relevant follow-up questions, uncovers motivations and decision-making patterns, and transforms conversations into structured, actionable insights.`,
7967
7968
  tags: ['research', 'customer-support', 'analysis'],
7968
7969
  domain: 'market-analyst',
7969
- enabled: false,
7970
+ enabled: true,
7970
7971
  model: 'bedrock:us.anthropic.claude-sonnet-4-6',
7972
+ modelAdditionals: ['alibaba:qwen-max'],
7971
7973
  mcpServers: [],
7972
7974
  skills: [
7973
7975
  SKILL_MAP['text-summarizer:0.0.1']
@@ -8249,8 +8251,9 @@ export const WORKER_DOCUMENT_QA_AGENTSPEC_0_0_1 = {
8249
8251
  'qa',
8250
8252
  ],
8251
8253
  domain: 'personal-assistant',
8252
- enabled: false,
8254
+ enabled: true,
8253
8255
  model: 'bedrock:us.anthropic.claude-sonnet-4-6',
8256
+ modelAdditionals: ['alibaba:qwen-max'],
8254
8257
  mcpServers: [],
8255
8258
  skills: [
8256
8259
  SKILL_MAP['events:0.0.1']