@webless/agent 0.6.8 → 0.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/embed.cjs CHANGED
@@ -407,6 +407,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
407
407
  sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
408
408
  }
409
409
 
410
+ // src/runtime/subagent-child-stream.ts
411
+ var INITIAL_RETRY_DELAY_MS = 100;
412
+ var MAX_RETRY_DELAY_MS = 2e3;
413
+ var MAX_CONSECUTIVE_RETRIES = 6;
414
+ function isRecord2(value) {
415
+ return typeof value === "object" && value !== null && !Array.isArray(value);
416
+ }
417
+ function parseError(value) {
418
+ if (!isRecord2(value)) return void 0;
419
+ const { code, message } = value;
420
+ if (typeof code !== "string" || typeof message !== "string") {
421
+ return void 0;
422
+ }
423
+ return { code, message };
424
+ }
425
+ function parseChildStreamEvent(value) {
426
+ if (!isRecord2(value) || typeof value.type !== "string") {
427
+ return { type: "other" };
428
+ }
429
+ if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
430
+ return { type: "session.boundary" };
431
+ }
432
+ if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
433
+ return parseChildStreamEvent(value.data.event);
434
+ }
435
+ if (value.type === "subagent.called" && isRecord2(value.data)) {
436
+ const { childStreamPath } = value.data;
437
+ if (typeof childStreamPath === "string") {
438
+ return { childStreamPath, type: "subagent.called" };
439
+ }
440
+ }
441
+ if (value.type !== "action.result" || !isRecord2(value.data)) {
442
+ return { type: "other" };
443
+ }
444
+ const { data } = value;
445
+ if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
446
+ return { type: "other" };
447
+ }
448
+ if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
449
+ return { type: "other" };
450
+ }
451
+ const result = data.result;
452
+ if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
453
+ return { type: "other" };
454
+ }
455
+ const error = parseError(data.error);
456
+ return {
457
+ type: "action.result",
458
+ hasOutput: Object.hasOwn(result, "output"),
459
+ result: {
460
+ callId: result.callId,
461
+ toolName: result.toolName,
462
+ status: data.status,
463
+ ...Object.hasOwn(result, "output") ? { output: result.output } : {},
464
+ ...error ? { error } : {}
465
+ }
466
+ };
467
+ }
468
+ async function* readNdjsonStream(body) {
469
+ const reader = body.getReader();
470
+ const decoder = new TextDecoder();
471
+ let buffer = "";
472
+ try {
473
+ while (true) {
474
+ const { done, value } = await reader.read();
475
+ buffer += decoder.decode(value, { stream: !done });
476
+ const lines = buffer.split("\n");
477
+ buffer = lines.pop() ?? "";
478
+ for (const line of lines) {
479
+ const trimmed2 = line.trim();
480
+ if (!trimmed2) continue;
481
+ try {
482
+ const parsed = JSON.parse(trimmed2);
483
+ yield parsed;
484
+ } catch {
485
+ }
486
+ }
487
+ if (done) break;
488
+ }
489
+ const trimmed = buffer.trim();
490
+ if (trimmed) {
491
+ try {
492
+ const parsed = JSON.parse(trimmed);
493
+ yield parsed;
494
+ } catch {
495
+ }
496
+ }
497
+ } finally {
498
+ reader.releaseLock();
499
+ }
500
+ }
501
+ function streamPathAt(path, streamIndex) {
502
+ if (streamIndex === 0) return path;
503
+ return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
504
+ }
505
+ function abortableDelay(delayMs, signal) {
506
+ if (signal.aborted) return Promise.resolve();
507
+ return new Promise((resolve) => {
508
+ const finish = () => {
509
+ clearTimeout(timeout);
510
+ signal.removeEventListener("abort", finish);
511
+ resolve();
512
+ };
513
+ const timeout = setTimeout(finish, delayMs);
514
+ signal.addEventListener("abort", finish, { once: true });
515
+ });
516
+ }
517
+ var SubagentChildStreamCoordinator = class {
518
+ constructor(client, handlers, parentSignal) {
519
+ this.client = client;
520
+ this.handlers = handlers;
521
+ this.parentSignal = parentSignal;
522
+ }
523
+ client;
524
+ handlers;
525
+ parentSignal;
526
+ controllers = /* @__PURE__ */ new Map();
527
+ tasks = /* @__PURE__ */ new Map();
528
+ begin(event) {
529
+ this.beginPath(event.data.childStreamPath);
530
+ }
531
+ async waitForAll() {
532
+ let observedTaskCount = -1;
533
+ while (observedTaskCount !== this.tasks.size) {
534
+ observedTaskCount = this.tasks.size;
535
+ await Promise.all(this.tasks.values());
536
+ }
537
+ }
538
+ abortAll() {
539
+ for (const controller of this.controllers.values()) controller.abort();
540
+ this.controllers.clear();
541
+ }
542
+ beginPath(childStreamPath) {
543
+ if (this.tasks.has(childStreamPath)) return;
544
+ const controller = new AbortController();
545
+ const abort = () => controller.abort();
546
+ if (this.parentSignal.aborted) {
547
+ controller.abort();
548
+ } else {
549
+ this.parentSignal.addEventListener("abort", abort, { once: true });
550
+ }
551
+ this.controllers.set(childStreamPath, controller);
552
+ const task = this.consume(childStreamPath, controller.signal).finally(
553
+ () => {
554
+ this.parentSignal.removeEventListener("abort", abort);
555
+ if (this.controllers.get(childStreamPath) === controller) {
556
+ this.controllers.delete(childStreamPath);
557
+ }
558
+ }
559
+ );
560
+ this.tasks.set(childStreamPath, task);
561
+ }
562
+ async consume(path, signal) {
563
+ let streamIndex = 0;
564
+ let consecutiveRetries = 0;
565
+ let retryDelayMs = INITIAL_RETRY_DELAY_MS;
566
+ while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
567
+ let receivedEvent = false;
568
+ try {
569
+ const response = await this.client.fetch(
570
+ streamPathAt(path, streamIndex),
571
+ {
572
+ cache: "no-store",
573
+ signal
574
+ }
575
+ );
576
+ if (!response.ok || response.body === null) {
577
+ await response.body?.cancel().catch(() => {
578
+ });
579
+ throw new Error(`Child stream returned ${response.status}.`);
580
+ }
581
+ for await (const rawEvent of readNdjsonStream(response.body)) {
582
+ if (signal.aborted) return;
583
+ receivedEvent = true;
584
+ streamIndex += 1;
585
+ const event = parseChildStreamEvent(rawEvent);
586
+ if (event.type === "session.boundary") return;
587
+ if (event.type === "subagent.called") {
588
+ this.beginPath(event.childStreamPath);
589
+ continue;
590
+ }
591
+ if (event.type !== "action.result") continue;
592
+ this.handlers.onToolResult?.(event.result);
593
+ if (event.hasOutput) {
594
+ this.handlers.onActionResult?.(event.result.output);
595
+ }
596
+ }
597
+ } catch {
598
+ if (signal.aborted) return;
599
+ }
600
+ consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
601
+ retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
602
+ await abortableDelay(retryDelayMs, signal);
603
+ }
604
+ }
605
+ };
606
+
410
607
  // src/runtime/tool-ui.ts
411
608
  var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
412
609
  var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
@@ -420,7 +617,7 @@ function formatAgentStructuredToolInput(surface, values) {
420
617
  };
421
618
  return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
422
619
  }
423
- function isRecord2(value) {
620
+ function isRecord3(value) {
424
621
  return value !== null && typeof value === "object" && !Array.isArray(value);
425
622
  }
426
623
  function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
@@ -469,7 +666,7 @@ function isFieldKind(value) {
469
666
  ].includes(value);
470
667
  }
471
668
  function parseField(value) {
472
- if (!isRecord2(value)) return null;
669
+ if (!isRecord3(value)) return null;
473
670
  if (!hasOnlyKeys(value, [
474
671
  "description",
475
672
  "kind",
@@ -520,7 +717,7 @@ function parseField(value) {
520
717
  if (!Array.isArray(value.options) || value.options.length > 100)
521
718
  return null;
522
719
  for (const option of value.options) {
523
- if (!isRecord2(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
720
+ if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
524
721
  return null;
525
722
  }
526
723
  }
@@ -543,7 +740,7 @@ function parseField(value) {
543
740
  };
544
741
  }
545
742
  function parseStep(value) {
546
- if (!isRecord2(value)) return null;
743
+ if (!isRecord3(value)) return null;
547
744
  if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
548
745
  return null;
549
746
  }
@@ -563,7 +760,7 @@ function parseStep(value) {
563
760
  };
564
761
  }
565
762
  function parseAction(value) {
566
- if (!isRecord2(value)) return null;
763
+ if (!isRecord3(value)) return null;
567
764
  if (!hasOnlyKeys(value, ["id", "label"])) return null;
568
765
  const label = boundedString(value.label, 80);
569
766
  if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
@@ -575,7 +772,7 @@ function parseAction(value) {
575
772
  };
576
773
  }
577
774
  function parseAgentToolUiSurface(value) {
578
- if (!isRecord2(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
775
+ if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
579
776
  return null;
580
777
  if (!hasOnlyKeys(value, [
581
778
  "actions",
@@ -613,7 +810,7 @@ function parseAgentToolUiSurface(value) {
613
810
  if (value.operationId !== void 0 && !operationId) return null;
614
811
  if (value.requestId !== void 0 && !requestId) return null;
615
812
  if (value.submitLabel !== void 0 && !submitLabel) return null;
616
- const values = value.values !== void 0 && isRecord2(value.values) ? value.values : void 0;
813
+ const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
617
814
  if (value.values !== void 0) {
618
815
  if (!values || !Object.values(values).every((item) => isJsonValue(item)))
619
816
  return null;
@@ -879,11 +1076,14 @@ var AgentSession = class {
879
1076
  clientHost;
880
1077
  session;
881
1078
  activeResponse;
1079
+ childStreams;
882
1080
  capability;
883
1081
  getActiveSessionId() {
884
1082
  return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
885
1083
  }
886
1084
  reset() {
1085
+ this.childStreams?.abortAll();
1086
+ this.childStreams = void 0;
887
1087
  if (this.activeResponse) {
888
1088
  void this.activeResponse.cancel().catch(() => {
889
1089
  });
@@ -979,6 +1179,12 @@ var AgentSession = class {
979
1179
  this.persistSessionCursor(session);
980
1180
  }
981
1181
  this.activeResponse = response;
1182
+ const childStreams = new SubagentChildStreamCoordinator(
1183
+ client,
1184
+ handlers,
1185
+ signal
1186
+ );
1187
+ this.childStreams = childStreams;
982
1188
  let streamIndex = session?.state.streamIndex ?? 0;
983
1189
  let rendered = "";
984
1190
  const workItems = /* @__PURE__ */ new Map();
@@ -986,6 +1192,7 @@ var AgentSession = class {
986
1192
  try {
987
1193
  for await (const event of response) {
988
1194
  if (signal.aborted) break;
1195
+ if (event.type === "subagent.called") childStreams.begin(event);
989
1196
  if (event.type === "input.requested") requestedInput = true;
990
1197
  rendered = applyMessageEvent(event, rendered, handlers, workItems);
991
1198
  streamIndex += 1;
@@ -998,8 +1205,11 @@ var AgentSession = class {
998
1205
  );
999
1206
  }
1000
1207
  }
1208
+ await childStreams.waitForAll();
1001
1209
  } finally {
1210
+ childStreams.abortAll();
1002
1211
  this.activeResponse = void 0;
1212
+ if (this.childStreams === childStreams) this.childStreams = void 0;
1003
1213
  if (session) {
1004
1214
  this.persistSessionCursor(session);
1005
1215
  }
@@ -1035,63 +1245,80 @@ var AgentSession = class {
1035
1245
  }
1036
1246
  let rendered = renderTurn(turnEvents);
1037
1247
  const workItems = /* @__PURE__ */ new Map();
1038
- for (const event of turnEvents) {
1039
- applyWorkEvent(event, handlers, workItems);
1040
- emitVisitorInteractionEvent(event, handlers);
1041
- }
1042
- if (rendered.startsWith(initialText)) {
1043
- const missedText = rendered.slice(initialText.length);
1044
- if (missedText) handlers.onDelta(missedText);
1045
- } else if (initialText.startsWith(rendered)) {
1046
- rendered = initialText;
1047
- } else if (!initialText.startsWith(rendered)) {
1048
- rendered = initialText + rendered;
1049
- }
1050
- let session = client.sessions.attach(snapshot.session.sessionId, {
1051
- streamIndex: snapshot.session.streamIndex
1052
- });
1053
- this.session = session;
1054
- this.persistSessionCursor(session);
1055
- let snapshotBoundary;
1056
- for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
1057
- const event = turnEvents[index];
1058
- if (event && isTurnBoundary(event)) {
1059
- snapshotBoundary = event;
1060
- break;
1248
+ const childStreams = new SubagentChildStreamCoordinator(
1249
+ client,
1250
+ handlers,
1251
+ signal
1252
+ );
1253
+ this.childStreams = childStreams;
1254
+ try {
1255
+ for (const event of turnEvents) {
1256
+ if (event.type === "subagent.called") childStreams.begin(event);
1257
+ applyWorkEvent(event, handlers, workItems);
1258
+ emitVisitorInteractionEvent(event, handlers);
1061
1259
  }
1062
- }
1063
- if (snapshotBoundary) {
1064
- if (snapshotBoundary.type === "session.failed") {
1065
- throw new Error(
1066
- snapshotBoundary.data.message || snapshotBoundary.data.code
1260
+ if (rendered.startsWith(initialText)) {
1261
+ const missedText = rendered.slice(initialText.length);
1262
+ if (missedText) handlers.onDelta(missedText);
1263
+ } else if (initialText.startsWith(rendered)) {
1264
+ rendered = initialText;
1265
+ } else if (!initialText.startsWith(rendered)) {
1266
+ rendered = initialText + rendered;
1267
+ }
1268
+ let session = client.sessions.attach(snapshot.session.sessionId, {
1269
+ streamIndex: snapshot.session.streamIndex
1270
+ });
1271
+ this.session = session;
1272
+ this.persistSessionCursor(session);
1273
+ let snapshotBoundary;
1274
+ for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
1275
+ const event = turnEvents[index];
1276
+ if (event && isTurnBoundary(event)) {
1277
+ snapshotBoundary = event;
1278
+ break;
1279
+ }
1280
+ }
1281
+ if (snapshotBoundary) {
1282
+ if (snapshotBoundary.type === "session.failed") {
1283
+ throw new Error(
1284
+ snapshotBoundary.data.message || snapshotBoundary.data.code
1285
+ );
1286
+ }
1287
+ handlers.onComplete?.();
1288
+ await childStreams.waitForAll();
1289
+ if (!rendered.trim() && !hasInputRequest) {
1290
+ throw new Error("Empty response from runtime");
1291
+ }
1292
+ return rendered.trim();
1293
+ }
1294
+ let streamIndex = snapshot.session.streamIndex;
1295
+ for await (const event of session.stream({ signal })) {
1296
+ if (signal.aborted) break;
1297
+ if (event.type === "subagent.called") childStreams.begin(event);
1298
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
1299
+ streamIndex += 1;
1300
+ savePersistedAgentSession(
1301
+ this.visitorSessionId,
1302
+ session.state.sessionId,
1303
+ streamIndex,
1304
+ this.storeOptions
1067
1305
  );
1306
+ if (isTurnBoundary(event)) break;
1068
1307
  }
1069
- handlers.onComplete?.();
1070
- if (!rendered.trim() && !hasInputRequest) {
1308
+ await childStreams.waitForAll();
1309
+ session = client.sessions.attach(session.state.sessionId, {
1310
+ streamIndex
1311
+ });
1312
+ this.session = session;
1313
+ this.persistSessionCursor(session);
1314
+ if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
1071
1315
  throw new Error("Empty response from runtime");
1072
1316
  }
1073
1317
  return rendered.trim();
1318
+ } finally {
1319
+ childStreams.abortAll();
1320
+ if (this.childStreams === childStreams) this.childStreams = void 0;
1074
1321
  }
1075
- let streamIndex = snapshot.session.streamIndex;
1076
- for await (const event of session.stream({ signal })) {
1077
- if (signal.aborted) break;
1078
- rendered = applyMessageEvent(event, rendered, handlers, workItems);
1079
- streamIndex += 1;
1080
- savePersistedAgentSession(
1081
- this.visitorSessionId,
1082
- session.state.sessionId,
1083
- streamIndex,
1084
- this.storeOptions
1085
- );
1086
- if (isTurnBoundary(event)) break;
1087
- }
1088
- session = client.sessions.attach(session.state.sessionId, { streamIndex });
1089
- this.session = session;
1090
- this.persistSessionCursor(session);
1091
- if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
1092
- throw new Error("Empty response from runtime");
1093
- }
1094
- return rendered.trim();
1095
1322
  }
1096
1323
  async respondTurn(responses, signal, handlers) {
1097
1324
  const client = this.ensureClient();
@@ -1112,6 +1339,12 @@ var AgentSession = class {
1112
1339
  () => session.respond(inputResponses, { signal })
1113
1340
  );
1114
1341
  this.activeResponse = response;
1342
+ const childStreams = new SubagentChildStreamCoordinator(
1343
+ client,
1344
+ handlers,
1345
+ signal
1346
+ );
1347
+ this.childStreams = childStreams;
1115
1348
  let streamIndex = session.state.streamIndex;
1116
1349
  let rendered = "";
1117
1350
  let requestedInput = false;
@@ -1119,6 +1352,7 @@ var AgentSession = class {
1119
1352
  try {
1120
1353
  for await (const event of response) {
1121
1354
  if (signal.aborted) break;
1355
+ if (event.type === "subagent.called") childStreams.begin(event);
1122
1356
  if (event.type === "input.requested") requestedInput = true;
1123
1357
  rendered = applyMessageEvent(event, rendered, handlers, workItems);
1124
1358
  streamIndex += 1;
@@ -1129,8 +1363,11 @@ var AgentSession = class {
1129
1363
  this.storeOptions
1130
1364
  );
1131
1365
  }
1366
+ await childStreams.waitForAll();
1132
1367
  } finally {
1368
+ childStreams.abortAll();
1133
1369
  this.activeResponse = void 0;
1370
+ if (this.childStreams === childStreams) this.childStreams = void 0;
1134
1371
  this.session = client.sessions.attach(session.state.sessionId, {
1135
1372
  streamIndex
1136
1373
  });
@@ -1142,6 +1379,7 @@ var AgentSession = class {
1142
1379
  return rendered.trim();
1143
1380
  }
1144
1381
  cancelActive() {
1382
+ this.childStreams?.abortAll();
1145
1383
  if (this.activeResponse) {
1146
1384
  this.activeResponse.cancel().catch(() => {
1147
1385
  });
@@ -1980,7 +2218,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
1980
2218
  "presentationKinds",
1981
2219
  "ui"
1982
2220
  ]);
1983
- function isRecord3(value) {
2221
+ function isRecord4(value) {
1984
2222
  return value !== null && typeof value === "object" && !Array.isArray(value);
1985
2223
  }
1986
2224
  function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
@@ -2007,7 +2245,7 @@ function decodeEnvelope(value) {
2007
2245
  }
2008
2246
  function parseAgentToolResultEnvelope(value) {
2009
2247
  const decoded = decodeEnvelope(value);
2010
- if (!isRecord3(decoded)) return null;
2248
+ if (!isRecord4(decoded)) return null;
2011
2249
  const keys = Object.keys(decoded);
2012
2250
  if (keys.some((key) => !ENVELOPE_KEYS.has(key)) || decoded.schemaVersion !== "webless.tool-result.v1" || !isJsonValue2(decoded.output) || !Array.isArray(decoded.presentationKinds) || decoded.presentationKinds.length < 1 || decoded.presentationKinds.length > 16) {
2013
2251
  return null;
@@ -3540,7 +3778,14 @@ function BookingCard({
3540
3778
  const [startTime, setStartTime] = (0, import_react7.useState)("");
3541
3779
  const [name, setName] = (0, import_react7.useState)("");
3542
3780
  const [email, setEmail] = (0, import_react7.useState)("");
3781
+ const activeStepRef = (0, import_react7.useRef)(null);
3782
+ const previousStepRef = (0, import_react7.useRef)(step);
3543
3783
  const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
3784
+ (0, import_react7.useEffect)(() => {
3785
+ if (previousStepRef.current === step) return;
3786
+ previousStepRef.current = step;
3787
+ activeStepRef.current?.scrollIntoView({ block: "nearest" });
3788
+ }, [step]);
3544
3789
  const slots = (0, import_react7.useMemo)(
3545
3790
  () => bookingSlotsForEventType(offer.slots, eventTypeUri),
3546
3791
  [eventTypeUri, offer.slots]
@@ -3634,7 +3879,7 @@ function BookingCard({
3634
3879
  },
3635
3880
  item.id
3636
3881
  )) }),
3637
- step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3882
+ step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3638
3883
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
3639
3884
  timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
3640
3885
  "Times in ",
@@ -3724,7 +3969,7 @@ function BookingCard({
3724
3969
  }
3725
3970
  )
3726
3971
  ] }, "date") : null,
3727
- step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3972
+ step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3728
3973
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
3729
3974
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3730
3975
  "button",
@@ -3755,7 +4000,7 @@ function BookingCard({
3755
4000
  slot.startTime
3756
4001
  )) })
3757
4002
  ] }, "time") : null,
3758
- step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
4003
+ step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3759
4004
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
3760
4005
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3761
4006
  "button",
@@ -3991,7 +4236,7 @@ function ConfirmationCard({
3991
4236
  // src/react/components/ToolInputCard/ToolInputCard.tsx
3992
4237
  var import_react9 = require("react");
3993
4238
  var import_jsx_runtime7 = require("react/jsx-runtime");
3994
- function isRecord4(value) {
4239
+ function isRecord5(value) {
3995
4240
  return value !== null && typeof value === "object" && !Array.isArray(value);
3996
4241
  }
3997
4242
  function pathSegments(path) {
@@ -4005,7 +4250,7 @@ function valueAtPath(root, path) {
4005
4250
  current = Number.isInteger(index) ? current[index] : void 0;
4006
4251
  continue;
4007
4252
  }
4008
- current = isRecord4(current) ? current[segment] : void 0;
4253
+ current = isRecord5(current) ? current[segment] : void 0;
4009
4254
  }
4010
4255
  return current;
4011
4256
  }
@@ -4028,7 +4273,7 @@ function initialValues(surface) {
4028
4273
  }
4029
4274
  function cloneJsonValue(value) {
4030
4275
  if (Array.isArray(value)) return value.map(cloneJsonValue);
4031
- if (isRecord4(value)) {
4276
+ if (isRecord5(value)) {
4032
4277
  return Object.fromEntries(
4033
4278
  Object.entries(value).map(([key, item]) => [key, cloneJsonValue(item)])
4034
4279
  );
@@ -4044,7 +4289,7 @@ function assignPath(target, path, value) {
4044
4289
  return;
4045
4290
  }
4046
4291
  const existing = current[segment];
4047
- if (!isRecord4(existing)) current[segment] = {};
4292
+ if (!isRecord5(existing)) current[segment] = {};
4048
4293
  current = current[segment];
4049
4294
  });
4050
4295
  }
@@ -4340,7 +4585,7 @@ function ToolInputCard({
4340
4585
  (field) => validateField(field, values[field.path] ?? "")
4341
4586
  );
4342
4587
  if (nextErrors.some(Boolean)) return;
4343
- const result = isRecord4(surface.values) ? cloneJsonValue(surface.values) : {};
4588
+ const result = isRecord5(surface.values) ? cloneJsonValue(surface.values) : {};
4344
4589
  for (const field of surface.fields) {
4345
4590
  const parsed = parsedFieldValue(field, values[field.path] ?? "");
4346
4591
  if (parsed !== void 0) assignPath(result, field.path, parsed);