@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/react.cjs CHANGED
@@ -383,6 +383,203 @@ function clearPersistedAgentSession(visitorSessionId, options) {
383
383
  sessionStorage.removeItem(runtimeLastMessageKey(visitorSessionId, prefix));
384
384
  }
385
385
 
386
+ // src/runtime/subagent-child-stream.ts
387
+ var INITIAL_RETRY_DELAY_MS = 100;
388
+ var MAX_RETRY_DELAY_MS = 2e3;
389
+ var MAX_CONSECUTIVE_RETRIES = 6;
390
+ function isRecord2(value) {
391
+ return typeof value === "object" && value !== null && !Array.isArray(value);
392
+ }
393
+ function parseError(value) {
394
+ if (!isRecord2(value)) return void 0;
395
+ const { code, message } = value;
396
+ if (typeof code !== "string" || typeof message !== "string") {
397
+ return void 0;
398
+ }
399
+ return { code, message };
400
+ }
401
+ function parseChildStreamEvent(value) {
402
+ if (!isRecord2(value) || typeof value.type !== "string") {
403
+ return { type: "other" };
404
+ }
405
+ if (value.type === "session.waiting" || value.type === "session.completed" || value.type === "session.failed") {
406
+ return { type: "session.boundary" };
407
+ }
408
+ if (value.type === "subagent.event" && isRecord2(value.data) && Object.hasOwn(value.data, "event")) {
409
+ return parseChildStreamEvent(value.data.event);
410
+ }
411
+ if (value.type === "subagent.called" && isRecord2(value.data)) {
412
+ const { childStreamPath } = value.data;
413
+ if (typeof childStreamPath === "string") {
414
+ return { childStreamPath, type: "subagent.called" };
415
+ }
416
+ }
417
+ if (value.type !== "action.result" || !isRecord2(value.data)) {
418
+ return { type: "other" };
419
+ }
420
+ const { data } = value;
421
+ if (data.status !== "completed" && data.status !== "failed" && data.status !== "rejected") {
422
+ return { type: "other" };
423
+ }
424
+ if (!isRecord2(data.result) || data.result.kind !== "tool-result") {
425
+ return { type: "other" };
426
+ }
427
+ const result = data.result;
428
+ if (typeof result.callId !== "string" || typeof result.toolName !== "string") {
429
+ return { type: "other" };
430
+ }
431
+ const error = parseError(data.error);
432
+ return {
433
+ type: "action.result",
434
+ hasOutput: Object.hasOwn(result, "output"),
435
+ result: {
436
+ callId: result.callId,
437
+ toolName: result.toolName,
438
+ status: data.status,
439
+ ...Object.hasOwn(result, "output") ? { output: result.output } : {},
440
+ ...error ? { error } : {}
441
+ }
442
+ };
443
+ }
444
+ async function* readNdjsonStream(body) {
445
+ const reader = body.getReader();
446
+ const decoder = new TextDecoder();
447
+ let buffer = "";
448
+ try {
449
+ while (true) {
450
+ const { done, value } = await reader.read();
451
+ buffer += decoder.decode(value, { stream: !done });
452
+ const lines = buffer.split("\n");
453
+ buffer = lines.pop() ?? "";
454
+ for (const line of lines) {
455
+ const trimmed2 = line.trim();
456
+ if (!trimmed2) continue;
457
+ try {
458
+ const parsed = JSON.parse(trimmed2);
459
+ yield parsed;
460
+ } catch {
461
+ }
462
+ }
463
+ if (done) break;
464
+ }
465
+ const trimmed = buffer.trim();
466
+ if (trimmed) {
467
+ try {
468
+ const parsed = JSON.parse(trimmed);
469
+ yield parsed;
470
+ } catch {
471
+ }
472
+ }
473
+ } finally {
474
+ reader.releaseLock();
475
+ }
476
+ }
477
+ function streamPathAt(path, streamIndex) {
478
+ if (streamIndex === 0) return path;
479
+ return `${path}${path.includes("?") ? "&" : "?"}startIndex=${streamIndex}`;
480
+ }
481
+ function abortableDelay(delayMs, signal) {
482
+ if (signal.aborted) return Promise.resolve();
483
+ return new Promise((resolve) => {
484
+ const finish = () => {
485
+ clearTimeout(timeout);
486
+ signal.removeEventListener("abort", finish);
487
+ resolve();
488
+ };
489
+ const timeout = setTimeout(finish, delayMs);
490
+ signal.addEventListener("abort", finish, { once: true });
491
+ });
492
+ }
493
+ var SubagentChildStreamCoordinator = class {
494
+ constructor(client, handlers, parentSignal) {
495
+ this.client = client;
496
+ this.handlers = handlers;
497
+ this.parentSignal = parentSignal;
498
+ }
499
+ client;
500
+ handlers;
501
+ parentSignal;
502
+ controllers = /* @__PURE__ */ new Map();
503
+ tasks = /* @__PURE__ */ new Map();
504
+ begin(event) {
505
+ this.beginPath(event.data.childStreamPath);
506
+ }
507
+ async waitForAll() {
508
+ let observedTaskCount = -1;
509
+ while (observedTaskCount !== this.tasks.size) {
510
+ observedTaskCount = this.tasks.size;
511
+ await Promise.all(this.tasks.values());
512
+ }
513
+ }
514
+ abortAll() {
515
+ for (const controller of this.controllers.values()) controller.abort();
516
+ this.controllers.clear();
517
+ }
518
+ beginPath(childStreamPath) {
519
+ if (this.tasks.has(childStreamPath)) return;
520
+ const controller = new AbortController();
521
+ const abort = () => controller.abort();
522
+ if (this.parentSignal.aborted) {
523
+ controller.abort();
524
+ } else {
525
+ this.parentSignal.addEventListener("abort", abort, { once: true });
526
+ }
527
+ this.controllers.set(childStreamPath, controller);
528
+ const task = this.consume(childStreamPath, controller.signal).finally(
529
+ () => {
530
+ this.parentSignal.removeEventListener("abort", abort);
531
+ if (this.controllers.get(childStreamPath) === controller) {
532
+ this.controllers.delete(childStreamPath);
533
+ }
534
+ }
535
+ );
536
+ this.tasks.set(childStreamPath, task);
537
+ }
538
+ async consume(path, signal) {
539
+ let streamIndex = 0;
540
+ let consecutiveRetries = 0;
541
+ let retryDelayMs = INITIAL_RETRY_DELAY_MS;
542
+ while (!signal.aborted && consecutiveRetries < MAX_CONSECUTIVE_RETRIES) {
543
+ let receivedEvent = false;
544
+ try {
545
+ const response = await this.client.fetch(
546
+ streamPathAt(path, streamIndex),
547
+ {
548
+ cache: "no-store",
549
+ signal
550
+ }
551
+ );
552
+ if (!response.ok || response.body === null) {
553
+ await response.body?.cancel().catch(() => {
554
+ });
555
+ throw new Error(`Child stream returned ${response.status}.`);
556
+ }
557
+ for await (const rawEvent of readNdjsonStream(response.body)) {
558
+ if (signal.aborted) return;
559
+ receivedEvent = true;
560
+ streamIndex += 1;
561
+ const event = parseChildStreamEvent(rawEvent);
562
+ if (event.type === "session.boundary") return;
563
+ if (event.type === "subagent.called") {
564
+ this.beginPath(event.childStreamPath);
565
+ continue;
566
+ }
567
+ if (event.type !== "action.result") continue;
568
+ this.handlers.onToolResult?.(event.result);
569
+ if (event.hasOutput) {
570
+ this.handlers.onActionResult?.(event.result.output);
571
+ }
572
+ }
573
+ } catch {
574
+ if (signal.aborted) return;
575
+ }
576
+ consecutiveRetries = receivedEvent ? 0 : consecutiveRetries + 1;
577
+ retryDelayMs = receivedEvent ? INITIAL_RETRY_DELAY_MS : Math.min(retryDelayMs * 2, MAX_RETRY_DELAY_MS);
578
+ await abortableDelay(retryDelayMs, signal);
579
+ }
580
+ }
581
+ };
582
+
386
583
  // src/runtime/tool-ui.ts
387
584
  var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
388
585
  var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
@@ -396,7 +593,7 @@ function formatAgentStructuredToolInput(surface, values) {
396
593
  };
397
594
  return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
398
595
  }
399
- function isRecord2(value) {
596
+ function isRecord3(value) {
400
597
  return value !== null && typeof value === "object" && !Array.isArray(value);
401
598
  }
402
599
  function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
@@ -445,7 +642,7 @@ function isFieldKind(value) {
445
642
  ].includes(value);
446
643
  }
447
644
  function parseField(value) {
448
- if (!isRecord2(value)) return null;
645
+ if (!isRecord3(value)) return null;
449
646
  if (!hasOnlyKeys(value, [
450
647
  "description",
451
648
  "kind",
@@ -496,7 +693,7 @@ function parseField(value) {
496
693
  if (!Array.isArray(value.options) || value.options.length > 100)
497
694
  return null;
498
695
  for (const option of value.options) {
499
- if (!isRecord2(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
696
+ if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
500
697
  return null;
501
698
  }
502
699
  }
@@ -519,7 +716,7 @@ function parseField(value) {
519
716
  };
520
717
  }
521
718
  function parseStep(value) {
522
- if (!isRecord2(value)) return null;
719
+ if (!isRecord3(value)) return null;
523
720
  if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
524
721
  return null;
525
722
  }
@@ -539,7 +736,7 @@ function parseStep(value) {
539
736
  };
540
737
  }
541
738
  function parseAction(value) {
542
- if (!isRecord2(value)) return null;
739
+ if (!isRecord3(value)) return null;
543
740
  if (!hasOnlyKeys(value, ["id", "label"])) return null;
544
741
  const label = boundedString(value.label, 80);
545
742
  if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
@@ -551,7 +748,7 @@ function parseAction(value) {
551
748
  };
552
749
  }
553
750
  function parseAgentToolUiSurface(value) {
554
- if (!isRecord2(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
751
+ if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
555
752
  return null;
556
753
  if (!hasOnlyKeys(value, [
557
754
  "actions",
@@ -589,7 +786,7 @@ function parseAgentToolUiSurface(value) {
589
786
  if (value.operationId !== void 0 && !operationId) return null;
590
787
  if (value.requestId !== void 0 && !requestId) return null;
591
788
  if (value.submitLabel !== void 0 && !submitLabel) return null;
592
- const values = value.values !== void 0 && isRecord2(value.values) ? value.values : void 0;
789
+ const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
593
790
  if (value.values !== void 0) {
594
791
  if (!values || !Object.values(values).every((item) => isJsonValue(item)))
595
792
  return null;
@@ -855,11 +1052,14 @@ var AgentSession = class {
855
1052
  clientHost;
856
1053
  session;
857
1054
  activeResponse;
1055
+ childStreams;
858
1056
  capability;
859
1057
  getActiveSessionId() {
860
1058
  return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
861
1059
  }
862
1060
  reset() {
1061
+ this.childStreams?.abortAll();
1062
+ this.childStreams = void 0;
863
1063
  if (this.activeResponse) {
864
1064
  void this.activeResponse.cancel().catch(() => {
865
1065
  });
@@ -955,6 +1155,12 @@ var AgentSession = class {
955
1155
  this.persistSessionCursor(session);
956
1156
  }
957
1157
  this.activeResponse = response;
1158
+ const childStreams = new SubagentChildStreamCoordinator(
1159
+ client,
1160
+ handlers,
1161
+ signal
1162
+ );
1163
+ this.childStreams = childStreams;
958
1164
  let streamIndex = session?.state.streamIndex ?? 0;
959
1165
  let rendered = "";
960
1166
  const workItems = /* @__PURE__ */ new Map();
@@ -962,6 +1168,7 @@ var AgentSession = class {
962
1168
  try {
963
1169
  for await (const event of response) {
964
1170
  if (signal.aborted) break;
1171
+ if (event.type === "subagent.called") childStreams.begin(event);
965
1172
  if (event.type === "input.requested") requestedInput = true;
966
1173
  rendered = applyMessageEvent(event, rendered, handlers, workItems);
967
1174
  streamIndex += 1;
@@ -974,8 +1181,11 @@ var AgentSession = class {
974
1181
  );
975
1182
  }
976
1183
  }
1184
+ await childStreams.waitForAll();
977
1185
  } finally {
1186
+ childStreams.abortAll();
978
1187
  this.activeResponse = void 0;
1188
+ if (this.childStreams === childStreams) this.childStreams = void 0;
979
1189
  if (session) {
980
1190
  this.persistSessionCursor(session);
981
1191
  }
@@ -1011,63 +1221,80 @@ var AgentSession = class {
1011
1221
  }
1012
1222
  let rendered = renderTurn(turnEvents);
1013
1223
  const workItems = /* @__PURE__ */ new Map();
1014
- for (const event of turnEvents) {
1015
- applyWorkEvent(event, handlers, workItems);
1016
- emitVisitorInteractionEvent(event, handlers);
1017
- }
1018
- if (rendered.startsWith(initialText)) {
1019
- const missedText = rendered.slice(initialText.length);
1020
- if (missedText) handlers.onDelta(missedText);
1021
- } else if (initialText.startsWith(rendered)) {
1022
- rendered = initialText;
1023
- } else if (!initialText.startsWith(rendered)) {
1024
- rendered = initialText + rendered;
1025
- }
1026
- let session = client.sessions.attach(snapshot.session.sessionId, {
1027
- streamIndex: snapshot.session.streamIndex
1028
- });
1029
- this.session = session;
1030
- this.persistSessionCursor(session);
1031
- let snapshotBoundary;
1032
- for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
1033
- const event = turnEvents[index];
1034
- if (event && isTurnBoundary(event)) {
1035
- snapshotBoundary = event;
1036
- break;
1224
+ const childStreams = new SubagentChildStreamCoordinator(
1225
+ client,
1226
+ handlers,
1227
+ signal
1228
+ );
1229
+ this.childStreams = childStreams;
1230
+ try {
1231
+ for (const event of turnEvents) {
1232
+ if (event.type === "subagent.called") childStreams.begin(event);
1233
+ applyWorkEvent(event, handlers, workItems);
1234
+ emitVisitorInteractionEvent(event, handlers);
1037
1235
  }
1038
- }
1039
- if (snapshotBoundary) {
1040
- if (snapshotBoundary.type === "session.failed") {
1041
- throw new Error(
1042
- snapshotBoundary.data.message || snapshotBoundary.data.code
1236
+ if (rendered.startsWith(initialText)) {
1237
+ const missedText = rendered.slice(initialText.length);
1238
+ if (missedText) handlers.onDelta(missedText);
1239
+ } else if (initialText.startsWith(rendered)) {
1240
+ rendered = initialText;
1241
+ } else if (!initialText.startsWith(rendered)) {
1242
+ rendered = initialText + rendered;
1243
+ }
1244
+ let session = client.sessions.attach(snapshot.session.sessionId, {
1245
+ streamIndex: snapshot.session.streamIndex
1246
+ });
1247
+ this.session = session;
1248
+ this.persistSessionCursor(session);
1249
+ let snapshotBoundary;
1250
+ for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
1251
+ const event = turnEvents[index];
1252
+ if (event && isTurnBoundary(event)) {
1253
+ snapshotBoundary = event;
1254
+ break;
1255
+ }
1256
+ }
1257
+ if (snapshotBoundary) {
1258
+ if (snapshotBoundary.type === "session.failed") {
1259
+ throw new Error(
1260
+ snapshotBoundary.data.message || snapshotBoundary.data.code
1261
+ );
1262
+ }
1263
+ handlers.onComplete?.();
1264
+ await childStreams.waitForAll();
1265
+ if (!rendered.trim() && !hasInputRequest) {
1266
+ throw new Error("Empty response from runtime");
1267
+ }
1268
+ return rendered.trim();
1269
+ }
1270
+ let streamIndex = snapshot.session.streamIndex;
1271
+ for await (const event of session.stream({ signal })) {
1272
+ if (signal.aborted) break;
1273
+ if (event.type === "subagent.called") childStreams.begin(event);
1274
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
1275
+ streamIndex += 1;
1276
+ savePersistedAgentSession(
1277
+ this.visitorSessionId,
1278
+ session.state.sessionId,
1279
+ streamIndex,
1280
+ this.storeOptions
1043
1281
  );
1282
+ if (isTurnBoundary(event)) break;
1044
1283
  }
1045
- handlers.onComplete?.();
1046
- if (!rendered.trim() && !hasInputRequest) {
1284
+ await childStreams.waitForAll();
1285
+ session = client.sessions.attach(session.state.sessionId, {
1286
+ streamIndex
1287
+ });
1288
+ this.session = session;
1289
+ this.persistSessionCursor(session);
1290
+ if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
1047
1291
  throw new Error("Empty response from runtime");
1048
1292
  }
1049
1293
  return rendered.trim();
1294
+ } finally {
1295
+ childStreams.abortAll();
1296
+ if (this.childStreams === childStreams) this.childStreams = void 0;
1050
1297
  }
1051
- let streamIndex = snapshot.session.streamIndex;
1052
- for await (const event of session.stream({ signal })) {
1053
- if (signal.aborted) break;
1054
- rendered = applyMessageEvent(event, rendered, handlers, workItems);
1055
- streamIndex += 1;
1056
- savePersistedAgentSession(
1057
- this.visitorSessionId,
1058
- session.state.sessionId,
1059
- streamIndex,
1060
- this.storeOptions
1061
- );
1062
- if (isTurnBoundary(event)) break;
1063
- }
1064
- session = client.sessions.attach(session.state.sessionId, { streamIndex });
1065
- this.session = session;
1066
- this.persistSessionCursor(session);
1067
- if (!rendered.trim() && !signal.aborted && !hasInputRequest) {
1068
- throw new Error("Empty response from runtime");
1069
- }
1070
- return rendered.trim();
1071
1298
  }
1072
1299
  async respondTurn(responses, signal, handlers) {
1073
1300
  const client = this.ensureClient();
@@ -1088,6 +1315,12 @@ var AgentSession = class {
1088
1315
  () => session.respond(inputResponses, { signal })
1089
1316
  );
1090
1317
  this.activeResponse = response;
1318
+ const childStreams = new SubagentChildStreamCoordinator(
1319
+ client,
1320
+ handlers,
1321
+ signal
1322
+ );
1323
+ this.childStreams = childStreams;
1091
1324
  let streamIndex = session.state.streamIndex;
1092
1325
  let rendered = "";
1093
1326
  let requestedInput = false;
@@ -1095,6 +1328,7 @@ var AgentSession = class {
1095
1328
  try {
1096
1329
  for await (const event of response) {
1097
1330
  if (signal.aborted) break;
1331
+ if (event.type === "subagent.called") childStreams.begin(event);
1098
1332
  if (event.type === "input.requested") requestedInput = true;
1099
1333
  rendered = applyMessageEvent(event, rendered, handlers, workItems);
1100
1334
  streamIndex += 1;
@@ -1105,8 +1339,11 @@ var AgentSession = class {
1105
1339
  this.storeOptions
1106
1340
  );
1107
1341
  }
1342
+ await childStreams.waitForAll();
1108
1343
  } finally {
1344
+ childStreams.abortAll();
1109
1345
  this.activeResponse = void 0;
1346
+ if (this.childStreams === childStreams) this.childStreams = void 0;
1110
1347
  this.session = client.sessions.attach(session.state.sessionId, {
1111
1348
  streamIndex
1112
1349
  });
@@ -1118,6 +1355,7 @@ var AgentSession = class {
1118
1355
  return rendered.trim();
1119
1356
  }
1120
1357
  cancelActive() {
1358
+ this.childStreams?.abortAll();
1121
1359
  if (this.activeResponse) {
1122
1360
  this.activeResponse.cancel().catch(() => {
1123
1361
  });
@@ -1956,7 +2194,7 @@ var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
1956
2194
  "presentationKinds",
1957
2195
  "ui"
1958
2196
  ]);
1959
- function isRecord3(value) {
2197
+ function isRecord4(value) {
1960
2198
  return value !== null && typeof value === "object" && !Array.isArray(value);
1961
2199
  }
1962
2200
  function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
@@ -1983,7 +2221,7 @@ function decodeEnvelope(value) {
1983
2221
  }
1984
2222
  function parseAgentToolResultEnvelope(value) {
1985
2223
  const decoded = decodeEnvelope(value);
1986
- if (!isRecord3(decoded)) return null;
2224
+ if (!isRecord4(decoded)) return null;
1987
2225
  const keys = Object.keys(decoded);
1988
2226
  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) {
1989
2227
  return null;
@@ -3532,7 +3770,14 @@ function BookingCard({
3532
3770
  const [startTime, setStartTime] = (0, import_react7.useState)("");
3533
3771
  const [name, setName] = (0, import_react7.useState)("");
3534
3772
  const [email, setEmail] = (0, import_react7.useState)("");
3773
+ const activeStepRef = (0, import_react7.useRef)(null);
3774
+ const previousStepRef = (0, import_react7.useRef)(step);
3535
3775
  const stepIndex = BOOKING_STEPS.findIndex((item) => item.id === step);
3776
+ (0, import_react7.useEffect)(() => {
3777
+ if (previousStepRef.current === step) return;
3778
+ previousStepRef.current = step;
3779
+ activeStepRef.current?.scrollIntoView({ block: "nearest" });
3780
+ }, [step]);
3536
3781
  const slots = (0, import_react7.useMemo)(
3537
3782
  () => bookingSlotsForEventType(offer.slots, eventTypeUri),
3538
3783
  [eventTypeUri, offer.slots]
@@ -3626,7 +3871,7 @@ function BookingCard({
3626
3871
  },
3627
3872
  item.id
3628
3873
  )) }),
3629
- step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3874
+ step === "date" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3630
3875
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "booking-card__title", children: selectedType?.name || "Pick a date" }),
3631
3876
  timeZone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "booking-card__tz", children: [
3632
3877
  "Times in ",
@@ -3716,7 +3961,7 @@ function BookingCard({
3716
3961
  }
3717
3962
  )
3718
3963
  ] }, "date") : null,
3719
- step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3964
+ step === "time" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3720
3965
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
3721
3966
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3722
3967
  "button",
@@ -3747,7 +3992,7 @@ function BookingCard({
3747
3992
  slot.startTime
3748
3993
  )) })
3749
3994
  ] }, "time") : null,
3750
- step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", children: [
3995
+ step === "details" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step", ref: activeStepRef, children: [
3751
3996
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "booking-card__step-bar", children: [
3752
3997
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3753
3998
  "button",
@@ -3983,7 +4228,7 @@ function ConfirmationCard({
3983
4228
  // src/react/components/ToolInputCard/ToolInputCard.tsx
3984
4229
  var import_react9 = require("react");
3985
4230
  var import_jsx_runtime7 = require("react/jsx-runtime");
3986
- function isRecord4(value) {
4231
+ function isRecord5(value) {
3987
4232
  return value !== null && typeof value === "object" && !Array.isArray(value);
3988
4233
  }
3989
4234
  function pathSegments(path) {
@@ -3997,7 +4242,7 @@ function valueAtPath(root, path) {
3997
4242
  current = Number.isInteger(index) ? current[index] : void 0;
3998
4243
  continue;
3999
4244
  }
4000
- current = isRecord4(current) ? current[segment] : void 0;
4245
+ current = isRecord5(current) ? current[segment] : void 0;
4001
4246
  }
4002
4247
  return current;
4003
4248
  }
@@ -4020,7 +4265,7 @@ function initialValues(surface) {
4020
4265
  }
4021
4266
  function cloneJsonValue(value) {
4022
4267
  if (Array.isArray(value)) return value.map(cloneJsonValue);
4023
- if (isRecord4(value)) {
4268
+ if (isRecord5(value)) {
4024
4269
  return Object.fromEntries(
4025
4270
  Object.entries(value).map(([key, item]) => [key, cloneJsonValue(item)])
4026
4271
  );
@@ -4036,7 +4281,7 @@ function assignPath(target, path, value) {
4036
4281
  return;
4037
4282
  }
4038
4283
  const existing = current[segment];
4039
- if (!isRecord4(existing)) current[segment] = {};
4284
+ if (!isRecord5(existing)) current[segment] = {};
4040
4285
  current = current[segment];
4041
4286
  });
4042
4287
  }
@@ -4332,7 +4577,7 @@ function ToolInputCard({
4332
4577
  (field) => validateField(field, values[field.path] ?? "")
4333
4578
  );
4334
4579
  if (nextErrors.some(Boolean)) return;
4335
- const result = isRecord4(surface.values) ? cloneJsonValue(surface.values) : {};
4580
+ const result = isRecord5(surface.values) ? cloneJsonValue(surface.values) : {};
4336
4581
  for (const field of surface.fields) {
4337
4582
  const parsed = parsedFieldValue(field, values[field.path] ?? "");
4338
4583
  if (parsed !== void 0) assignPath(result, field.path, parsed);