@tangle-network/agent-runtime 0.21.1 → 0.23.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 +116 -1
- package/dist/agent.d.ts +1 -1
- package/dist/chunk-7HN72MF3.js +200 -0
- package/dist/chunk-7HN72MF3.js.map +1 -0
- package/dist/{chunk-Z5LKAYAS.js → chunk-CBQVID7G.js} +2 -2
- package/dist/chunk-IQHYOJU3.js +427 -0
- package/dist/chunk-IQHYOJU3.js.map +1 -0
- package/dist/{chunk-EDVCVFQB.js → chunk-TZ53F7M7.js} +4 -3
- package/dist/chunk-TZ53F7M7.js.map +1 -0
- package/dist/{chunk-QDNJLAEU.js → chunk-UNQM6XQO.js} +34 -433
- package/dist/chunk-UNQM6XQO.js.map +1 -0
- package/dist/{chunk-XLWPTPRP.js → chunk-URDSRUPQ.js} +2 -2
- package/dist/{chunk-RZAOYKCO.js → chunk-XZYF3YJN.js} +9 -1
- package/dist/{chunk-RZAOYKCO.js.map → chunk-XZYF3YJN.js.map} +1 -1
- package/dist/index.d.ts +77 -4
- package/dist/index.js +209 -41
- package/dist/index.js.map +1 -1
- package/dist/loops.d.ts +4 -4
- package/dist/loops.js +3 -3
- package/dist/mcp/bin.js +6 -5
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +54 -4
- package/dist/mcp/index.js +60 -11
- package/dist/mcp/index.js.map +1 -1
- package/dist/otel-export-B33Cy_60.d.ts +114 -0
- package/dist/profiles.d.ts +3 -3
- package/dist/profiles.js +3 -3
- package/dist/{runtime-run-B2j-hvBj.d.ts → runtime-run-D5ItCKl_.d.ts} +1 -1
- package/dist/{types-DvJIha6w.d.ts → types-BFgFD_sl.d.ts} +87 -1
- package/dist/{types-Cu-SkGa0.d.ts → types-DmkRGTBn.d.ts} +18 -1
- package/package.json +1 -1
- package/dist/chunk-EDVCVFQB.js.map +0 -1
- package/dist/chunk-QDNJLAEU.js.map +0 -1
- /package/dist/{chunk-Z5LKAYAS.js.map → chunk-CBQVID7G.js.map} +0 -0
- /package/dist/{chunk-XLWPTPRP.js.map → chunk-URDSRUPQ.js.map} +0 -0
package/README.md
CHANGED
|
@@ -213,6 +213,33 @@ Or run the ready-made bin:
|
|
|
213
213
|
TANGLE_API_KEY=sk_sandbox_... agent-runtime-mcp
|
|
214
214
|
```
|
|
215
215
|
|
|
216
|
+
### Surfacing the tools through `createOpenAICompatibleBackend`
|
|
217
|
+
|
|
218
|
+
Sandbox callers discover MCP tools through the runtime mount. Callers that
|
|
219
|
+
route through the OpenAI-compat backend (tcloud, OpenRouter, cli-bridge,
|
|
220
|
+
OpenAI direct) must hand the model an explicit `tools[]` array — the
|
|
221
|
+
backend does not auto-discover. `mcpToolsForRuntimeMcp()` returns the
|
|
222
|
+
canonical projection so the model can call any of the 5 delegation tools
|
|
223
|
+
through the OpenAI-compat path:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import {
|
|
227
|
+
createOpenAICompatibleBackend,
|
|
228
|
+
mcpToolsForRuntimeMcp,
|
|
229
|
+
} from '@tangle-network/agent-runtime'
|
|
230
|
+
|
|
231
|
+
const backend = createOpenAICompatibleBackend({
|
|
232
|
+
apiKey,
|
|
233
|
+
baseUrl,
|
|
234
|
+
model,
|
|
235
|
+
tools: mcpToolsForRuntimeMcp(),
|
|
236
|
+
})
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Use `mcpToolsForRuntimeMcpSubset(['delegate_research', 'delegation_status'])`
|
|
240
|
+
when you want a curated subset (e.g. read-only research without the coder
|
|
241
|
+
queue).
|
|
242
|
+
|
|
216
243
|
The bin auto-wires the coder delegate and, when
|
|
217
244
|
`@tangle-network/agent-knowledge` is installed as a peer, the researcher
|
|
218
245
|
delegate. Environment knobs:
|
|
@@ -362,6 +389,94 @@ const researcherDelegate: ResearcherDelegate = async (args, ctx) => {
|
|
|
362
389
|
createMcpServer({ researcherDelegate })
|
|
363
390
|
```
|
|
364
391
|
|
|
392
|
+
## OpenAI-compat backend — tools + fail-loud errors
|
|
393
|
+
|
|
394
|
+
`createOpenAICompatibleBackend` forwards an OpenAI Chat Completions
|
|
395
|
+
`tools[]` array on every request when configured. Streamed tool calls
|
|
396
|
+
(both OpenAI delta shape and the Anthropic `tool_use` shape proxied by
|
|
397
|
+
the router) are assembled across SSE chunks and emitted as a single
|
|
398
|
+
`tool_call` RuntimeStreamEvent per call. The backend does NOT execute
|
|
399
|
+
tools — surfacing the call is the contract; dispatch is the caller's
|
|
400
|
+
problem.
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
import {
|
|
404
|
+
createOpenAICompatibleBackend,
|
|
405
|
+
runAgentTaskStream,
|
|
406
|
+
type OpenAIChatTool,
|
|
407
|
+
} from '@tangle-network/agent-runtime'
|
|
408
|
+
|
|
409
|
+
const delegateResearch: OpenAIChatTool = {
|
|
410
|
+
type: 'function',
|
|
411
|
+
function: {
|
|
412
|
+
name: 'delegate_research',
|
|
413
|
+
description: 'Spin up a researcher loop and return a taskId.',
|
|
414
|
+
parameters: {
|
|
415
|
+
type: 'object',
|
|
416
|
+
properties: { question: { type: 'string' } },
|
|
417
|
+
required: ['question'],
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const backend = createOpenAICompatibleBackend({
|
|
423
|
+
apiKey: process.env.TANGLE_API_KEY!,
|
|
424
|
+
baseUrl: 'https://router.tangle.tools/v1',
|
|
425
|
+
model: 'claude-sonnet-4-6',
|
|
426
|
+
tools: [delegateResearch /* + delegate_code, delegate_feedback, etc. */],
|
|
427
|
+
toolChoice: 'auto', // or 'none' | 'required' | { type: 'function', function: { name } }
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
for await (const event of runAgentTaskStream({ task, backend, input })) {
|
|
431
|
+
if (event.type === 'tool_call') {
|
|
432
|
+
// Dispatch through your MCP / sandbox runtime. `args` is JSON-parsed
|
|
433
|
+
// when the model produced a valid object, raw string otherwise.
|
|
434
|
+
const result = await dispatch(event.toolName, event.args)
|
|
435
|
+
// Feed `result` back on a follow-up turn via `input.messages`.
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Callers integrating with `agent-runtime/mcp` typically project the MCP
|
|
441
|
+
server's `tools/list` response into this shape once at config time and
|
|
442
|
+
pass the array as `tools`. The runtime intentionally does NOT depend on
|
|
443
|
+
`@modelcontextprotocol/sdk` — keeping the backend transport thin lets
|
|
444
|
+
domain repos own MCP plumbing.
|
|
445
|
+
|
|
446
|
+
### Transport errors fail loud
|
|
447
|
+
|
|
448
|
+
Non-success HTTP responses (4xx/5xx after retry exhaustion) and
|
|
449
|
+
connection failures throw `BackendTransportError` from inside the
|
|
450
|
+
`stream()` generator. `runAgentTaskStream` catches the throw and emits:
|
|
451
|
+
|
|
452
|
+
- `backend_error` event with `error: { kind: 'transport', message, status, body }`
|
|
453
|
+
- terminal `final` event with `status: 'failed'` carrying the same `error` detail
|
|
454
|
+
|
|
455
|
+
Consumers building a `RunRecord` MUST map `final.error` onto
|
|
456
|
+
`RunRecord.error`. Treating an empty `finalText` as "agent produced
|
|
457
|
+
nothing" hides credit exhaustion (HTTP 402), auth failure (401),
|
|
458
|
+
model-not-found (404), and upstream outages (5xx).
|
|
459
|
+
|
|
460
|
+
```ts
|
|
461
|
+
for await (const event of runAgentTaskStream({ task, backend, input })) {
|
|
462
|
+
run.observe(event)
|
|
463
|
+
if (event.type === 'final') {
|
|
464
|
+
run.complete({
|
|
465
|
+
status: event.status === 'completed' ? 'completed' : 'failed',
|
|
466
|
+
resultSummary: event.text ?? '',
|
|
467
|
+
error: event.error
|
|
468
|
+
? `${event.error.kind} ${event.error.status ?? ''}: ${event.error.message}`
|
|
469
|
+
: undefined,
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
The body is captured truncated to 2 KiB. By default the sanitized
|
|
476
|
+
telemetry envelope surfaces `error.kind` + `error.status` but redacts
|
|
477
|
+
`error.body` (it can echo user-visible text from a provider's error
|
|
478
|
+
page). Opt in with `RuntimeTelemetryOptions.includeControlPayloads`.
|
|
479
|
+
|
|
365
480
|
## Error taxonomy
|
|
366
481
|
|
|
367
482
|
| Error | When |
|
|
@@ -369,7 +484,7 @@ createMcpServer({ researcherDelegate })
|
|
|
369
484
|
| `ValidationError` | Caller passed invalid arguments |
|
|
370
485
|
| `ConfigError` | Required env / config missing |
|
|
371
486
|
| `NotFoundError` | A named resource does not exist |
|
|
372
|
-
| `BackendTransportError` | Backend HTTP / IPC call returned non-success |
|
|
487
|
+
| `BackendTransportError` | Backend HTTP / IPC call returned non-success — carries `status` + truncated `body` |
|
|
373
488
|
| `SessionMismatchError` | Resume requested against a different backend |
|
|
374
489
|
| `RuntimeRunStateError` | `RuntimeRunHandle` lifecycle methods called out of order |
|
|
375
490
|
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _tangle_network_agent_eval from '@tangle-network/agent-eval';
|
|
2
2
|
import { FindingSubject, TraceAnalystKindSpec, AnalystFinding } from '@tangle-network/agent-eval';
|
|
3
|
-
import { R as RuntimeStreamEvent } from './types-
|
|
3
|
+
import { R as RuntimeStreamEvent } from './types-BFgFD_sl.js';
|
|
4
4
|
import { I as ImprovementAdapter, K as KnowledgeAdapter, a as RunAnalystLoopResult } from './types-D_MXrmJP.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DELEGATE_CODE_DESCRIPTION,
|
|
3
|
+
DELEGATE_CODE_INPUT_SCHEMA,
|
|
4
|
+
DELEGATE_CODE_TOOL_NAME,
|
|
5
|
+
DELEGATE_FEEDBACK_DESCRIPTION,
|
|
6
|
+
DELEGATE_FEEDBACK_INPUT_SCHEMA,
|
|
7
|
+
DELEGATE_FEEDBACK_TOOL_NAME,
|
|
8
|
+
DELEGATE_RESEARCH_DESCRIPTION,
|
|
9
|
+
DELEGATE_RESEARCH_INPUT_SCHEMA,
|
|
10
|
+
DELEGATE_RESEARCH_TOOL_NAME,
|
|
11
|
+
DELEGATION_HISTORY_DESCRIPTION,
|
|
12
|
+
DELEGATION_HISTORY_INPUT_SCHEMA,
|
|
13
|
+
DELEGATION_HISTORY_TOOL_NAME,
|
|
14
|
+
DELEGATION_STATUS_DESCRIPTION,
|
|
15
|
+
DELEGATION_STATUS_INPUT_SCHEMA,
|
|
16
|
+
DELEGATION_STATUS_TOOL_NAME
|
|
17
|
+
} from "./chunk-UNQM6XQO.js";
|
|
18
|
+
|
|
19
|
+
// src/mcp/openai-tools.ts
|
|
20
|
+
function buildTool(name, description, parameters) {
|
|
21
|
+
return {
|
|
22
|
+
type: "function",
|
|
23
|
+
function: { name, description, parameters: { ...parameters } }
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function mcpToolsForRuntimeMcp() {
|
|
27
|
+
return [
|
|
28
|
+
buildTool(
|
|
29
|
+
DELEGATE_CODE_TOOL_NAME,
|
|
30
|
+
DELEGATE_CODE_DESCRIPTION,
|
|
31
|
+
DELEGATE_CODE_INPUT_SCHEMA
|
|
32
|
+
),
|
|
33
|
+
buildTool(
|
|
34
|
+
DELEGATE_RESEARCH_TOOL_NAME,
|
|
35
|
+
DELEGATE_RESEARCH_DESCRIPTION,
|
|
36
|
+
DELEGATE_RESEARCH_INPUT_SCHEMA
|
|
37
|
+
),
|
|
38
|
+
buildTool(
|
|
39
|
+
DELEGATE_FEEDBACK_TOOL_NAME,
|
|
40
|
+
DELEGATE_FEEDBACK_DESCRIPTION,
|
|
41
|
+
DELEGATE_FEEDBACK_INPUT_SCHEMA
|
|
42
|
+
),
|
|
43
|
+
buildTool(
|
|
44
|
+
DELEGATION_STATUS_TOOL_NAME,
|
|
45
|
+
DELEGATION_STATUS_DESCRIPTION,
|
|
46
|
+
DELEGATION_STATUS_INPUT_SCHEMA
|
|
47
|
+
),
|
|
48
|
+
buildTool(
|
|
49
|
+
DELEGATION_HISTORY_TOOL_NAME,
|
|
50
|
+
DELEGATION_HISTORY_DESCRIPTION,
|
|
51
|
+
DELEGATION_HISTORY_INPUT_SCHEMA
|
|
52
|
+
)
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
function mcpToolsForRuntimeMcpSubset(names) {
|
|
56
|
+
const allowed = new Set(names);
|
|
57
|
+
return mcpToolsForRuntimeMcp().filter((tool) => allowed.has(tool.function.name));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/otel-export.ts
|
|
61
|
+
var SCOPE = { name: "@tangle-network/agent-runtime", version: "0.23.0" };
|
|
62
|
+
function createOtelExporter(config) {
|
|
63
|
+
const resolvedEndpoint = config?.endpoint ?? (typeof process !== "undefined" ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : void 0);
|
|
64
|
+
if (!resolvedEndpoint) return void 0;
|
|
65
|
+
const endpoint = resolvedEndpoint;
|
|
66
|
+
const headers = config?.headers ?? parseHeadersFromEnv();
|
|
67
|
+
const batchSize = config?.batchSize ?? 64;
|
|
68
|
+
const flushIntervalMs = config?.flushIntervalMs ?? 5e3;
|
|
69
|
+
const serviceName = config?.serviceName ?? "agent-runtime";
|
|
70
|
+
const resourceAttrs = config?.resourceAttributes ?? {};
|
|
71
|
+
const pending = [];
|
|
72
|
+
let timer;
|
|
73
|
+
let stopped = false;
|
|
74
|
+
const exporter = {
|
|
75
|
+
exportSpan(span) {
|
|
76
|
+
if (stopped) return;
|
|
77
|
+
pending.push(span);
|
|
78
|
+
if (pending.length >= batchSize) {
|
|
79
|
+
void doFlush();
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
async flush() {
|
|
83
|
+
await doFlush();
|
|
84
|
+
},
|
|
85
|
+
async shutdown() {
|
|
86
|
+
stopped = true;
|
|
87
|
+
if (timer !== void 0) {
|
|
88
|
+
clearInterval(timer);
|
|
89
|
+
timer = void 0;
|
|
90
|
+
}
|
|
91
|
+
await doFlush();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
timer = setInterval(() => {
|
|
95
|
+
if (pending.length > 0) void doFlush();
|
|
96
|
+
}, flushIntervalMs);
|
|
97
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
98
|
+
;
|
|
99
|
+
timer.unref();
|
|
100
|
+
}
|
|
101
|
+
async function doFlush() {
|
|
102
|
+
if (pending.length === 0) return;
|
|
103
|
+
const batch = pending.splice(0);
|
|
104
|
+
const body = {
|
|
105
|
+
resourceSpans: [
|
|
106
|
+
{
|
|
107
|
+
resource: {
|
|
108
|
+
attributes: toAttributes({
|
|
109
|
+
"service.name": serviceName,
|
|
110
|
+
...resourceAttrs
|
|
111
|
+
})
|
|
112
|
+
},
|
|
113
|
+
scopeSpans: [{ scope: SCOPE, spans: batch }]
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
const url = endpoint.replace(/\/+$/, "") + "/v1/traces";
|
|
118
|
+
try {
|
|
119
|
+
await fetch(url, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "content-type": "application/json", ...headers },
|
|
122
|
+
body: JSON.stringify(body)
|
|
123
|
+
});
|
|
124
|
+
} catch {
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return exporter;
|
|
128
|
+
}
|
|
129
|
+
function loopEventToOtelSpan(event, traceId, parentSpanId) {
|
|
130
|
+
const spanId = generateSpanId();
|
|
131
|
+
const attrs = {
|
|
132
|
+
"loop.event_kind": event.kind,
|
|
133
|
+
"loop.run_id": event.runId
|
|
134
|
+
};
|
|
135
|
+
for (const [k, v] of Object.entries(event.payload)) {
|
|
136
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
137
|
+
attrs[`loop.${k}`] = v;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const ts = msToNs(event.timestamp);
|
|
141
|
+
return {
|
|
142
|
+
traceId: padTraceId(traceId),
|
|
143
|
+
spanId,
|
|
144
|
+
parentSpanId: parentSpanId ? padSpanId(parentSpanId) : void 0,
|
|
145
|
+
name: event.kind,
|
|
146
|
+
kind: 1,
|
|
147
|
+
startTimeUnixNano: ts,
|
|
148
|
+
endTimeUnixNano: ts,
|
|
149
|
+
attributes: toAttributes(attrs),
|
|
150
|
+
status: { code: 1 }
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function parseHeadersFromEnv() {
|
|
154
|
+
if (typeof process === "undefined") return {};
|
|
155
|
+
const raw = process.env.OTEL_EXPORTER_OTLP_HEADERS;
|
|
156
|
+
if (!raw) return {};
|
|
157
|
+
const out = {};
|
|
158
|
+
for (const pair of raw.split(",")) {
|
|
159
|
+
const eq = pair.indexOf("=");
|
|
160
|
+
if (eq < 0) continue;
|
|
161
|
+
const key = pair.slice(0, eq).trim();
|
|
162
|
+
const value = pair.slice(eq + 1).trim();
|
|
163
|
+
if (key) out[key] = value;
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
function toAttributes(record) {
|
|
168
|
+
return Object.entries(record).map(([key, value]) => ({
|
|
169
|
+
key,
|
|
170
|
+
value: typeof value === "number" ? Number.isInteger(value) ? { intValue: value.toString() } : { doubleValue: value } : typeof value === "boolean" ? { boolValue: value } : { stringValue: value }
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
function msToNs(ms) {
|
|
174
|
+
return (BigInt(Math.floor(ms)) * 1000000n).toString();
|
|
175
|
+
}
|
|
176
|
+
function padSpanId(id) {
|
|
177
|
+
const cleaned = id.replace(/-/g, "");
|
|
178
|
+
return cleaned.slice(0, 16).padEnd(16, "0");
|
|
179
|
+
}
|
|
180
|
+
function padTraceId(id) {
|
|
181
|
+
const cleaned = id.replace(/-/g, "");
|
|
182
|
+
return cleaned.slice(0, 32).padEnd(32, "0");
|
|
183
|
+
}
|
|
184
|
+
function generateSpanId() {
|
|
185
|
+
const bytes = new Uint8Array(8);
|
|
186
|
+
if (typeof globalThis.crypto?.getRandomValues === "function") {
|
|
187
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
188
|
+
} else {
|
|
189
|
+
for (let i = 0; i < 8; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
190
|
+
}
|
|
191
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export {
|
|
195
|
+
mcpToolsForRuntimeMcp,
|
|
196
|
+
mcpToolsForRuntimeMcpSubset,
|
|
197
|
+
createOtelExporter,
|
|
198
|
+
loopEventToOtelSpan
|
|
199
|
+
};
|
|
200
|
+
//# sourceMappingURL=chunk-7HN72MF3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/openai-tools.ts","../src/otel-export.ts"],"sourcesContent":["/**\n * @experimental\n *\n * OpenAI Chat Completions `tools[]` projection of the 5 agent-runtime MCP\n * delegation tools.\n *\n * Use when configuring `createOpenAICompatibleBackend({ tools: ... })` so the\n * model can call `delegate_code`, `delegate_research`, `delegate_feedback`,\n * `delegation_status`, and `delegation_history` through the OpenAI-compat\n * transport (tcloud, OpenRouter, OpenAI direct, cli-bridge). The runtime\n * surfaces tool calls as `tool_call` stream events — execution is the\n * caller's responsibility (typically the parent sandbox runtime's MCP\n * mount).\n *\n * Sandbox-SDK callers do NOT need this helper: the sandbox runtime mounts\n * MCP servers natively and the in-sandbox harness discovers tools via the\n * runtime, not via an OpenAI tools array.\n *\n * Tool name + description + JSON-schema are pulled from the canonical\n * `DELEGATE_*` constants exported by `./tools/*` so the projection cannot\n * drift from the server's own validators.\n */\n\nimport type { OpenAIChatTool } from '../types'\nimport {\n DELEGATE_CODE_DESCRIPTION,\n DELEGATE_CODE_INPUT_SCHEMA,\n DELEGATE_CODE_TOOL_NAME,\n} from './tools/delegate-code'\nimport {\n DELEGATE_FEEDBACK_DESCRIPTION,\n DELEGATE_FEEDBACK_INPUT_SCHEMA,\n DELEGATE_FEEDBACK_TOOL_NAME,\n} from './tools/delegate-feedback'\nimport {\n DELEGATE_RESEARCH_DESCRIPTION,\n DELEGATE_RESEARCH_INPUT_SCHEMA,\n DELEGATE_RESEARCH_TOOL_NAME,\n} from './tools/delegate-research'\nimport {\n DELEGATION_HISTORY_DESCRIPTION,\n DELEGATION_HISTORY_INPUT_SCHEMA,\n DELEGATION_HISTORY_TOOL_NAME,\n} from './tools/delegation-history'\nimport {\n DELEGATION_STATUS_DESCRIPTION,\n DELEGATION_STATUS_INPUT_SCHEMA,\n DELEGATION_STATUS_TOOL_NAME,\n} from './tools/delegation-status'\n\nfunction buildTool(\n name: string,\n description: string,\n parameters: Readonly<Record<string, unknown>>,\n): OpenAIChatTool {\n // `parameters` arrives as a deeply-readonly `as const` literal. The\n // OpenAI-compat backend JSON-serializes the body so a shallow copy\n // into a plain object is sufficient — and shields callers that mutate\n // the returned descriptor from corrupting the source constant.\n return {\n type: 'function',\n function: { name, description, parameters: { ...parameters } },\n }\n}\n\n/**\n * @experimental\n *\n * Returns the 5 delegation tools projected into OpenAI Chat Completions\n * `tools[]` shape. The order is stable: `delegate_code`,\n * `delegate_research`, `delegate_feedback`, `delegation_status`,\n * `delegation_history`.\n */\nexport function mcpToolsForRuntimeMcp(): OpenAIChatTool[] {\n return [\n buildTool(\n DELEGATE_CODE_TOOL_NAME,\n DELEGATE_CODE_DESCRIPTION,\n DELEGATE_CODE_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATE_RESEARCH_TOOL_NAME,\n DELEGATE_RESEARCH_DESCRIPTION,\n DELEGATE_RESEARCH_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATE_FEEDBACK_TOOL_NAME,\n DELEGATE_FEEDBACK_DESCRIPTION,\n DELEGATE_FEEDBACK_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATION_STATUS_TOOL_NAME,\n DELEGATION_STATUS_DESCRIPTION,\n DELEGATION_STATUS_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n buildTool(\n DELEGATION_HISTORY_TOOL_NAME,\n DELEGATION_HISTORY_DESCRIPTION,\n DELEGATION_HISTORY_INPUT_SCHEMA as Readonly<Record<string, unknown>>,\n ),\n ]\n}\n\n/**\n * @experimental\n *\n * Subset filter — return only the projected tools whose `function.name`\n * appears in `names`. Useful for curated mounts (e.g. only the queue-bound\n * delegation tools, omitting `delegate_feedback`). Unknown names are\n * silently ignored; pass an empty array to get an empty result.\n */\nexport function mcpToolsForRuntimeMcpSubset(names: ReadonlyArray<string>): OpenAIChatTool[] {\n const allowed = new Set(names)\n return mcpToolsForRuntimeMcp().filter((tool) => allowed.has(tool.function.name))\n}\n","/**\n * OTEL span exporter — streams LoopTraceEvents to an OTLP/HTTP collector.\n *\n * Reads OTEL_EXPORTER_OTLP_ENDPOINT + OTEL_EXPORTER_OTLP_HEADERS from env\n * when no explicit config is given. Keeps the runtime dep-free from\n * @opentelemetry/sdk-trace-base — minimal OTLP/JSON serializer.\n *\n * The exporter accepts both raw OtelSpan objects and LoopTraceEvents\n * (which get converted to OTLP spans automatically).\n */\n\nexport interface OtelExportConfig {\n /** OTLP endpoint. Reads OTEL_EXPORTER_OTLP_ENDPOINT env by default. */\n endpoint?: string\n /** OTLP headers. Reads OTEL_EXPORTER_OTLP_HEADERS env by default. */\n headers?: Record<string, string>\n /** Batch size before flush. Default 64. */\n batchSize?: number\n /** Flush interval ms. Default 5000. */\n flushIntervalMs?: number\n /** Resource attributes stamped on every export. */\n resourceAttributes?: Record<string, string | number | boolean>\n /** Service name. Default 'agent-runtime'. */\n serviceName?: string\n}\n\nexport interface OtelExporter {\n /** Export a span. */\n exportSpan(span: OtelSpan): void\n /** Force flush pending spans. */\n flush(): Promise<void>\n /** Shutdown cleanly. */\n shutdown(): Promise<void>\n}\n\nexport interface OtelSpan {\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind?: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n attributes?: OtelAttribute[]\n status?: { code: number; message?: string }\n}\n\nexport interface OtelAttribute {\n key: string\n value: { stringValue?: string; intValue?: string; doubleValue?: number; boolValue?: boolean }\n}\n\ninterface OtlpResourceSpans {\n resource: { attributes: OtelAttribute[] }\n scopeSpans: Array<{ scope: { name: string; version: string }; spans: OtelSpan[] }>\n}\n\ninterface OtlpExport {\n resourceSpans: OtlpResourceSpans[]\n}\n\nconst SCOPE = { name: '@tangle-network/agent-runtime', version: '0.23.0' }\n\n/**\n * Create an OTEL exporter. Returns undefined when no endpoint is configured.\n */\nexport function createOtelExporter(config?: OtelExportConfig): OtelExporter | undefined {\n const resolvedEndpoint =\n config?.endpoint ?? (typeof process !== 'undefined' ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT : undefined)\n if (!resolvedEndpoint) return undefined\n const endpoint: string = resolvedEndpoint\n\n const headers = config?.headers ?? parseHeadersFromEnv()\n const batchSize = config?.batchSize ?? 64\n const flushIntervalMs = config?.flushIntervalMs ?? 5000\n const serviceName = config?.serviceName ?? 'agent-runtime'\n const resourceAttrs = config?.resourceAttributes ?? {}\n\n const pending: OtelSpan[] = []\n let timer: ReturnType<typeof setInterval> | undefined\n let stopped = false\n\n const exporter: OtelExporter = {\n exportSpan(span: OtelSpan): void {\n if (stopped) return\n pending.push(span)\n if (pending.length >= batchSize) {\n void doFlush()\n }\n },\n\n async flush(): Promise<void> {\n await doFlush()\n },\n\n async shutdown(): Promise<void> {\n stopped = true\n if (timer !== undefined) {\n clearInterval(timer)\n timer = undefined\n }\n await doFlush()\n },\n }\n\n timer = setInterval(() => {\n if (pending.length > 0) void doFlush()\n }, flushIntervalMs)\n if (typeof timer === 'object' && 'unref' in timer) {\n ;(timer as NodeJS.Timeout).unref()\n }\n\n async function doFlush(): Promise<void> {\n if (pending.length === 0) return\n const batch = pending.splice(0)\n const body: OtlpExport = {\n resourceSpans: [\n {\n resource: {\n attributes: toAttributes({\n 'service.name': serviceName,\n ...resourceAttrs,\n }),\n },\n scopeSpans: [{ scope: SCOPE, spans: batch }],\n },\n ],\n }\n const url = endpoint.replace(/\\/+$/, '') + '/v1/traces'\n try {\n await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...headers },\n body: JSON.stringify(body),\n })\n } catch {\n // Best-effort — telemetry export must not crash the runtime.\n }\n }\n\n return exporter\n}\n\n/**\n * Convert a LoopTraceEvent into an OtelSpan for export.\n */\nexport function loopEventToOtelSpan(\n event: {\n kind: string\n runId: string\n timestamp: number\n payload: object\n },\n traceId: string,\n parentSpanId?: string,\n): OtelSpan {\n const spanId = generateSpanId()\n const attrs: Record<string, string | number | boolean> = {\n 'loop.event_kind': event.kind,\n 'loop.run_id': event.runId,\n }\n for (const [k, v] of Object.entries(event.payload)) {\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n attrs[`loop.${k}`] = v\n }\n }\n const ts = msToNs(event.timestamp)\n return {\n traceId: padTraceId(traceId),\n spanId,\n parentSpanId: parentSpanId ? padSpanId(parentSpanId) : undefined,\n name: event.kind,\n kind: 1,\n startTimeUnixNano: ts,\n endTimeUnixNano: ts,\n attributes: toAttributes(attrs),\n status: { code: 1 },\n }\n}\n\nfunction parseHeadersFromEnv(): Record<string, string> {\n if (typeof process === 'undefined') return {}\n const raw = process.env.OTEL_EXPORTER_OTLP_HEADERS\n if (!raw) return {}\n const out: Record<string, string> = {}\n for (const pair of raw.split(',')) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const key = pair.slice(0, eq).trim()\n const value = pair.slice(eq + 1).trim()\n if (key) out[key] = value\n }\n return out\n}\n\nfunction toAttributes(record: Record<string, string | number | boolean>): OtelAttribute[] {\n return Object.entries(record).map(([key, value]) => ({\n key,\n value:\n typeof value === 'number'\n ? Number.isInteger(value)\n ? { intValue: value.toString() }\n : { doubleValue: value }\n : typeof value === 'boolean'\n ? { boolValue: value }\n : { stringValue: value },\n }))\n}\n\nfunction msToNs(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString()\n}\n\nfunction padSpanId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 16).padEnd(16, '0')\n}\n\nfunction padTraceId(id: string): string {\n const cleaned = id.replace(/-/g, '')\n return cleaned.slice(0, 32).padEnd(32, '0')\n}\n\nfunction generateSpanId(): string {\n const bytes = new Uint8Array(8)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 8; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createFanoutVoteDriver
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-URDSRUPQ.js";
|
|
4
4
|
|
|
5
5
|
// src/profiles/coder.ts
|
|
6
6
|
var DEFAULT_MAX_DIFF_LINES = 400;
|
|
@@ -245,4 +245,4 @@ export {
|
|
|
245
245
|
multiHarnessCoderFanout,
|
|
246
246
|
createCoderValidator
|
|
247
247
|
};
|
|
248
|
-
//# sourceMappingURL=chunk-
|
|
248
|
+
//# sourceMappingURL=chunk-CBQVID7G.js.map
|