@tangle-network/agent-runtime 0.8.0 → 0.11.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/README.md +42 -13
- package/dist/agent.d.ts +537 -0
- package/dist/agent.js +475 -0
- package/dist/agent.js.map +1 -0
- package/dist/analyst-loop.d.ts +26 -0
- package/dist/analyst-loop.js +262 -0
- package/dist/analyst-loop.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/index.d.ts +235 -35
- package/dist/index.js +284 -3
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +197 -0
- package/dist/platform.js +187 -0
- package/dist/platform.js.map +1 -0
- package/dist/types-D_MXrmJP.d.ts +245 -0
- package/package.json +39 -14
- package/docs/domain-agent-runtime-integration-issues.md +0 -165
- package/docs/product-runtime-kernel.md +0 -326
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import "./chunk-DGUM43GV.js";
|
|
2
|
+
|
|
1
3
|
// src/errors.ts
|
|
2
4
|
import { AgentEvalError } from "@tangle-network/agent-eval";
|
|
3
5
|
import {
|
|
@@ -290,6 +292,279 @@ function stringValue(value) {
|
|
|
290
292
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
291
293
|
}
|
|
292
294
|
|
|
295
|
+
// src/chat-turn.ts
|
|
296
|
+
import { mergeAgentProfiles } from "@tangle-network/sandbox";
|
|
297
|
+
var RUNTIME_PATH = "/runtime/agents/run/stream";
|
|
298
|
+
async function* runChatTurn(options) {
|
|
299
|
+
const turnProfile = options.overlay ? composeTurnProfile(options.profile, options.overlay) : options.profile;
|
|
300
|
+
const url = `${options.sandbox.runtimeUrl}${RUNTIME_PATH}`;
|
|
301
|
+
const backendType = turnProfile.metadata?.backend?.type ?? "claude-code";
|
|
302
|
+
const body = JSON.stringify({
|
|
303
|
+
backend: {
|
|
304
|
+
type: backendType,
|
|
305
|
+
profile: turnProfile,
|
|
306
|
+
...options.modelOverride ? { model: { default: options.modelOverride } } : {}
|
|
307
|
+
},
|
|
308
|
+
messages: [...options.priorMessages, { role: "user", content: options.message }]
|
|
309
|
+
});
|
|
310
|
+
const headers = {
|
|
311
|
+
"Content-Type": "application/json",
|
|
312
|
+
Accept: "text/event-stream"
|
|
313
|
+
};
|
|
314
|
+
if (options.sandbox.authHeader) {
|
|
315
|
+
headers[options.sandbox.authHeader.name] = options.sandbox.authHeader.value;
|
|
316
|
+
}
|
|
317
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
318
|
+
const response = await fetchImpl(url, {
|
|
319
|
+
method: "POST",
|
|
320
|
+
headers,
|
|
321
|
+
body,
|
|
322
|
+
signal: options.signal
|
|
323
|
+
});
|
|
324
|
+
if (!response.ok || !response.body) {
|
|
325
|
+
const text = response.body ? await response.text() : "";
|
|
326
|
+
throw new ChatTurnError(
|
|
327
|
+
`runChatTurn: sandbox returned ${response.status} ${response.statusText}: ${text.slice(0, 500)}`,
|
|
328
|
+
response.status
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
yield* parseSseStream(response.body);
|
|
332
|
+
}
|
|
333
|
+
function composeTurnProfile(base, overlay) {
|
|
334
|
+
const partial = {};
|
|
335
|
+
if (overlay.promptOverlay) partial.prompt = overlay.promptOverlay;
|
|
336
|
+
if (overlay.resourcesOverlay) partial.resources = overlay.resourcesOverlay;
|
|
337
|
+
if (overlay.subagentsOverlay) partial.subagents = overlay.subagentsOverlay;
|
|
338
|
+
if (overlay.metadata) partial.metadata = overlay.metadata;
|
|
339
|
+
return mergeAgentProfiles(base, partial) ?? base;
|
|
340
|
+
}
|
|
341
|
+
async function* parseSseStream(stream) {
|
|
342
|
+
const decoder = new TextDecoder();
|
|
343
|
+
const reader = stream.getReader();
|
|
344
|
+
let buffer = "";
|
|
345
|
+
try {
|
|
346
|
+
while (true) {
|
|
347
|
+
const { value, done } = await reader.read();
|
|
348
|
+
if (done) break;
|
|
349
|
+
buffer += decoder.decode(value, { stream: true });
|
|
350
|
+
let idx = buffer.indexOf("\n");
|
|
351
|
+
while (idx >= 0) {
|
|
352
|
+
const line = buffer.slice(0, idx).replace(/\r$/, "").trim();
|
|
353
|
+
buffer = buffer.slice(idx + 1);
|
|
354
|
+
idx = buffer.indexOf("\n");
|
|
355
|
+
if (!line) continue;
|
|
356
|
+
const payload = line.startsWith("data:") ? line.slice(5).trim() : line;
|
|
357
|
+
if (payload === "[DONE]" || payload === "") continue;
|
|
358
|
+
try {
|
|
359
|
+
const parsed = JSON.parse(payload);
|
|
360
|
+
yield parsed;
|
|
361
|
+
} catch {
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
} finally {
|
|
366
|
+
reader.releaseLock();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
var ChatTurnError = class extends Error {
|
|
370
|
+
constructor(message, status) {
|
|
371
|
+
super(message);
|
|
372
|
+
this.status = status;
|
|
373
|
+
this.name = "ChatTurnError";
|
|
374
|
+
}
|
|
375
|
+
status;
|
|
376
|
+
};
|
|
377
|
+
function sandboxAsChatTurnTarget(instance, opts) {
|
|
378
|
+
const base = instance.url ?? instance.connection?.runtimeUrl ?? "";
|
|
379
|
+
if (!base) {
|
|
380
|
+
throw new ChatTurnError(
|
|
381
|
+
`sandboxAsChatTurnTarget: SandboxInstance has neither .url nor .connection.runtimeUrl set`
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
id: instance.id,
|
|
386
|
+
runtimeUrl: base.replace(/\/+$/, ""),
|
|
387
|
+
authHeader: opts?.authHeader
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/intent-router.ts
|
|
392
|
+
var DEFAULT_PATTERN_WEIGHT = 1.5;
|
|
393
|
+
var DEFAULT_MIN_SCORE = 1;
|
|
394
|
+
function isMatcher(value) {
|
|
395
|
+
if (!value || typeof value !== "object") return false;
|
|
396
|
+
const v = value;
|
|
397
|
+
return Array.isArray(v.keywords) || Array.isArray(v.patterns) || typeof v.minScore === "number";
|
|
398
|
+
}
|
|
399
|
+
function readMatcher(subagent) {
|
|
400
|
+
const m = subagent.metadata;
|
|
401
|
+
if (!m) return null;
|
|
402
|
+
const raw = m.matchers ?? m.matcher ?? null;
|
|
403
|
+
if (!raw) return null;
|
|
404
|
+
if (Array.isArray(raw)) {
|
|
405
|
+
const merged = { keywords: [], patterns: [], minScore: DEFAULT_MIN_SCORE };
|
|
406
|
+
for (const entry of raw) {
|
|
407
|
+
if (!isMatcher(entry)) continue;
|
|
408
|
+
merged.keywords = [...merged.keywords ?? [], ...entry.keywords ?? []];
|
|
409
|
+
merged.patterns = [...merged.patterns ?? [], ...entry.patterns ?? []];
|
|
410
|
+
if (entry.minScore !== void 0) merged.minScore = entry.minScore;
|
|
411
|
+
}
|
|
412
|
+
return merged;
|
|
413
|
+
}
|
|
414
|
+
if (isMatcher(raw)) return raw;
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
function classifyIntent(profile, message, opts = {}) {
|
|
418
|
+
const lower = message.toLowerCase();
|
|
419
|
+
const subagents = profile.subagents ?? {};
|
|
420
|
+
const skip = new Set(opts.skip ?? []);
|
|
421
|
+
const defaultMinScore = opts.defaultMinScore ?? DEFAULT_MIN_SCORE;
|
|
422
|
+
const scores = {};
|
|
423
|
+
const evaluated = {};
|
|
424
|
+
let bestId = null;
|
|
425
|
+
let bestScore = -Infinity;
|
|
426
|
+
let bestSubagent = null;
|
|
427
|
+
for (const [id, subagent] of Object.entries(subagents)) {
|
|
428
|
+
if (skip.has(id)) continue;
|
|
429
|
+
if (opts.filter && !opts.filter(subagent, id)) continue;
|
|
430
|
+
const matcher = readMatcher(subagent);
|
|
431
|
+
if (!matcher) {
|
|
432
|
+
evaluated[id] = { keywordHits: 0, patternHits: 0, minScore: defaultMinScore };
|
|
433
|
+
scores[id] = 0;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
const weight = matcher.weight ?? 1;
|
|
437
|
+
let kHits = 0;
|
|
438
|
+
for (const kw of matcher.keywords ?? []) {
|
|
439
|
+
if (kw && lower.includes(kw.toLowerCase())) kHits += 1;
|
|
440
|
+
}
|
|
441
|
+
let pHits = 0;
|
|
442
|
+
for (const p of matcher.patterns ?? []) {
|
|
443
|
+
const re = p instanceof RegExp ? p : new RegExp(p, "i");
|
|
444
|
+
if (re.test(message)) pHits += 1;
|
|
445
|
+
}
|
|
446
|
+
const score = kHits * weight + pHits * DEFAULT_PATTERN_WEIGHT * weight;
|
|
447
|
+
const minScore = matcher.minScore ?? defaultMinScore;
|
|
448
|
+
scores[id] = score;
|
|
449
|
+
evaluated[id] = { keywordHits: kHits, patternHits: pHits, minScore };
|
|
450
|
+
if (score >= minScore && score > bestScore) {
|
|
451
|
+
bestScore = score;
|
|
452
|
+
bestId = id;
|
|
453
|
+
bestSubagent = subagent;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (bestId === null) {
|
|
457
|
+
return { id: null, subagent: null, score: 0, scores, evaluated };
|
|
458
|
+
}
|
|
459
|
+
return { id: bestId, subagent: bestSubagent, score: bestScore, scores, evaluated };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// src/profile-conformance.ts
|
|
463
|
+
var DEFAULT_SHELL_CAPS = [
|
|
464
|
+
"bash",
|
|
465
|
+
"sh",
|
|
466
|
+
"python",
|
|
467
|
+
"node",
|
|
468
|
+
"curl",
|
|
469
|
+
"web",
|
|
470
|
+
"browser",
|
|
471
|
+
"shell"
|
|
472
|
+
];
|
|
473
|
+
var DEFAULT_MIN_PROMPT_CHARS = 800;
|
|
474
|
+
function checkSystemPrompt(profile, minChars) {
|
|
475
|
+
const prompt = profile.prompt?.systemPrompt;
|
|
476
|
+
if (!prompt || prompt.trim().length < minChars) {
|
|
477
|
+
return [
|
|
478
|
+
{
|
|
479
|
+
severity: "error",
|
|
480
|
+
code: "system-prompt-too-short",
|
|
481
|
+
path: "prompt.systemPrompt",
|
|
482
|
+
message: `prompt.systemPrompt is ${prompt?.length ?? 0} chars; min required is ${minChars}. Profiles below this threshold are almost always placeholders.`
|
|
483
|
+
}
|
|
484
|
+
];
|
|
485
|
+
}
|
|
486
|
+
return [];
|
|
487
|
+
}
|
|
488
|
+
function checkToolsVsMcp(profile, opts) {
|
|
489
|
+
const issues = [];
|
|
490
|
+
const shellCaps = new Set(opts.knownShellCapabilities ?? DEFAULT_SHELL_CAPS);
|
|
491
|
+
const allowedWithoutMcp = new Set(opts.toolsAllowedWithoutMcp ?? []);
|
|
492
|
+
const tools = profile.tools ?? {};
|
|
493
|
+
const mcp = profile.mcp ?? {};
|
|
494
|
+
for (const [name, value] of Object.entries(tools)) {
|
|
495
|
+
if (shellCaps.has(name)) {
|
|
496
|
+
issues.push({
|
|
497
|
+
severity: "error",
|
|
498
|
+
code: "shell-capability-as-tool",
|
|
499
|
+
path: `tools.${name}`,
|
|
500
|
+
message: `'${name}' is a shell capability, not a tool. Move to permissions and remove from tools.`
|
|
501
|
+
});
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (allowedWithoutMcp.has(name)) continue;
|
|
505
|
+
if (value === false) continue;
|
|
506
|
+
if (!mcp[name]) {
|
|
507
|
+
issues.push({
|
|
508
|
+
severity: "error",
|
|
509
|
+
code: "decorative-tool-without-mcp",
|
|
510
|
+
path: `tools.${name}`,
|
|
511
|
+
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.`
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return issues;
|
|
516
|
+
}
|
|
517
|
+
function checkSubagentShape(subagent, id) {
|
|
518
|
+
const issues = [];
|
|
519
|
+
if (!subagent.description || subagent.description.trim().length < 40) {
|
|
520
|
+
issues.push({
|
|
521
|
+
severity: "error",
|
|
522
|
+
code: "subagent-description-too-short",
|
|
523
|
+
path: `subagents.${id}.description`,
|
|
524
|
+
message: `subagents.${id}.description is missing or too short. Required for routing UX + audit trail.`
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
if (!subagent.prompt || subagent.prompt.trim().length < 100) {
|
|
528
|
+
issues.push({
|
|
529
|
+
severity: "error",
|
|
530
|
+
code: "subagent-prompt-too-short",
|
|
531
|
+
path: `subagents.${id}.prompt`,
|
|
532
|
+
message: `subagents.${id}.prompt is missing or below 100 chars. Either ship the specialist prompt or move this subagent under metadata.plannedSubagents.`
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
return issues;
|
|
536
|
+
}
|
|
537
|
+
function checkScaffoldSubagents(profile, strict) {
|
|
538
|
+
const issues = [];
|
|
539
|
+
const subagents = profile.subagents ?? {};
|
|
540
|
+
for (const [id, subagent] of Object.entries(subagents)) {
|
|
541
|
+
const meta = subagent.metadata;
|
|
542
|
+
const status = meta?.status;
|
|
543
|
+
if (status === "scaffold" || status === "not-implemented" || meta?.implemented === false) {
|
|
544
|
+
issues.push({
|
|
545
|
+
severity: strict ? "error" : "warn",
|
|
546
|
+
code: "subagent-scaffold-shipped",
|
|
547
|
+
path: `subagents.${id}`,
|
|
548
|
+
message: `subagents.${id} is a scaffold (metadata.status='${status}'). Router must gate on metadata.status === 'full' OR caller must opt into scaffolds explicitly.`
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return issues;
|
|
553
|
+
}
|
|
554
|
+
function assertProfileConformance(profile, opts = {}) {
|
|
555
|
+
const issues = [
|
|
556
|
+
...checkSystemPrompt(profile, opts.minSystemPromptChars ?? DEFAULT_MIN_PROMPT_CHARS),
|
|
557
|
+
...checkToolsVsMcp(profile, opts),
|
|
558
|
+
...checkScaffoldSubagents(profile, opts.strictNoScaffolds ?? false)
|
|
559
|
+
];
|
|
560
|
+
for (const [id, subagent] of Object.entries(profile.subagents ?? {})) {
|
|
561
|
+
issues.push(...checkSubagentShape(subagent, id));
|
|
562
|
+
}
|
|
563
|
+
const errors = issues.filter((i) => i.severity === "error");
|
|
564
|
+
const warnings = issues.filter((i) => i.severity === "warn");
|
|
565
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
566
|
+
}
|
|
567
|
+
|
|
293
568
|
// src/readiness.ts
|
|
294
569
|
var DEFAULT_MINIMUM_READINESS_SCORE = 0.7;
|
|
295
570
|
function decideKnowledgeReadiness(report, options = {}) {
|
|
@@ -1296,9 +1571,9 @@ function projectToTraceEvent(event) {
|
|
|
1296
1571
|
phase: "tool_call",
|
|
1297
1572
|
toolName: event.toolName,
|
|
1298
1573
|
toolCallId: event.toolCallId
|
|
1299
|
-
// Args
|
|
1300
|
-
//
|
|
1301
|
-
//
|
|
1574
|
+
// Args omitted — trace events are point-in-time markers, not the
|
|
1575
|
+
// canonical store for tool I/O. Attach payloads to a `ToolSpan`
|
|
1576
|
+
// when retention is required.
|
|
1302
1577
|
}
|
|
1303
1578
|
};
|
|
1304
1579
|
case "tool_result":
|
|
@@ -1363,6 +1638,7 @@ export {
|
|
|
1363
1638
|
AgentEvalError2 as AgentEvalError,
|
|
1364
1639
|
BackendTransportError,
|
|
1365
1640
|
CaptureIntegrityError,
|
|
1641
|
+
ChatTurnError,
|
|
1366
1642
|
ConfigError,
|
|
1367
1643
|
InMemoryRuntimeSessionStore,
|
|
1368
1644
|
JudgeError,
|
|
@@ -1372,6 +1648,9 @@ export {
|
|
|
1372
1648
|
SessionMismatchError,
|
|
1373
1649
|
ValidationError,
|
|
1374
1650
|
VerificationError,
|
|
1651
|
+
assertProfileConformance,
|
|
1652
|
+
classifyIntent,
|
|
1653
|
+
composeTurnProfile,
|
|
1375
1654
|
createIterableBackend,
|
|
1376
1655
|
createOpenAICompatibleBackend,
|
|
1377
1656
|
createRuntimeEventCollector,
|
|
@@ -1383,7 +1662,9 @@ export {
|
|
|
1383
1662
|
readinessServerSentEvent,
|
|
1384
1663
|
runAgentTask,
|
|
1385
1664
|
runAgentTaskStream,
|
|
1665
|
+
runChatTurn,
|
|
1386
1666
|
runtimeStreamServerSentEvent,
|
|
1667
|
+
sandboxAsChatTurnTarget,
|
|
1387
1668
|
sanitizeAgentRuntimeEvent,
|
|
1388
1669
|
sanitizeKnowledgeReadinessReport,
|
|
1389
1670
|
sanitizeRuntimeStreamEvent,
|