@webless/agent 0.8.0 → 0.9.1

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/index.js CHANGED
@@ -1,3 +1,14 @@
1
+ import {
2
+ AGENT_STRUCTURED_TOOL_INPUT_HEADER,
3
+ AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION,
4
+ AGENT_TOOL_UI_SCHEMA_VERSION,
5
+ completeConnectedToolWork,
6
+ connectedToolWork,
7
+ formatAgentStructuredToolInput,
8
+ parseAgentToolResultEnvelope,
9
+ parseAgentToolUiSurface
10
+ } from "./chunk-TCO62TRN.js";
11
+
1
12
  // src/runtime/client.ts
2
13
  import {
3
14
  Client,
@@ -299,6 +310,18 @@ function parseChildStreamEvent(value) {
299
310
  return { childStreamPath, type: "subagent.called" };
300
311
  }
301
312
  }
313
+ if (value.type === "actions.requested" && isRecord2(value.data) && Array.isArray(value.data.actions)) {
314
+ const items = value.data.actions.flatMap((action) => {
315
+ if (!isRecord2(action) || action.kind !== "tool-call" || typeof action.callId !== "string" || typeof action.toolName !== "string" || !isRecord2(action.input)) return [];
316
+ const item = connectedToolWork({
317
+ callId: action.callId,
318
+ toolName: action.toolName,
319
+ input: action.input
320
+ });
321
+ return item ? [item] : [];
322
+ });
323
+ return { type: "actions.requested", items };
324
+ }
302
325
  if (value.type !== "action.result" || !isRecord2(value.data)) {
303
326
  return { type: "other" };
304
327
  }
@@ -320,7 +343,7 @@ function parseChildStreamEvent(value) {
320
343
  result: {
321
344
  callId: result.callId,
322
345
  toolName: result.toolName,
323
- status: data.status,
346
+ status: result.isError === true ? "failed" : data.status,
324
347
  ...Object.hasOwn(result, "output") ? { output: result.output } : {},
325
348
  ...error ? { error } : {}
326
349
  }
@@ -421,6 +444,7 @@ var SubagentChildStreamCoordinator = class {
421
444
  this.tasks.set(childStreamPath, task);
422
445
  }
423
446
  async consume(path, signal) {
447
+ const workItems = /* @__PURE__ */ new Map();
424
448
  let streamIndex = 0;
425
449
  let consecutiveRetries = 0;
426
450
  let retryDelayMs = INITIAL_RETRY_DELAY_MS;
@@ -449,7 +473,18 @@ var SubagentChildStreamCoordinator = class {
449
473
  this.beginPath(event.childStreamPath);
450
474
  continue;
451
475
  }
476
+ if (event.type === "actions.requested") {
477
+ for (const item2 of event.items) {
478
+ workItems.set(item2.id, item2);
479
+ this.handlers.onWork?.(item2);
480
+ }
481
+ continue;
482
+ }
452
483
  if (event.type !== "action.result") continue;
484
+ const item = workItems.get(event.result.callId);
485
+ if (item) {
486
+ this.handlers.onWork?.(completeConnectedToolWork(item, event.result));
487
+ }
453
488
  this.handlers.onToolResult?.(event.result);
454
489
  if (event.hasOutput) {
455
490
  this.handlers.onActionResult?.(event.result.output);
@@ -465,237 +500,6 @@ var SubagentChildStreamCoordinator = class {
465
500
  }
466
501
  };
467
502
 
468
- // src/runtime/tool-ui.ts
469
- var AGENT_TOOL_UI_SCHEMA_VERSION = "webless.tool-ui.v1";
470
- var AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION = "webless.structured-tool-input.v1";
471
- var AGENT_STRUCTURED_TOOL_INPUT_HEADER = "Webless-Structured-Tool-Input-JSON:";
472
- function formatAgentStructuredToolInput(surface, values) {
473
- const payload = {
474
- schemaVersion: AGENT_STRUCTURED_TOOL_INPUT_SCHEMA_VERSION,
475
- toolSlug: surface.toolSlug,
476
- ...surface.operationId ? { operationId: surface.operationId } : {},
477
- values
478
- };
479
- return `${AGENT_STRUCTURED_TOOL_INPUT_HEADER} ${JSON.stringify(payload)}`;
480
- }
481
- function isRecord3(value) {
482
- return value !== null && typeof value === "object" && !Array.isArray(value);
483
- }
484
- function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
485
- if (value === null || typeof value === "string" || typeof value === "boolean") {
486
- return true;
487
- }
488
- if (typeof value === "number") return Number.isFinite(value);
489
- if (typeof value !== "object") return false;
490
- if (seen.has(value)) return false;
491
- seen.add(value);
492
- const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, seen)) : Object.entries(value).every(
493
- ([key, item]) => typeof key === "string" && isJsonValue(item, seen)
494
- );
495
- seen.delete(value);
496
- return valid;
497
- }
498
- function boundedString(value, max) {
499
- if (typeof value !== "string" || value.trim().length === 0 || value.length > max) {
500
- return void 0;
501
- }
502
- return value.trim();
503
- }
504
- function numberValue(value) {
505
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
506
- }
507
- function integerValue(value) {
508
- return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 8e3 ? value : void 0;
509
- }
510
- function isFieldKind(value) {
511
- return typeof value === "string" && [
512
- "text",
513
- "textarea",
514
- "email",
515
- "number",
516
- "select",
517
- "multi-select",
518
- "checkbox",
519
- "confirmation",
520
- "radio",
521
- "date",
522
- "time",
523
- "date-time",
524
- "calendar",
525
- "range",
526
- "json"
527
- ].includes(value);
528
- }
529
- function parseField(value) {
530
- if (!isRecord3(value)) return null;
531
- if (!hasOnlyKeys(value, [
532
- "description",
533
- "kind",
534
- "label",
535
- "max",
536
- "maxItems",
537
- "maxLength",
538
- "min",
539
- "minLength",
540
- "options",
541
- "path",
542
- "placeholder",
543
- "required",
544
- "step",
545
- "defaultValue"
546
- ])) {
547
- return null;
548
- }
549
- if (!isFieldKind(value.kind)) return null;
550
- const path = boundedString(value.path, 160);
551
- const label = boundedString(value.label, 160);
552
- const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
553
- const placeholder = value.placeholder === void 0 || typeof value.placeholder !== "string" ? void 0 : value.placeholder;
554
- const required = value.required === void 0 || typeof value.required !== "boolean" ? void 0 : value.required;
555
- const min = value.min === void 0 ? void 0 : numberValue(value.min);
556
- const max = value.max === void 0 ? void 0 : numberValue(value.max);
557
- const maxItems = value.maxItems === void 0 ? void 0 : integerValue(value.maxItems);
558
- const step = value.step === void 0 ? void 0 : numberValue(value.step);
559
- const minLength = value.minLength === void 0 ? void 0 : integerValue(value.minLength);
560
- const maxLength = value.maxLength === void 0 ? void 0 : integerValue(value.maxLength);
561
- const defaultValue = value.defaultValue === void 0 || !isJsonValue(value.defaultValue) ? void 0 : value.defaultValue;
562
- if (!path || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || !label) {
563
- return null;
564
- }
565
- if (value.description !== void 0 && !description) return null;
566
- if (value.placeholder !== void 0 && placeholder === void 0) return null;
567
- if (value.required !== void 0 && required === void 0) return null;
568
- if (value.min !== void 0 && min === void 0) return null;
569
- if (value.max !== void 0 && max === void 0) return null;
570
- if (value.maxItems !== void 0 && (maxItems === void 0 || maxItems < 1 || maxItems > 100))
571
- return null;
572
- if (value.step !== void 0 && step === void 0) return null;
573
- if (value.minLength !== void 0 && minLength === void 0) return null;
574
- if (value.maxLength !== void 0 && maxLength === void 0) return null;
575
- if (value.defaultValue !== void 0 && defaultValue === void 0)
576
- return null;
577
- if (value.options !== void 0) {
578
- if (!Array.isArray(value.options) || value.options.length > 100)
579
- return null;
580
- for (const option of value.options) {
581
- if (!isRecord3(option) || !boundedString(option.label, 160) || !isJsonValue(option.value)) {
582
- return null;
583
- }
584
- }
585
- }
586
- return {
587
- kind: value.kind,
588
- path,
589
- label,
590
- ...description ? { description } : {},
591
- ...placeholder !== void 0 ? { placeholder } : {},
592
- ...required !== void 0 ? { required } : {},
593
- ...defaultValue !== void 0 ? { defaultValue } : {},
594
- ...value.options !== void 0 ? { options: value.options } : {},
595
- ...min !== void 0 ? { min } : {},
596
- ...max !== void 0 ? { max } : {},
597
- ...maxItems !== void 0 ? { maxItems } : {},
598
- ...step !== void 0 ? { step } : {},
599
- ...minLength !== void 0 ? { minLength } : {},
600
- ...maxLength !== void 0 ? { maxLength } : {}
601
- };
602
- }
603
- function parseStep(value) {
604
- if (!isRecord3(value)) return null;
605
- if (!hasOnlyKeys(value, ["description", "fieldPaths", "id", "label"])) {
606
- return null;
607
- }
608
- const id = boundedString(value.id, 80);
609
- const label = boundedString(value.label, 160);
610
- const description = value.description === void 0 ? void 0 : boundedString(value.description, 500);
611
- if (!id || !/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(id) || !label || value.description !== void 0 && !description || !Array.isArray(value.fieldPaths) || value.fieldPaths.length < 1 || value.fieldPaths.length > 32 || value.fieldPaths.some(
612
- (path) => typeof path !== "string" || !/^[A-Za-z0-9_.[\]-]+$/u.test(path) || path.length > 160
613
- )) {
614
- return null;
615
- }
616
- return {
617
- id,
618
- label,
619
- fieldPaths: value.fieldPaths,
620
- ...description ? { description } : {}
621
- };
622
- }
623
- function parseAction(value) {
624
- if (!isRecord3(value)) return null;
625
- if (!hasOnlyKeys(value, ["id", "label"])) return null;
626
- const label = boundedString(value.label, 80);
627
- if (value.id !== "submit" && value.id !== "back" && value.id !== "next" && value.id !== "reset" || !label) {
628
- return null;
629
- }
630
- return {
631
- id: value.id,
632
- label
633
- };
634
- }
635
- function parseAgentToolUiSurface(value) {
636
- if (!isRecord3(value) || value.schemaVersion !== AGENT_TOOL_UI_SCHEMA_VERSION)
637
- return null;
638
- if (!hasOnlyKeys(value, [
639
- "actions",
640
- "description",
641
- "fields",
642
- "id",
643
- "operationId",
644
- "requestId",
645
- "schemaVersion",
646
- "steps",
647
- "submitLabel",
648
- "title",
649
- "toolSlug",
650
- "values"
651
- ])) {
652
- return null;
653
- }
654
- const id = boundedString(value.id, 200);
655
- const title = boundedString(value.title, 200);
656
- const toolSlug = boundedString(value.toolSlug, 200);
657
- const description = value.description === void 0 ? void 0 : boundedString(value.description, 800);
658
- const operationId = value.operationId === void 0 ? void 0 : boundedString(value.operationId, 200);
659
- const requestId = value.requestId === void 0 ? void 0 : boundedString(value.requestId, 200);
660
- const submitLabel = value.submitLabel === void 0 ? void 0 : boundedString(value.submitLabel, 80);
661
- if (!id || !title || !toolSlug || !Array.isArray(value.fields) || value.fields.length < 1 || value.fields.length > 32) {
662
- return null;
663
- }
664
- const fields = value.fields.map(parseField);
665
- if (fields.some((field) => field === null)) return null;
666
- const steps = value.steps === void 0 ? void 0 : Array.isArray(value.steps) && value.steps.length <= 8 ? value.steps.map(parseStep) : null;
667
- if (steps?.some((step) => step === null)) return null;
668
- const actions = value.actions === void 0 ? void 0 : Array.isArray(value.actions) && value.actions.length <= 8 ? value.actions.map(parseAction) : null;
669
- if (actions?.some((action) => action === null)) return null;
670
- if (value.description !== void 0 && !description) return null;
671
- if (value.operationId !== void 0 && !operationId) return null;
672
- if (value.requestId !== void 0 && !requestId) return null;
673
- if (value.submitLabel !== void 0 && !submitLabel) return null;
674
- const values = value.values !== void 0 && isRecord3(value.values) ? value.values : void 0;
675
- if (value.values !== void 0) {
676
- if (!values || !Object.values(values).every((item) => isJsonValue(item)))
677
- return null;
678
- }
679
- return {
680
- schemaVersion: AGENT_TOOL_UI_SCHEMA_VERSION,
681
- id,
682
- title,
683
- toolSlug,
684
- fields,
685
- ...actions ? { actions } : {},
686
- ...description ? { description } : {},
687
- ...operationId ? { operationId } : {},
688
- ...requestId ? { requestId } : {},
689
- ...submitLabel ? { submitLabel } : {},
690
- ...steps ? { steps } : {},
691
- ...values ? { values } : {}
692
- };
693
- }
694
- function hasOnlyKeys(value, allowed) {
695
- const allowedKeys = new Set(allowed);
696
- return Object.keys(value).every((key) => allowedKeys.has(key));
697
- }
698
-
699
503
  // src/runtime/client.ts
700
504
  function isTurnBoundary(event) {
701
505
  return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
@@ -728,7 +532,7 @@ function emitActionResult(event, handlers) {
728
532
  handlers.onToolResult?.({
729
533
  callId: result.callId,
730
534
  toolName: result.toolName,
731
- status: event.data.status,
535
+ status: result.isError ? "failed" : event.data.status,
732
536
  output: result.output,
733
537
  ...event.data.error ? { error: event.data.error } : {}
734
538
  });
@@ -854,9 +658,13 @@ function requestedWorkItem(action) {
854
658
  state: "active"
855
659
  };
856
660
  }
857
- return null;
661
+ return action.kind === "tool-call" ? connectedToolWork(action) : null;
858
662
  }
859
663
  function applyWorkEvent(event, handlers, workItems) {
664
+ if (event.type === "subagent.event") {
665
+ applyWorkEvent(event.data.event, handlers, workItems);
666
+ return;
667
+ }
860
668
  if (event.type === "step.started" && workItems.size === 0) {
861
669
  emitWorkItem(
862
670
  {
@@ -915,6 +723,15 @@ function applyWorkEvent(event, handlers, workItems) {
915
723
  const { result, status } = event.data;
916
724
  const current = workItems.get(result.callId);
917
725
  if (!current) return;
726
+ if (current.kind === "tool" && result.kind === "tool-result") {
727
+ emitWorkItem(completeConnectedToolWork(current, {
728
+ callId: result.callId,
729
+ toolName: result.toolName,
730
+ status: result.isError ? "failed" : status,
731
+ output: result.output
732
+ }), handlers, workItems);
733
+ return;
734
+ }
918
735
  const failed = status !== "completed" || result.isError === true;
919
736
  emitWorkItem(
920
737
  {
@@ -1402,63 +1219,6 @@ function formatAgentError(error) {
1402
1219
  return TRANSIENT_AGENT_ERROR_MESSAGE;
1403
1220
  }
1404
1221
 
1405
- // src/runtime/tool-result-envelope.ts
1406
- var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
1407
- "schemaVersion",
1408
- "output",
1409
- "presentationKinds",
1410
- "ui"
1411
- ]);
1412
- function isRecord4(value) {
1413
- return value !== null && typeof value === "object" && !Array.isArray(value);
1414
- }
1415
- function isJsonValue2(value, seen = /* @__PURE__ */ new Set()) {
1416
- if (value === null || typeof value === "string" || typeof value === "boolean") {
1417
- return true;
1418
- }
1419
- if (typeof value === "number") return Number.isFinite(value);
1420
- if (typeof value !== "object") return false;
1421
- if (seen.has(value)) return false;
1422
- seen.add(value);
1423
- const valid = Array.isArray(value) ? value.every((item) => isJsonValue2(item, seen)) : Object.entries(value).every(
1424
- ([key, item]) => typeof key === "string" && isJsonValue2(item, seen)
1425
- );
1426
- seen.delete(value);
1427
- return valid;
1428
- }
1429
- function decodeEnvelope(value) {
1430
- if (typeof value !== "string") return value;
1431
- try {
1432
- return JSON.parse(value);
1433
- } catch {
1434
- return null;
1435
- }
1436
- }
1437
- function parseAgentToolResultEnvelope(value) {
1438
- const decoded = decodeEnvelope(value);
1439
- if (!isRecord4(decoded)) return null;
1440
- const keys = Object.keys(decoded);
1441
- 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) {
1442
- return null;
1443
- }
1444
- const presentationKinds = decoded.presentationKinds.flatMap((kind) => {
1445
- if (typeof kind !== "string") return [];
1446
- const normalized = kind.trim();
1447
- return normalized && normalized.length <= 128 ? [normalized] : [];
1448
- });
1449
- if (presentationKinds.length !== decoded.presentationKinds.length) {
1450
- return null;
1451
- }
1452
- const ui = decoded.ui === void 0 ? void 0 : parseAgentToolUiSurface(decoded.ui);
1453
- if (decoded.ui !== void 0 && !ui) return null;
1454
- return {
1455
- schemaVersion: "webless.tool-result.v1",
1456
- output: decoded.output,
1457
- presentationKinds,
1458
- ...ui ? { ui } : {}
1459
- };
1460
- }
1461
-
1462
1222
  // src/runtime/health.ts
1463
1223
  async function pingAgentHealth(runtimeOrigin, fetchImpl = fetch) {
1464
1224
  const healthUrl = agentHealthUrl(runtimeOrigin);