@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/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@vextlabs/theron-agent-sdk` are documented here.
4
+ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.3.0] - 2026-06-13
9
+
10
+ ### Added
11
+ - **`patterns`** primitives — framework-agnostic, verifier/score-gated reasoning patterns no public agent SDK ships as first-class composables: `selfConsistency` (sample N paths → majority answer + agreement ratio), `bestOfN` (verifier-guided best-of-N), `selfRefine` (draft → critique → revise, early-exit when clean), `treeOfThoughts` (best-first branch/score/expand search), `chainOfVerification` (draft → verify claims independently → revise; hallucination reduction), `mixtureOfAgents` (layered multi-agent propose → refine-seeing-peers → aggregate), `reflexion` (retry with accumulated verbal reflections; learns from outcome feedback, not just output quality). Provider-agnostic (take async `generate`/`score`/`verify`/`critique` fns); pure, deterministic, zero-network. The SDK-side counterparts of Theron's server Hive loops.
12
+ - **`measureLift`** — measure a pattern/loop's score lift + win-rate over a single-shot baseline on a task set. The empirical backbone for proving the harness beats raw single-shot ("the system is the moat") rather than asserting it. Pure; no benchmark framework required.
13
+ - **`loop`** primitives: `verifiedRatchet` (advance only on a confident verifier pass), verifier-in-the-loop `stopWhen` predicates (`stepCountIs`/`costUsdAtLeast`/`verifierSatisfied`/`anyOf`/`allOf`), `runImprovementCycle`.
14
+ - **Long-horizon primitives** — `compactHistory` (summarize-and-continue: fold older messages into a summary, keep recent verbatim, so a conversation/loop runs far past the context window), `runUntil` (a bounded, checkpointable long-horizon driver: run `step` until a predicate holds or `maxSteps`, with an `onCheckpoint` hook for durable resume), and `boundWorkingSet` (keep a long agent's working memory bounded by importance + recency; pinned items never evicted). Provider-agnostic + pure. The "run soo long, hold soo much context" kit.
15
+
16
+ ## [0.1.0] - 2026-05-23
17
+
18
+ First stable npm release. The five primitives and the runtime ship under the
19
+ `@vextlabs/theron-agent-sdk` name with no API breaks expected through the 0.1
20
+ line.
21
+
22
+ ### Added (v0.1.0 release polish)
23
+ - **`Receipts`** primitive: `ReceiptEmitter` + `InMemoryReceiptSink` + `fileReceiptSink` + `httpReceiptSink` + `ReceiptSigner` interface. Stoa-shaped receipts (`stoa.receipt.v1`) with deterministic SHA-256 content hash, ULID ids, optional detached signature. Importable as `@vextlabs/theron-agent-sdk/receipts` for tree-shake.
24
+ - **Three sample agents** that ship in `examples/`:
25
+ - `cyber-recon-bot.ts` — passive recon (subdomains → ports → TLS → tech), receipts per tool call.
26
+ - `meeting-prep-bot.ts` — one-page meeting brief from calendar + docs + memory.
27
+ - `support-triage-bot.ts` — three-specialist Council that classifies + retrieves + drafts a reply, with the routing decision emitted as a signable receipt.
28
+ - New tests at `test/receipts.test.ts` cover canonicalization, signing, sink fan-out, ULID ordering, and sink-failure isolation.
29
+
30
+ ### Added
31
+ - **`Agent`** primitive: model + instruction + tools + sub-agents + verifier kernels.
32
+ - **`Council`** primitive: N specialists + verifier kernels + reconciler. Built-in deterministic claim-merge reconciler; bring your own for semantic merging.
33
+ - **`Session`** primitive: append-only event log + scoped state, with `toJSON` / `fromJSON` for persistence.
34
+ - **`Memory`** primitive with `InMemoryStore` reference implementation. Tenant-scoped; ready to swap in pgvector, R2, SQLite, etc.
35
+ - **`defineTool`** factory backed by Zod schemas (auto-converts to JSON schema for OpenAI/Anthropic-style tool calls).
36
+ - **`defineVerifier`** factory + `VerifierKernels.{emDash, aiIsm, arithmetic, citationPresence}` built-ins.
37
+ - **`Runner`** with pluggable `ModelAdapter` interface. Streams events (`agent_thinking`, `tool_call_*`, `verifier_run`, `council_done`, etc.). Supports per-specialist timeouts in `runCouncil`.
38
+ - **Reference adapters** in `examples/adapters/`:
39
+ - `openrouter.ts` — works against 200+ models with SSE streaming + tool-call buffering.
40
+ - `theron.ts` — points at the hosted Vext Theron endpoint at `tryvext.com/api/theron-chat-phased`.
41
+ - **Three runnable examples**: `basic-agent.ts`, `council-deliberation.ts`, `verifier-kernel.ts`.
42
+ - **MCP client** at `@vextlabs/theron-agent-sdk/mcp` — `MCPClient` speaks the Model Context Protocol over streamable HTTP / SSE. `collectMcpTools()` collapses multiple servers into one namespaced `Tool[]`. Tests land in v0.1.x.
43
+
44
+ ### Build & tooling
45
+ - Switched build from `tsc` to **`tsup`**. Emits ESM + CJS + `.d.ts` for every entry point. Tree-shakeable.
46
+ - Added **`vitest`** test suite with 58 tests covering the 5 primitives + runtime + built-in kernels.
47
+ - Added **`@vitest/coverage-v8`** with thresholds at 80% lines / 80% functions / 70% branches; current coverage 95%+ lines.
48
+ - Added **`typedoc`** for API reference generation (`npm run docs`); output lands in `docs/`.
49
+
50
+ ### Notes
51
+ - Runner's `runCouncil` passes `claims: []` to the reconciler — claim extraction is the reconciler's job. The default deterministic reconciler therefore returns `refuted` for generic prose; swap in a semantic reconciler or a claim-extracting one for production deliberation.
52
+ - The MCP subpath is excluded from the 80% coverage threshold pending dedicated tests.
53
+
54
+ ## [0.1.0-alpha] - 2026-05-12
55
+
56
+ Pre-release. SDK surface defined under five primitives; `tsc` build; node `--test` harness; sample agents under numeric prefixes (`01_*`, `02_*`, `03_*`).
57
+
58
+ [0.1.0]: https://github.com/Vext-Labs-Inc/theron-agent-sdk/releases/tag/v0.1.0
59
+ [0.1.0-alpha]: https://github.com/Vext-Labs-Inc/theron-agent-sdk/releases/tag/v0.1.0-alpha
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vext Labs, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # Theron Agent SDK
2
+
3
+ > Build agents that work, with receipts you can verify. Any model. MIT.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@vextlabs/theron-agent-sdk.svg)](https://www.npmjs.com/package/@vextlabs/theron-agent-sdk)
6
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![node](https://img.shields.io/badge/node-%E2%89%A520-brightgreen.svg)](https://nodejs.org/)
8
+ [![tests](https://img.shields.io/badge/tests-64%20passing-brightgreen.svg)](#tests)
9
+
10
+ ```sh
11
+ npm install @vextlabs/theron-agent-sdk
12
+ ```
13
+
14
+ ```ts
15
+ import { Agent, Runner } from "@vextlabs/theron-agent-sdk";
16
+ import { openrouterAdapter } from "@vextlabs/theron-agent-sdk/examples/adapters/openrouter.js";
17
+
18
+ const agent = new Agent({ name: "helper", instruction: "Answer helpfully." });
19
+ const runner = new Runner({ model: openrouterAdapter({ apiKey: process.env.OPENROUTER_API_KEY! }), default_model: "openai/gpt-4o-mini" });
20
+ const result = await runner.run(agent, "What's 2+2?");
21
+ console.log(result.output);
22
+ ```
23
+
24
+ That is a runnable agent in five lines. Requires Node 20+. An `OPENROUTER_API_KEY` gets you 200+ models through one adapter; swap in Anthropic, OpenAI, or your own OSS endpoint by writing a 30-line `ModelAdapter`.
25
+
26
+ ---
27
+
28
+ ## 15-line Council
29
+
30
+ ```ts
31
+ import { Agent, Council, Runner, VerifierKernels } from "@vextlabs/theron-agent-sdk";
32
+
33
+ const engineer = new Agent({ name: "engineer", instruction: "Answer from a backend reliability perspective." });
34
+ const security = new Agent({ name: "security", instruction: "Answer from a threat-model perspective." });
35
+ const product = new Agent({ name: "product", instruction: "Answer from a user-impact perspective." });
36
+
37
+ const council = new Council({
38
+ name: "engineering-review",
39
+ specialists: [engineer, security, product],
40
+ verifiers: [VerifierKernels.emDash, VerifierKernels.aiIsm, VerifierKernels.citationPresence],
41
+ });
42
+
43
+ const result = await runner.runCouncil(council, "Should we store API keys in localStorage?");
44
+ console.log(result.answer); // synthesized answer
45
+ console.log(result.consensus); // "ratified" | "split" | "refuted"
46
+ console.log(result.disagreements); // surfaced if specialists disagreed
47
+ ```
48
+
49
+ ## Why Theron
50
+
51
+ | | Theron Agent SDK | Claude Agent SDK | OpenAI Assistants | Vercel AI SDK |
52
+ |---|---|---|---|---|
53
+ | Multi-specialist deliberation | First-class `Council` primitive with deterministic reconciliation | Sub-agents, you write the deliberation loop | Single assistant, you wire fan-out | Single model, you wire fan-out |
54
+ | Output verification before return | Built-in `VerifierKernels` (em-dash, AI-ism, arithmetic, citation) plus `defineVerifier` | Hooks pattern, you implement the checkers | None built-in | None built-in |
55
+ | Audit chain on every agent action | `Receipts` primitive: content-hashed, optionally ES256-signed, Merkle-anchorable via Stoa | None built-in | None built-in | None built-in |
56
+
57
+ The receipt chain is the differentiator. Every tool call, every Council vote, every output emits a content-hashed receipt you can sign with your own key and anchor in a daily Merkle root. When someone asks "did an AI do this," you hand them a document, not a vibe.
58
+
59
+ The SDK is model-agnostic. The verifier kernels and the receipt chain work the same whether you point at OpenRouter, Anthropic, OpenAI, a local Ollama, or the hosted Theron substrate.
60
+
61
+ ## The five primitives
62
+
63
+ | Primitive | What it is | Why it matters |
64
+ |---|---|---|
65
+ | `Agent` (composer) | A model + instruction + tools + sub-agents + verifier slugs | The 5-line agent — every other framework starts here |
66
+ | `Runner` | The execution loop — LLM call + tool dispatch + verifier sweep + event stream | Pluggable `ModelAdapter` (OpenRouter, Anthropic, OpenAI, your own endpoint) |
67
+ | `Verifier` | Deterministic render-then-judge / regex / arithmetic / citation kernels | Fast, free, no second LLM call — built-ins in `VerifierKernels` |
68
+ | `Receipts` | `ReceiptEmitter` + sinks — Stoa-shaped, content-hashed, optionally signed | Audit trail every external system can verify, no Vext lock-in |
69
+ | `Council` | N specialists + verifier kernels + a reconciler | Multi-specialist deliberation as a first-class primitive |
70
+
71
+ Plus:
72
+ - `Session` — append-only event log + scoped state (checkpoint + time-travel debug)
73
+ - `Memory` — cross-session, durable knowledge (`InMemoryStore` ships; plug in pgvector / R2 / SQLite for production)
74
+ - `Tool` — typed function with auto-injected `ToolContext`; schema-from-Zod
75
+ - `MCPClient` — Model Context Protocol over HTTP/SSE; surfaces any MCP server as `Tool[]`
76
+
77
+ ## Why a Council?
78
+
79
+ Every other agent framework binds to a model name string (`gpt-4o`, `claude-3-5-sonnet`). Theron Agent SDK binds to a Council of N specialists who deliberate and produce a reconciled answer.
80
+
81
+ ```ts
82
+ // Standard agent — one model decides
83
+ const out = await runner.run(agent, "Review this PR for security risks");
84
+
85
+ // Council — three specialists deliberate, verifier kernels check, reconciler synthesizes
86
+ const out = await runner.runCouncil(council, "Review this PR for security risks");
87
+ // out.consensus === "ratified" — all three agreed
88
+ // or out.consensus === "split" — disagreements surfaced (don't hide them — show them to the user)
89
+ ```
90
+
91
+ **The Council primitive doesn't require Vext's managed substrate.** You can run a Council of three generic OpenRouter agents and the SDK handles the deliberation + verifier dispatch + reconciliation locally.
92
+
93
+ When you upgrade to Vext-managed Theron, the same Council code points at our 15 trained Layer-1 LoRA specialists — same SDK surface, dramatically better per-domain output.
94
+
95
+ ## Verifier kernels: fast, deterministic, free
96
+
97
+ Verifier kernels are NOT another LLM call. They're small typed checkers that run after your agent produces output:
98
+
99
+ ```ts
100
+ import { VerifierKernels, defineVerifier } from "@vextlabs/theron-agent-sdk";
101
+
102
+ // Built-in kernels
103
+ VerifierKernels.emDash // block em-dashes (AI tell)
104
+ VerifierKernels.aiIsm // block "delve", "tapestry", "leverage", etc.
105
+ VerifierKernels.arithmetic // re-evaluate "X op Y = Z" claims
106
+ VerifierKernels.citationPresence // require at least one citation
107
+
108
+ // Roll your own
109
+ const noProfanity = defineVerifier({
110
+ name: "no_profanity",
111
+ description: "Block profanity in customer-facing output.",
112
+ check: async (output) => {
113
+ const bad = ["badword1", "badword2"];
114
+ const issues = bad
115
+ .filter((w) => output.toLowerCase().includes(w))
116
+ .map((w) => ({ kernel: "no_profanity", severity: "error" as const, message: `profanity: ${w}` }));
117
+ return { pass: issues.length === 0, issues };
118
+ },
119
+ });
120
+ ```
121
+
122
+ Every kernel runs in milliseconds. Pure regex / arithmetic / hash-equal. **No additional LLM cost.**
123
+
124
+ ## Reasoning patterns & loop primitives
125
+
126
+ Framework- and provider-agnostic primitives for verifier/score-gated reasoning —
127
+ the SDK-side counterparts of Theron's server Hive loops. Each takes plain async
128
+ functions (`generate` / `score` / `verify` / `critique`), so they work on any
129
+ model and compose anywhere. No other public agent SDK ships these as first-class
130
+ typed primitives.
131
+
132
+ ```ts
133
+ import {
134
+ selfConsistency, // sample N paths → majority answer + agreement ratio
135
+ bestOfN, // verifier-guided best-of-N
136
+ selfRefine, // draft → critique → revise (early-exit when clean)
137
+ treeOfThoughts, // best-first branch / score / expand search
138
+ chainOfVerification,// draft → verify claims independently → revise
139
+ mixtureOfAgents, // layered multi-agent propose → refine → aggregate
140
+ reflexion, // retry with accumulated verbal reflections (verbal RL)
141
+ measureLift, // measure a pattern's score-lift vs single-shot baseline
142
+ verifiedRatchet, // advance loop state ONLY on a confident verifier pass
143
+ stepCountIs, verifierSatisfied, anyOf, allOf, // verifier-in-the-loop stop predicates
144
+ runImprovementCycle,
145
+ compactHistory, // summarize-and-continue: run far past the context window
146
+ runUntil, // bounded, checkpointable long-horizon driver (run soo long)
147
+ } from "@vextlabs/theron-agent-sdk";
148
+
149
+ const { answer, consistency } = await selfConsistency({
150
+ samples: 5,
151
+ generate: (i) => model.complete(prompt, { seed: i }),
152
+ });
153
+ ```
154
+
155
+ See [`examples/reasoning-patterns.ts`](examples/reasoning-patterns.ts) for all
156
+ five run end-to-end (offline, no API key).
157
+
158
+ ## How this compares
159
+
160
+ | | Theron Agent SDK | Hermes-Agent | Claude Agent SDK | Google ADK | LangGraph |
161
+ |---|---|---|---|---|---|
162
+ | License | **MIT** | MIT | Apache 2.0 | Apache 2.0 | MIT |
163
+ | Multi-agent / Council | **First-class primitive with reconciler** | Sub-agents | Sub-agents | Multi-agent patterns | Supervisor / swarm |
164
+ | Verifier kernels | **First-class typed kernels** | Skill assertions | Hooks pattern | User-implemented | User-implemented |
165
+ | Memory + Session | Session (event log) + Memory (cross-session, swappable backend) | Honcho dialectic | Hooks-based | ADK Memory | Checkpointer |
166
+ | Tool typing | **Zod schemas, validated I/O** | Function decorators | Pydantic schemas | Pydantic | Pydantic |
167
+ | Model-agnostic | **Yes — any OpenAI-compatible endpoint** | Yes — 200+ via OpenRouter | Claude-optimized | Gemini-optimized | Yes |
168
+ | Signed integrations | **Stoa cap protocol (ES256 receipts + Merkle anchor)** | MCP (no integrity) | MCP | MCP | Custom |
169
+ | Managed substrate path | [Vext Theron — 15-specialist Council + per-tenant LoRA tuning](https://theron.tryvext.com) | Nous Portal | Anthropic API | Vertex AI | LangGraph Cloud |
170
+
171
+ We're not trying to beat Hermes-Agent on community size or Claude Agent SDK on Claude-specific polish. We're shipping the three primitives nobody else ships first-class: **Council + Verifier kernels + Signed integrations.** Plus the optional managed substrate where you get our trained specialists.
172
+
173
+ ## Receipts: every agent action, signable
174
+
175
+ The `Receipts` primitive gives every agent action a portable, content-hashed,
176
+ optionally signed record. Receipts are shaped to drop straight into a Stoa
177
+ sink, but the SDK runs offline with an in-memory sink for tests.
178
+
179
+ ```ts
180
+ import {
181
+ ReceiptEmitter, InMemoryReceiptSink, fileReceiptSink, httpReceiptSink,
182
+ } from "@vextlabs/theron-agent-sdk";
183
+
184
+ const receipts = new ReceiptEmitter({
185
+ sinks: [
186
+ new InMemoryReceiptSink(),
187
+ fileReceiptSink("./receipts.jsonl"),
188
+ httpReceiptSink({ url: "https://stoa.tryvext.com/sink", token: process.env.STOA }),
189
+ ],
190
+ issuer: "did:web:acme.com",
191
+ actor: "support-triage-bot",
192
+ });
193
+
194
+ runner.on(async (event) => {
195
+ if (event.type === "tool_call_done") {
196
+ await receipts.emit({
197
+ cap: `vext.${event.tool}`,
198
+ input: { tool: event.tool },
199
+ output: event.output,
200
+ });
201
+ }
202
+ });
203
+ ```
204
+
205
+ Every receipt has a deterministic `content_hash` (sorted-key SHA-256). Provide
206
+ a `ReceiptSigner` to attach an ES256 / Ed25519 / HMAC detached signature.
207
+
208
+ ## Runnable examples
209
+
210
+ The SDK ships with runnable examples in `examples/`. None require external
211
+ network credentials — the agent examples mock every tool so they run offline
212
+ against any OpenRouter-compatible model, and the pattern/loop examples are fully
213
+ offline (no key at all).
214
+
215
+ | Example | What it shows |
216
+ |---|---|
217
+ | `cyber-recon-bot.ts` | Multi-tool recon chain (subdomains → ports → TLS → tech). Every tool call emits a receipt. |
218
+ | `meeting-prep-bot.ts` | Calendar + docs + memory composition; produces a one-page meeting brief. |
219
+ | `support-triage-bot.ts` | Three-specialist Council (classifier + retriever + writer); routing decision emitted as a signable receipt. |
220
+ | `reasoning-patterns.ts` | All five reasoning patterns end-to-end (self-consistency, best-of-N, self-refine, tree-of-thoughts, chain-of-verification). **No key — fully offline.** |
221
+ | `loop-primitives.ts` | Verified ratchet, `runImprovementCycle`, and verifier-in-the-loop stop predicates. **No key — fully offline.** |
222
+
223
+ ```sh
224
+ OPENROUTER_API_KEY=sk-or-... npm run example:cyber
225
+ OPENROUTER_API_KEY=sk-or-... npm run example:meeting
226
+ OPENROUTER_API_KEY=sk-or-... npm run example:support
227
+ # offline, no key needed:
228
+ npx tsx examples/reasoning-patterns.ts
229
+ npx tsx examples/loop-primitives.ts
230
+ ```
231
+
232
+ ## What this SDK is NOT
233
+
234
+ This package is the framework. It is intentionally NOT:
235
+
236
+ - A pre-trained model — bring your own (OpenRouter / OpenAI / Anthropic / your own OSS base)
237
+ - A pre-built agent fleet — there are 3 sample agents in `examples/` to show you how to build, then you build your own
238
+ - A hosted runtime — run it on your own infra (Node, Bun, Deno, serverless, container)
239
+
240
+ If you want the trained 15-specialist Council, the 450+ curated industry-pack worker agents, the auto-improving Meta agents, or per-tenant overnight LoRA tuning — that's [Vext's managed Theron](https://theron.tryvext.com). The SDK is free; the substrate is the product.
241
+
242
+ ## Documentation
243
+
244
+ - [Docs site](https://tryvext.com/adk)
245
+ - [Architecture](./docs/architecture.md)
246
+ - [API reference](./docs/api.md)
247
+ - [Migration guide (from LangChain / CrewAI / AutoGen)](./docs/migration.md)
248
+ - [Stoa cap protocol](https://github.com/Vext-Labs-Inc/stoa)
249
+
250
+ ## More from Vext Labs
251
+
252
+ The SDK is one corner of a larger surface. The full picture lives on the Vext Labs organization page: [github.com/Vext-Labs-Inc](https://github.com/Vext-Labs-Inc). Theron the product is at [theron.tryvext.com](https://theron.tryvext.com).
253
+
254
+ ## Contributing
255
+
256
+ PRs welcome. See [CONTRIBUTING.md](CONTRIBUTING.md). We're particularly interested in:
257
+ - Model adapters (Anthropic Claude direct, AWS Bedrock, etc.)
258
+ - Verifier kernels for specific domains (SQL syntax check, K8s YAML lint, etc.)
259
+ - Memory backends (pgvector, sqlite-vec, R2)
260
+ - Persistence adapters for `Session` (Postgres, Redis, KV)
261
+
262
+ ## License
263
+
264
+ MIT — see [LICENSE](LICENSE).
265
+
266
+ Built by [Vext Labs, Inc.](https://tryvext.com) (Maryland). Founder: Annalea Layton.
267
+
268
+ ---
269
+
270
+ *The framework is yours forever. The moat is the substrate underneath.*
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+
3
+ // src/adapters/theron.ts
4
+ function theronAdapter(opts = {}) {
5
+ const base = (opts.base ?? "https://itstheron.com").replace(/\/$/, "");
6
+ const url = `${base}/api/v1/chat/completions`;
7
+ const councilMode = opts.councilMode ?? "fast";
8
+ return {
9
+ name: "theron",
10
+ async chat({ model, messages, tools, max_tokens, temperature, onDelta }) {
11
+ const body = {
12
+ model: model || "theron-council",
13
+ council_mode: councilMode,
14
+ messages,
15
+ max_tokens: max_tokens ?? 2048,
16
+ temperature: temperature ?? 0.2,
17
+ stream: !!onDelta
18
+ };
19
+ if (tools && tools.length > 0) {
20
+ body.tools = tools.map((t) => ({
21
+ type: "function",
22
+ function: { name: t.name, description: t.description, parameters: t.input_schema }
23
+ }));
24
+ }
25
+ const headers = { "Content-Type": "application/json" };
26
+ if (opts.apiKey) headers.Authorization = `Bearer ${opts.apiKey}`;
27
+ const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
28
+ if (!res.ok) {
29
+ throw new Error(`Theron ${res.status} (${url}): ${(await res.text().catch(() => "")).slice(0, 500)}`);
30
+ }
31
+ if (onDelta && res.body) {
32
+ const reader = res.body.getReader();
33
+ const decoder = new TextDecoder();
34
+ let content = "";
35
+ let inputTokens = 0;
36
+ let outputTokens = 0;
37
+ let buf = "";
38
+ for (; ; ) {
39
+ const { value, done } = await reader.read();
40
+ if (done) break;
41
+ buf += decoder.decode(value, { stream: true });
42
+ const lines = buf.split("\n");
43
+ buf = lines.pop() ?? "";
44
+ for (const line of lines) {
45
+ if (!line.startsWith("data:")) continue;
46
+ const data = line.slice(5).trim();
47
+ if (!data || data === "[DONE]") continue;
48
+ try {
49
+ const json2 = JSON.parse(data);
50
+ const delta = json2.choices?.[0]?.delta?.content;
51
+ if (delta) {
52
+ onDelta(delta);
53
+ content += delta;
54
+ }
55
+ if (json2.usage) {
56
+ inputTokens = json2.usage.prompt_tokens ?? inputTokens;
57
+ outputTokens = json2.usage.completion_tokens ?? outputTokens;
58
+ }
59
+ } catch {
60
+ }
61
+ }
62
+ }
63
+ return { content, tokens: { input: inputTokens, output: outputTokens } };
64
+ }
65
+ const json = await res.json();
66
+ const msg = json.choices?.[0]?.message ?? { content: "" };
67
+ const tool_calls = msg.tool_calls?.map((tc) => ({
68
+ name: tc.function.name,
69
+ input: safeJson(tc.function.arguments)
70
+ }));
71
+ return {
72
+ content: msg.content ?? "",
73
+ tool_calls,
74
+ tokens: {
75
+ input: json.usage?.prompt_tokens ?? 0,
76
+ output: json.usage?.completion_tokens ?? 0
77
+ }
78
+ };
79
+ }
80
+ };
81
+ }
82
+ var theron = theronAdapter;
83
+ function safeJson(s) {
84
+ try {
85
+ return JSON.parse(s || "{}");
86
+ } catch {
87
+ return {};
88
+ }
89
+ }
90
+
91
+ exports.theron = theron;
92
+ exports.theronAdapter = theronAdapter;
@@ -0,0 +1,42 @@
1
+ import { ModelAdapter } from '../runtime/index.cjs';
2
+ import '../agent/index.cjs';
3
+ import '../tools/index.cjs';
4
+ import 'zod';
5
+ import '../verifiers/index.cjs';
6
+ import '../council/index.cjs';
7
+ import '../session/index.cjs';
8
+ import '../memory/index.cjs';
9
+
10
+ /**
11
+ * Theron ModelAdapter — first-class, built-in. Drives the Vext-hosted Theron
12
+ * council so agents you build with this SDK run on Theron's substrate (the
13
+ * trained specialists + verifier kernels), not a single foundation model.
14
+ *
15
+ * import { Agent, Runner, theronAdapter } from "@vextlabs/theron-agent-sdk";
16
+ *
17
+ * const runner = new Runner({
18
+ * model: theronAdapter({ apiKey: process.env.THERON_API_KEY }),
19
+ * default_model: "theron-council",
20
+ * });
21
+ *
22
+ * Talks to the OpenAI-compatible council endpoint
23
+ * (`<base>/api/v1/chat/completions`), so tool-calling and streaming work the
24
+ * same way they do for the OpenAI/OpenRouter reference adapters — unlike the
25
+ * older phased-SSE example, which could not call tools.
26
+ */
27
+
28
+ interface TheronAdapterOptions {
29
+ /** Endpoint base. Defaults to the hosted council at itstheron.com. */
30
+ base?: string;
31
+ /** Vext / Theron bearer key. Optional for free-tier LLM caps; required for
32
+ * anything privileged. */
33
+ apiKey?: string;
34
+ /** Council mode: "fast" (cheaper cascade) or "full" (deep). Default "fast". */
35
+ councilMode?: "fast" | "full";
36
+ }
37
+ /** Build a first-class Theron adapter. Alias: `theron`. */
38
+ declare function theronAdapter(opts?: TheronAdapterOptions): ModelAdapter;
39
+ /** Convenience alias matching the docs voice (`theron({...})`). */
40
+ declare const theron: typeof theronAdapter;
41
+
42
+ export { type TheronAdapterOptions, theron, theronAdapter };
@@ -0,0 +1,42 @@
1
+ import { ModelAdapter } from '../runtime/index.js';
2
+ import '../agent/index.js';
3
+ import '../tools/index.js';
4
+ import 'zod';
5
+ import '../verifiers/index.js';
6
+ import '../council/index.js';
7
+ import '../session/index.js';
8
+ import '../memory/index.js';
9
+
10
+ /**
11
+ * Theron ModelAdapter — first-class, built-in. Drives the Vext-hosted Theron
12
+ * council so agents you build with this SDK run on Theron's substrate (the
13
+ * trained specialists + verifier kernels), not a single foundation model.
14
+ *
15
+ * import { Agent, Runner, theronAdapter } from "@vextlabs/theron-agent-sdk";
16
+ *
17
+ * const runner = new Runner({
18
+ * model: theronAdapter({ apiKey: process.env.THERON_API_KEY }),
19
+ * default_model: "theron-council",
20
+ * });
21
+ *
22
+ * Talks to the OpenAI-compatible council endpoint
23
+ * (`<base>/api/v1/chat/completions`), so tool-calling and streaming work the
24
+ * same way they do for the OpenAI/OpenRouter reference adapters — unlike the
25
+ * older phased-SSE example, which could not call tools.
26
+ */
27
+
28
+ interface TheronAdapterOptions {
29
+ /** Endpoint base. Defaults to the hosted council at itstheron.com. */
30
+ base?: string;
31
+ /** Vext / Theron bearer key. Optional for free-tier LLM caps; required for
32
+ * anything privileged. */
33
+ apiKey?: string;
34
+ /** Council mode: "fast" (cheaper cascade) or "full" (deep). Default "fast". */
35
+ councilMode?: "fast" | "full";
36
+ }
37
+ /** Build a first-class Theron adapter. Alias: `theron`. */
38
+ declare function theronAdapter(opts?: TheronAdapterOptions): ModelAdapter;
39
+ /** Convenience alias matching the docs voice (`theron({...})`). */
40
+ declare const theron: typeof theronAdapter;
41
+
42
+ export { type TheronAdapterOptions, theron, theronAdapter };
@@ -0,0 +1,89 @@
1
+ // src/adapters/theron.ts
2
+ function theronAdapter(opts = {}) {
3
+ const base = (opts.base ?? "https://itstheron.com").replace(/\/$/, "");
4
+ const url = `${base}/api/v1/chat/completions`;
5
+ const councilMode = opts.councilMode ?? "fast";
6
+ return {
7
+ name: "theron",
8
+ async chat({ model, messages, tools, max_tokens, temperature, onDelta }) {
9
+ const body = {
10
+ model: model || "theron-council",
11
+ council_mode: councilMode,
12
+ messages,
13
+ max_tokens: max_tokens ?? 2048,
14
+ temperature: temperature ?? 0.2,
15
+ stream: !!onDelta
16
+ };
17
+ if (tools && tools.length > 0) {
18
+ body.tools = tools.map((t) => ({
19
+ type: "function",
20
+ function: { name: t.name, description: t.description, parameters: t.input_schema }
21
+ }));
22
+ }
23
+ const headers = { "Content-Type": "application/json" };
24
+ if (opts.apiKey) headers.Authorization = `Bearer ${opts.apiKey}`;
25
+ const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
26
+ if (!res.ok) {
27
+ throw new Error(`Theron ${res.status} (${url}): ${(await res.text().catch(() => "")).slice(0, 500)}`);
28
+ }
29
+ if (onDelta && res.body) {
30
+ const reader = res.body.getReader();
31
+ const decoder = new TextDecoder();
32
+ let content = "";
33
+ let inputTokens = 0;
34
+ let outputTokens = 0;
35
+ let buf = "";
36
+ for (; ; ) {
37
+ const { value, done } = await reader.read();
38
+ if (done) break;
39
+ buf += decoder.decode(value, { stream: true });
40
+ const lines = buf.split("\n");
41
+ buf = lines.pop() ?? "";
42
+ for (const line of lines) {
43
+ if (!line.startsWith("data:")) continue;
44
+ const data = line.slice(5).trim();
45
+ if (!data || data === "[DONE]") continue;
46
+ try {
47
+ const json2 = JSON.parse(data);
48
+ const delta = json2.choices?.[0]?.delta?.content;
49
+ if (delta) {
50
+ onDelta(delta);
51
+ content += delta;
52
+ }
53
+ if (json2.usage) {
54
+ inputTokens = json2.usage.prompt_tokens ?? inputTokens;
55
+ outputTokens = json2.usage.completion_tokens ?? outputTokens;
56
+ }
57
+ } catch {
58
+ }
59
+ }
60
+ }
61
+ return { content, tokens: { input: inputTokens, output: outputTokens } };
62
+ }
63
+ const json = await res.json();
64
+ const msg = json.choices?.[0]?.message ?? { content: "" };
65
+ const tool_calls = msg.tool_calls?.map((tc) => ({
66
+ name: tc.function.name,
67
+ input: safeJson(tc.function.arguments)
68
+ }));
69
+ return {
70
+ content: msg.content ?? "",
71
+ tool_calls,
72
+ tokens: {
73
+ input: json.usage?.prompt_tokens ?? 0,
74
+ output: json.usage?.completion_tokens ?? 0
75
+ }
76
+ };
77
+ }
78
+ };
79
+ }
80
+ var theron = theronAdapter;
81
+ function safeJson(s) {
82
+ try {
83
+ return JSON.parse(s || "{}");
84
+ } catch {
85
+ return {};
86
+ }
87
+ }
88
+
89
+ export { theron, theronAdapter };
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ // src/agent/index.ts
4
+ var Agent = class {
5
+ name;
6
+ model;
7
+ instruction;
8
+ tools;
9
+ sub_agents;
10
+ verifiers;
11
+ max_turns;
12
+ constructor(config) {
13
+ if (!config.name) throw new Error("Agent requires a `name`.");
14
+ if (!config.instruction) throw new Error(`Agent "${config.name}" requires an \`instruction\`.`);
15
+ this.name = config.name;
16
+ this.model = config.model;
17
+ this.instruction = typeof config.instruction === "string" ? { system: config.instruction } : config.instruction;
18
+ this.tools = config.tools ?? [];
19
+ this.sub_agents = config.sub_agents ?? [];
20
+ this.verifiers = config.verifiers ?? [];
21
+ this.max_turns = config.max_turns ?? 10;
22
+ }
23
+ /** Render the tools as JSON schemas for the model. */
24
+ toolSchemas() {
25
+ return this.tools.map((t) => t.schema);
26
+ }
27
+ /** True if the agent has any sub-agents (i.e., this is a supervisor). */
28
+ isSupervisor() {
29
+ return this.sub_agents.length > 0;
30
+ }
31
+ };
32
+
33
+ exports.Agent = Agent;