@vextlabs/theron-agent-sdk 0.3.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/LICENSE +21 -0
  3. package/README.md +270 -0
  4. package/dist/adapters/theron.cjs +92 -0
  5. package/dist/adapters/theron.d.cts +42 -0
  6. package/dist/adapters/theron.d.ts +42 -0
  7. package/dist/adapters/theron.js +89 -0
  8. package/dist/agent/index.cjs +33 -0
  9. package/dist/agent/index.d.cts +84 -0
  10. package/dist/agent/index.d.ts +84 -0
  11. package/dist/agent/index.js +31 -0
  12. package/dist/council/index.cjs +68 -0
  13. package/dist/council/index.d.cts +96 -0
  14. package/dist/council/index.d.ts +96 -0
  15. package/dist/council/index.js +66 -0
  16. package/dist/index.cjs +1288 -0
  17. package/dist/index.d.cts +60 -0
  18. package/dist/index.d.ts +60 -0
  19. package/dist/index.js +1244 -0
  20. package/dist/loop/index.cjs +106 -0
  21. package/dist/loop/index.d.cts +285 -0
  22. package/dist/loop/index.d.ts +285 -0
  23. package/dist/loop/index.js +95 -0
  24. package/dist/mcp/index.cjs +153 -0
  25. package/dist/mcp/index.d.cts +69 -0
  26. package/dist/mcp/index.d.ts +69 -0
  27. package/dist/mcp/index.js +150 -0
  28. package/dist/memory/index.cjs +53 -0
  29. package/dist/memory/index.d.cts +73 -0
  30. package/dist/memory/index.d.ts +73 -0
  31. package/dist/memory/index.js +50 -0
  32. package/dist/patterns/index.cjs +159 -0
  33. package/dist/patterns/index.d.cts +200 -0
  34. package/dist/patterns/index.d.ts +200 -0
  35. package/dist/patterns/index.js +150 -0
  36. package/dist/receipts/index.cjs +151 -0
  37. package/dist/receipts/index.d.cts +132 -0
  38. package/dist/receipts/index.d.ts +132 -0
  39. package/dist/receipts/index.js +146 -0
  40. package/dist/runtime/index.cjs +205 -0
  41. package/dist/runtime/index.d.cts +148 -0
  42. package/dist/runtime/index.d.ts +148 -0
  43. package/dist/runtime/index.js +203 -0
  44. package/dist/session/index.cjs +49 -0
  45. package/dist/session/index.d.cts +79 -0
  46. package/dist/session/index.d.ts +79 -0
  47. package/dist/session/index.js +47 -0
  48. package/dist/tools/index.cjs +51 -0
  49. package/dist/tools/index.d.cts +52 -0
  50. package/dist/tools/index.d.ts +52 -0
  51. package/dist/tools/index.js +46 -0
  52. package/dist/verifiers/index.cjs +96 -0
  53. package/dist/verifiers/index.d.cts +63 -0
  54. package/dist/verifiers/index.d.ts +63 -0
  55. package/dist/verifiers/index.js +93 -0
  56. package/examples/01_code_reviewer.ts +90 -0
  57. package/examples/02_research_assistant.ts +85 -0
  58. package/examples/03_council_of_three.ts +91 -0
  59. package/examples/_adapters/openrouter.ts +90 -0
  60. package/examples/adapters/openrouter.ts +144 -0
  61. package/examples/adapters/theron.ts +105 -0
  62. package/examples/basic-agent.ts +56 -0
  63. package/examples/council-deliberation.ts +90 -0
  64. package/examples/cyber-recon-bot.ts +163 -0
  65. package/examples/loop-primitives.ts +50 -0
  66. package/examples/meeting-prep-bot.ts +172 -0
  67. package/examples/reasoning-patterns.ts +125 -0
  68. package/examples/support-triage-bot.ts +181 -0
  69. package/examples/verifier-kernel.ts +108 -0
  70. package/package.json +154 -0
package/dist/index.js ADDED
@@ -0,0 +1,1244 @@
1
+ import { z } from 'zod';
2
+ export { z as zod } from 'zod';
3
+
4
+ // src/agent/index.ts
5
+ var Agent = class {
6
+ name;
7
+ model;
8
+ instruction;
9
+ tools;
10
+ sub_agents;
11
+ verifiers;
12
+ max_turns;
13
+ constructor(config) {
14
+ if (!config.name) throw new Error("Agent requires a `name`.");
15
+ if (!config.instruction) throw new Error(`Agent "${config.name}" requires an \`instruction\`.`);
16
+ this.name = config.name;
17
+ this.model = config.model;
18
+ this.instruction = typeof config.instruction === "string" ? { system: config.instruction } : config.instruction;
19
+ this.tools = config.tools ?? [];
20
+ this.sub_agents = config.sub_agents ?? [];
21
+ this.verifiers = config.verifiers ?? [];
22
+ this.max_turns = config.max_turns ?? 10;
23
+ }
24
+ /** Render the tools as JSON schemas for the model. */
25
+ toolSchemas() {
26
+ return this.tools.map((t) => t.schema);
27
+ }
28
+ /** True if the agent has any sub-agents (i.e., this is a supervisor). */
29
+ isSupervisor() {
30
+ return this.sub_agents.length > 0;
31
+ }
32
+ };
33
+
34
+ // src/council/index.ts
35
+ var Council = class {
36
+ name;
37
+ specialists;
38
+ verifiers;
39
+ reconciler;
40
+ specialist_timeout_ms;
41
+ constructor(config) {
42
+ if (!config.name) throw new Error("Council requires a `name`.");
43
+ if (!config.specialists || config.specialists.length === 0) {
44
+ throw new Error(`Council "${config.name}" requires at least one specialist.`);
45
+ }
46
+ this.name = config.name;
47
+ this.specialists = config.specialists;
48
+ this.verifiers = config.verifiers ?? [];
49
+ this.reconciler = config.reconciler ?? deterministicClaimMerge;
50
+ this.specialist_timeout_ms = config.specialist_timeout_ms ?? 3e4;
51
+ }
52
+ /**
53
+ * Convenience entry point — pointed at the Runner you've already constructed.
54
+ * Most users will call `runner.runCouncil(council, query)` directly; this
55
+ * exists for symmetry with `agent.run`-style ergonomics in user code.
56
+ */
57
+ async deliberate(_query) {
58
+ throw new Error(
59
+ "Council.deliberate() requires a Runner. Use:\n const runner = new Runner({ ... });\n const result = await runner.runCouncil(council, query);\nSee: https://github.com/Vext-Labs-Inc/theron-agent-sdk/blob/main/examples/03_council_of_three.ts"
60
+ );
61
+ }
62
+ };
63
+ var deterministicClaimMerge = async (specialists) => {
64
+ if (specialists.length === 0) {
65
+ return { answer: "(no specialists responded)", consensus: "refuted" };
66
+ }
67
+ if (specialists.length === 1) {
68
+ return { answer: specialists[0].output, consensus: "ratified" };
69
+ }
70
+ const claimMap = /* @__PURE__ */ new Map();
71
+ for (const s of specialists) {
72
+ for (const c of s.claims) {
73
+ const key = c.text.toLowerCase().trim();
74
+ if (!claimMap.has(key)) claimMap.set(key, []);
75
+ claimMap.get(key).push(s.specialist);
76
+ }
77
+ }
78
+ const ratified = [];
79
+ const disagreements = [];
80
+ const majorityThreshold = specialists.length / 2;
81
+ for (const [claim, voters] of claimMap.entries()) {
82
+ if (voters.length === specialists.length) {
83
+ ratified.push(claim);
84
+ } else if (voters.length > majorityThreshold) {
85
+ ratified.push(claim);
86
+ } else {
87
+ disagreements.push({
88
+ claim,
89
+ specialists_for: voters,
90
+ specialists_against: specialists.map((s) => s.specialist).filter((n) => !voters.includes(n))
91
+ });
92
+ }
93
+ }
94
+ const answer = ratified.join(" ") || specialists[0].output;
95
+ const consensus = disagreements.length > 0 ? "split" : ratified.length > 0 ? "ratified" : "refuted";
96
+ return { answer, consensus, disagreements: disagreements.length > 0 ? disagreements : void 0 };
97
+ };
98
+
99
+ // src/session/index.ts
100
+ var Session = class _Session {
101
+ id;
102
+ tenant_id;
103
+ state;
104
+ events;
105
+ constructor(config = {}) {
106
+ this.id = config.id ?? cryptoRandomId();
107
+ this.tenant_id = config.tenant_id;
108
+ this.state = new Map(Object.entries(config.initial_state ?? {}));
109
+ this.events = [];
110
+ }
111
+ append(event) {
112
+ this.events.push(event);
113
+ }
114
+ /** Get a read-only snapshot of all events. */
115
+ getEvents() {
116
+ return this.events;
117
+ }
118
+ /** Get events of a specific type (typed). */
119
+ getEventsOfType(type) {
120
+ return this.events.filter((e) => e.type === type);
121
+ }
122
+ /** Serialize the session for persistence. */
123
+ toJSON() {
124
+ return {
125
+ id: this.id,
126
+ tenant_id: this.tenant_id,
127
+ state: Object.fromEntries(this.state.entries()),
128
+ events: this.events.slice()
129
+ };
130
+ }
131
+ /** Restore a session from its serialized form. */
132
+ static fromJSON(data) {
133
+ const sess = new _Session({ id: data.id, tenant_id: data.tenant_id, initial_state: data.state });
134
+ for (const e of data.events) sess.events.push(e);
135
+ return sess;
136
+ }
137
+ };
138
+ function cryptoRandomId() {
139
+ if (typeof globalThis.crypto?.randomUUID === "function") {
140
+ return globalThis.crypto.randomUUID();
141
+ }
142
+ return `sess_${Math.random().toString(36).slice(2)}_${Date.now()}`;
143
+ }
144
+
145
+ // src/memory/index.ts
146
+ var Memory = class {
147
+ };
148
+ var InMemoryStore = class extends Memory {
149
+ records = /* @__PURE__ */ new Map();
150
+ async set(record) {
151
+ const id = record.id ?? `mem_${Math.random().toString(36).slice(2)}_${Date.now()}`;
152
+ const full = {
153
+ ...record,
154
+ id,
155
+ created_at: record.created_at ?? Date.now(),
156
+ last_accessed_at: record.last_accessed_at ?? Date.now()
157
+ };
158
+ this.records.set(id, full);
159
+ return full;
160
+ }
161
+ async get(id) {
162
+ const r = this.records.get(id);
163
+ if (r) {
164
+ r.last_accessed_at = Date.now();
165
+ }
166
+ return r;
167
+ }
168
+ async query(q) {
169
+ let results = Array.from(this.records.values());
170
+ if (q.tenant_id !== void 0) {
171
+ results = results.filter((r) => r.tenant_id === q.tenant_id);
172
+ }
173
+ if (q.key !== void 0) {
174
+ results = results.filter((r) => r.key === q.key);
175
+ }
176
+ if (q.tags !== void 0 && q.tags.length > 0) {
177
+ results = results.filter((r) => r.tags?.some((t) => q.tags.includes(t)));
178
+ }
179
+ if (q.semantic_query !== void 0) {
180
+ const ql = q.semantic_query.toLowerCase();
181
+ results = results.filter((r) => r.value.toLowerCase().includes(ql));
182
+ }
183
+ results.sort((a, b) => b.last_accessed_at - a.last_accessed_at);
184
+ if (q.limit !== void 0) {
185
+ results = results.slice(0, q.limit);
186
+ }
187
+ return results;
188
+ }
189
+ async delete(id) {
190
+ this.records.delete(id);
191
+ }
192
+ };
193
+ function defineTool(opts) {
194
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(opts.name)) {
195
+ throw new Error(
196
+ `Tool name "${opts.name}" is invalid. Must match /^[a-zA-Z][a-zA-Z0-9_-]*$/ for OpenAI/Anthropic tool-call compatibility.`
197
+ );
198
+ }
199
+ return {
200
+ schema: {
201
+ name: opts.name,
202
+ description: opts.description,
203
+ input_schema: zodToJsonSchema(opts.input)
204
+ },
205
+ async execute(input, ctx) {
206
+ const parsed = opts.input.safeParse(input);
207
+ if (!parsed.success) {
208
+ const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
209
+ throw new Error(`Tool "${opts.name}" received invalid input: ${issues}`);
210
+ }
211
+ return opts.execute(parsed.data, ctx);
212
+ }
213
+ };
214
+ }
215
+ function zodToJsonSchema(schema) {
216
+ if (schema instanceof z.ZodObject) {
217
+ const properties = {};
218
+ const required = [];
219
+ for (const [key, value] of Object.entries(schema.shape)) {
220
+ properties[key] = zodToJsonSchema(value);
221
+ if (!(value instanceof z.ZodOptional)) required.push(key);
222
+ }
223
+ return { type: "object", properties, ...required.length > 0 ? { required } : {} };
224
+ }
225
+ if (schema instanceof z.ZodString) return { type: "string" };
226
+ if (schema instanceof z.ZodNumber) return { type: "number" };
227
+ if (schema instanceof z.ZodBoolean) return { type: "boolean" };
228
+ if (schema instanceof z.ZodArray) return { type: "array", items: zodToJsonSchema(schema.element) };
229
+ if (schema instanceof z.ZodOptional) return zodToJsonSchema(schema.unwrap());
230
+ if (schema instanceof z.ZodEnum) return { type: "string", enum: schema.options };
231
+ return { type: "string" };
232
+ }
233
+
234
+ // src/tools/local-contract.ts
235
+ var LOCAL_TOOL_PARAMETERS = {
236
+ Read: {
237
+ type: "object",
238
+ properties: {
239
+ file_path: { type: "string", description: "Absolute or relative path to the file." },
240
+ offset: { type: "number", description: "Optional 1-indexed line to start reading from." },
241
+ limit: { type: "number", description: "Optional max lines to read." }
242
+ },
243
+ required: ["file_path"]
244
+ },
245
+ Write: {
246
+ type: "object",
247
+ properties: {
248
+ file_path: { type: "string" },
249
+ content: { type: "string", description: "Full file contents \u2014 overwrites whatever was there." }
250
+ },
251
+ required: ["file_path", "content"]
252
+ },
253
+ Edit: {
254
+ type: "object",
255
+ properties: {
256
+ file_path: { type: "string" },
257
+ old_string: { type: "string" },
258
+ new_string: { type: "string" },
259
+ replace_all: { type: "boolean", default: false }
260
+ },
261
+ required: ["file_path", "old_string", "new_string"]
262
+ },
263
+ Bash: {
264
+ type: "object",
265
+ properties: {
266
+ command: { type: "string" },
267
+ timeout: { type: "number", description: "Timeout in ms (default 120000, max 600000)." },
268
+ description: { type: "string", description: "Short label for what the command does, shown to the user." }
269
+ },
270
+ required: ["command"]
271
+ },
272
+ Glob: {
273
+ type: "object",
274
+ properties: {
275
+ pattern: { type: "string", description: "Glob like 'src/**/*.ts'." },
276
+ path: { type: "string", description: "Root directory to search from. Defaults to the working directory." }
277
+ },
278
+ required: ["pattern"]
279
+ },
280
+ Grep: {
281
+ type: "object",
282
+ properties: {
283
+ pattern: { type: "string", description: "Regex pattern." },
284
+ path: { type: "string", description: "Optional file or directory to limit the search." },
285
+ glob: { type: "string", description: "Optional glob filter, e.g. '*.ts'." },
286
+ case_insensitive: { type: "boolean", default: false }
287
+ },
288
+ required: ["pattern"]
289
+ },
290
+ LS: {
291
+ type: "object",
292
+ properties: {
293
+ path: { type: "string", description: "Path to list. Defaults to the working directory." }
294
+ }
295
+ }
296
+ };
297
+ var LOCAL_TOOL_NAMES = [
298
+ "Read",
299
+ "Write",
300
+ "Edit",
301
+ "Bash",
302
+ "Glob",
303
+ "Grep",
304
+ "LS"
305
+ ];
306
+ var MUTATING_LOCAL_TOOLS = /* @__PURE__ */ new Set([
307
+ "Write",
308
+ "Edit",
309
+ "Bash"
310
+ ]);
311
+ function buildLocalToolSchemas(descriptions) {
312
+ return LOCAL_TOOL_NAMES.map((name) => ({
313
+ type: "function",
314
+ function: {
315
+ name,
316
+ description: descriptions[name] ?? "",
317
+ parameters: LOCAL_TOOL_PARAMETERS[name]
318
+ }
319
+ }));
320
+ }
321
+
322
+ // src/verifiers/index.ts
323
+ function defineVerifier(opts) {
324
+ return {
325
+ name: opts.name,
326
+ description: opts.description,
327
+ async check(output, context) {
328
+ const t0 = Date.now();
329
+ const result = await opts.check(output, context);
330
+ return { kernel: opts.name, pass: result.pass, issues: result.issues, ms: Date.now() - t0 };
331
+ }
332
+ };
333
+ }
334
+ var VerifierKernels = {
335
+ /** Block em-dashes (common AI tell). */
336
+ emDash: defineVerifier({
337
+ name: "em_dash_check",
338
+ description: "Block em-dashes in output (common AI tell).",
339
+ check: async (output) => {
340
+ const matches = [...output.matchAll(/—/g)];
341
+ const issues = matches.map((m) => ({
342
+ kernel: "em_dash_check",
343
+ severity: "error",
344
+ message: "Em-dash detected",
345
+ span: { start: m.index, end: m.index + 1 }
346
+ }));
347
+ return { pass: issues.length === 0, issues };
348
+ }
349
+ }),
350
+ /** Block common AI-ism words. Word-boundary aware to avoid false positives
351
+ * (e.g., "leverage" matches but not "delivered"). */
352
+ aiIsm: defineVerifier({
353
+ name: "ai_ism_check",
354
+ description: "Block common AI-ism words.",
355
+ check: async (output) => {
356
+ const aiisms = ["delve", "tapestry", "leverage", "robust", "seamless", "navigate", "embark"];
357
+ const issues = [];
358
+ for (const w of aiisms) {
359
+ const re = new RegExp(`\\b${w}\\b`, "gi");
360
+ if (re.test(output)) {
361
+ issues.push({
362
+ kernel: "ai_ism_check",
363
+ severity: "warning",
364
+ message: `AI-ism detected: "${w}"`
365
+ });
366
+ }
367
+ }
368
+ return { pass: issues.length === 0, issues };
369
+ }
370
+ }),
371
+ /** Re-evaluate arithmetic claims like "X op Y = Z". */
372
+ arithmetic: defineVerifier({
373
+ name: "arithmetic_recheck",
374
+ description: "Re-evaluate arithmetic in 'X op Y = Z' form.",
375
+ check: async (output) => {
376
+ const pattern = /(-?\d+(?:\.\d+)?)\s*([+\-*/])\s*(-?\d+(?:\.\d+)?)\s*=\s*(-?\d+(?:\.\d+)?)/g;
377
+ const issues = [];
378
+ for (const m of output.matchAll(pattern)) {
379
+ const a = parseFloat(m[1]);
380
+ const op = m[2];
381
+ const b = parseFloat(m[3]);
382
+ const claimed = parseFloat(m[4]);
383
+ const actual = op === "+" ? a + b : op === "-" ? a - b : op === "*" ? a * b : op === "/" ? b === 0 ? NaN : a / b : NaN;
384
+ if (!Number.isFinite(actual) || Math.abs(actual - claimed) > 1e-6) {
385
+ issues.push({
386
+ kernel: "arithmetic_recheck",
387
+ severity: "error",
388
+ message: `Claimed ${a} ${op} ${b} = ${claimed}; actual ${Number.isFinite(actual) ? actual : "undefined"}`
389
+ });
390
+ }
391
+ }
392
+ return { pass: issues.length === 0, issues };
393
+ }
394
+ }),
395
+ /** Require at least one citation pattern ([N], (Author Year), https://...). */
396
+ citationPresence: defineVerifier({
397
+ name: "citation_presence",
398
+ description: "Require at least one citation in output.",
399
+ check: async (output) => {
400
+ const patterns = [/\[\d+\]/, /\([A-Z][a-z]+(?: et al\.?)? \d{4}\)/, /https?:\/\//];
401
+ const found = patterns.some((p) => p.test(output));
402
+ const issues = found ? [] : [
403
+ {
404
+ kernel: "citation_presence",
405
+ severity: "error",
406
+ message: "No citation found. Expected one of: [N], (Author YEAR), or a URL."
407
+ }
408
+ ];
409
+ return { pass: found, issues };
410
+ }
411
+ })
412
+ };
413
+
414
+ // src/runtime/index.ts
415
+ var Runner = class {
416
+ model;
417
+ default_model;
418
+ memory;
419
+ session;
420
+ tool_context;
421
+ listeners = [];
422
+ constructor(config) {
423
+ if (!config.model) throw new Error("Runner requires a `model` adapter.");
424
+ if (!config.default_model) throw new Error("Runner requires a `default_model` identifier.");
425
+ this.model = config.model;
426
+ this.default_model = config.default_model;
427
+ this.memory = config.memory;
428
+ this.session = config.session;
429
+ this.tool_context = config.tool_context ?? { cwd: process.cwd(), yolo: false };
430
+ }
431
+ /** Subscribe to runner events for streaming UIs / observability. */
432
+ on(handler) {
433
+ this.listeners.push(handler);
434
+ return () => {
435
+ this.listeners = this.listeners.filter((h) => h !== handler);
436
+ };
437
+ }
438
+ emit(event) {
439
+ for (const h of this.listeners) h(event);
440
+ }
441
+ /**
442
+ * Run a single agent on a query.
443
+ *
444
+ * Loop:
445
+ * 1. Send messages + tool schemas to the model
446
+ * 2. If model returns a tool call → execute the tool → append result to messages → repeat
447
+ * 3. If model returns content + end_turn → finalize
448
+ * 4. Run any registered verifier kernels on the final output
449
+ * 5. Return the AgentResult
450
+ */
451
+ async run(agent, query) {
452
+ const startedAt = Date.now();
453
+ this.emit({ type: "agent_start", agent: agent.name, query });
454
+ const messages = [
455
+ { role: "system", content: agent.instruction.system }
456
+ ];
457
+ for (const ex of agent.instruction.examples ?? []) {
458
+ messages.push({ role: "user", content: ex.user });
459
+ messages.push({ role: "assistant", content: ex.assistant });
460
+ }
461
+ messages.push({ role: "user", content: query });
462
+ const toolCalls = [];
463
+ let tokensIn = 0;
464
+ let tokensOut = 0;
465
+ let finalOutput = "";
466
+ for (let turn = 0; turn < agent.max_turns; turn++) {
467
+ const response = await this.model.chat({
468
+ model: agent.model ?? this.default_model,
469
+ messages,
470
+ tools: agent.toolSchemas(),
471
+ onDelta: (delta) => this.emit({ type: "agent_thinking", agent: agent.name, delta })
472
+ });
473
+ tokensIn += response.tokens.input;
474
+ tokensOut += response.tokens.output;
475
+ if (response.tool_calls && response.tool_calls.length > 0) {
476
+ messages.push({ role: "assistant", content: response.content });
477
+ for (const call of response.tool_calls) {
478
+ const tool = agent.tools.find((t) => t.schema.name === call.name);
479
+ if (!tool) {
480
+ this.emit({
481
+ type: "error",
482
+ agent: agent.name,
483
+ message: `Model called unknown tool: ${call.name}`
484
+ });
485
+ messages.push({ role: "tool", content: `error: unknown tool ${call.name}` });
486
+ continue;
487
+ }
488
+ this.emit({ type: "tool_call_start", agent: agent.name, tool: call.name, input: call.input });
489
+ const t0 = Date.now();
490
+ try {
491
+ const output = await tool.execute(call.input, this.tool_context);
492
+ const ms = Date.now() - t0;
493
+ this.emit({ type: "tool_call_done", agent: agent.name, tool: call.name, output, ms });
494
+ toolCalls.push({ name: call.name, input: call.input, output });
495
+ messages.push({ role: "tool", content: JSON.stringify(output) });
496
+ } catch (err) {
497
+ const msg = err instanceof Error ? err.message : String(err);
498
+ this.emit({ type: "error", agent: agent.name, message: `Tool ${call.name} threw: ${msg}` });
499
+ messages.push({ role: "tool", content: `error: ${msg}` });
500
+ }
501
+ }
502
+ continue;
503
+ }
504
+ finalOutput = response.content;
505
+ messages.push({ role: "assistant", content: finalOutput });
506
+ break;
507
+ }
508
+ this.emit({ type: "agent_output", agent: agent.name, output: finalOutput });
509
+ const verifier_results = [];
510
+ for (const v of agent.verifiers) {
511
+ try {
512
+ const result = await v.check(finalOutput);
513
+ verifier_results.push(result);
514
+ this.emit({ type: "verifier_run", agent: agent.name, kernel: v.name, result });
515
+ } catch (err) {
516
+ this.emit({
517
+ type: "error",
518
+ agent: agent.name,
519
+ message: `Verifier ${v.name} threw: ${err instanceof Error ? err.message : String(err)}`
520
+ });
521
+ }
522
+ }
523
+ const latency_ms = Date.now() - startedAt;
524
+ return {
525
+ agent: agent.name,
526
+ output: finalOutput,
527
+ tool_calls: toolCalls,
528
+ verifier_results,
529
+ tokens_used: { input: tokensIn, output: tokensOut },
530
+ cost_usd: 0,
531
+ // adapter-specific; populated by adapter
532
+ latency_ms
533
+ };
534
+ }
535
+ /**
536
+ * Run a Council on a query.
537
+ *
538
+ * Fan out to all specialists in parallel (with timeout), gather outputs,
539
+ * run council-level verifier kernels on each, and reconcile.
540
+ */
541
+ async runCouncil(council, query) {
542
+ const startedAt = Date.now();
543
+ this.emit({ type: "council_start", council: council.name, query });
544
+ const withTimeout = (p, ms) => Promise.race([
545
+ p,
546
+ new Promise((resolve) => setTimeout(() => resolve(null), ms))
547
+ ]);
548
+ const specialistResults = await Promise.all(
549
+ council.specialists.map(async (spec) => {
550
+ try {
551
+ const result = await withTimeout(this.run(spec, query), council.specialist_timeout_ms);
552
+ if (result === null) {
553
+ this.emit({
554
+ type: "error",
555
+ agent: spec.name,
556
+ message: `Specialist timed out after ${council.specialist_timeout_ms}ms`
557
+ });
558
+ return null;
559
+ }
560
+ const councilVerifierResults = [];
561
+ for (const v of council.verifiers) {
562
+ try {
563
+ const r = await v.check(result.output);
564
+ councilVerifierResults.push(r);
565
+ this.emit({ type: "verifier_run", agent: spec.name, kernel: v.name, result: r });
566
+ } catch (err) {
567
+ this.emit({
568
+ type: "error",
569
+ agent: spec.name,
570
+ message: `Council verifier ${v.name} threw: ${err instanceof Error ? err.message : String(err)}`
571
+ });
572
+ }
573
+ }
574
+ const out = {
575
+ specialist: spec.name,
576
+ output: result.output,
577
+ claims: [],
578
+ // claim extraction is the reconciler's job
579
+ // AgentResult.verifier_results widens issues to unknown[]; at the
580
+ // runtime layer we know every entry came from a Verifier.check()
581
+ // call (which produces VerifierIssue[]), so the cast is sound.
582
+ verifier_results: [
583
+ ...result.verifier_results,
584
+ ...councilVerifierResults
585
+ ],
586
+ cost_usd: result.cost_usd,
587
+ latency_ms: result.latency_ms
588
+ };
589
+ this.emit({ type: "specialist_done", specialist: spec.name, output: out });
590
+ return out;
591
+ } catch (err) {
592
+ this.emit({
593
+ type: "error",
594
+ agent: spec.name,
595
+ message: err instanceof Error ? err.message : String(err)
596
+ });
597
+ return null;
598
+ }
599
+ })
600
+ );
601
+ const survivors = specialistResults.filter((s) => s !== null);
602
+ const reconciled = await council.reconciler(survivors);
603
+ const output = {
604
+ answer: reconciled.answer,
605
+ specialists: survivors,
606
+ consensus: reconciled.consensus,
607
+ disagreements: reconciled.disagreements,
608
+ total_cost_usd: survivors.reduce((s, x) => s + x.cost_usd, 0),
609
+ total_latency_ms: Date.now() - startedAt
610
+ };
611
+ this.emit({ type: "council_done", council: council.name, output });
612
+ return output;
613
+ }
614
+ };
615
+
616
+ // src/mcp/index.ts
617
+ var MCP_PROTOCOL_VERSION = "2024-11-05";
618
+ var DEFAULT_TIMEOUT_MS = 12e3;
619
+ var MCPClient = class {
620
+ config;
621
+ initialized = false;
622
+ toolCache = null;
623
+ constructor(config) {
624
+ if (!/^[a-z0-9_-]+$/.test(config.slug)) {
625
+ throw new Error(
626
+ `MCPClient slug "${config.slug}" must match /^[a-z0-9_-]+$/`
627
+ );
628
+ }
629
+ this.config = { timeout_ms: DEFAULT_TIMEOUT_MS, ...config };
630
+ }
631
+ /** Fetch the server's tool catalog. Cached for the lifetime of the client. */
632
+ async listTools(signal) {
633
+ if (this.toolCache) return this.toolCache;
634
+ await this.ensureInitialized(signal);
635
+ const result = await this.rpc("tools/list", {}, signal);
636
+ this.toolCache = Array.isArray(result?.tools) ? result.tools : [];
637
+ return this.toolCache;
638
+ }
639
+ /** Call a tool by its bare (non-namespaced) name. Returns the text payload. */
640
+ async callTool(name, args, signal) {
641
+ await this.ensureInitialized(signal);
642
+ const result = await this.rpc(
643
+ "tools/call",
644
+ { name, arguments: args },
645
+ signal
646
+ );
647
+ const blocks = Array.isArray(result?.content) ? result.content : [];
648
+ const text = blocks.map((b) => b.type === "text" && typeof b.text === "string" ? b.text : "").filter(Boolean).join("\n").trim();
649
+ return text || JSON.stringify(result ?? {}).slice(0, 4e3);
650
+ }
651
+ /**
652
+ * Return the server's tool catalog as SDK Tool[] objects, namespaced so they
653
+ * compose with tools from other sources without colliding.
654
+ *
655
+ * Pass these directly to a Runner. The Runner sees standard SDK tools; it
656
+ * never has to know MCP existed.
657
+ */
658
+ async asTools(signal) {
659
+ const raw = await this.listTools(signal);
660
+ return raw.map((t) => this.toSdkTool(t));
661
+ }
662
+ /** Health-check: returns toolCount on success, throws on failure. */
663
+ async probe(signal) {
664
+ const tools = await this.listTools(signal);
665
+ return { toolCount: tools.length };
666
+ }
667
+ // -------------------------------------------------------------- internals
668
+ toSdkTool(raw) {
669
+ const ns = `${this.config.slug}__${raw.name}`.slice(0, 64).replace(/[^a-zA-Z0-9_-]/g, "_");
670
+ const schema = {
671
+ name: ns,
672
+ description: `[${this.config.name}] ${raw.description || raw.name}`,
673
+ input_schema: raw.inputSchema ?? {
674
+ type: "object",
675
+ properties: {}
676
+ }
677
+ };
678
+ const client = this;
679
+ return {
680
+ schema,
681
+ async execute(input, _ctx) {
682
+ return client.callTool(raw.name, input);
683
+ }
684
+ };
685
+ }
686
+ async ensureInitialized(signal) {
687
+ if (this.initialized) return;
688
+ await this.rpc(
689
+ "initialize",
690
+ {
691
+ protocolVersion: MCP_PROTOCOL_VERSION,
692
+ capabilities: {},
693
+ clientInfo: { name: "theron-agent-sdk", version: "0.1" }
694
+ },
695
+ signal
696
+ );
697
+ this.rpc("notifications/initialized", {}, signal).catch(() => void 0);
698
+ this.initialized = true;
699
+ }
700
+ async rpc(method, params, externalSignal) {
701
+ const ac = new AbortController();
702
+ const timer = setTimeout(
703
+ () => ac.abort(),
704
+ this.config.timeout_ms ?? DEFAULT_TIMEOUT_MS
705
+ );
706
+ if (externalSignal) {
707
+ if (externalSignal.aborted) ac.abort();
708
+ else externalSignal.addEventListener("abort", () => ac.abort());
709
+ }
710
+ const body = {
711
+ jsonrpc: "2.0",
712
+ id: Date.now() + Math.floor(Math.random() * 1e3),
713
+ method,
714
+ params
715
+ };
716
+ try {
717
+ const r = await fetch(this.config.url, {
718
+ method: "POST",
719
+ signal: ac.signal,
720
+ headers: {
721
+ "Content-Type": "application/json",
722
+ Accept: "application/json, text/event-stream",
723
+ ...this.config.token ? { Authorization: `Bearer ${this.config.token}` } : {},
724
+ "MCP-Protocol-Version": MCP_PROTOCOL_VERSION
725
+ },
726
+ body: JSON.stringify(body)
727
+ });
728
+ if (!r.ok) {
729
+ const errText = await r.text().catch(() => "");
730
+ throw new Error(
731
+ `mcp http ${r.status} on ${method}: ${errText.slice(0, 200)}`
732
+ );
733
+ }
734
+ const ct = r.headers.get("content-type") || "";
735
+ if (ct.includes("text/event-stream")) {
736
+ const text = await r.text();
737
+ const m = text.match(/data:\s*(\{[\s\S]*?\})\s*\n/);
738
+ if (!m) throw new Error("mcp sse stream had no data event");
739
+ const env2 = JSON.parse(m[1]);
740
+ if (env2.error) throw new Error(`mcp error: ${env2.error.message}`);
741
+ return env2.result;
742
+ }
743
+ const env = await r.json();
744
+ if (env.error) throw new Error(`mcp error: ${env.error.message}`);
745
+ return env.result;
746
+ } finally {
747
+ clearTimeout(timer);
748
+ }
749
+ }
750
+ };
751
+ async function collectMcpTools(clients, signal) {
752
+ const lists = await Promise.all(
753
+ clients.map(async (c) => {
754
+ try {
755
+ return await c.asTools(signal);
756
+ } catch (err) {
757
+ console.warn(`[mcp] ${c.config.slug} listTools failed:`, err);
758
+ return [];
759
+ }
760
+ })
761
+ );
762
+ return lists.flat();
763
+ }
764
+
765
+ // src/adapters/theron.ts
766
+ function theronAdapter(opts = {}) {
767
+ const base = (opts.base ?? "https://itstheron.com").replace(/\/$/, "");
768
+ const url = `${base}/api/v1/chat/completions`;
769
+ const councilMode = opts.councilMode ?? "fast";
770
+ return {
771
+ name: "theron",
772
+ async chat({ model, messages, tools, max_tokens, temperature, onDelta }) {
773
+ const body = {
774
+ model: model || "theron-council",
775
+ council_mode: councilMode,
776
+ messages,
777
+ max_tokens: max_tokens ?? 2048,
778
+ temperature: temperature ?? 0.2,
779
+ stream: !!onDelta
780
+ };
781
+ if (tools && tools.length > 0) {
782
+ body.tools = tools.map((t) => ({
783
+ type: "function",
784
+ function: { name: t.name, description: t.description, parameters: t.input_schema }
785
+ }));
786
+ }
787
+ const headers = { "Content-Type": "application/json" };
788
+ if (opts.apiKey) headers.Authorization = `Bearer ${opts.apiKey}`;
789
+ const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
790
+ if (!res.ok) {
791
+ throw new Error(`Theron ${res.status} (${url}): ${(await res.text().catch(() => "")).slice(0, 500)}`);
792
+ }
793
+ if (onDelta && res.body) {
794
+ const reader = res.body.getReader();
795
+ const decoder = new TextDecoder();
796
+ let content = "";
797
+ let inputTokens = 0;
798
+ let outputTokens = 0;
799
+ let buf = "";
800
+ for (; ; ) {
801
+ const { value, done } = await reader.read();
802
+ if (done) break;
803
+ buf += decoder.decode(value, { stream: true });
804
+ const lines = buf.split("\n");
805
+ buf = lines.pop() ?? "";
806
+ for (const line of lines) {
807
+ if (!line.startsWith("data:")) continue;
808
+ const data = line.slice(5).trim();
809
+ if (!data || data === "[DONE]") continue;
810
+ try {
811
+ const json2 = JSON.parse(data);
812
+ const delta = json2.choices?.[0]?.delta?.content;
813
+ if (delta) {
814
+ onDelta(delta);
815
+ content += delta;
816
+ }
817
+ if (json2.usage) {
818
+ inputTokens = json2.usage.prompt_tokens ?? inputTokens;
819
+ outputTokens = json2.usage.completion_tokens ?? outputTokens;
820
+ }
821
+ } catch {
822
+ }
823
+ }
824
+ }
825
+ return { content, tokens: { input: inputTokens, output: outputTokens } };
826
+ }
827
+ const json = await res.json();
828
+ const msg = json.choices?.[0]?.message ?? { content: "" };
829
+ const tool_calls = msg.tool_calls?.map((tc) => ({
830
+ name: tc.function.name,
831
+ input: safeJson(tc.function.arguments)
832
+ }));
833
+ return {
834
+ content: msg.content ?? "",
835
+ tool_calls,
836
+ tokens: {
837
+ input: json.usage?.prompt_tokens ?? 0,
838
+ output: json.usage?.completion_tokens ?? 0
839
+ }
840
+ };
841
+ }
842
+ };
843
+ }
844
+ var theron = theronAdapter;
845
+ function safeJson(s) {
846
+ try {
847
+ return JSON.parse(s || "{}");
848
+ } catch {
849
+ return {};
850
+ }
851
+ }
852
+
853
+ // src/receipts/index.ts
854
+ var ReceiptEmitter = class {
855
+ sinks;
856
+ signer;
857
+ issuer;
858
+ actor;
859
+ tenant_id;
860
+ constructor(config) {
861
+ if (!config.sinks || config.sinks.length === 0) {
862
+ throw new Error("ReceiptEmitter requires at least one sink.");
863
+ }
864
+ this.sinks = config.sinks;
865
+ this.signer = config.signer;
866
+ this.issuer = config.signer?.issuer ?? config.issuer ?? "did:web:local";
867
+ this.actor = config.actor;
868
+ this.tenant_id = config.tenant_id;
869
+ }
870
+ async emit(input) {
871
+ const ts = Date.now();
872
+ const payload = {
873
+ input: input.input,
874
+ output: input.output,
875
+ ...input.metadata !== void 0 ? { metadata: input.metadata } : {}
876
+ };
877
+ const content_hash = await sha256Hex(canonicalize(payload));
878
+ let receipt = {
879
+ v: "stoa.receipt.v1",
880
+ id: ulid(),
881
+ cap: input.cap,
882
+ issuer: this.issuer,
883
+ actor: input.actor ?? this.actor,
884
+ ts,
885
+ session_id: input.session_id,
886
+ tenant_id: input.tenant_id ?? this.tenant_id,
887
+ content_hash,
888
+ payload
889
+ };
890
+ if (this.signer) {
891
+ const signature = await this.signer.sign(receipt);
892
+ receipt = { ...receipt, signature };
893
+ }
894
+ await Promise.all(
895
+ this.sinks.map(async (sink) => {
896
+ try {
897
+ await sink.emit(receipt);
898
+ } catch (err) {
899
+ console.warn(`[receipts] sink "${sink.name}" failed:`, err);
900
+ }
901
+ })
902
+ );
903
+ return receipt;
904
+ }
905
+ };
906
+ var InMemoryReceiptSink = class {
907
+ name = "in-memory";
908
+ records = [];
909
+ async emit(receipt) {
910
+ this.records.push(receipt);
911
+ }
912
+ list() {
913
+ return this.records;
914
+ }
915
+ clear() {
916
+ this.records.length = 0;
917
+ }
918
+ };
919
+ function fileReceiptSink(path) {
920
+ return {
921
+ name: `file:${path}`,
922
+ async emit(receipt) {
923
+ const fs = await import('fs/promises');
924
+ await fs.appendFile(path, JSON.stringify(receipt) + "\n", "utf8");
925
+ }
926
+ };
927
+ }
928
+ function httpReceiptSink(opts) {
929
+ const timeout_ms = opts.timeout_ms ?? 5e3;
930
+ return {
931
+ name: `http:${new URL(opts.url).host}`,
932
+ async emit(receipt) {
933
+ const ac = new AbortController();
934
+ const timer = setTimeout(() => ac.abort(), timeout_ms);
935
+ try {
936
+ const res = await fetch(opts.url, {
937
+ method: "POST",
938
+ signal: ac.signal,
939
+ headers: {
940
+ "Content-Type": "application/json",
941
+ ...opts.token ? { Authorization: `Bearer ${opts.token}` } : {}
942
+ },
943
+ body: JSON.stringify(receipt)
944
+ });
945
+ if (!res.ok) {
946
+ const text = await res.text().catch(() => "");
947
+ throw new Error(
948
+ `http sink ${opts.url} returned ${res.status}: ${text.slice(0, 200)}`
949
+ );
950
+ }
951
+ } finally {
952
+ clearTimeout(timer);
953
+ }
954
+ }
955
+ };
956
+ }
957
+ function canonicalize(value) {
958
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
959
+ if (Array.isArray(value)) {
960
+ return "[" + value.map((v) => canonicalize(v)).join(",") + "]";
961
+ }
962
+ const keys = Object.keys(value).sort();
963
+ return "{" + keys.map(
964
+ (k) => JSON.stringify(k) + ":" + canonicalize(value[k])
965
+ ).join(",") + "}";
966
+ }
967
+ async function sha256Hex(input) {
968
+ const data = new TextEncoder().encode(input);
969
+ const buf = await globalThis.crypto.subtle.digest("SHA-256", data);
970
+ const bytes = new Uint8Array(buf);
971
+ let hex = "";
972
+ for (let i = 0; i < bytes.length; i++) {
973
+ hex += bytes[i].toString(16).padStart(2, "0");
974
+ }
975
+ return hex;
976
+ }
977
+ function ulid() {
978
+ const ts = Date.now();
979
+ const ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
980
+ let tsPart = "";
981
+ let t = ts;
982
+ for (let i = 9; i >= 0; i--) {
983
+ tsPart = ALPHABET[t % 32] + tsPart;
984
+ t = Math.floor(t / 32);
985
+ }
986
+ let randPart = "";
987
+ if (globalThis.crypto?.getRandomValues) {
988
+ const bytes = new Uint8Array(16);
989
+ globalThis.crypto.getRandomValues(bytes);
990
+ for (let i = 0; i < 16; i++) randPart += ALPHABET[bytes[i] % 32];
991
+ } else {
992
+ for (let i = 0; i < 16; i++)
993
+ randPart += ALPHABET[Math.floor(Math.random() * 32)];
994
+ }
995
+ return tsPart + randPart;
996
+ }
997
+
998
+ // src/loop/index.ts
999
+ function stepCountIs(n) {
1000
+ return (s) => s.step >= n;
1001
+ }
1002
+ function costUsdAtLeast(min) {
1003
+ return (s) => s.cost_usd >= min;
1004
+ }
1005
+ function verifierSatisfied(kernelName) {
1006
+ return (s) => {
1007
+ if (!s.verifier_results) return false;
1008
+ return s.verifier_results.some((r) => r.kernel === kernelName && r.pass === true);
1009
+ };
1010
+ }
1011
+ function anyOf(...preds) {
1012
+ return (s) => preds.some((p) => p(s));
1013
+ }
1014
+ function allOf(...preds) {
1015
+ return (s) => preds.every((p) => p(s));
1016
+ }
1017
+ function verifiedRatchet(opts) {
1018
+ const threshold = opts?.minConfidence ?? 0.6;
1019
+ return (v) => {
1020
+ if (v === void 0) {
1021
+ return { advance: false, reason: "no verdict" };
1022
+ }
1023
+ if (v.verdict !== "sufficient") {
1024
+ return {
1025
+ advance: false,
1026
+ reason: `verdict '${v.verdict}' is not 'sufficient'${v.source ? ` (source: ${v.source})` : ""}`
1027
+ };
1028
+ }
1029
+ if (v.confidence < threshold) {
1030
+ return {
1031
+ advance: false,
1032
+ reason: `verdict is 'sufficient' but confidence ${v.confidence.toFixed(3)} < threshold ${threshold.toFixed(3)}`
1033
+ };
1034
+ }
1035
+ return {
1036
+ advance: true,
1037
+ reason: `verified sufficient at confidence ${v.confidence.toFixed(3)} >= ${threshold.toFixed(3)}${v.source ? ` (source: ${v.source})` : ""}`
1038
+ };
1039
+ };
1040
+ }
1041
+ async function runImprovementCycle(spec) {
1042
+ const ratchet = spec.ratchet ?? verifiedRatchet();
1043
+ const proposal = await spec.propose();
1044
+ const trial = await spec.trial(proposal);
1045
+ const verdict = await spec.verify(proposal, trial);
1046
+ const decision = ratchet(verdict);
1047
+ return { proposal, trial, verdict, decision };
1048
+ }
1049
+ var SUMMARY_PREFIX = "[Summary of earlier conversation]";
1050
+ async function compactHistory(opts) {
1051
+ const keepRecent = Math.max(1, Math.floor(opts.keepRecent ?? 6));
1052
+ const msgs = opts.messages ?? [];
1053
+ const totalChars = msgs.reduce((n, m) => n + (m.content?.length ?? 0), 0);
1054
+ const maxChars = opts.maxChars ?? 0;
1055
+ if (msgs.length <= keepRecent || maxChars > 0 && totalChars <= maxChars) {
1056
+ return { messages: msgs, compacted: false, droppedCount: 0 };
1057
+ }
1058
+ const older = msgs.slice(0, msgs.length - keepRecent);
1059
+ const recent = msgs.slice(msgs.length - keepRecent);
1060
+ const summary = String(await opts.summarize(older));
1061
+ return {
1062
+ messages: [{ role: "system", content: `${SUMMARY_PREFIX}
1063
+ ${summary}` }, ...recent],
1064
+ compacted: true,
1065
+ summary,
1066
+ droppedCount: older.length
1067
+ };
1068
+ }
1069
+ async function runUntil(opts) {
1070
+ const maxSteps = Math.max(1, Math.floor(opts.maxSteps ?? 100));
1071
+ let state = opts.initial;
1072
+ for (let i = 0; i < maxSteps; i++) {
1073
+ state = await opts.step(state, i);
1074
+ if (opts.onCheckpoint) await opts.onCheckpoint(state, i);
1075
+ if (opts.stopWhen(state, i)) return { state, steps: i + 1, stopped: "predicate" };
1076
+ }
1077
+ return { state, steps: maxSteps, stopped: "maxSteps" };
1078
+ }
1079
+ function boundWorkingSet(items, max) {
1080
+ const cap = Math.max(0, Math.floor(max));
1081
+ if (items.length <= cap) return { kept: items, evicted: [] };
1082
+ const pinned = items.filter((i) => i.pinned);
1083
+ const rest = items.filter((i) => !i.pinned);
1084
+ const slots = Math.max(0, cap - pinned.length);
1085
+ const ranked = [...rest].sort((a, b) => (b.importance ?? 0) - (a.importance ?? 0) || b.seq - a.seq);
1086
+ const keepRest = new Set(ranked.slice(0, slots));
1087
+ const kept = items.filter((i) => i.pinned || keepRest.has(i));
1088
+ const evicted = items.filter((i) => !i.pinned && !keepRest.has(i));
1089
+ return { kept, evicted };
1090
+ }
1091
+
1092
+ // src/patterns/index.ts
1093
+ async function selfConsistency(opts) {
1094
+ const n = Math.max(1, Math.floor(opts.samples));
1095
+ const keyOf = opts.key ?? ((v) => JSON.stringify(v));
1096
+ const clusters = /* @__PURE__ */ new Map();
1097
+ let total = 0;
1098
+ for (let i = 0; i < n; i++) {
1099
+ const v = await opts.generate(i);
1100
+ if (v === void 0 || v === null) continue;
1101
+ total += 1;
1102
+ const k = keyOf(v);
1103
+ const c = clusters.get(k) ?? { count: 0, sample: v };
1104
+ c.count += 1;
1105
+ clusters.set(k, c);
1106
+ }
1107
+ if (total === 0) throw new Error("selfConsistency: generate produced no values");
1108
+ const ranked = [...clusters.entries()].map(([key, { count, sample }]) => ({ key, count, sample })).sort((a, b) => b.count - a.count);
1109
+ const winner = ranked[0];
1110
+ return {
1111
+ answer: winner.sample,
1112
+ consistency: Math.round(winner.count / total * 1e3) / 1e3,
1113
+ votes: winner.count,
1114
+ total,
1115
+ clusters: ranked
1116
+ };
1117
+ }
1118
+ async function bestOfN(opts) {
1119
+ const n = Math.max(1, Math.floor(opts.n));
1120
+ let best = null;
1121
+ const scores = [];
1122
+ for (let i = 0; i < n; i++) {
1123
+ const v = await opts.generate(i);
1124
+ const s = await opts.score(v, i);
1125
+ scores.push(s);
1126
+ if (!best || s > best.score) best = { value: v, score: s, index: i };
1127
+ }
1128
+ if (!best) throw new Error("bestOfN: generate produced no candidates");
1129
+ return { best: best.value, score: best.score, index: best.index, scores };
1130
+ }
1131
+ var DEFAULT_CLEAN = /\b(no (issues|problems|flaws|changes)|looks good|lgtm|nothing to (fix|improve))\b/i;
1132
+ async function selfRefine(opts) {
1133
+ const maxIters = Math.max(1, Math.floor(opts.maxIters ?? 2));
1134
+ const isClean = opts.isClean ?? ((c) => DEFAULT_CLEAN.test(c));
1135
+ let value = await opts.draft();
1136
+ const trace = [];
1137
+ let revised = 0;
1138
+ for (let iter = 1; iter <= maxIters; iter++) {
1139
+ const critique = String(await opts.critique(value, iter));
1140
+ if (isClean(critique)) {
1141
+ trace.push({ iter, critique, revised: false });
1142
+ break;
1143
+ }
1144
+ value = await opts.revise(value, critique, iter);
1145
+ revised += 1;
1146
+ trace.push({ iter, critique, revised: true });
1147
+ }
1148
+ return { answer: value, iterations: trace.length, revised, trace };
1149
+ }
1150
+ async function treeOfThoughts(opts) {
1151
+ const breadth = Math.max(1, Math.floor(opts.breadth));
1152
+ const depth = Math.max(1, Math.floor(opts.depth));
1153
+ const path = [];
1154
+ const scored = [];
1155
+ for (let d = 0; d < depth; d++) {
1156
+ let best = null;
1157
+ for (let b = 0; b < breadth; b++) {
1158
+ const cand = await opts.expand(path, b);
1159
+ const s = await opts.score(cand, path);
1160
+ if (!best || s > best.score) best = { thought: cand, score: s };
1161
+ }
1162
+ if (!best) break;
1163
+ path.push(best.thought);
1164
+ scored.push(best);
1165
+ }
1166
+ const answer = opts.synthesize ? await opts.synthesize(path) : path[path.length - 1];
1167
+ return { answer, path: scored };
1168
+ }
1169
+ async function chainOfVerification(opts) {
1170
+ const draft = await opts.draft();
1171
+ const questions = await opts.planChecks(draft) ?? [];
1172
+ const checks = [];
1173
+ for (const q of questions) {
1174
+ checks.push({ q, a: String(await opts.answerCheck(q)) });
1175
+ }
1176
+ const answer = checks.length ? await opts.revise(draft, checks) : draft;
1177
+ return { answer, checks };
1178
+ }
1179
+ async function reflexion(opts) {
1180
+ const maxAttempts = Math.max(1, Math.floor(opts.maxAttempts));
1181
+ const reflections = [];
1182
+ let last;
1183
+ for (let i = 0; i < maxAttempts; i++) {
1184
+ last = await opts.attempt(reflections, i);
1185
+ const { success, feedback } = await opts.evaluate(last, i);
1186
+ if (success) return { answer: last, attempts: i + 1, succeeded: true, reflections };
1187
+ if (i < maxAttempts - 1) reflections.push(String(await opts.reflect(last, feedback, i)));
1188
+ }
1189
+ return { answer: last, attempts: maxAttempts, succeeded: false, reflections };
1190
+ }
1191
+ async function mixtureOfAgents(opts) {
1192
+ const agents = Math.max(1, Math.floor(opts.agents));
1193
+ const layers = Math.max(1, Math.floor(opts.layers));
1194
+ const layerOutputs = [];
1195
+ let current = [];
1196
+ for (let a = 0; a < agents; a++) current.push(String(await opts.propose(a)));
1197
+ layerOutputs.push([...current]);
1198
+ for (let layer = 2; layer <= layers; layer++) {
1199
+ if (!opts.refine) break;
1200
+ const next = [];
1201
+ for (let a = 0; a < agents; a++) {
1202
+ const others = current.filter((_, i) => i !== a);
1203
+ next.push(String(await opts.refine(a, others, layer)));
1204
+ }
1205
+ current = next;
1206
+ layerOutputs.push([...current]);
1207
+ }
1208
+ const answer = String(await opts.aggregate(current));
1209
+ return { answer, layerOutputs };
1210
+ }
1211
+ var mean = (xs) => xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0;
1212
+ var round = (x) => Math.round(x * 1e3) / 1e3;
1213
+ async function measureLift(opts) {
1214
+ const perTask = [];
1215
+ const baseScores = [];
1216
+ const treatScores = [];
1217
+ let wins = 0;
1218
+ for (let i = 0; i < opts.tasks.length; i++) {
1219
+ const task = opts.tasks[i];
1220
+ const bOut = await opts.baseline(task, i);
1221
+ const tOut = await opts.treatment(task, i);
1222
+ const b = await opts.score(task, bOut, i);
1223
+ const t = await opts.score(task, tOut, i);
1224
+ baseScores.push(b);
1225
+ treatScores.push(t);
1226
+ if (t > b) wins += 1;
1227
+ perTask.push({ task, baseline: round(b), treatment: round(t), delta: round(t - b) });
1228
+ }
1229
+ const baselineMean = round(mean(baseScores));
1230
+ const treatmentMean = round(mean(treatScores));
1231
+ return {
1232
+ n: opts.tasks.length,
1233
+ baselineMean,
1234
+ treatmentMean,
1235
+ lift: round(treatmentMean - baselineMean),
1236
+ winRate: opts.tasks.length ? round(wins / opts.tasks.length) : 0,
1237
+ perTask
1238
+ };
1239
+ }
1240
+
1241
+ // src/index.ts
1242
+ var VERSION = "0.3.0";
1243
+
1244
+ export { Agent, Council, InMemoryReceiptSink, InMemoryStore, LOCAL_TOOL_NAMES, LOCAL_TOOL_PARAMETERS, MCPClient, MUTATING_LOCAL_TOOLS, Memory, ReceiptEmitter, Runner, Session, VERSION, VerifierKernels, allOf, anyOf, bestOfN, boundWorkingSet, buildLocalToolSchemas, chainOfVerification, collectMcpTools, compactHistory, costUsdAtLeast, defineTool, defineVerifier, fileReceiptSink, httpReceiptSink, measureLift, mixtureOfAgents, reflexion, runImprovementCycle, runUntil, selfConsistency, selfRefine, stepCountIs, theron, theronAdapter, treeOfThoughts, verifiedRatchet, verifierSatisfied };