@datalayer/agent-runtimes 1.3.63 → 1.3.65

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 (60) hide show
  1. package/lib/chat/ChatFloating.d.ts +9 -1
  2. package/lib/chat/ChatFloating.js +69 -18
  3. package/lib/chat/assistant/AssistantStage.d.ts +14 -1
  4. package/lib/chat/assistant/AssistantStage.js +48 -1
  5. package/lib/chat/assistant/state.d.ts +7 -1
  6. package/lib/chat/assistant/state.js +3 -2
  7. package/lib/chat/base/ChatBase.js +32 -4
  8. package/lib/chat/messages/ChatMessageList.d.ts +0 -6
  9. package/lib/chat/messages/ChatMessageList.js +8 -2
  10. package/lib/components/teams/A2ATeamGraph.d.ts +58 -0
  11. package/lib/components/teams/A2ATeamGraph.js +190 -0
  12. package/lib/components/teams/a2aTeamFlow.d.ts +33 -0
  13. package/lib/components/teams/a2aTeamFlow.js +32 -0
  14. package/lib/components/teams/index.d.ts +11 -0
  15. package/lib/components/teams/index.js +15 -0
  16. package/lib/components/teams/useA2ATeam.d.ts +57 -0
  17. package/lib/components/teams/useA2ATeam.js +233 -0
  18. package/lib/examples/AgentA2ATeamExample.d.ts +6 -3
  19. package/lib/examples/AgentA2ATeamExample.js +42 -208
  20. package/lib/examples/VoiceChatExample.d.ts +20 -0
  21. package/lib/examples/VoiceChatExample.js +64 -0
  22. package/lib/examples/example-selector.js +1 -0
  23. package/lib/examples/main.js +7 -1
  24. package/lib/loop/apps/appspec.d.ts +3 -1
  25. package/lib/loop/apps/appspec.js +31 -0
  26. package/lib/protocols/VercelAIAdapter.js +5 -0
  27. package/lib/specs/apps.js +112 -0
  28. package/lib/specs/appspecSchema.js +65 -0
  29. package/lib/specs/index.d.ts +1 -0
  30. package/lib/specs/index.js +1 -0
  31. package/lib/specs/voices.d.ts +72 -0
  32. package/lib/specs/voices.js +344 -0
  33. package/lib/types/agentspecs.d.ts +16 -0
  34. package/lib/types/chat.d.ts +11 -0
  35. package/lib/voice/VoiceInput.d.ts +35 -0
  36. package/lib/voice/VoiceInput.js +233 -0
  37. package/lib/voice/capture.d.ts +30 -0
  38. package/lib/voice/capture.js +113 -0
  39. package/lib/voice/consent.d.ts +6 -0
  40. package/lib/voice/consent.js +34 -0
  41. package/lib/voice/hearing.d.ts +37 -0
  42. package/lib/voice/hearing.js +168 -0
  43. package/lib/voice/index.d.ts +47 -0
  44. package/lib/voice/index.js +13 -0
  45. package/lib/voice/pinned.d.ts +28 -0
  46. package/lib/voice/pinned.js +75 -0
  47. package/lib/voice/sentences.d.ts +26 -0
  48. package/lib/voice/sentences.js +71 -0
  49. package/lib/voice/speaker.d.ts +66 -0
  50. package/lib/voice/speaker.js +168 -0
  51. package/lib/voice/types.d.ts +92 -0
  52. package/lib/voice/types.js +5 -0
  53. package/lib/voice/useSpokenAnswers.d.ts +12 -0
  54. package/lib/voice/useSpokenAnswers.js +90 -0
  55. package/package.json +7 -3
  56. package/scripts/codegen/generate_voices.py +279 -0
  57. package/scripts/voice/measure.py +244 -0
  58. package/scripts/voice/pin_store.py +159 -0
  59. package/scripts/voice/serve_store.py +70 -0
  60. package/scripts/voice/transcribe.mjs +58 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Answers heard, from Datalayer's speech service (VOICE.md VO-20, VO-33,
3
+ * decision 1): each sentence is sent to ai-agents as soon as it is written
4
+ * and played as soon as its audio arrives, one after the other, while the
5
+ * next ones are being made. The level of what plays moves the assistant's
6
+ * mouth (VO-23). Nothing is kept: each sentence's audio is dropped once played.
7
+ *
8
+ * @module voice/speaker
9
+ */
10
+ /** The path of the syntheses on ai-agents. */
11
+ export declare const SYNTHESES_PATH = "/api/ai-agents/v1/speech/syntheses";
12
+ /** What the speaker is doing, for the assistant and the controls. */
13
+ export interface SpeakerState {
14
+ /** Sound is playing. */
15
+ speaking: boolean;
16
+ /** The sentence being said, for the balloon (VO-26). */
17
+ sentence?: string;
18
+ /** Why the last sentence could not be said, in a sentence. */
19
+ refused?: string;
20
+ }
21
+ export interface SpeakerOptions {
22
+ /** ai-agents' origin, `https://r1.datalayer.run` or a local one. */
23
+ speechUrl: string;
24
+ /** The voice of the catalogue. */
25
+ voice: string;
26
+ language: string;
27
+ /** The person's token, an application's principal's, or a visitor's. */
28
+ token?: string;
29
+ /** Called whenever the state changes. */
30
+ onState?: (state: SpeakerState) => void;
31
+ /** Called with how long a sentence took from asked to first sound, in ms. */
32
+ onFirstSound?: (ms: number) => void;
33
+ fetcher?: typeof fetch;
34
+ }
35
+ /** Plays an answer's sentences, said by the speech service. */
36
+ export declare class ServerSpeaker {
37
+ private options;
38
+ private context?;
39
+ private analyser?;
40
+ private buffer?;
41
+ private queue;
42
+ private playing?;
43
+ private running;
44
+ private generation;
45
+ private state;
46
+ constructor(options: SpeakerOptions);
47
+ /** Change the voice, the language or the token for the sentences to come. */
48
+ update(options: Partial<SpeakerOptions>): void;
49
+ /**
50
+ * Must be called from a gesture once (a press, a click): a browser plays
51
+ * nothing a page did not start from one.
52
+ */
53
+ unlock(): void;
54
+ private audio;
55
+ /** How loud what plays is, between 0 and 1: what moves the mouth. */
56
+ level(): number;
57
+ private set;
58
+ /** Say a sentence after those already given. */
59
+ say(text: string): void;
60
+ private fetch;
61
+ private run;
62
+ /** Stop at once: what plays and what waits (barge-in, `Esc`; VO-13). */
63
+ stop(): void;
64
+ /** Stop, and let the audio context go. */
65
+ close(): void;
66
+ }
@@ -0,0 +1,168 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Answers heard, from Datalayer's speech service (VOICE.md VO-20, VO-33,
7
+ * decision 1): each sentence is sent to ai-agents as soon as it is written
8
+ * and played as soon as its audio arrives, one after the other, while the
9
+ * next ones are being made. The level of what plays moves the assistant's
10
+ * mouth (VO-23). Nothing is kept: each sentence's audio is dropped once played.
11
+ *
12
+ * @module voice/speaker
13
+ */
14
+ /** The path of the syntheses on ai-agents. */
15
+ export const SYNTHESES_PATH = '/api/ai-agents/v1/speech/syntheses';
16
+ /** Plays an answer's sentences, said by the speech service. */
17
+ export class ServerSpeaker {
18
+ options;
19
+ context;
20
+ analyser;
21
+ buffer;
22
+ queue = [];
23
+ playing;
24
+ running = false;
25
+ generation = 0;
26
+ state = { speaking: false };
27
+ constructor(options) {
28
+ this.options = options;
29
+ }
30
+ /** Change the voice, the language or the token for the sentences to come. */
31
+ update(options) {
32
+ this.options = { ...this.options, ...options };
33
+ }
34
+ /**
35
+ * Must be called from a gesture once (a press, a click): a browser plays
36
+ * nothing a page did not start from one.
37
+ */
38
+ unlock() {
39
+ this.audio();
40
+ void this.context?.resume();
41
+ }
42
+ audio() {
43
+ if (!this.context) {
44
+ this.context = new AudioContext();
45
+ this.analyser = this.context.createAnalyser();
46
+ this.analyser.fftSize = 512;
47
+ this.analyser.connect(this.context.destination);
48
+ this.buffer = new Float32Array(this.analyser.fftSize);
49
+ }
50
+ return this.context;
51
+ }
52
+ /** How loud what plays is, between 0 and 1: what moves the mouth. */
53
+ level() {
54
+ if (!this.analyser || !this.buffer || !this.state.speaking) {
55
+ return 0;
56
+ }
57
+ this.analyser.getFloatTimeDomainData(this.buffer);
58
+ let sum = 0;
59
+ for (const sample of this.buffer) {
60
+ sum += sample * sample;
61
+ }
62
+ return Math.min(1, Math.sqrt(sum / this.buffer.length) * 6);
63
+ }
64
+ set(state) {
65
+ this.state = { ...this.state, ...state };
66
+ this.options.onState?.(this.state);
67
+ }
68
+ /** Say a sentence after those already given. */
69
+ say(text) {
70
+ const sentence = text.trim();
71
+ if (!sentence) {
72
+ return;
73
+ }
74
+ this.queue.push({
75
+ text: sentence,
76
+ audio: this.fetch(sentence),
77
+ asked: performance.now(),
78
+ });
79
+ if (!this.running) {
80
+ void this.run(this.generation);
81
+ }
82
+ }
83
+ async fetch(text) {
84
+ const { speechUrl, voice, language, token, fetcher = fetch } = this.options;
85
+ try {
86
+ const answered = await fetcher(`${speechUrl.replace(/\/+$/, '')}${SYNTHESES_PATH}`, {
87
+ method: 'POST',
88
+ headers: {
89
+ 'Content-Type': 'application/json',
90
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
91
+ },
92
+ body: JSON.stringify({ text, voice, language, format: 'opus' }),
93
+ });
94
+ if (!answered.ok) {
95
+ const body = await answered.json().catch(() => ({}));
96
+ return typeof body?.detail === 'string'
97
+ ? body.detail
98
+ : `The answer could not be spoken (${answered.status}).`;
99
+ }
100
+ return await answered.arrayBuffer();
101
+ }
102
+ catch {
103
+ return 'Datalayer’s speech service could not be reached: the answer is still written here.';
104
+ }
105
+ }
106
+ async run(generation) {
107
+ this.running = true;
108
+ try {
109
+ while (this.queue.length && generation === this.generation) {
110
+ const next = this.queue.shift();
111
+ const audio = await next.audio;
112
+ if (generation !== this.generation) {
113
+ return;
114
+ }
115
+ if (typeof audio === 'string') {
116
+ // Refused: say why once, and drop what was waiting.
117
+ this.queue = [];
118
+ this.set({ speaking: false, sentence: undefined, refused: audio });
119
+ return;
120
+ }
121
+ const context = this.audio();
122
+ const decoded = await context.decodeAudioData(audio);
123
+ if (generation !== this.generation) {
124
+ return;
125
+ }
126
+ await new Promise(resolve => {
127
+ const source = context.createBufferSource();
128
+ source.buffer = decoded;
129
+ source.connect(this.analyser);
130
+ source.onended = () => resolve();
131
+ this.playing = source;
132
+ this.set({ speaking: true, sentence: next.text, refused: undefined });
133
+ this.options.onFirstSound?.(Math.round(performance.now() - next.asked));
134
+ source.start();
135
+ });
136
+ this.playing = undefined;
137
+ }
138
+ }
139
+ finally {
140
+ if (generation === this.generation) {
141
+ this.running = false;
142
+ if (this.state.speaking) {
143
+ this.set({ speaking: false, sentence: undefined });
144
+ }
145
+ }
146
+ }
147
+ }
148
+ /** Stop at once: what plays and what waits (barge-in, `Esc`; VO-13). */
149
+ stop() {
150
+ this.generation += 1;
151
+ this.queue = [];
152
+ this.running = false;
153
+ try {
154
+ this.playing?.stop();
155
+ }
156
+ catch {
157
+ // Already ended.
158
+ }
159
+ this.playing = undefined;
160
+ this.set({ speaking: false, sentence: undefined });
161
+ }
162
+ /** Stop, and let the audio context go. */
163
+ close() {
164
+ this.stop();
165
+ void this.context?.close();
166
+ this.context = undefined;
167
+ }
168
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Voice in the page (VOICE.md §6): what the chat needs to listen and speak.
3
+ *
4
+ * The packages that hear — transformers.js for Moonshine and Whisper, and
5
+ * vad-web for Silero VAD — are given by the host page (`VoiceEngines`), each
6
+ * loaded only once the person turns voice on: nothing of them is in a page
7
+ * that does not ask, and the library names no package it does not need.
8
+ * Their shapes are written here as far as voice uses them, against the
9
+ * packages' published types (`@huggingface/transformers` 4.3.0,
10
+ * `@ricky0123/vad-web` 0.0.31).
11
+ *
12
+ * @module voice/types
13
+ */
14
+ /** What transformers.js's `env` holds, as far as voice sets it. */
15
+ export interface TransformersEnv {
16
+ allowLocalModels: boolean;
17
+ allowRemoteModels: boolean;
18
+ remoteHost: string;
19
+ remotePathTemplate: string;
20
+ useBrowserCache: boolean;
21
+ fetch: (input: string | URL, init?: any) => Promise<any>;
22
+ backends: {
23
+ onnx: {
24
+ versions?: Record<string, string | undefined>;
25
+ wasm?: {
26
+ wasmPaths?: unknown;
27
+ proxy?: boolean;
28
+ };
29
+ };
30
+ };
31
+ }
32
+ /** A speech-recognition pipeline: audio at 16 kHz in, words out. */
33
+ export type SpeechRecognizer = (audio: Float32Array, options?: Record<string, unknown>) => Promise<{
34
+ text: string;
35
+ } | Array<{
36
+ text: string;
37
+ }>>;
38
+ /** The precisions a speech model of the catalogue is published in. */
39
+ export type SpeechDtype = 'fp32' | 'fp16' | 'q8' | 'int8' | 'uint8' | 'q4';
40
+ /** The part of `@huggingface/transformers` voice uses. */
41
+ export interface TransformersModule {
42
+ env: TransformersEnv;
43
+ pipeline: (task: 'automatic-speech-recognition', model: string, options?: {
44
+ dtype?: SpeechDtype;
45
+ device?: 'wasm' | 'webgpu';
46
+ progress_callback?: (info: any) => void;
47
+ }) => Promise<unknown>;
48
+ }
49
+ /** A speech segment Silero VAD found, in milliseconds. */
50
+ export interface VadSegment {
51
+ audio: Float32Array;
52
+ start: number;
53
+ end: number;
54
+ }
55
+ /** The part of `@ricky0123/vad-web` voice uses. */
56
+ export interface VadModule {
57
+ NonRealTimeVAD: {
58
+ new: (options: {
59
+ modelURL: string;
60
+ modelFetcher: (path: string) => Promise<ArrayBuffer>;
61
+ ortConfig?: (ort: any) => void;
62
+ positiveSpeechThreshold?: number;
63
+ negativeSpeechThreshold?: number;
64
+ minSpeechMs?: number;
65
+ preSpeechPadMs?: number;
66
+ redemptionMs?: number;
67
+ }) => Promise<{
68
+ run: (audio: Float32Array, sampleRate: number) => AsyncIterable<VadSegment>;
69
+ }>;
70
+ };
71
+ }
72
+ /** How the host page loads the packages that hear, once voice is turned on. */
73
+ export interface VoiceEngines {
74
+ transformers: () => Promise<TransformersModule>;
75
+ vad: () => Promise<VadModule>;
76
+ }
77
+ /** How a message was heard: what rides on it as `metadata` (VO-27). */
78
+ export interface SpokenMetadata {
79
+ input: 'voice';
80
+ language: string;
81
+ engine: string;
82
+ where: 'device' | 'server';
83
+ }
84
+ /** What the person said, once heard. */
85
+ export interface Transcript {
86
+ text: string;
87
+ metadata: SpokenMetadata;
88
+ /** Seconds of speech kept by the VAD. */
89
+ seconds: number;
90
+ /** How long hearing took, from release to words, in ms. */
91
+ ms: number;
92
+ }
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export {};
@@ -0,0 +1,12 @@
1
+ /** What the speaker is given. */
2
+ export interface SentenceSink {
3
+ say: (sentence: string) => void;
4
+ stop: () => void;
5
+ }
6
+ /** An item's text, when it is the agent's own answer and not a tool call. */
7
+ export declare function answerText(item: unknown): string | undefined;
8
+ /**
9
+ * Speaks the newest answer of `items` while `on`; `writing` says whether the
10
+ * agent is still writing it — once it stops, what is left is said.
11
+ */
12
+ export declare function useSpokenAnswers(items: readonly unknown[], writing: boolean, on: boolean, sink: SentenceSink | undefined): void;
@@ -0,0 +1,90 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * The answers of a conversation, heard as they are written (VOICE.md VO-20,
7
+ * VO-21): the newest answer of the agent is cut into sentences as it grows,
8
+ * and each is given to the speaker as soon as it is complete. The answers
9
+ * already there when voice was turned on are not read.
10
+ *
11
+ * @module voice/useSpokenAnswers
12
+ */
13
+ import { useEffect, useRef } from 'react';
14
+ import { SentenceCutter } from './sentences';
15
+ /** An item's text, when it is the agent's own answer and not a tool call. */
16
+ export function answerText(item) {
17
+ const message = item;
18
+ if (!message ||
19
+ message.role !== 'assistant' ||
20
+ typeof message.toolName === 'string') {
21
+ return undefined;
22
+ }
23
+ if (typeof message.content === 'string') {
24
+ return message.content;
25
+ }
26
+ if (Array.isArray(message.content)) {
27
+ return message.content
28
+ .map(part => part &&
29
+ typeof part === 'object' &&
30
+ part.type === 'text'
31
+ ? String(part.text ?? '')
32
+ : '')
33
+ .join(' ');
34
+ }
35
+ return undefined;
36
+ }
37
+ /**
38
+ * Speaks the newest answer of `items` while `on`; `writing` says whether the
39
+ * agent is still writing it — once it stops, what is left is said.
40
+ */
41
+ export function useSpokenAnswers(items, writing, on, sink) {
42
+ const heard = useRef(new Set());
43
+ const current = useRef(undefined);
44
+ const started = useRef(false);
45
+ useEffect(() => {
46
+ if (!on || !sink) {
47
+ started.current = false;
48
+ current.current = undefined;
49
+ return;
50
+ }
51
+ const answers = items
52
+ .map((item, index) => ({
53
+ id: String(item?.id ?? index),
54
+ text: answerText(item),
55
+ }))
56
+ .filter(answer => answer.text !== undefined);
57
+ if (!started.current) {
58
+ // What was there before voice was on is not read.
59
+ started.current = true;
60
+ answers.forEach(answer => heard.current.add(answer.id));
61
+ return;
62
+ }
63
+ const newest = answers[answers.length - 1];
64
+ if (!newest ||
65
+ (heard.current.has(newest.id) && current.current?.id !== newest.id)) {
66
+ return;
67
+ }
68
+ if (current.current?.id !== newest.id) {
69
+ heard.current.add(newest.id);
70
+ current.current = {
71
+ id: newest.id,
72
+ cutter: new SentenceCutter(),
73
+ ended: false,
74
+ };
75
+ }
76
+ const reading = current.current;
77
+ if (reading.ended) {
78
+ return;
79
+ }
80
+ for (const sentence of reading.cutter.feed(newest.text ?? '')) {
81
+ sink.say(sentence);
82
+ }
83
+ if (!writing) {
84
+ for (const sentence of reading.cutter.end(newest.text ?? '')) {
85
+ sink.say(sentence);
86
+ }
87
+ reading.ended = true;
88
+ }
89
+ }, [items, writing, on, sink]);
90
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.3.63",
3
+ "version": "1.3.65",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -69,13 +69,13 @@
69
69
  "clean:dist": "rimraf dist",
70
70
  "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
71
71
  "create:patches": "bash scripts/create-patches.sh",
72
- "examples": "run-p server:start server:start:codemode jupyter:start examples:vite",
72
+ "examples": "run-p server:start server:start:codemode server:start:accounting server:accounting jupyter:start examples:vite",
73
73
  "examples2": "run-p server:start server:start:codemode jupyter:start examples2:vite",
74
74
  "example-local": "make example-local",
75
75
  "examples:fresh": "npm run clean:cache && npm run examples",
76
76
  "examples:jupyter": "run-p jupyter:start server:start server:start:codemode examples:vite",
77
77
  "examples:nextjs": "npm run dev --workspace=nextjs-notebook-example",
78
- "examples:vite": "VITE_DATALAYER_RUNTIMES_URL=${VITE_DATALAYER_RUNTIMES_URL:-https://r1.datalayer.run} VITE_DATALAYER_AGENT_RUNTIMES_URL=${VITE_DATALAYER_AGENT_RUNTIMES_URL:-https://r1.datalayer.run} VITE_APP_TARGET=examples vite",
78
+ "examples:vite": "VITE_A2A_ACCOUNTING_URL=${VITE_A2A_ACCOUNTING_URL:-http://localhost:8767/api/v1/a2a/agents/accounting} VITE_DATALAYER_RUNTIMES_URL=${VITE_DATALAYER_RUNTIMES_URL:-https://r1.datalayer.run} VITE_DATALAYER_AGENT_RUNTIMES_URL=${VITE_DATALAYER_AGENT_RUNTIMES_URL:-https://r1.datalayer.run} VITE_APP_TARGET=examples vite",
79
79
  "examples2:vite": "VITE_DATALAYER_RUNTIMES_URL=${VITE_DATALAYER_RUNTIMES_URL:-https://r1.datalayer.run} VITE_DATALAYER_AGENT_RUNTIMES_URL=${VITE_DATALAYER_AGENT_RUNTIMES_URL:-https://r1.datalayer.run} VITE_APP_TARGET=examples2 vite",
80
80
  "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,css,json,md}\" \"examples/**/*.{js,jsx,ts,tsx,css,json,md,mjs}\"",
81
81
  "format:all": "npm run format && npm run format --workspaces --if-present",
@@ -98,6 +98,8 @@
98
98
  "server:start": "PYTHONIOENCODING=utf-8 AGENT_RUNTIMES_DEBUG=false AGENT_RUNTIMES_LOG_LEVEL=info DATALAYER_EVALS_MODE=interactive DATALAYER_EVALS_EMIT_LIVE_EVENTS=true python -m agent_runtimes serve --port 8765 --log-level info",
99
99
  "server:start:agent-node": "AGENT_NODE_JUPYTER_URL=${AGENT_NODE_JUPYTER_URL:-http://127.0.0.1:8888/api/jupyter-server} AGENT_NODE_JUPYTER_TOKEN=${AGENT_NODE_JUPYTER_TOKEN:-60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6} PYTHONIOENCODING=utf-8 AGENT_RUNTIMES_DEBUG=false AGENT_RUNTIMES_LOG_LEVEL=info DATALAYER_EVALS_MODE=interactive DATALAYER_EVALS_EMIT_LIVE_EVENTS=true AGENT_RUNTIMES_INFERENCE_PROVIDER_OVERRIDE=${AGENT_RUNTIMES_INFERENCE_PROVIDER_OVERRIDE:-datalayer} python -m agent_runtimes serve --node --port 8765 --log-level info",
100
100
  "server:start:codemode": "PYTHONIOENCODING=utf-8 AGENT_RUNTIMES_DEBUG=false AGENT_RUNTIMES_LOG_LEVEL=info DATALAYER_EVALS_MODE=interactive DATALAYER_EVALS_EMIT_LIVE_EVENTS=true python -m agent_runtimes serve --port 8766 --log-level info",
101
+ "server:start:accounting": "PYTHONIOENCODING=utf-8 AGENT_RUNTIMES_DEBUG=false AGENT_RUNTIMES_LOG_LEVEL=info python -m agent_runtimes serve --port 8767 --log-level info",
102
+ "server:accounting": "python examples/sales-accounting-a2a/serve_accounting.py --url http://127.0.0.1:8767 --wait 300 || echo 'Accounting was not served on 8767: the Agent A2A Team example will say it is not reachable.'",
101
103
  "examples:codemode": "run-p server:start server:start:codemode examples:vite",
102
104
  "start": "vite",
103
105
  "start:acp": "run-p server:start start:acp:vite",
@@ -159,6 +161,7 @@
159
161
  "@datalayer/reactor-manager": "^1.0.4",
160
162
  "@datalayer/reactor-shell": "^1.0.4",
161
163
  "@excalidraw/excalidraw": "^0.18.0",
164
+ "@huggingface/transformers": "^4.3.0",
162
165
  "@jupyter-widgets/base-manager": "^1.0.12",
163
166
  "@jupyter-widgets/schema": "^0.5.6",
164
167
  "@jupyterlab/apputils": "^4.6.0",
@@ -213,6 +216,7 @@
213
216
  "@radix-ui/react-toggle-group": "^1.1.11",
214
217
  "@radix-ui/react-tooltip": "^1.2.8",
215
218
  "@radix-ui/react-use-controllable-state": "^1.2.2",
219
+ "@ricky0123/vad-web": "^0.0.31",
216
220
  "@rjsf/validator-ajv8": "^5.24.13",
217
221
  "@styled-system/css": "^5.1.5",
218
222
  "@tailwindcss/vite": "^4.1.13",