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