@datalayer/agent-runtimes 1.5.27 → 1.5.30

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 (46) hide show
  1. package/dist-embed/chunks/ChatView-C_NOLqwI.js +32 -0
  2. package/dist-embed/datalayer-app-main.js +103 -93
  3. package/lib/apps/apps/AppKept.js +5 -1
  4. package/lib/apps/apps/appspec.d.ts +0 -5
  5. package/lib/apps/apps/appspec.js +1 -6
  6. package/lib/apps/apps/checks.js +4 -9
  7. package/lib/apps/embed/element.js +24 -7
  8. package/lib/apps/embed/embedConfig.d.ts +11 -2
  9. package/lib/apps/embed/embedConfig.js +26 -2
  10. package/lib/apps/embed/visitorApp.d.ts +9 -2
  11. package/lib/apps/embed/visitorApp.js +9 -2
  12. package/lib/apps/plugins/chat/ChatView.js +6 -3
  13. package/lib/chat/assistant/AssistantStage.js +17 -0
  14. package/lib/chat/assistant/clearance.d.ts +10 -0
  15. package/lib/chat/assistant/clearance.js +14 -0
  16. package/lib/chat/base/ChatBase.js +12 -3
  17. package/lib/specs/appspecSchema.js +2 -2
  18. package/lib/specs/voices.js +89 -0
  19. package/lib/types/agentspecs.d.ts +1 -1
  20. package/lib/voice/ComposerVoice.d.ts +10 -2
  21. package/lib/voice/ComposerVoice.js +35 -5
  22. package/lib/voice/HandsFree.d.ts +55 -0
  23. package/lib/voice/HandsFree.js +211 -0
  24. package/lib/voice/VoiceInput.d.ts +2 -2
  25. package/lib/voice/VoiceInput.js +6 -4
  26. package/lib/voice/VoiceMenu.js +2 -1
  27. package/lib/voice/chatVoice.d.ts +6 -4
  28. package/lib/voice/chatVoice.js +11 -12
  29. package/lib/voice/consent.d.ts +8 -0
  30. package/lib/voice/consent.js +10 -0
  31. package/lib/voice/handsFree.d.ts +58 -0
  32. package/lib/voice/handsFree.js +48 -0
  33. package/lib/voice/hearing.d.ts +23 -1
  34. package/lib/voice/hearing.js +18 -3
  35. package/lib/voice/index.d.ts +21 -8
  36. package/lib/voice/index.js +3 -0
  37. package/lib/voice/serverHearing.d.ts +58 -0
  38. package/lib/voice/serverHearing.js +136 -0
  39. package/lib/voice/settings.d.ts +5 -0
  40. package/lib/voice/settings.js +8 -0
  41. package/lib/voice/speaker.d.ts +4 -3
  42. package/lib/voice/speaker.js +1 -2
  43. package/lib/voice/useVoiceSpeaker.js +0 -3
  44. package/package.json +2 -2
  45. package/scripts/voice/measure.py +74 -0
  46. package/dist-embed/chunks/ChatView-CUWE6I5M.js +0 -32
@@ -13,6 +13,9 @@ export * from './sentences';
13
13
  export * from './pinned';
14
14
  export * from './capture';
15
15
  export * from './hearing';
16
+ export * from './serverHearing';
17
+ export * from './handsFree';
18
+ export { HandsFree, type HandsFreeProps } from './HandsFree';
16
19
  export * from './speaker';
17
20
  export * from './consent';
18
21
  export * from './settings';
@@ -46,8 +49,14 @@ export type { VoiceSpeaker } from './useVoiceSpeaker';
46
49
  export interface ChatVoice {
47
50
  /** The language listened to and spoken, BCP 47. */
48
51
  language: string;
49
- /** `push_to_talk`: the microphone in the composer; `off`: none. Hands-free is Phase V3. */
50
- input: 'off' | 'push_to_talk';
52
+ /**
53
+ * `push_to_talk`: the microphone in the composer; `hands_free`: that, and
54
+ * *Talk with it* beside it — a conversation by voice (VO-12, VO-13);
55
+ * `off`: none.
56
+ */
57
+ input: 'off' | 'push_to_talk' | 'hands_free';
58
+ /** The silence after speech that ends a hands-free turn, in ms (VO-12): 700 when unsaid. */
59
+ turnSilenceMs?: number;
51
60
  /**
52
61
  * When answers are heard: `always`, as they are written; `on_request`, a
53
62
  * *Read aloud* under each answer (VO-21); or `off`, the default.
@@ -64,15 +73,19 @@ export interface ChatVoice {
64
73
  * (VO-10, VO-69): 1,500 when unsaid; longer for a person who pauses.
65
74
  */
66
75
  silenceMs?: number;
67
- /** ai-agents, whose speech service says the answers. */
76
+ /** ai-agents, whose speech service says the answers, and hears where the browser does not. */
68
77
  speechUrl?: string;
69
- /** The token the speech service is asked with. */
70
- token?: string;
71
78
  /**
72
- * The deployment an embedded application's page speaks for (VO-19): what
73
- * the speech service checks an embed token against, and counts its spend on.
79
+ * Where what is said is heard (§5): `device`, the browser; `server`,
80
+ * Datalayer's speech service; `auto`, the default, the browser where a
81
+ * model there hears the language, else the server. The Appspec's
82
+ * `interface.voice.where`.
74
83
  */
75
- deployment?: string;
84
+ where?: 'auto' | 'device' | 'server';
85
+ /** The person asked for their language to be found by Whisper on the server (VO-14). */
86
+ detect?: boolean;
87
+ /** The token the speech service is asked with. */
88
+ token?: string;
76
89
  /** Send what is said at once, rather than put it in the composer. */
77
90
  sendWhatISay?: boolean;
78
91
  /**
@@ -7,6 +7,9 @@ export * from './sentences';
7
7
  export * from './pinned';
8
8
  export * from './capture';
9
9
  export * from './hearing';
10
+ export * from './serverHearing';
11
+ export * from './handsFree';
12
+ export { HandsFree } from './HandsFree';
10
13
  export * from './speaker';
11
14
  export * from './consent';
12
15
  export * from './settings';
@@ -0,0 +1,58 @@
1
+ import type { Hearing, HearingProgress, HeardSoFar } from './hearing';
2
+ import type { Transcript } from './types';
3
+ /** Where the speech service hears a recording, on ai-agents' host. */
4
+ export declare const TRANSCRIPTIONS_PATH = "/api/ai-agents/v1/speech/transcriptions";
5
+ /** The model the speech service hears with (agentspecs' catalogue). */
6
+ export declare const SERVER_HEARING_MODEL = "whisper-large-v3-turbo";
7
+ /** Where a chat's voice hears: in the browser, or on Datalayer's servers. */
8
+ export type HearingPlace = 'device' | 'server';
9
+ /** What decides where a chat's voice hears. */
10
+ export interface HearingAsked {
11
+ language: string;
12
+ /** The application's `interface.voice.where`; `auto` when unsaid. */
13
+ where?: 'auto' | 'device' | 'server';
14
+ /** The person asked for their language to be detected (VO-14). */
15
+ detect?: boolean;
16
+ /** The speech service; none, and everything is heard in the browser. */
17
+ speechUrl?: string;
18
+ }
19
+ /**
20
+ * Where a chat's voice hears (§5): in the browser unless the speech service
21
+ * is named and the person asked for detection, the application says
22
+ * `server`, or it says `auto` and no model in the browser hears the language.
23
+ */
24
+ export declare function hearingPlace(voice: HearingAsked): HearingPlace;
25
+ /** Mono samples at 16 kHz as a 16-bit PCM WAV file: what the service reads. */
26
+ export declare function wavOf(samples: Float32Array, rate?: number): ArrayBuffer;
27
+ /** What finds the speech in what was heard: the browser's VAD (`DeviceHearing`). */
28
+ export interface SpeechFinder {
29
+ readyToFindSpeech(progress?: HearingProgress): Promise<void>;
30
+ findSpeech(audio: Float32Array): Promise<{
31
+ speech: Float32Array;
32
+ silentMs: number;
33
+ }>;
34
+ }
35
+ export interface ServerHearingOptions {
36
+ /** ai-agents' origin, where the speech service is. */
37
+ speechUrl: string;
38
+ /** The token the conversation speaks with: the person's, a visitor's, an embed's. */
39
+ token?: string;
40
+ /** Let Whisper find the language (VO-14), rather than tell it. */
41
+ detect?: boolean;
42
+ fetcher?: typeof fetch;
43
+ }
44
+ /**
45
+ * Hears on Datalayer's servers: the browser's VAD finds the speech and when
46
+ * it stopped; Whisper, on the speech service, writes it.
47
+ */
48
+ export declare class ServerHearing implements Hearing {
49
+ private readonly finder;
50
+ private readonly options;
51
+ readonly where: "server";
52
+ constructor(finder: SpeechFinder, options: ServerHearingOptions);
53
+ /** Only the VAD loads in the page: the words are written on the server. */
54
+ ready(_language: string, progress?: HearingProgress): Promise<void>;
55
+ /** Whether speech was found and how long it has been silent; its words come at the end. */
56
+ hearSoFar(audio: Float32Array): Promise<HeardSoFar>;
57
+ hear(audio: Float32Array, language: string): Promise<Transcript | undefined>;
58
+ }
@@ -0,0 +1,136 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Hearing on Datalayer's servers (VOICE.md VO-34, VO-14, §5): what was said
7
+ * in one press, kept to its speech by Silero VAD in the page, then sent as a
8
+ * WAV recording to the speech service's `POST /speech/transcriptions`, where
9
+ * Whisper large-v3-turbo hears it — in any language it knows, and finding
10
+ * the language itself when the person asks for that (detection, VO-14). The
11
+ * sound is held in the request only: the service keeps neither it nor the
12
+ * words (VO-60).
13
+ *
14
+ * Used where the application's voice says `where: server`, where it says
15
+ * `auto` and no model in the browser hears the language, and where the
16
+ * person asked for their language to be detected — never when they chose to
17
+ * keep speech on the device. A clip model: its words come at the end, not
18
+ * while the person speaks (VO-11).
19
+ *
20
+ * @module voice/serverHearing
21
+ */
22
+ import { transcriberFor } from '../specs/voices';
23
+ import { HEARING_RATE } from './capture';
24
+ /** Where the speech service hears a recording, on ai-agents' host. */
25
+ export const TRANSCRIPTIONS_PATH = '/api/ai-agents/v1/speech/transcriptions';
26
+ /** The model the speech service hears with (agentspecs' catalogue). */
27
+ export const SERVER_HEARING_MODEL = 'whisper-large-v3-turbo';
28
+ /** The shortest speech worth hearing, in samples: a word said alone. */
29
+ const SHORTEST = HEARING_RATE * 0.2;
30
+ /**
31
+ * Where a chat's voice hears (§5): in the browser unless the speech service
32
+ * is named and the person asked for detection, the application says
33
+ * `server`, or it says `auto` and no model in the browser hears the language.
34
+ */
35
+ export function hearingPlace(voice) {
36
+ if (!voice.speechUrl) {
37
+ return 'device';
38
+ }
39
+ if (voice.detect || voice.where === 'server') {
40
+ return 'server';
41
+ }
42
+ if (voice.where === 'device') {
43
+ return 'device';
44
+ }
45
+ return transcriberFor(voice.language) ? 'device' : 'server';
46
+ }
47
+ /** Mono samples at 16 kHz as a 16-bit PCM WAV file: what the service reads. */
48
+ export function wavOf(samples, rate = HEARING_RATE) {
49
+ const bytes = new ArrayBuffer(44 + samples.length * 2);
50
+ const view = new DataView(bytes);
51
+ const text = (at, value) => {
52
+ for (let i = 0; i < value.length; i++) {
53
+ view.setUint8(at + i, value.charCodeAt(i));
54
+ }
55
+ };
56
+ text(0, 'RIFF');
57
+ view.setUint32(4, 36 + samples.length * 2, true);
58
+ text(8, 'WAVE');
59
+ text(12, 'fmt ');
60
+ view.setUint32(16, 16, true);
61
+ view.setUint16(20, 1, true); // PCM
62
+ view.setUint16(22, 1, true); // mono
63
+ view.setUint32(24, rate, true);
64
+ view.setUint32(28, rate * 2, true);
65
+ view.setUint16(32, 2, true);
66
+ view.setUint16(34, 16, true);
67
+ text(36, 'data');
68
+ view.setUint32(40, samples.length * 2, true);
69
+ for (let i = 0; i < samples.length; i++) {
70
+ const sample = Math.max(-1, Math.min(1, samples[i]));
71
+ view.setInt16(44 + i * 2, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true);
72
+ }
73
+ return bytes;
74
+ }
75
+ /**
76
+ * Hears on Datalayer's servers: the browser's VAD finds the speech and when
77
+ * it stopped; Whisper, on the speech service, writes it.
78
+ */
79
+ export class ServerHearing {
80
+ finder;
81
+ options;
82
+ where = 'server';
83
+ constructor(finder, options) {
84
+ this.finder = finder;
85
+ this.options = options;
86
+ }
87
+ /** Only the VAD loads in the page: the words are written on the server. */
88
+ ready(_language, progress) {
89
+ return this.finder.readyToFindSpeech(progress);
90
+ }
91
+ /** Whether speech was found and how long it has been silent; its words come at the end. */
92
+ async hearSoFar(audio) {
93
+ const { speech, silentMs } = await this.finder.findSpeech(audio);
94
+ return { text: '', spoke: speech.length >= SHORTEST, silentMs };
95
+ }
96
+ async hear(audio, language) {
97
+ const started = performance.now();
98
+ const { speech } = await this.finder.findSpeech(audio);
99
+ if (speech.length < SHORTEST) {
100
+ return undefined;
101
+ }
102
+ const { speechUrl, token, detect, fetcher = fetch } = this.options;
103
+ const query = detect ? '' : `?language=${encodeURIComponent(language)}`;
104
+ const answered = await fetcher(`${speechUrl.replace(/\/+$/, '')}${TRANSCRIPTIONS_PATH}${query}`, {
105
+ method: 'POST',
106
+ headers: {
107
+ 'Content-Type': 'audio/wav',
108
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
109
+ },
110
+ body: wavOf(speech),
111
+ });
112
+ const body = (await answered.json().catch(() => ({})));
113
+ if (!answered.ok) {
114
+ throw new Error(typeof body.detail === 'string' && body.detail
115
+ ? body.detail
116
+ : `What you said could not be heard on Datalayer's servers (${answered.status}).`);
117
+ }
118
+ const text = typeof body.text === 'string' ? body.text.trim() : '';
119
+ if (!text) {
120
+ return undefined;
121
+ }
122
+ return {
123
+ text,
124
+ metadata: {
125
+ input: 'voice',
126
+ language: typeof body.language === 'string' && body.language
127
+ ? body.language
128
+ : language,
129
+ engine: SERVER_HEARING_MODEL,
130
+ where: 'server',
131
+ },
132
+ seconds: speech.length / HEARING_RATE,
133
+ ms: Math.round(performance.now() - started),
134
+ };
135
+ }
136
+ }
@@ -57,6 +57,11 @@ export interface VoiceSettings {
57
57
  * speech service, so answers are spoken only if the browser can do it.
58
58
  */
59
59
  onDeviceOnly?: boolean;
60
+ /**
61
+ * Let Whisper find the language they speak (VO-14): what they say is
62
+ * heard on Datalayer's servers, which detect it, rather than in the browser.
63
+ */
64
+ detectLanguage?: boolean;
60
65
  }
61
66
  /** The settings as they can be used: numbers in range, nothing else trusted. */
62
67
  export declare function saneVoiceSettings(settings: VoiceSettings | null | undefined): VoiceSettings;
@@ -40,6 +40,9 @@ export function saneVoiceSettings(settings) {
40
40
  if (typeof kept.onDeviceOnly === 'boolean') {
41
41
  sane.onDeviceOnly = kept.onDeviceOnly;
42
42
  }
43
+ if (typeof kept.detectLanguage === 'boolean') {
44
+ sane.detectLanguage = kept.detectLanguage;
45
+ }
43
46
  return sane;
44
47
  }
45
48
  /** What was kept, or nothing. Storage may be refused, or hold nonsense. */
@@ -174,6 +177,9 @@ export function voiceForPerson(voice, person = {}, browser = browserLanguage())
174
177
  if (chosen.microphoneId) {
175
178
  next.microphoneId = chosen.microphoneId;
176
179
  }
180
+ if (chosen.detectLanguage) {
181
+ next.detect = true;
182
+ }
177
183
  if (chosen.onDeviceOnly) {
178
184
  // Nothing is asked of the speech service: no token, no origin. Answers
179
185
  // are said by that service only (decision 1: no voice made in the
@@ -181,6 +187,8 @@ export function voiceForPerson(voice, person = {}, browser = browserLanguage())
181
187
  next.speechUrl = undefined;
182
188
  next.token = undefined;
183
189
  next.output = 'off';
190
+ next.where = 'device';
191
+ next.detect = false;
184
192
  }
185
193
  return next;
186
194
  }
@@ -24,10 +24,11 @@ export interface SpeakerOptions {
24
24
  /** The voice of the catalogue. */
25
25
  voice: string;
26
26
  language: string;
27
- /** The person's token, an application's principal's, a visitor's or an embed's. */
27
+ /**
28
+ * The person's token, an application's principal's, a visitor's or an
29
+ * embed's — whose deployment is the one it names (VO-19, decision 16).
30
+ */
28
31
  token?: string;
29
- /** The deployment an embed's page speaks for (VO-19): sent with each sentence. */
30
- deployment?: string;
31
32
  /**
32
33
  * How fast it speaks, as a multiplier of the voice's own pace (VO-25,
33
34
  * VO-30). Applied here rather than asked of the service: `POST
@@ -114,7 +114,7 @@ export class ServerSpeaker {
114
114
  }
115
115
  }
116
116
  async fetch(text) {
117
- const { speechUrl, voice, language, token, deployment, fetcher = fetch, } = this.options;
117
+ const { speechUrl, voice, language, token, fetcher = fetch } = this.options;
118
118
  try {
119
119
  const answered = await fetcher(`${speechUrl.replace(/\/+$/, '')}${SYNTHESES_PATH}`, {
120
120
  method: 'POST',
@@ -127,7 +127,6 @@ export class ServerSpeaker {
127
127
  voice,
128
128
  language,
129
129
  format: 'opus',
130
- ...(deployment ? { deployment } : {}),
131
130
  }),
132
131
  });
133
132
  if (!answered.ok) {
@@ -27,7 +27,6 @@ export function useVoiceSpeaker(voice, on = true) {
27
27
  voice: voice.voice,
28
28
  language: voice.language,
29
29
  token: voice.token,
30
- deployment: voice.deployment,
31
30
  rate: voice.rate,
32
31
  volume: voice.volume,
33
32
  onState: setState,
@@ -40,7 +39,6 @@ export function useVoiceSpeaker(voice, on = true) {
40
39
  voice: voice?.voice,
41
40
  language: voice?.language,
42
41
  token: voice?.token,
43
- deployment: voice?.deployment,
44
42
  rate: voice?.rate,
45
43
  volume: voice?.volume,
46
44
  });
@@ -49,7 +47,6 @@ export function useVoiceSpeaker(voice, on = true) {
49
47
  voice?.voice,
50
48
  voice?.language,
51
49
  voice?.token,
52
- voice?.deployment,
53
50
  voice?.rate,
54
51
  voice?.volume,
55
52
  ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.5.27",
3
+ "version": "1.5.30",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -158,7 +158,7 @@
158
158
  "@datalayer/jupyter-react": "^2.0.20",
159
159
  "@datalayer/jupyter-server-nbmodel": "^0.2.8",
160
160
  "@datalayer/lexical-loro": "^1.0.6",
161
- "@datalayer/primer-addons": "^1.0.39",
161
+ "@datalayer/primer-addons": "^1.0.40",
162
162
  "@datalayer/primer-rjsf": "^1.0.3",
163
163
  "@datalayer/personal-agent-protocol": "^0.24.0",
164
164
  "@datalayer/reactor": "^1.3.0",
@@ -92,6 +92,67 @@ def transcribe(
92
92
  return json.loads(done.stdout.strip().splitlines()[-1])
93
93
 
94
94
 
95
+ def measure_server(
96
+ store: Path,
97
+ voices: Any,
98
+ fixtures: List[Dict[str, Any]],
99
+ wavs: Dict[str, Path],
100
+ measured: Path,
101
+ threads: int,
102
+ ) -> None:
103
+ """Each server speech-to-text model on the fixtures, as the speech service runs it (VO-47).
104
+
105
+ faster-whisper, 8-bit on the CPU with ``threads`` threads, told the
106
+ language, one clip at a time: what it heard and how long it took.
107
+ """
108
+ from faster_whisper import WhisperModel # the speech image's own
109
+
110
+ for model in voices.SPEECH_MODEL_CATALOGUE.values():
111
+ if model["task"] != "stt" or model["where"] != ["server"]:
112
+ continue
113
+ started = time.monotonic()
114
+ whisper = WhisperModel(
115
+ str(store / model["provider"] / model["id"]),
116
+ device="cpu",
117
+ compute_type="int8",
118
+ cpu_threads=threads,
119
+ )
120
+ load_ms = round((time.monotonic() - started) * 1000)
121
+ by_language = {}
122
+ for language in ("en", "fr"):
123
+ clips = [clip for clip in fixtures if clip["language"] == language]
124
+ print(f"{model['id']} on {len(clips)} {language} clips", flush=True)
125
+ results = []
126
+ for clip in clips:
127
+ samples, _ = sf.read(wavs[clip["id"]], dtype="float32")
128
+ started = time.monotonic()
129
+ parts, _ = whisper.transcribe(
130
+ samples, language=language, vad_filter=True
131
+ )
132
+ text = " ".join(part.text.strip() for part in parts).strip()
133
+ results.append(
134
+ {
135
+ "id": clip["id"],
136
+ "heard": text,
137
+ "ms": round((time.monotonic() - started) * 1000),
138
+ "audio_s": round(len(samples) / 16000, 2),
139
+ }
140
+ )
141
+ by_language[language] = {"load_ms": load_ms, "clips": results}
142
+ (measured / f"stt-{model['id']}.json").write_text(
143
+ json.dumps(
144
+ {
145
+ "model": model["id"],
146
+ "runtime": f"faster-whisper, int8 on the CPU, {threads} threads",
147
+ "languages": by_language,
148
+ },
149
+ ensure_ascii=False,
150
+ indent=2,
151
+ )
152
+ + "\n"
153
+ )
154
+
155
+
95
156
  def main() -> int:
96
157
  parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
97
158
  parser.add_argument("--store", type=Path, required=True)
@@ -101,6 +162,14 @@ def main() -> int:
101
162
  default=None,
102
163
  help="Where @huggingface/transformers is installed, when not in this checkout",
103
164
  )
165
+ parser.add_argument(
166
+ "--server",
167
+ action="store_true",
168
+ help="Measure the server's speech-to-text models instead, with faster-whisper (in the speech image)",
169
+ )
170
+ parser.add_argument(
171
+ "--threads", type=int, default=4, help="CPU threads for --server"
172
+ )
104
173
  args = parser.parse_args()
105
174
  voices = catalogue()
106
175
  env = dict(os.environ)
@@ -124,6 +193,11 @@ def main() -> int:
124
193
  wav = Path(scratch) / f"{clip['id']}.wav"
125
194
  sf.write(wav, resample(samples, rate), 16000, subtype="PCM_16")
126
195
  wavs[clip["id"]] = wav
196
+ if args.server:
197
+ measure_server(
198
+ args.store, voices, fixtures, wavs, measured, args.threads
199
+ )
200
+ return 0
127
201
  # --- speech to text, on the device's models ---------------------------------
128
202
  for model in voices.SPEECH_MODEL_CATALOGUE.values():
129
203
  if model["task"] != "stt" or "device" not in model["where"]:
@@ -1,32 +0,0 @@
1
- import{E as N,e$ as xo,r as o,j as t,f0 as vo,f1 as So,b_ as Rn,B as p,H as bt,T as H,c as Y,cu as zt,eu as Dt,f2 as ce,co as xt,e as yo,f3 as Co,f4 as wo,e3 as ko,f5 as jo,aH as Io,dX as zn,dV as Eo,dY as Gt,f6 as To,f7 as Ro,f8 as Ao,f9 as Mo,fa as Po,fb as Uo,fc as $o,d3 as Fo,a_ as Lo,fd as Oo,fe as _o,ff as zo,fg as No,fh as Bo,fi as Vo,x as Nt,fj as Ho,fk as Wo,fl as Do,fm as Go,fn as Ko,fo as Yo,fp as qo,fq as Jo,fr as Qo,fs as Xo,ft as Zo,fu as es,fv as ts,fw as ns,fx as os,fy as ss,fz as as,fA as is,fB as rs,fC as ls,fD as tt,fE as cs,fF as ds,fG as us,fH as fs,fI as An,fJ as ps,fK as Le,fL as ms,fM as gs,a$ as vt,fN as hs,fO as bs,fP as Mn,fQ as xs,fR as vs,fS as Ss,fT as ys,eC as Cs,fU as Bt,fV as Ce,fW as ws,fX as ks,fY as js,fZ as Pn,f_ as Is,f$ as Un,g0 as Es,g1 as Ts,g2 as Rs,g3 as As,g4 as Ms,g5 as Ps,g6 as Us,g7 as $s,g8 as Fs,g9 as Ls,ga as St,gb as Os,gc as _s,gd as zs,I as Ns,ge as Bs,gf as Vs,gg as $n,gh as Hs,gi as Ws,gj as Ds,gk as Kt,gl as Gs,gm as Ks,ek as Vt,gn as Ys,go as qs}from"../datalayer-app-main.js";import{S as Js,E as Qs,a as Xs}from"./SignInIcon-4HkE48mS.js";import{F as Zs,a as ea,b as ta}from"./LinkedInGreyIcon-BoWXE-HS.js";function Nn(){const n=N(xo);return o.useMemo(()=>n.map(a=>a.value),[n])}const Ht={github:{name:"github",oauth2CallbackServerRoute:"jupyter_iam/oauth2/callback",oauth2CallbackUIRoute:"/iam/oauth2/github/callback"},google:{name:"google",oauth2CallbackServerRoute:"jupyter_iam/oauth2/callback",oauth2CallbackUIRoute:"/iam/oauth2/google/callback"},linkedin:{name:"linkedin",oauth2CallbackServerRoute:"jupyter_iam/oauth2/callback",oauth2CallbackUIRoute:"/iam/oauth2/linkedin/callback"}},Fn=()=>{if(typeof document>"u")return"";const n=document.getElementById("datalayer-config-data");if(!n?.textContent)return"";try{const a=JSON.parse(n.textContent);return String(a?.iamUrl||"").replace(/\/$/,"")}catch{return""}},na=(n,a="Unable to start social sign-in.")=>{if(n instanceof Error&&n.message)return n.message;if(typeof n=="string"&&n.trim())return n;if(n&&typeof n=="object"&&"message"in n){const l=n.message;if(typeof l=="string"&&l.trim())return l}return a},oa=jo`
2
- .signin-input-theme-scope input:-webkit-autofill,
3
- .signin-input-theme-scope input:-webkit-autofill:hover,
4
- .signin-input-theme-scope input:-webkit-autofill:focus,
5
- .signin-input-theme-scope input:-webkit-autofill:active,
6
- .signin-input-theme-scope input:-webkit-autofill:disabled,
7
- .signin-input-theme-scope textarea:-webkit-autofill,
8
- .signin-input-theme-scope textarea:-webkit-autofill:hover,
9
- .signin-input-theme-scope textarea:-webkit-autofill:focus,
10
- .signin-input-theme-scope textarea:-webkit-autofill:active,
11
- .signin-input-theme-scope textarea:-webkit-autofill:disabled {
12
- -webkit-text-fill-color: var(--fgColor-default) !important;
13
- caret-color: var(--fgColor-default) !important;
14
- -webkit-box-shadow: 0 0 0 1000px var(--bgColor-default) inset !important;
15
- box-shadow: 0 0 0 1000px var(--bgColor-default) inset !important;
16
- background-color: var(--bgColor-default) !important;
17
- transition: background-color 9999s ease-in-out 0s !important;
18
- }
19
-
20
- .signin-input-theme-scope input:disabled,
21
- .signin-input-theme-scope textarea:disabled {
22
- -webkit-text-fill-color: var(--fgColor-muted) !important;
23
- -webkit-box-shadow: 0 0 0 1000px var(--bgColor-default) inset !important;
24
- box-shadow: 0 0 0 1000px var(--bgColor-default) inset !important;
25
- background-color: var(--bgColor-default) !important;
26
- opacity: 1 !important;
27
- }
28
- `,sa=({onSignIn:n,onApiKeySignIn:a,loginUrl:l,name:r,title:f="Datalayer OTEL",description:x="Sign in to access the observability dashboard.",icon:y,leadingIcon:I=t.jsx(ko,{size:24}),github:d=!1,google:we=!1,linkedin:q=!1,apiKey:nt=!1,signUp:F=!0,socialSignInNavigationTarget:ee,asDoc:v=!1,fillHeight:E=!0,hideHero:te=!1,calloutTitle:Oe,calloutDescription:ot,passwordToggleLabel:de="Sign in with a password",signUpTitle:Yt="Don't have an account?",signUpDescription:J="Create a free Datalayer account with your email address.",signUpLabel:yt="Sign up with email",signUpHref:_e="https://datalayer.ai/signup",onSignUp:B,forgotPasswordHref:Q="/password",forgotPasswordLabel:ze="Forgot password?",showForgotPassword:Ct=!0,socialButtonMarginTop:h=3,actionButtonMaxWidth:X=320})=>{const ne=v&&!te,st=r??(v&&f==="Datalayer OTEL"?"Datalayer Sign In":f),wt=y??(v?t.jsx(Js,{size:24}):I),L=o.useMemo(()=>{if(l)return l;const c=Fn();return c?`${c}/api/iam/v1/login`:"/api/iam/v1/login"},[l]),[W,ke]=o.useState(""),[ue,kt]=o.useState(""),[at,jt]=o.useState(!1),[je,fe]=o.useState(!1),[w,pe]=o.useState(!1),[oe,it]=o.useState(!1),[Ne,Ie]=o.useState(null),[O,It]=o.useState(null),[me,Ee]=o.useState(""),[Te,rt]=o.useState(null),[Re,$]=o.useState(null),{enqueueToast:ge}=vo(),[Ae,se]=o.useState(!1),[ae,he]=o.useState(""),j=o.useRef(null),Me=o.useCallback(c=>So()?Rn.URLExt.join(Rn.PageConfig.getBaseUrl(),c.oauth2CallbackServerRoute):`${window.location.protocol}//${window.location.hostname}${window.location.port?`:${window.location.port}`:""}${c.oauth2CallbackUIRoute}`,[]),D=o.useMemo(()=>{if(typeof window>"u")return"/";const c=`${window.location.pathname}${window.location.search}${window.location.hash}`;return c.startsWith("/")?c:"/"},[]),V=o.useCallback(async c=>{if(!oe){$(null),Ie(c.name),it(!0);try{const k=Fn(),P=new URLSearchParams({provider:c.name,callback_uri:Me(c)}),g=ee===void 0?void 0:String(ee||"").trim(),R=g===void 0?D&&D!=="/"?D:void 0:g&&g.startsWith("/")&&!g.startsWith("//")?g:void 0;R&&P.set("post_auth_redirect",R);const re=`${k||""}/api/iam/v1/oauth2/authz/url?${P.toString()}`,S=await fetch(re),De=await S.json(),Pe=De?.autorization_url;if(!S.ok||!Pe)throw new Error(De?.message||"Unable to start social sign-in.");window.location.assign(Pe)}catch(k){const P=na(k);$(P),ge(P,{variant:"error"}),Ie(null),it(!1)}}},[Me,D,ge,oe,ee]);o.useEffect(()=>{Ae&&j.current?.focus()},[Ae]);const ie=o.useCallback(()=>{se(!1),he("")},[]),lt=o.useCallback(()=>{!ae.trim()||!a||(a(ae.trim()),ie())},[ae,a,ie]),ct=o.useCallback(()=>{if(B){B();return}window.location.assign(_e)},[B,_e]),G=o.useCallback(()=>{if(Q){if(Q.startsWith("http://")||Q.startsWith("https://")){window.open(Q,"_blank","noopener,noreferrer");return}window.location.assign(Q)}},[Q]),Be=o.useCallback(async()=>{if(!(v||!W||!ue||w)){pe(!0),$(null);try{const c=await fetch(L,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({handle:W,password:ue})});if(!c.ok)throw new Error(`HTTP ${c.status}`);const k=await c.json();if(k.success&&k.token){const P=String(k?.user?.id||k?.user?.uid||"").trim();if(!!k?.user?.mfaUrl&&P){It(P),rt(k.token),$(null);return}n&&n(k.token,W)}else $(k.message||"Invalid username or password.")}catch(c){$(c instanceof Error?c.message:String(c))}finally{pe(!1)}}},[v,W,ue,w,L,n]),Ve=o.useCallback(async()=>{if(!(v||w||!O||!me.trim()||!Te)){pe(!0),$(null);try{const c=new URL(L,window.location.origin),k=c.pathname.endsWith("/api/iam/v1/login")?c.href.replace(/\/api\/iam\/v1\/login$/,""):`${c.origin}`,P=await fetch(`${k}/api/iam/v1/users/${O}/mfa/validate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userUid:O,code:me.trim()})}),g=await P.json();if(!P.ok||!g?.success)throw new Error(g?.message||"Failed to validate your MFA code.");n&&n(Te,W)}catch(c){const k=c instanceof Error?c.message:String(c);$(k),ge(k,{variant:"error"})}finally{pe(!1)}}},[v,ge,W,w,L,me,Te,O,n]),He=o.useCallback(c=>{c.key==="Enter"&&(O?Ve():Be())},[O,Be,Ve]),We=oe||w||v;return t.jsxs(p,{className:"signin-input-theme-scope",display:"flex",alignItems:te||ne||!E?"flex-start":"center",justifyContent:"center",minHeight:te||ne||!E?"auto":"100vh",bg:te?"transparent":"canvas.default",color:"fg.default",py:te?0:ne?2:4,children:[t.jsx(oa,{}),t.jsxs(p,{width:"100%",maxWidth:440,p:0,children:[!te&&t.jsxs(t.Fragment,{children:[t.jsxs(p,{display:"flex",alignItems:"center",gap:2,mb:ne?2:3,justifyContent:"center",children:[wt,t.jsx(bt,{sx:{fontSize:3},children:st})]}),t.jsx(H,{as:"p",sx:{fontSize:1,color:"fg.muted",mb:ne?2:3,textAlign:"center"},children:x})]}),(Oe||ot)&&t.jsxs(p,{mb:3,textAlign:"center",children:[Oe&&t.jsx(bt,{as:"h3",sx:{fontSize:2,mb:1},children:Oe}),ot&&t.jsx(H,{sx:{color:"fg.muted",fontSize:1},children:ot})]}),!O&&(d||we||q)&&t.jsxs(t.Fragment,{children:[d&&t.jsx(Y,{block:!0,size:"large",leadingVisual:Ne==="github"?()=>t.jsx(zt,{size:"small"}):Zs,disabled:We,onClick:()=>V(Ht.github),sx:{mt:h,maxWidth:X,mx:"auto"},children:"Sign in with GitHub"}),we&&t.jsx(Y,{block:!0,size:"large",leadingVisual:Ne==="google"?()=>t.jsx(zt,{size:"small"}):ea,disabled:We,onClick:()=>V(Ht.google),sx:{mt:h,maxWidth:X,mx:"auto"},children:"Sign in with Google"}),q&&t.jsx(Y,{block:!0,size:"large",leadingVisual:Ne==="linkedin"?()=>t.jsx(zt,{size:"small"}):ta,disabled:We,onClick:()=>V(Ht.linkedin),sx:{mt:h,maxWidth:X,mx:"auto"},children:"Sign in with LinkedIn"})]}),!O&&!at&&t.jsx(p,{mt:3,display:"flex",justifyContent:"center",children:t.jsx(Y,{leadingVisual:Dt,size:"large",block:!0,disabled:v||w||oe,onClick:()=>jt(!0),sx:{maxWidth:X,mx:"auto"},children:de})}),!O&&at&&t.jsxs(p,{mt:4,children:[t.jsxs(ce,{required:!0,sx:{mb:3},children:[t.jsx(ce.Label,{children:"Username"}),t.jsx(xt,{autoFocus:!0,block:!0,placeholder:"Your username",value:W,disabled:w||v,onChange:c=>ke(c.target.value),onKeyDown:He})]}),t.jsxs(ce,{required:!0,sx:{mb:3},children:[t.jsx(ce.Label,{children:"Password"}),t.jsx(xt,{block:!0,placeholder:"Your password",type:je?"text":"password",value:ue,disabled:w||v,onChange:c=>kt(c.target.value),onKeyDown:He,trailingAction:t.jsx(xt.Action,{onClick:()=>fe(!je),disabled:w||v,icon:je?Qs:Xs,"aria-label":je?"Hide password":"Show password",sx:{color:"var(--fgColor-muted)"}})})]}),t.jsxs(p,{display:"flex",alignItems:"center",justifyContent:"space-between",mt:3,children:[t.jsx(Y,{variant:"primary",disabled:w||v||!W||!ue,onClick:Be,children:w?"Signing in…":"Sign In"}),Ct&&t.jsx(yo,{as:"button",sx:{fontSize:1,cursor:v?"not-allowed":"pointer",background:"none",border:"none",opacity:v?.6:1},onClick:()=>{v||w||G()},children:ze})]})]}),O&&t.jsxs(t.Fragment,{children:[t.jsxs(ce,{required:!0,sx:{mb:3,mt:2},children:[t.jsx(ce.Label,{children:"MFA Code"}),t.jsx(xt,{autoFocus:!0,block:!0,placeholder:"Your MFA code",value:me,disabled:w||v,onChange:c=>Ee(c.target.value),onKeyDown:He})]}),t.jsx(Y,{variant:"primary",block:!0,disabled:w||v||!me.trim(),onClick:Ve,sx:{maxWidth:X,mx:"auto"},children:w?"Validating…":"Validate MFA Code"})]}),Re&&t.jsx(H,{sx:{color:"danger.fg",fontSize:1,mt:3,display:"block"},children:Re}),F&&t.jsxs(p,{mt:4,pt:4,textAlign:"center",borderTop:"1px solid",borderColor:"border.muted",children:[t.jsx(bt,{as:"h3",sx:{fontSize:2,mb:2},children:Yt}),t.jsx(H,{as:"p",sx:{color:"fg.muted",fontSize:1,mb:3},children:J}),t.jsx(p,{display:"flex",justifyContent:"center",children:t.jsx(Y,{variant:"primary",size:"large",leadingVisual:Co,disabled:v||w,onClick:ct,children:yt})})]}),nt&&a&&t.jsxs(t.Fragment,{children:[t.jsxs(p,{display:"flex",alignItems:"center",gap:2,my:3,children:[t.jsx(p,{flex:1,height:"1px",bg:"border.default"}),t.jsx(H,{sx:{fontSize:0,color:"fg.muted"},children:"or"}),t.jsx(p,{flex:1,height:"1px",bg:"border.default"})]}),t.jsx(Y,{block:!0,leadingVisual:Dt,disabled:v||w||oe,onClick:()=>se(!0),sx:{maxWidth:X,mx:"auto"},children:"Sign in with an API Key"}),Ae&&t.jsx(p,{role:"dialog","aria-modal":"true","aria-labelledby":"signin-api-key-title",onKeyDown:c=>{c.key==="Escape"&&ie()},onClick:ie,position:"fixed",inset:0,zIndex:200,p:3,bg:"canvas.backdrop",display:"flex",alignItems:"center",justifyContent:"center",children:t.jsxs(p,{as:"form",onClick:c=>c.stopPropagation(),onSubmit:c=>{c.preventDefault(),lt()},width:"min(560px, 100%)",p:3,borderRadius:2,border:"1px solid",borderColor:"border.default",bg:"canvas.overlay",color:"fg.default",boxShadow:"shadow.large",children:[t.jsx(bt,{id:"signin-api-key-title",sx:{fontSize:2,mb:2},children:"Enter your API Key"}),t.jsxs(ce,{required:!0,children:[t.jsx(ce.Label,{children:"API Key"}),t.jsx(wo,{block:!0,required:!0,autoFocus:!0,placeholder:"Paste your API key here",value:ae,onInput:c=>he(c.currentTarget.value),ref:j})]}),t.jsxs(p,{mt:3,display:"flex",justifyContent:"flex-end",gap:2,children:[t.jsx(Y,{type:"button",onClick:ie,children:"Cancel"}),t.jsx(Y,{type:"submit",variant:"primary",disabled:!ae.trim(),children:"Authenticate"})]})]})})]})]})]})};function aa(n){const{agentId:a,instructions:l,model:r,frontendTools:f,inference:x,subagents:y,sharing:I,onSubagentEvent:d,modeEffect:we}=n;return{type:"browser-vercel-ai",endpoint:"",agentId:a,enableConfigQuery:!1,options:{instructions:l,model:r,frontendTools:f,inference:x,subagents:y,sharing:I,onSubagentEvent:d,modeEffect:we}}}const Ln=Io((n,a)=>({pending:void 0,suggest:(l,r)=>{const f=l.trim();f&&n({pending:{text:f,submit:r?.submit??!1,nonce:(a().pending?.nonce??0)+1}})},consume:()=>n({pending:void 0})}));function ia({agentName:n,sandboxStillRuns:a=!1,temporary:l=!0,onSignedIn:r,onSignUp:f}){const{configuration:x}=zn(),y=o.useCallback(I=>{Eo.getState().checkIAMToken(I),r?.()},[r]);return t.jsx(p,{height:"100%",minHeight:0,overflowY:"auto",bg:"canvas.default",px:4,py:4,children:t.jsxs(p,{maxWidth:440,mx:"auto",children:[t.jsxs(p,{display:"flex",alignItems:"center",justifyContent:"center",gap:2,color:"attention.fg",mb:2,children:[t.jsx(Dt,{size:20}),t.jsx(H,{sx:{fontSize:2,fontWeight:"semibold",color:"fg.default"},children:l?"This demo runs on a shared key":"Your key has expired"})]}),t.jsxs(H,{as:"p",sx:{fontSize:1,color:"fg.muted",textAlign:"center",mb:3},children:[l?`${n??"The agent"} has used the time this key allows. Sign in to point your own agent at it, use your own data, and drop the time limit.`:`${n??"The agent"} stopped because your session ran out.`,a?" Your notebook is still running in this page.":""]}),t.jsx(sa,{hideHero:!0,fillHeight:!1,calloutTitle:"Sign in to keep going",github:!0,google:!0,linkedin:!0,socialSignInNavigationTarget:typeof window>"u"?void 0:`${window.location.pathname}${window.location.search}`,loginUrl:x?.iamUrl?`${x.iamUrl}/api/iam/v1/login`:void 0,onSignIn:y,onSignUp:f})]})})}const ra="https://r1.datalayer.run";function la(n=!0){const{configuration:a}=zn(),l=Gt(I=>I.token),r=a?.aiInferenceUrl||ra,f=To(r,n&&!l),x=l||f.token,y=o.useMemo(()=>({inferenceUrl:r,token:x||void 0}),[r,x]);return{inference:y,needsSignIn:Ro(y),anonymous:f,inferenceUrl:r}}const ca={name:"general-purpose",description:"A capable generalist for a task none of the specialists covers: research, reasoning, drafting, checking.",instructions:"You are a capable general-purpose assistant. Carry out the task you are given completely and report the result plainly, saying what you could not do."};function On(n){const a=n?.subagents;if(!a)return[];const l=(a.subagents??[]).map(r=>{const f=r.ref?Ao(r.ref):void 0;return{name:r.name,description:r.description||f?.description||r.name,instructions:r.instructions??f?.systemPrompt,model:r.model??f?.model??a.defaultModel,icon:f?.icon}});return a.includeGeneralPurpose?[...l,ca]:l}function da(n){return n.replace(/^datalayer_/,"").replace(/_lexical$/,"")}function ua(n){const a=da(n);return/^executeCodeIn(Notebook|Document)$/.test(a)||/^(read|list)[A-Z]/.test(a)}function fa(n,a){return n.filter(l=>a?.has(l.name)||ua(l.name))}function pa(n,a){const l=r=>a&&r.value.id===`${a}-tools`?0:r.value.id==="notebook-tools"?1:2;return n.map((r,f)=>({entry:r,index:f,rank:l(r)})).sort((r,f)=>r.rank-f.rank||r.index-f.index).map(r=>r.entry)}function ma(n,a,l){if(!l||!n.endsWith("-tools"))return!1;const r=n.slice(0,-6);return a.has(r)&&r!==l}const ga={type:"object",properties:{}};function ha(n,a){const l=new Set(n.toolset);return n.commands.filter(r=>l.has(r.name)).map(r=>({name:r.name,description:r.description,parameters:r.parameters??ga,location:"frontend",handler:async f=>{if(!a)throw new Error(`${r.name}: the ${n.plugin??n.id} plugin is not mounted on this page.`);const x=Object.keys(f??{}).length>0?f:void 0,y=await a.executeCommand(r.command,x);return y===void 0?{ok:!0,command:r.command,argument:x}:y}}))}function Bn(n,a){return n.flatMap(l=>ha(l,a))}function ba(){const n=Mo(),a=Nn();return o.useMemo(()=>Bn(a,n),[a,n])}function xa(n){const a=n?.app_instance;if(!a||typeof a!="object")return"";const l=a.deployment_uid;return typeof l=="string"?l.trim():""}function va(n,a,l){return n||!a?n:{id:l,messages:[]}}const Sa=({state:n})=>Po[n],ya="var(--theme-accent)";function Vn({face:n,size:a}){return typeof n=="string"?t.jsx(Uo,{emoji:n,size:a,label:""}):t.jsx(t.Fragment,{children:n})}function Ca({face:n,size:a,state:l}){const r=l==="thinking"||l==="working",f=l==="paused";return t.jsxs(p,{as:"span","aria-hidden":!0,"data-presence":l,position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"center",width:a+8,height:a+8,flexShrink:0,fontSize:a,lineHeight:1,children:[t.jsx(p,{as:"span",position:"absolute",inset:0,borderRadius:"50%",boxShadow:f?"none":`0 0 0 2px ${ya}`,border:f?"2px dashed":"none",borderColor:"border.default",opacity:r||l==="waiting"||f?.9:0,transition:"opacity var(--theme-motion-status, 0ms) var(--theme-motion-easing, ease)",animation:r?"loopPresenceBreath 1.8s ease-in-out infinite":"none",reducedMotion:{animation:"none"},sx:{"@keyframes loopPresenceBreath":{"0%, 100%":{transform:"scale(0.92)",opacity:.35},"50%":{transform:"scale(1.06)",opacity:.9}}}}),t.jsx(p,{as:"span",display:"inline-flex",opacity:f?.55:1,filter:f?"grayscale(0.6)":"none",transition:"opacity var(--theme-motion-status, 0ms) var(--theme-motion-easing, ease)",children:t.jsx(Vn,{face:n,size:a})})]})}function wa({state:n}){return t.jsx(H,{role:"status","aria-live":"polite","data-presence-line":n,sx:{fontSize:0,color:n==="waiting"?"fg.default":"fg.muted",fontWeight:n==="waiting"?"semibold":"normal",whiteSpace:"nowrap",flexShrink:0},children:Sa({state:n})})}const ka=Kt(void 0),ja=Kt(""),Ia=Kt({}),Z="",Ea=1400,_n=parseInt(Ys["--loop-face-large"],10);function Pa({workspace:n}){const a=$o(),l=Fo(),r=o.useRef(null),{setViewControls:f}=n,[x,y]=o.useState(null),I=Lo(),d=I.getConfig(Oo),we=d?.placeholder||a.placeholder,q=d?.defaultSurface??"notebook",nt=I.getConfig(_o),[F,ee]=o.useState(Z),v=o.useRef(!1),E=N(zo),te=N(No),Oe=N(Bo),de=N(Vo)[0]?.value,J=Nt(de?.promptStance??ka)??de?.prompt,yt=N(Ho),_e=Wo(yt[0]?.value),B=o.useRef(_e);B.current=_e;const Q=o.useRef(""),ze=N(Do),Ct=o.useMemo(()=>Go(()=>ze.reduce((e,i)=>({...e,...i.value.extras.value}),{})),[ze]),h=Nt(ze.length>0?Ct:Ia),X=o.useRef(new Set),ne=Ko(Gs,n),st=!ne.allowed,wt=st?ne.reason??"Chat is unavailable for this sandbox":void 0,[L,W]=o.useState(!1),[ke,ue]=o.useState(!1),[kt,at]=o.useState(!1),[jt,je]=o.useState({open:!1,pendingApproval:!1}),fe=Yo(L,jt,d?.presence?.paused===!0),w=d?.presence?.onPresence;o.useEffect(()=>{w?.(fe),B.current?.setPresence(fe)},[w,fe]);const pe=o.useRef(d?.presence?.onSaying);pe.current=d?.presence?.onSaying;const oe=o.useRef({answering:!1}),it=o.useCallback(e=>{r.current=e,ue(!!e)},[]),Ne=o.useCallback(e=>{const{open:i,pendingApproval:s}=qo(e);je(ye=>ye.open===i&&ye.pendingApproval===s?ye:{open:i,pendingApproval:s});const m={saying:Qo(e),answering:Jo(e)},u=oe.current;(u.saying?.id!==m.saying?.id||u.saying?.text!==m.saying?.text||u.answering!==m.answering)&&(oe.current=m,pe.current?.(m));const z=B.current;if(!z)return;z.items(e);const M=new Set(["complete","completed","done","error","failed","cancelled","canceled","rejected","denied","stopped"]),K={insertcell:"adding a cell",updatecell:"editing a cell",runcell:"running a cell",deletecells:"removing cells",readallcells:"reading the notebook",readcell:"reading a cell",executecode:"running code",insertblock:"adding a block",updateblock:"editing a block",runblock:"running a block",readdocument:"reading the document"};let b;for(let ye=e.length-1;ye>=0;ye-=1){const ht=e[ye];if(typeof ht.toolName=="string"&&ht.toolCallId){M.has(String(ht.status).toLowerCase())||(b=ht);break}}if(!b){z.activity(void 0);return}const Se=b.toolName.toLowerCase().replace(/^datalayer_/,"").replace(/_lexical$/,"").replace(/[^a-z]/g,""),bo=K[Se]??`using ${b.toolName}`;z.activity(`${Q.current||"The agent"} is ${bo}…`)},[]),Ie=o.useRef(h);Ie.current=h;const O=o.useCallback(e=>{eo(e),B.current?.usage(e),Ie.current.onUsage?.(e)},[]),It=o.useCallback(e=>{W(e),e||B.current?.end("done")},[]),me=o.useCallback(e=>{const i=B.current;if(!i)return;let s=-1;for(let u=e.length-1;u>=0;u-=1)if(e[u].role==="user"){s=u;break}const m=e.slice(s+1).filter(u=>u.role==="assistant").map(Xo).filter(u=>u.trim().length>0).join(`
29
-
30
- `);i.assistant(m)},[]),Ee=o.useRef([]),Te=o.useRef(!1),rt=o.useRef(void 0),Re=o.useRef(void 0),$=o.useRef(void 0),ge=N(Zo),Ae=o.useRef(ge);Ae.current=ge;const se=o.useCallback((e,i)=>{if(Re.current)return Re.current;const s=$.current;$.current=void 0;const m=es(Ae.current.map(M=>M.value),s?{...i??{},voice:s}:i),u=m?.loop;if(Te.current&&u?.files&&u.files.length>0){const M=rt.current;if(!M)return"A file is given to an application running on a runtime: run it on Datalayer or on your machine to give it one.";let K;try{K=u.files.map(b=>({file:ns(String(b.name??"")),base64:ts(String(b.data_url??""))}))}catch(b){return b instanceof Error?b.message:String(b)}M.execute(os(K)).then(b=>{if(!b.success){y(`The files could not be put in the sandbox: ${b.error??"it failed"}.`);return}se(`${e}
31
-
32
- ${ss(K.map(Se=>Se.file))}`,{...m,loop:Object.fromEntries(Object.entries(u).filter(([Se])=>Se!=="files"))})});return}B.current?.begin(e,r.current?.thread());const z=r.current?.send;if(!z){Ee.current.push([e,m]);return}z(e,m)},[]);o.useEffect(()=>{f(ke?{busy:L,stop:r.current?.stop,newChat:r.current?.newChat,send:se}:null)},[L,ke,f,se]),o.useEffect(()=>()=>f(null),[f]),o.useEffect(()=>n.prompts.subscribe(se),[n.prompts,se]),o.useEffect(()=>{if(!ke||Ee.current.length===0)return;const e=Ee.current.splice(0,Ee.current.length);for(const[i,s]of e)r.current?.send(i,s)},[ke]);const ae=o.useRef(!1),he=o.useCallback(async e=>{y(null);const i=await as(Ie.current,e);if(i){i.sent?Je(""):y(i.refused);return}ae.current||(ae.current=!0,nt?.firstPromptHook?.());const s=await n.submit(e);if(!s.handled){y(s.reason??null);return}Je(""),s.result?.content&&y(s.result.content)},[n,nt?.firstPromptHook]),j=o.useMemo(()=>E.find(e=>e.value.surfaceId===F)?.value,[E,F]),Me=o.useCallback(e=>{v.current=!0,ee(e)},[]);o.useEffect(()=>is(Me),[Me]),o.useEffect(()=>{rs(E.map(e=>e.value.surfaceId))},[E]),o.useEffect(()=>{ls(F&&F!==Z?F:qs)},[F]);const D=o.useMemo(()=>q===Z||q==="none"?void 0:E.find(e=>e.value.surfaceId===q),[E,q]);o.useEffect(()=>{v.current||!D||tt(D.value,n)&&ee(q)},[D,n,q]);const[V,ie]=o.useState(null),lt=o.useRef(null),ct=d?.fullScreenTopOffset??0,{fullScreen:G,usingApi:Be,toggle:Ve,topOffsetPx:He}=cs(lt,{forceOverlay:!!ct,topOffset:ct}),[We,c]=o.useState(!1),k=o.useRef(!1);o.useEffect(()=>{!L||k.current||G||(k.current=!0,c(!0))},[L,G]),o.useEffect(()=>{G&&c(!1)},[G]),o.useEffect(()=>{j&&!tt(j,n)&&(ie(j.surfaceId),ee(Z))},[j,n]);const P=o.useMemo(()=>{if(V)return E.find(e=>e.value.surfaceId===V)?.value;if(!v.current&&F===Z)return D?.value},[E,V,F,D]);o.useEffect(()=>{if(!V||F!==Z)return;const e=E.find(i=>i.value.surfaceId===V);e&&tt(e.value,n)&&(ie(null),ee(V))},[E,F,V,n]);const g=n.agentId?.trim()||"default",R=ds(n.sandbox.target??"local");Te.current=R;const C=us(),re=Nt(C?.selected??ja),S=C?.members.find(e=>e.id===re),De=N(fs)[0]?.value,Pe=De?.specId,A=An(S?.specId??g)??(Pe?An(Pe):void 0),Ge=S?void 0:De,qt=R&&!S?Ds(Pe,A):void 0;Q.current=S?.name??A?.name??g;const Jt=N(ps),Qt=h.hiddenOpeners,Xt=h.hideOpeners,Et=h.openers,Tt=o.useMemo(()=>{if(Xt)return[];const e=new Set(Qt??[]),i=b=>e.size===0?b:b.filter(Se=>!e.has(Se.text));if(Et)return i(Et);const s=Jt.flatMap(b=>b.value.suggestions);if(s.length>0)return i(s);const m=i(A?.suggestions??[]),u=i(C?.team.suggestions??[]);if(u.length===0)return m;const z=new Set(u.map(b=>b.text)),M=C?.team.name??"Team",K=S?.name??A?.name??g;return[...u.map(b=>({...b,group:M})),...m.filter(b=>!z.has(b.text)).map(b=>({...b,group:K}))]},[Jt,C,A,S,g,Qt,Xt,Et]),dt=o.useMemo(()=>Tt.map(e=>({title:e.summary??e.text,message:e.message??e.text,group:e.group})),[Tt]),Rt=Le(A?.icon),_=d?.presence,Hn=Le(C?.team.icon),Zt=N(ms),ut=o.useMemo(()=>{const e=[],i=new Map,s=new Set,m=new Set(E.map(u=>u.value.surfaceId));for(const u of pa(Zt,j?.surfaceId)){if(ma(u.value.id,m,j?.surfaceId))continue;let z;try{z=u.value.tools(n)}catch(M){console.warn(`[loop] frontend tools from '${u.plugin}' failed:`,M);continue}for(const M of z){const K=i.get(M.name);if(K){console.warn(`[loop] frontend tool '${M.name}' from '${u.plugin}' is shadowed by the one from '${K}'.`);continue}i.set(M.name,u.plugin),e.push(M),u.value.chatView&&s.add(M.name)}}for(const u of h.frontendTools??[])i.has(u.name)||(i.set(u.name,"chat-extras"),e.push(u),s.add(u.name));return j?e:fa(e,s)},[Zt,n.surfaceId,n.agentId,h.frontendTools,j?.surfaceId,E]),At=ba(),Ke=o.useMemo(()=>{if(At.length===0)return ut;const e=new Set(ut.map(i=>i.name));return[...ut,...At.filter(i=>!e.has(i.name))]},[ut,At]),en=Nn(),Mt=h.agentToolBundles,Wn=o.useMemo(()=>{const e=h.frontendTools??[];if(!Mt?.length)return h.frontendTools;const i=Bn(en.filter(m=>Mt.includes(m.id)),I),s=new Set(e.map(m=>m.name));return[...e,...i.filter(m=>!s.has(m.name))]},[h.frontendTools,Mt,en,I]);rt.current=R&&Ke.some(e=>e.name===gs)?I.getOutput(vt)?.sandbox:void 0;const T=hs(n.sandbox,n.serverUrl),tn=N(bs),Dn=o.useMemo(()=>tn.filter(e=>e.value.composer).map(e=>({name:e.value.name,description:e.value.description})),[tn]),Gn=o.useMemo(()=>{if(!C||!S)return On(A).map(s=>({name:s.name,description:s.description,icon:Le(s.icon)}));const e=C.members.map(s=>({name:s.name,description:s.description,emoji:s.emoji,icon:Le(s.icon),disabled:s.id===S.id,disabledReason:s.id===S.id?`You are already talking to ${s.name}`:void 0})),i=Mn(C.team,S.id).filter(s=>!C.members.some(m=>m.name===s.name)).map(s=>({name:s.name,description:s.description,icon:Le(s.icon)}));return[...e,...i]},[C,S,A]),{inference:nn,anonymous:Kn}=la(R),Yn=Gt(e=>e.user),Pt=R&&Kn.status==="expired",on=!Yn,Ye=xs();Re.current=Ye.disabled?Ye.disableReason||"This conversation is closed here.":void 0;const Ut=T===void 0?vs(n.sandbox,a):void 0,qe=st||Pt||!!qt||!!Ut||Ye.disabled,sn=Pt?on?a.demoKeyExpired:a.keyExpired:qt??Ut??wt??(Ye.disabled?Ye.disableReason:void 0),[$t,Je]=o.useState(""),[an]=Ss(),Qe=o.useMemo(()=>d?.voice?ys(d.voice,an):void 0,[d?.voice,an]),[qn,Jn]=o.useState(!1),[Qn,rn]=o.useState(),ft=Qn??Ge?.model??A?.model??n.model??"",Ue=Cs(),ln=o.useRef(Ue),cn=o.useRef(re),dn=o.useRef(Ue);dn.current=Ue,o.useEffect(()=>{cn.current!==re&&(cn.current=re,ln.current=dn.current,rn(void 0))},[re]);const Xn=Ue&&Ue!==ln.current?Ue:null,[Zn,eo]=o.useState(),to=Xn??Zn??null,no=Bt(Ce.inpromptMenu),un=Bt(Ce.promptAction),fn=Bt(Ce.chatHeader),oo=o.useMemo(()=>C?.members.map(e=>({id:e.id,name:e.name,description:e.description,icon:Le(e.icon)}))??[],[C]),be=Ln(e=>e.pending),[pn,so]=o.useState(0);o.useEffect(()=>ws(()=>so(e=>e+1)),[]),o.useEffect(()=>{be&&(Je(be.text),Ln.getState().consume(),be.submit&&he(be.text))},[be]);const mn=I.getConfig(vt)?.datalayerCreatePayload,xe=!!(Ge?.createPayload?.app_spec||mn?.app_spec),Xe=xa(mn),ao=Gt(e=>e.token),Ft=I.getConfig(vt)?.datalayerVisitors,io=ks(Ft),ro=I.getConfig(vt)?.embedToken,ve=Ft?io.token:ro||ao,lo=o.useMemo(()=>js(d?.voice,ve||void 0,Xe),[d?.voice,ve,Xe]),le=!!(Xe||Ft);if(le&&!xe)throw new Error("A deployment’s page runs its application: its host gave no app_spec.");const[gn]=o.useState(Pn),U=o.useMemo(()=>va(d?.thread,Xe,gn),[d?.thread,Xe,gn]),[$e,hn]=o.useState(null),co=!!(U?.fromRuntime&&$e?.given!==U.id);o.useEffect(()=>{if(!U?.fromRuntime||!xe||!T)return;let e=!0;return(async()=>{let i="";for(let s=0;s<4&&e;s+=1)try{const m=await Is({agentBaseUrl:T,agentId:g,uid:U.id,token:ve});e&&hn({given:U.id,thread:{...U,fromRuntime:!1,messages:m}});return}catch(m){i=m instanceof Error?m.message:String(m),await new Promise(u=>setTimeout(u,1500))}e&&hn({given:U.id,thread:{id:Pn(),messages:[],onStarted:U.onStarted},said:Un.notOpened(i)})})(),()=>{e=!1}},[U?.id,U?.fromRuntime,xe,T,g,ve]);const bn=U?.fromRuntime?$e?.given===U.id?$e.thread:void 0:U,Lt=o.useMemo(()=>R?aa({agentId:S?.specId??g,instructions:Es(A,Ge?.instructions),model:ft||void 0,inference:nn,frontendTools:Ke,subagents:C&&S?Mn(C.team,S.id):On(A),sharing:C?.sharing,onSubagentEvent:e=>Ks.getState().appendSubagentEvent(e),modeEffect:Ge?.modeEffect}):T!==void 0?{type:"ag-ui",endpoint:xe?`${T}/api/v1/apps/agents/${encodeURIComponent(g)}/ag-ui/`:`${T}/api/v1/ag-ui/${g}/`,...xe&&ve?{authToken:ve}:{},...xe?{uiSocket:`${T.replace(/^http/,"ws")}/api/v1/apps/ui`,uiFiles:`${T}/api/v1/apps/agents/${encodeURIComponent(g)}/files`,appSessions:`${T}/api/v1/apps/sessions`,...le?{ownRoutesOnly:!0}:{}}:{},agentId:g,configEndpoint:`${T}/api/v1/configure`,enableConfigQuery:!0}:void 0,[g,R,nn,S,Ke,C,A,Ge,ft,T,xe,ve,le]),pt=Ts(!R,Lt?.type==="ag-ui"?Lt.configEndpoint:void 0,void 0,g),Ze=Rs(),mt=As(g),[xn,Ot]=o.useState(void 0),[uo,fo]=o.useState(void 0);o.useEffect(()=>{if(R||T===void 0)return;const e=Ms(T,g,le);if(!e){Ot([]);return}let i=!1;return fetch(e).then(s=>s.ok?s.json():null).then(s=>{i||(Ot(s?Ps(s):[]),fo(s?Us(s):void 0))}).catch(()=>{i||Ot([])}),()=>{i=!0}},[T,g,R,le]);const po=o.useMemo(()=>$s(xn,()=>Object.values(Fs).filter(e=>e.available&&Ls(e)).map(e=>({id:e.id,name:e.name,provider:e.provider}))),[xn]),vn=o.useMemo(()=>{const e=pt.data?.builtinTools??[],i=new Set(e.map(s=>s.name));return{runtime:e,frontend:Ke.filter(s=>!i.has(s.name)).map(s=>({id:s.name,name:s.name}))}},[pt.data?.builtinTools,Ke]),Sn=o.useMemo(()=>new Set((Ze.data?.skills??[]).filter(e=>e.status==="enabled"||e.status==="loaded").map(e=>e.id)),[Ze.data]),mo=o.useCallback(async e=>{if(le)throw new Error("A deployment’s chat does not switch its runtime’s model.");rn(e),!(R||T===void 0)&&await fetch(`${T}/api/v1/configure/inference/provider`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({model:e})}).catch(()=>{})},[T,R,le]),yn=d?.promptPlacement==="bottom-chat",go=d?.promptPlacement==="floating",Fe=d?.promptPlacement==="top",et=d?.hidePrompt===!0||h.hidePrompt===!0,ho={onSend:()=>{he($t)},input:$t,setInput:Je,focusTrigger:be||pn?(be?.nonce??0)+pn:void 0,placement:go||J==="floating"||J==="floating-top"||J==="floating-bottom"?"floating":"docked",floatingAnchor:J==="floating-top"?"top":"bottom",isLoading:L,onStop:()=>n.viewControls.stop?.(),placeholder:sn??h.sendInstead?.says??we,typingSuggestions:Tt.map(e=>e.text),suggestions:dt,disableInputPrompt:qe,connectionConfirmed:!qe,interim:qn,padding:Fe||J==="floating-top"||J==="floating-bottom"||J==="docked-top"?2:3,promptVariant:"lexical",autoFocus:d?.autoFocusPrompt??!0,mentionableAgents:Gn,promptCommands:Dn,headerContent:no.length>0?t.jsx(St,{slot:Ce.inpromptMenu,props:{workspace:n}}):void 0,footerExtras:un.length>0||Qe&&Qe.input!=="off"?t.jsxs(t.Fragment,{children:[un.length>0?t.jsx(St,{slot:Ce.promptAction,props:{workspace:n}}):null,Qe&&Qe.input!=="off"?t.jsx(Os,{voice:Qe,input:$t,setInput:Je,disabled:qe,speaking:kt,onStopSpeaking:()=>r.current?.stopSpeaking?.(),onInterimChange:Jn,answers:!!(d?.voice?.output&&d.voice.output!=="off"&&d.voice.speechUrl),onSpoken:e=>{$.current=e},send:(e,i)=>{$.current=i,he(e)}}):null]}):void 0,showAgentsMenu:!_,showInlineAgentsMenu:!1,agents:oo,selectedAgentId:re,onSelectAgent:e=>C?.select(e),showTokenUsage:h.showTokenUsage??d?.showTokenUsage??!0,showContextRing:!0,agentUsage:to??void 0,showModelSelector:!_&&!le,models:po,decisions:uo,selectedModel:ft,onModelSelect:e=>{mo(e)},showToolsMenu:!_,availableTools:vn.runtime,availableFrontendTools:vn.frontend,mcpServers:pt.data?.mcpServers??[],mcpStatusData:h.mcpStatusData??void 0,showSkillsMenu:!_,skills:Ze.data?.skills??[],skillsLoading:Ze.isLoading,enabledSkills:Sn,onToggleSkill:e=>Sn.has(e)?mt.disableSkill(e):mt.enableSkill(e),onToggleAllSkills:(e,i)=>e.forEach(s=>i?mt.enableSkill(s):mt.disableSkill(s)),codemodeEnabled:h.codemodeEnabled??!1,onToggleCodemode:h.onToggleCodemode,isA2AProtocol:!1,hasConfigData:!!pt.data,hasSkillsData:!!Ze.data},Cn=te[0]?.value.Component,_t=Oe[0]?.value.Component,wn=!d?.hideHeader&&!!_t,gt=Cn?t.jsx(Cn,{workspace:n,composer:ho}):null,kn=E.length>0&&d?.showSurfaceSelector!==!1?t.jsx(Ta,{surfaces:E.map(e=>e.value),active:j?.surfaceId??P?.surfaceId??Z,onChange:Me,workspace:n}):null,jn=t.jsxs(t.Fragment,{children:[E.map(e=>{const i=e.value,s=j?.surfaceId===i.surfaceId;return s||X.current.has(i.surfaceId)||tt(i,n)?(X.current.add(i.surfaceId),t.jsx(p,{sx:s?{flex:"1 1 0",minWidth:0,minHeight:0}:{position:"absolute",inset:0,visibility:"hidden",pointerEvents:"none",zIndex:-1},children:t.jsx(_s,{load:i.load,props:{surfaceId:i.surfaceId,workspace:n},fallback:t.jsxs(Wt,{children:["Loading ",i.title,"…"]}),errorFallback:u=>t.jsxs(Wt,{children:[i.title," failed to load: ",u.message]})})},i.surfaceId)):null}),!j&&P?t.jsx(p,{flex:"1 1 0",minWidth:0,minHeight:0,children:t.jsxs(Wt,{children:["Starting ",P.title,"…"]})}):null]}),In=t.jsx(t.Fragment,{children:t.jsxs(p,{flex:Fe&&j?"0 0 34%":"1 1 0",maxWidth:Fe&&j?460:void 0,minWidth:0,minHeight:0,display:"flex",flexDirection:"column",borderLeft:j?"1px solid":void 0,borderColor:"border.default",position:"relative",children:[h.errorBanner?t.jsx(p,{flexShrink:0,px:3,py:2,fontSize:1,borderBottom:"1px solid",bg:h.errorBanner.variant==="warning"?"attention.subtle":"danger.subtle",color:h.errorBanner.variant==="warning"?"attention.fg":"danger.fg",borderColor:h.errorBanner.variant==="warning"?"attention.muted":"danger.muted",children:h.errorBanner.message}):null,$e?.said&&$e.given===U?.id?t.jsx(H,{as:"p",role:"status",sx:{m:0,px:3,py:2,fontSize:1,color:"fg.muted"},children:$e.said}):null,t.jsx(p,{flex:"1 1 auto",minHeight:0,display:"flex",children:co?t.jsx(H,{as:"p",role:"status",sx:{m:0,p:3,fontSize:1,color:"fg.muted"},children:Un.opening}):t.jsx(zs,{themeVariant:d?.themeVariant,themeOverrides:d?.themeOverrides,colorMode:d?.colorMode,thread:bn,voice:lo,disabled:qe,disableReason:sn,protocol:Lt,frontendTools:R?void 0:Wn,initialModel:ft||void 0,title:_?.name??S?.name??A?.name??g,description:_?.welcome??A?.description,brandIcon:_?.face?t.jsx(Ca,{face:_.face,size:20,state:fe}):t.jsx(Rt,{size:20}),headerContent:_&&!Ut?t.jsx(wa,{state:fe}):void 0,emptyState:{icon:_?.face?t.jsx("span",{"aria-hidden":!0,style:{fontSize:_n,lineHeight:1},children:t.jsx(Vn,{face:_.face,size:_n})}):t.jsx(Rt,{size:48}),title:_?.name??S?.name??A?.name??g,...C&&S?{sections:[{group:C.team.name,icon:t.jsx(Hn,{size:48}),title:C.team.name,subtitle:C.team.description},{group:S.name,icon:t.jsx(Rt,{size:32}),title:S.name,subtitle:A?.description}]}:null},suggestions:Fe||de||d?.suggestionLabels===!1?[]:dt,showHeader:wn,headerButtons:{showNewChat:d?.headerButtons?.newChat??!1,showClear:d?.headerButtons?.clear??!1},renderHeader:_t?e=>t.jsx(_t,{workspace:n,header:n.chatViewModes?{...e,chatViewMode:n.chatViewModes.value,onChatViewModeChange:n.chatViewModes.onChange,offeredViewModes:n.chatViewModes.offered}:e}):void 0,showInformation:!0,headerActions:t.jsxs(p,{display:"inline-flex",alignItems:"center",gap:2,children:[n.chatHeaderActions,fn.length>0?t.jsx(St,{slot:Ce.chatHeader,props:{workspace:n}}):null,t.jsx(Ns,{icon:G?Bs:Vs,"aria-label":G?"Exit full screen":"Enter full screen",variant:"invisible",size:"small",onClick:()=>{c(!1),Ve()},sx:We?{"@keyframes dla-fullscreen-hint":{"0%, 100%":{opacity:1},"50%":{opacity:.4}},"&&":{bg:`color-mix(in srgb, ${l.primary} 16%, transparent)`,boxShadow:`inset 0 0 0 1.5px ${l.primary}`,animation:`dla-fullscreen-hint ${Ea}ms ease-in-out infinite`},"@media (prefers-reduced-motion: reduce)":{"&&":{animation:"none"}}}:void 0})]}),showInput:!1,onSendReady:it,notebookToolSurfacesId:j?void 0:n.surfaceId,showTurnFooter:h.showTokenUsage??d?.showTokenUsage??!0,onContextSnapshot:O,onLoadingChange:It,onSpeakingChange:at,onItemsChange:me,onDisplayItemsChange:Ne,enableStreaming:!0},bn?.id)}),!wn&&fn.length>0?t.jsx(p,{hidden:!0,children:t.jsx(St,{slot:Ce.chatHeader,props:{workspace:n}})}):null,yn&&!et?gt:null]})}),En=d?.suggestionLabels!==!1&&dt.length>0?t.jsx(p,{"aria-label":a.suggestedPrompts,display:"flex",flexWrap:"wrap",gap:2,px:2,pb:"6px",children:dt.map(e=>t.jsx(p,{as:"button",type:"button",title:e.message,disabled:L||qe,onClick:()=>{he(e.message)},appearance:"none",font:"inherit",fontSize:0,fontWeight:"semibold",lineHeight:1.25,px:"10px",py:"5px",width:$n,flex:`0 0 ${$n}px`,borderRadius:"999px",border:"1px solid",bg:"canvas.subtle",whiteSpace:"nowrap",sx:{borderColor:"border.default",color:"fg.default",cursor:"pointer","&:hover:not(:disabled)":{borderColor:"accent.fg",color:"accent.fg"},"&:disabled":{opacity:.5,cursor:"default"}},children:t.jsx(Hs,{title:e.title,maxWidth:"100%",sx:{minWidth:0},children:e.title})},e.title))}):null,Tn=x?t.jsx(p,{flex:"0 0 auto",px:3,py:2,borderTop:"1px solid",borderColor:"border.default",bg:"canvas.subtle",fontSize:1,maxHeight:"40%",overflowY:"auto",children:x}):null;return t.jsxs(p,{ref:lt,sx:{height:"100%",minHeight:0,display:"flex",flexDirection:"column",position:"relative",...G?{bg:"canvas.default"}:null,...G&&!Be.current?{position:"fixed",top:He,right:0,bottom:0,left:0,height:"auto",zIndex:1e3}:null},children:[de?t.jsx(de.Component,{workspace:n,editors:jn,hasEditor:!!j,transcript:In,prompt:et?null:gt,chips:et?null:En,picker:kn,transient:Tn}):t.jsxs(t.Fragment,{children:[Fe&&!et?t.jsxs(p,{flex:"0 0 auto",borderBottom:"1px solid",borderColor:"border.default",children:[gt,En]}):null,kn,t.jsxs(p,{flex:"1 1 auto",minHeight:0,display:"flex",position:"relative",children:[jn,In]}),Tn,yn||et||Fe?null:gt]}),Pt?t.jsx(p,{position:"absolute",inset:0,zIndex:5,bg:"canvas.default",display:"flex",flexDirection:"column",minHeight:0,children:t.jsx(ia,{agentName:S?.name??A?.name,sandboxStillRuns:R,temporary:on,onSignedIn:()=>Ws.getState().clear()})}):null]})}function Ta({surfaces:n,active:a,onChange:l,workspace:r}){const f=[...n].sort((x,y)=>(x.order??100)-(y.order??100));return t.jsxs(p,{flex:"0 0 auto",display:"flex",alignItems:"center",gap:2,px:3,py:2,borderBottom:"1px solid",borderColor:"border.default",children:[t.jsx(H,{sx:{fontSize:0,color:"fg.muted"},children:"Beside the chat"}),t.jsxs(Vt,{"aria-label":"Editor beside the chat",size:"small",children:[t.jsx(Vt.Button,{selected:a===Z,onClick:()=>l(Z),children:"Chat"}),f.map(x=>{const y=tt(x,r),I=y?void 0:x.unavailableReason?.(r)??"Not available right now";return t.jsx(Vt.Button,{selected:a===x.surfaceId,"aria-disabled":!y,title:I??x.title,leadingIcon:x.icon,onClick:()=>{y&&l(x.surfaceId)},children:x.title},x.surfaceId)})]})]})}function Wt({children:n}){return t.jsx(p,{height:"100%",display:"flex",alignItems:"center",justifyContent:"center",color:"fg.muted",fontSize:1,px:3,textAlign:"center",children:n})}export{Pa as default};