@tangle-network/agent-runtime 0.16.0 → 0.17.0

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
@@ -252,7 +252,9 @@ function mapCommonBackendEvent(event, context) {
252
252
  const type = String(record.type ?? "");
253
253
  const data = record.data && typeof record.data === "object" ? record.data : record;
254
254
  if (type === "message.part.updated" || type === "text_delta" || type === "delta") {
255
- const text = stringValue(data.text) ?? stringValue(data.delta) ?? stringValue(record.text);
255
+ const part = data.part;
256
+ const partText = part !== void 0 && typeof part === "object" && (part.type === "text" || part.type === void 0) ? stringValue(part.text) : void 0;
257
+ const text = stringValue(data.text) ?? stringValue(data.delta) ?? stringValue(record.text) ?? partText;
256
258
  return text ? {
257
259
  type: "text_delta",
258
260
  task: context.task,
@@ -418,107 +420,6 @@ function stringValue(value) {
418
420
  return typeof value === "string" && value.length > 0 ? value : void 0;
419
421
  }
420
422
 
421
- // src/chat-turn.ts
422
- import { mergeAgentProfiles } from "@tangle-network/sandbox";
423
- var RUNTIME_PATH = "/runtime/agents/run/stream";
424
- async function* runChatTurn(options) {
425
- const turnProfile = options.overlay ? composeTurnProfile(options.profile, options.overlay) : options.profile;
426
- const url = `${options.sandbox.runtimeUrl}${RUNTIME_PATH}`;
427
- const backendType = turnProfile.metadata?.backend?.type ?? "claude-code";
428
- const body = JSON.stringify({
429
- backend: {
430
- type: backendType,
431
- profile: turnProfile,
432
- ...options.modelOverride ? { model: { default: options.modelOverride } } : {}
433
- },
434
- messages: [...options.priorMessages, { role: "user", content: options.message }]
435
- });
436
- const headers = {
437
- "Content-Type": "application/json",
438
- Accept: "text/event-stream"
439
- };
440
- if (options.sandbox.authHeader) {
441
- headers[options.sandbox.authHeader.name] = options.sandbox.authHeader.value;
442
- }
443
- const fetchImpl = options.fetch ?? fetch;
444
- const response = await fetchImpl(url, {
445
- method: "POST",
446
- headers,
447
- body,
448
- signal: options.signal
449
- });
450
- if (!response.ok || !response.body) {
451
- const text = response.body ? await response.text() : "";
452
- throw new ChatTurnError(
453
- `runChatTurn: sandbox returned ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,
454
- response.status
455
- );
456
- }
457
- yield* parseSseStream(response.body);
458
- }
459
- function composeTurnProfile(base, overlay) {
460
- const partial = {};
461
- if (overlay.promptOverlay) partial.prompt = overlay.promptOverlay;
462
- if (overlay.resourcesOverlay) partial.resources = overlay.resourcesOverlay;
463
- if (overlay.subagentsOverlay) partial.subagents = overlay.subagentsOverlay;
464
- if (overlay.metadata) partial.metadata = overlay.metadata;
465
- return mergeAgentProfiles(base, partial) ?? base;
466
- }
467
- async function* parseSseStream(stream) {
468
- const decoder = new TextDecoder();
469
- const reader = stream.getReader();
470
- let buffer = "";
471
- try {
472
- while (true) {
473
- const { value, done } = await reader.read();
474
- if (done) break;
475
- buffer += decoder.decode(value, { stream: true });
476
- let idx = buffer.indexOf("\n");
477
- while (idx >= 0) {
478
- const line = buffer.slice(0, idx).replace(/\r$/, "").trim();
479
- buffer = buffer.slice(idx + 1);
480
- idx = buffer.indexOf("\n");
481
- if (!line) continue;
482
- const payload = line.startsWith("data:") ? line.slice(5).trim() : line;
483
- if (payload === "[DONE]" || payload === "") continue;
484
- try {
485
- const parsed = JSON.parse(payload);
486
- yield parsed;
487
- } catch {
488
- }
489
- }
490
- }
491
- } finally {
492
- reader.releaseLock();
493
- }
494
- }
495
- var ChatTurnError = class extends Error {
496
- constructor(message, status) {
497
- super(message);
498
- this.status = status;
499
- this.name = "ChatTurnError";
500
- }
501
- status;
502
- };
503
- function sandboxAsChatTurnTarget(instance, opts) {
504
- const base = instance.url ?? instance.connection?.runtimeUrl ?? "";
505
- if (!base) {
506
- throw new ChatTurnError(
507
- `sandboxAsChatTurnTarget: SandboxInstance has neither .url nor .connection.runtimeUrl set`
508
- );
509
- }
510
- return {
511
- id: instance.id,
512
- runtimeUrl: base.replace(/\/+$/, ""),
513
- authHeader: opts?.authHeader
514
- };
515
- }
516
-
517
- // src/durable/execution-handle.ts
518
- function deriveExecutionId(input) {
519
- return `${input.projectId}:${input.sessionId}:${input.turnIndex}`;
520
- }
521
-
522
423
  // src/durable/chat-engine.ts
523
424
  var encoder = new TextEncoder();
524
425
  function encodeLine(event) {
@@ -606,75 +507,9 @@ function handleChatTurn(input) {
606
507
  return { body, contentType: "application/x-ndjson" };
607
508
  }
608
509
 
609
- // src/intent-router.ts
610
- var DEFAULT_PATTERN_WEIGHT = 1.5;
611
- var DEFAULT_MIN_SCORE = 1;
612
- function isMatcher(value) {
613
- if (!value || typeof value !== "object") return false;
614
- const v = value;
615
- return Array.isArray(v.keywords) || Array.isArray(v.patterns) || typeof v.minScore === "number";
616
- }
617
- function readMatcher(subagent) {
618
- const m = subagent.metadata;
619
- if (!m) return null;
620
- const raw = m.matchers ?? m.matcher ?? null;
621
- if (!raw) return null;
622
- if (Array.isArray(raw)) {
623
- const merged = { keywords: [], patterns: [], minScore: DEFAULT_MIN_SCORE };
624
- for (const entry of raw) {
625
- if (!isMatcher(entry)) continue;
626
- merged.keywords = [...merged.keywords ?? [], ...entry.keywords ?? []];
627
- merged.patterns = [...merged.patterns ?? [], ...entry.patterns ?? []];
628
- if (entry.minScore !== void 0) merged.minScore = entry.minScore;
629
- }
630
- return merged;
631
- }
632
- if (isMatcher(raw)) return raw;
633
- return null;
634
- }
635
- function classifyIntent(profile, message, opts = {}) {
636
- const lower = message.toLowerCase();
637
- const subagents = profile.subagents ?? {};
638
- const skip = new Set(opts.skip ?? []);
639
- const defaultMinScore = opts.defaultMinScore ?? DEFAULT_MIN_SCORE;
640
- const scores = {};
641
- const evaluated = {};
642
- let bestId = null;
643
- let bestScore = -Infinity;
644
- let bestSubagent = null;
645
- for (const [id, subagent] of Object.entries(subagents)) {
646
- if (skip.has(id)) continue;
647
- if (opts.filter && !opts.filter(subagent, id)) continue;
648
- const matcher = readMatcher(subagent);
649
- if (!matcher) {
650
- evaluated[id] = { keywordHits: 0, patternHits: 0, minScore: defaultMinScore };
651
- scores[id] = 0;
652
- continue;
653
- }
654
- const weight = matcher.weight ?? 1;
655
- let kHits = 0;
656
- for (const kw of matcher.keywords ?? []) {
657
- if (kw && lower.includes(kw.toLowerCase())) kHits += 1;
658
- }
659
- let pHits = 0;
660
- for (const p of matcher.patterns ?? []) {
661
- const re = p instanceof RegExp ? p : new RegExp(p, "i");
662
- if (re.test(message)) pHits += 1;
663
- }
664
- const score = kHits * weight + pHits * DEFAULT_PATTERN_WEIGHT * weight;
665
- const minScore = matcher.minScore ?? defaultMinScore;
666
- scores[id] = score;
667
- evaluated[id] = { keywordHits: kHits, patternHits: pHits, minScore };
668
- if (score >= minScore && score > bestScore) {
669
- bestScore = score;
670
- bestId = id;
671
- bestSubagent = subagent;
672
- }
673
- }
674
- if (bestId === null) {
675
- return { id: null, subagent: null, score: 0, scores, evaluated };
676
- }
677
- return { id: bestId, subagent: bestSubagent, score: bestScore, scores, evaluated };
510
+ // src/durable/execution-handle.ts
511
+ function deriveExecutionId(input) {
512
+ return `${input.projectId}:${input.sessionId}:${input.turnIndex}`;
678
513
  }
679
514
 
680
515
  // src/model-resolution.ts
@@ -690,22 +525,6 @@ async function getModels(routerBaseUrl = DEFAULT_ROUTER_BASE_URL) {
690
525
  const body = await res.json();
691
526
  return Array.isArray(body.data) ? body.data : [];
692
527
  }
693
- function withConfiguredModels(models, extraIds) {
694
- const known = new Set(models.map((model) => model.id));
695
- const extra = extraIds.map((id) => cleanModelId(id)).filter((id) => id !== void 0 && !known.has(id)).map(
696
- (id) => ({
697
- id,
698
- name: id,
699
- description: "Configured chat model for this environment.",
700
- architecture: {
701
- modality: "text->text",
702
- input_modalities: ["text"],
703
- output_modalities: ["text"]
704
- }
705
- })
706
- );
707
- return extra.length > 0 ? [...extra, ...models] : models;
708
- }
709
528
  function cleanModelId(value) {
710
529
  if (typeof value !== "string") return void 0;
711
530
  const trimmed = value.trim();
@@ -756,112 +575,6 @@ async function validateChatModelId(modelId, options = {}) {
756
575
  return { succeeded: true, value: cleaned };
757
576
  }
758
577
 
759
- // src/profile-conformance.ts
760
- var DEFAULT_SHELL_CAPS = [
761
- "bash",
762
- "sh",
763
- "python",
764
- "node",
765
- "curl",
766
- "web",
767
- "browser",
768
- "shell"
769
- ];
770
- var DEFAULT_MIN_PROMPT_CHARS = 800;
771
- function checkSystemPrompt(profile, minChars) {
772
- const prompt = profile.prompt?.systemPrompt;
773
- if (!prompt || prompt.trim().length < minChars) {
774
- return [
775
- {
776
- severity: "error",
777
- code: "system-prompt-too-short",
778
- path: "prompt.systemPrompt",
779
- message: `prompt.systemPrompt is ${prompt?.length ?? 0} chars; min required is ${minChars}. Profiles below this threshold are almost always placeholders.`
780
- }
781
- ];
782
- }
783
- return [];
784
- }
785
- function checkToolsVsMcp(profile, opts) {
786
- const issues = [];
787
- const shellCaps = new Set(opts.knownShellCapabilities ?? DEFAULT_SHELL_CAPS);
788
- const allowedWithoutMcp = new Set(opts.toolsAllowedWithoutMcp ?? []);
789
- const tools = profile.tools ?? {};
790
- const mcp = profile.mcp ?? {};
791
- for (const [name, value] of Object.entries(tools)) {
792
- if (shellCaps.has(name)) {
793
- issues.push({
794
- severity: "error",
795
- code: "shell-capability-as-tool",
796
- path: `tools.${name}`,
797
- message: `'${name}' is a shell capability, not a tool. Move to permissions and remove from tools.`
798
- });
799
- continue;
800
- }
801
- if (allowedWithoutMcp.has(name)) continue;
802
- if (value === false) continue;
803
- if (!mcp[name]) {
804
- issues.push({
805
- severity: "error",
806
- code: "decorative-tool-without-mcp",
807
- path: `tools.${name}`,
808
- message: `'${name}' declared in tools but no corresponding mcp[${name}] AgentProfileMcpServer. Either wire an MCP server, list this name in toolsAllowedWithoutMcp (if it's a file-mounted CLI binary), or remove from tools.`
809
- });
810
- }
811
- }
812
- return issues;
813
- }
814
- function checkSubagentShape(subagent, id) {
815
- const issues = [];
816
- if (!subagent.description || subagent.description.trim().length < 40) {
817
- issues.push({
818
- severity: "error",
819
- code: "subagent-description-too-short",
820
- path: `subagents.${id}.description`,
821
- message: `subagents.${id}.description is missing or too short. Required for routing UX + audit trail.`
822
- });
823
- }
824
- if (!subagent.prompt || subagent.prompt.trim().length < 100) {
825
- issues.push({
826
- severity: "error",
827
- code: "subagent-prompt-too-short",
828
- path: `subagents.${id}.prompt`,
829
- message: `subagents.${id}.prompt is missing or below 100 chars. Either ship the specialist prompt or move this subagent under metadata.plannedSubagents.`
830
- });
831
- }
832
- return issues;
833
- }
834
- function checkScaffoldSubagents(profile, strict) {
835
- const issues = [];
836
- const subagents = profile.subagents ?? {};
837
- for (const [id, subagent] of Object.entries(subagents)) {
838
- const meta = subagent.metadata;
839
- const status = meta?.status;
840
- if (status === "scaffold" || status === "not-implemented" || meta?.implemented === false) {
841
- issues.push({
842
- severity: strict ? "error" : "warn",
843
- code: "subagent-scaffold-shipped",
844
- path: `subagents.${id}`,
845
- message: `subagents.${id} is a scaffold (metadata.status='${status}'). Router must gate on metadata.status === 'full' OR caller must opt into scaffolds explicitly.`
846
- });
847
- }
848
- }
849
- return issues;
850
- }
851
- function assertProfileConformance(profile, opts = {}) {
852
- const issues = [
853
- ...checkSystemPrompt(profile, opts.minSystemPromptChars ?? DEFAULT_MIN_PROMPT_CHARS),
854
- ...checkToolsVsMcp(profile, opts),
855
- ...checkScaffoldSubagents(profile, opts.strictNoScaffolds ?? false)
856
- ];
857
- for (const [id, subagent] of Object.entries(profile.subagents ?? {})) {
858
- issues.push(...checkSubagentShape(subagent, id));
859
- }
860
- const errors = issues.filter((i) => i.severity === "error");
861
- const warnings = issues.filter((i) => i.severity === "warn");
862
- return { valid: errors.length === 0, errors, warnings };
863
- }
864
-
865
578
  // src/readiness.ts
866
579
  var DEFAULT_MINIMUM_READINESS_SCORE = 0.7;
867
580
  function decideKnowledgeReadiness(report, options = {}) {
@@ -1007,29 +720,6 @@ async function runAgentTask(options) {
1007
720
  )
1008
721
  };
1009
722
  }
1010
- function summarizeAgentTaskRun(result) {
1011
- return {
1012
- taskId: result.task.id,
1013
- domain: result.task.domain,
1014
- status: result.status,
1015
- reason: result.control.reason,
1016
- readinessStatus: decideKnowledgeReadiness(result.knowledge).status,
1017
- readinessScore: result.knowledge.readinessScore,
1018
- recommendedAction: result.knowledge.recommendedAction,
1019
- blockingGapIds: result.knowledge.blockingMissingRequirements.map(
1020
- (requirement) => requirement.id
1021
- ),
1022
- nonBlockingGapIds: result.knowledge.nonBlockingGaps.map((requirement) => requirement.id),
1023
- questionCount: result.questions.length,
1024
- acquisitionPlanCount: result.acquisitionPlans.length,
1025
- acquiredEvidenceCount: result.acquiredEvidenceIds.length,
1026
- controlStepCount: result.control.steps.length,
1027
- pass: result.control.pass,
1028
- failureClass: result.control.failureClass,
1029
- wallMs: result.control.wallMs,
1030
- costUsd: result.control.spentCostUsd
1031
- };
1032
- }
1033
723
  async function* runAgentTaskStream(options) {
1034
724
  const task = options.task;
1035
725
  const input = { task, ...options.input ?? {} };
@@ -1765,222 +1455,23 @@ function runtimeStreamServerSentEvent(event, options = {}) {
1765
1455
  function stripNewlines(value) {
1766
1456
  return value.replace(/[\r\n]/g, " ");
1767
1457
  }
1768
-
1769
- // src/trace-bridge.ts
1770
- function createTraceBridge(options) {
1771
- if (!options.runId) {
1772
- throw new ValidationError("createTraceBridge: runId is required");
1773
- }
1774
- let counter = 0;
1775
- const newEventId = options.newEventId ?? (() => `evt-${++counter}`);
1776
- const baseSpanId = options.spanId;
1777
- const toTraceEvent = (event) => {
1778
- const projection = projectToTraceEvent(event);
1779
- if (!projection) return void 0;
1780
- return {
1781
- eventId: newEventId(),
1782
- runId: options.runId,
1783
- spanId: baseSpanId,
1784
- kind: projection.kind,
1785
- timestamp: timestampFor(event),
1786
- payload: projection.payload
1787
- };
1788
- };
1789
- return {
1790
- toTraceEvent,
1791
- drain(events) {
1792
- const out = [];
1793
- for (const event of events) {
1794
- const trace = toTraceEvent(event);
1795
- if (trace) out.push(trace);
1796
- }
1797
- return out;
1798
- }
1799
- };
1800
- }
1801
- function toAgentEvalTrace(event, options) {
1802
- return createTraceBridge(options).toTraceEvent(event);
1803
- }
1804
- function projectToTraceEvent(event) {
1805
- switch (event.type) {
1806
- case "task_start":
1807
- return {
1808
- kind: "log",
1809
- payload: { phase: "task_start", taskId: event.task.id, intent: event.task.intent }
1810
- };
1811
- case "readiness_start":
1812
- return { kind: "log", payload: { phase: "readiness_start", taskId: event.task.id } };
1813
- case "readiness_end":
1814
- return {
1815
- kind: event.decision.passed ? "log" : "policy_violation",
1816
- payload: {
1817
- phase: "readiness_end",
1818
- taskId: event.task.id,
1819
- status: event.decision.status,
1820
- readinessScore: event.decision.readinessScore,
1821
- blockingGapIds: event.decision.blockingGapIds,
1822
- nonBlockingGapIds: event.decision.nonBlockingGapIds,
1823
- reason: event.decision.reason
1824
- }
1825
- };
1826
- case "questions_start":
1827
- return {
1828
- kind: "log",
1829
- payload: { phase: "questions_start", questionCount: event.questions.length }
1830
- };
1831
- case "questions_end":
1832
- return {
1833
- kind: "log",
1834
- payload: {
1835
- phase: "questions_end",
1836
- questionCount: event.questions.length,
1837
- answerCount: Object.keys(event.userAnswers).length
1838
- }
1839
- };
1840
- case "acquisition_start":
1841
- return {
1842
- kind: "log",
1843
- payload: { phase: "acquisition_start", planCount: event.acquisitionPlans.length }
1844
- };
1845
- case "acquisition_end":
1846
- return {
1847
- kind: "log",
1848
- payload: {
1849
- phase: "acquisition_end",
1850
- planCount: event.acquisitionPlans.length,
1851
- evidenceCount: event.acquiredEvidenceIds.length
1852
- }
1853
- };
1854
- case "session_created":
1855
- case "session_resumed":
1856
- return {
1857
- kind: "log",
1858
- payload: {
1859
- phase: event.type,
1860
- sessionId: event.session.id,
1861
- backend: event.session.backend
1862
- }
1863
- };
1864
- case "backend_start":
1865
- case "backend_end":
1866
- return { kind: "log", payload: { phase: event.type, backend: event.backend } };
1867
- case "backend_error":
1868
- return {
1869
- kind: "error",
1870
- payload: {
1871
- backend: event.backend,
1872
- message: event.message,
1873
- recoverable: event.recoverable
1874
- }
1875
- };
1876
- case "tool_call":
1877
- return {
1878
- kind: "log",
1879
- payload: {
1880
- phase: "tool_call",
1881
- toolName: event.toolName,
1882
- toolCallId: event.toolCallId
1883
- // Args omitted — trace events are point-in-time markers, not the
1884
- // canonical store for tool I/O. Attach payloads to a `ToolSpan`
1885
- // when retention is required.
1886
- }
1887
- };
1888
- case "tool_result":
1889
- return {
1890
- kind: "log",
1891
- payload: {
1892
- phase: "tool_result",
1893
- toolName: event.toolName,
1894
- toolCallId: event.toolCallId
1895
- }
1896
- };
1897
- case "llm_call":
1898
- return {
1899
- kind: "log",
1900
- payload: {
1901
- phase: "llm_call",
1902
- model: event.model,
1903
- tokensIn: event.tokensIn,
1904
- tokensOut: event.tokensOut,
1905
- costUsd: event.costUsd,
1906
- latencyMs: event.latencyMs,
1907
- finishReason: event.finishReason
1908
- }
1909
- };
1910
- case "artifact":
1911
- return {
1912
- kind: "state_mutation",
1913
- payload: {
1914
- phase: "artifact",
1915
- artifactId: event.artifactId,
1916
- name: event.name,
1917
- mimeType: event.mimeType
1918
- }
1919
- };
1920
- case "proposal_created":
1921
- return {
1922
- kind: "state_mutation",
1923
- payload: {
1924
- phase: "proposal_created",
1925
- proposalId: event.proposalId,
1926
- title: event.title,
1927
- status: event.status
1928
- }
1929
- };
1930
- case "task_end":
1931
- return {
1932
- kind: event.status === "failed" || event.status === "aborted" ? "error" : "log",
1933
- payload: { phase: "task_end", status: event.status, reason: event.reason }
1934
- };
1935
- case "final":
1936
- return {
1937
- kind: event.status === "failed" || event.status === "aborted" ? "error" : "log",
1938
- payload: { phase: "final", status: event.status, reason: event.reason }
1939
- };
1940
- case "text_delta":
1941
- case "reasoning_delta":
1942
- return void 0;
1943
- default: {
1944
- const exhaust = event;
1945
- void exhaust;
1946
- return void 0;
1947
- }
1948
- }
1949
- }
1950
- function timestampFor(event) {
1951
- const iso = "timestamp" in event ? event.timestamp : void 0;
1952
- if (!iso) return Date.now();
1953
- const parsed = Date.parse(iso);
1954
- return Number.isFinite(parsed) ? parsed : Date.now();
1955
- }
1956
1458
  export {
1957
1459
  AgentEvalError2 as AgentEvalError,
1958
- BackendTransportError,
1959
- CaptureIntegrityError,
1960
- ChatTurnError,
1961
1460
  ConfigError,
1962
1461
  DEFAULT_ROUTER_BASE_URL,
1963
1462
  InMemoryRuntimeSessionStore,
1964
1463
  JudgeError,
1965
1464
  NotFoundError,
1966
- ReplayError,
1967
1465
  RuntimeRunStateError,
1968
- SessionMismatchError,
1969
1466
  ValidationError,
1970
- VerificationError,
1971
- assertProfileConformance,
1972
- classifyIntent,
1973
1467
  cleanModelId,
1974
- composeTurnProfile,
1975
1468
  createIterableBackend,
1976
1469
  createOpenAICompatibleBackend,
1977
1470
  createRuntimeEventCollector,
1978
1471
  createRuntimeStreamEventCollector,
1979
1472
  createSandboxPromptBackend,
1980
- createTraceBridge,
1981
1473
  decideKnowledgeReadiness,
1982
1474
  deriveExecutionId,
1983
- encodeServerSentEvent,
1984
1475
  getModels,
1985
1476
  handleChatTurn,
1986
1477
  readinessServerSentEvent,
@@ -1988,16 +1479,11 @@ export {
1988
1479
  resolveRouterBaseUrl,
1989
1480
  runAgentTask,
1990
1481
  runAgentTaskStream,
1991
- runChatTurn,
1992
1482
  runtimeStreamServerSentEvent,
1993
- sandboxAsChatTurnTarget,
1994
1483
  sanitizeAgentRuntimeEvent,
1995
1484
  sanitizeKnowledgeReadinessReport,
1996
1485
  sanitizeRuntimeStreamEvent,
1997
1486
  startRuntimeRun,
1998
- summarizeAgentTaskRun,
1999
- toAgentEvalTrace,
2000
- validateChatModelId,
2001
- withConfiguredModels
1487
+ validateChatModelId
2002
1488
  };
2003
1489
  //# sourceMappingURL=index.js.map