determinate 0.0.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/dist/agent.d.ts +17 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +131 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/context/assembler.d.ts +19 -0
  8. package/dist/context/assembler.d.ts.map +1 -0
  9. package/dist/context/assembler.js +87 -0
  10. package/dist/context/assembler.js.map +1 -0
  11. package/dist/context/budget.d.ts +10 -0
  12. package/dist/context/budget.d.ts.map +1 -0
  13. package/dist/context/budget.js +13 -0
  14. package/dist/context/budget.js.map +1 -0
  15. package/dist/context/tokenizer.d.ts +6 -0
  16. package/dist/context/tokenizer.d.ts.map +1 -0
  17. package/dist/context/tokenizer.js +34 -0
  18. package/dist/context/tokenizer.js.map +1 -0
  19. package/dist/errors.d.ts +29 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +44 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +8 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/oauth/anthropic.d.ts +5 -0
  28. package/dist/oauth/anthropic.d.ts.map +1 -0
  29. package/dist/oauth/anthropic.js +84 -0
  30. package/dist/oauth/anthropic.js.map +1 -0
  31. package/dist/oauth/index.d.ts +18 -0
  32. package/dist/oauth/index.d.ts.map +1 -0
  33. package/dist/oauth/index.js +44 -0
  34. package/dist/oauth/index.js.map +1 -0
  35. package/dist/oauth/openai.d.ts +14 -0
  36. package/dist/oauth/openai.d.ts.map +1 -0
  37. package/dist/oauth/openai.js +328 -0
  38. package/dist/oauth/openai.js.map +1 -0
  39. package/dist/oauth/pkce.d.ts +9 -0
  40. package/dist/oauth/pkce.d.ts.map +1 -0
  41. package/dist/oauth/pkce.js +22 -0
  42. package/dist/oauth/pkce.js.map +1 -0
  43. package/dist/oauth/token-store.d.ts +10 -0
  44. package/dist/oauth/token-store.d.ts.map +1 -0
  45. package/dist/oauth/token-store.js +36 -0
  46. package/dist/oauth/token-store.js.map +1 -0
  47. package/dist/oauth/types.d.ts +32 -0
  48. package/dist/oauth/types.d.ts.map +1 -0
  49. package/dist/oauth/types.js +2 -0
  50. package/dist/oauth/types.js.map +1 -0
  51. package/dist/providers/anthropic.d.ts +9 -0
  52. package/dist/providers/anthropic.d.ts.map +1 -0
  53. package/dist/providers/anthropic.js +101 -0
  54. package/dist/providers/anthropic.js.map +1 -0
  55. package/dist/providers/factory.d.ts +4 -0
  56. package/dist/providers/factory.d.ts.map +1 -0
  57. package/dist/providers/factory.js +25 -0
  58. package/dist/providers/factory.js.map +1 -0
  59. package/dist/providers/openai.d.ts +9 -0
  60. package/dist/providers/openai.d.ts.map +1 -0
  61. package/dist/providers/openai.js +57 -0
  62. package/dist/providers/openai.js.map +1 -0
  63. package/dist/providers/parse-action.d.ts +3 -0
  64. package/dist/providers/parse-action.d.ts.map +1 -0
  65. package/dist/providers/parse-action.js +18 -0
  66. package/dist/providers/parse-action.js.map +1 -0
  67. package/dist/providers/types.d.ts +22 -0
  68. package/dist/providers/types.d.ts.map +1 -0
  69. package/dist/providers/types.js +2 -0
  70. package/dist/providers/types.js.map +1 -0
  71. package/dist/schema/action-schema.d.ts +9 -0
  72. package/dist/schema/action-schema.d.ts.map +1 -0
  73. package/dist/schema/action-schema.js +33 -0
  74. package/dist/schema/action-schema.js.map +1 -0
  75. package/dist/schema/history-schema.d.ts +11 -0
  76. package/dist/schema/history-schema.d.ts.map +1 -0
  77. package/dist/schema/history-schema.js +18 -0
  78. package/dist/schema/history-schema.js.map +1 -0
  79. package/dist/types.d.ts +75 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +2 -0
  82. package/dist/types.js.map +1 -0
  83. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 cahaseler
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,236 @@
1
+ # determinate
2
+
3
+ A TypeScript library that treats LLMs as next-action predictors instead of conversational partners.
4
+
5
+ ## The Problem
6
+
7
+ Current agentic frameworks are built around a conversation metaphor: an append-only chat history, a static list of tools, and a loop that generates the next message given everything that came before. This works well for coding assistants where the environment is deterministic and stable, but falls apart in dynamic environments where:
8
+
9
+ - **State goes stale.** If you inject environment state each turn across a 50-turn interaction, you have 50 snapshots in context, 49 of which are wrong. The oldest, most incorrect snapshot has the strongest positional signal.
10
+ - **Context fills with noise.** Failed tool calls, redundant observations, and retry loops consume tokens without contributing to decisions. Half the conversation history in a typical agentic run is the agent's own mistakes.
11
+ - **Tools are over-injected.** For a system with 180 possible actions, all 180 schemas are injected every call, even when only 20 are relevant in the current state.
12
+ - **The model does housekeeping instead of reasoning.** The model spends capacity reconciling stale state, filtering irrelevant tools, and formatting output instead of making the actual decision.
13
+
14
+ For the full argument, see [Beyond the Sacred Conversation](beyond-the-sacred-conversation.md).
15
+
16
+ ## The Approach
17
+
18
+ The unit of work is not a conversation turn. It is a **state-to-action decision**.
19
+
20
+ `determinate` is a decision engine, not a framework. It does not own the loop, manage side effects, or implement tool handlers. You provide the situation; it returns an action.
21
+
22
+ Each call to `nextAction()`:
23
+
24
+ 1. Filters tools to only those valid in the current state
25
+ 2. Generates a constrained output schema — the model *cannot* choose an invalid action
26
+ 3. Assembles an optimized context with explicit token budgets per section
27
+ 4. Makes a single LLM call with structured output (constrained decoding)
28
+ 5. Returns the chosen action with validated parameters
29
+
30
+ No conversation history accumulates inside the library. Context is an intentional budget, not a dumping ground.
31
+
32
+ ## Quick Start
33
+
34
+ ```bash
35
+ bun add determinate
36
+ # zod is a peer dependency
37
+ bun add zod
38
+ ```
39
+
40
+ ```typescript
41
+ import { z } from "zod";
42
+ import { createAgent } from "determinate";
43
+
44
+ const agent = createAgent({
45
+ provider: {
46
+ type: "openai", // or "anthropic", "vllm", "openrouter"
47
+ model: "gpt-5-nano",
48
+ apiKey: process.env.OPENAI_API_KEY,
49
+ },
50
+ state: z.object({
51
+ order: z.object({
52
+ status: z.enum(["pending", "approved", "shipped"]),
53
+ riskScore: z.number(),
54
+ items: z.array(z.object({ name: z.string(), qty: z.number() })),
55
+ }),
56
+ }),
57
+ tools: [
58
+ {
59
+ name: "approve_order",
60
+ description: "Approve a pending order",
61
+ params: z.object({ note: z.string() }),
62
+ validWhen: (s) => s.order.status === "pending" && s.order.riskScore < 0.7,
63
+ },
64
+ {
65
+ name: "escalate_order",
66
+ description: "Escalate order for human review",
67
+ params: z.object({ reason: z.string() }),
68
+ validWhen: (s) => s.order.status === "pending" && s.order.riskScore >= 0.7,
69
+ },
70
+ {
71
+ name: "ship_order",
72
+ description: "Ship an approved order",
73
+ params: z.object({ carrier: z.enum(["fedex", "ups", "usps"]) }),
74
+ validWhen: (s) => s.order.status === "approved",
75
+ },
76
+ ],
77
+ instructions: (s) =>
78
+ `You are an order processing agent. Evaluate order risk and take appropriate action.
79
+ Current risk score: ${s.order.riskScore}`,
80
+ context: {
81
+ budgets: { instructions: 5000, state: 5000, history: 10000, tools: 3000 },
82
+ },
83
+ });
84
+
85
+ // Your loop — you own it
86
+ agent.setState({
87
+ order: { status: "pending", riskScore: 0.3, items: [{ name: "Widget", qty: 2 }] },
88
+ });
89
+
90
+ const result = await agent.nextAction();
91
+ // { action: { tool: "approve_order", params: { note: "Low risk, standard order" } },
92
+ // meta: { tokensUsed: { input: 180, output: 30 }, model: "gpt-5-nano", latency: 892 } }
93
+
94
+ // You execute the action, update state, call nextAction() again
95
+ ```
96
+
97
+ ## Core Concepts
98
+
99
+ ### State
100
+
101
+ Define your environment state as a Zod schema. The library validates it, serializes it for the model, and passes it to your tool predicates and instruction function. You replace it entirely each turn via `setState()` — no stale snapshots accumulating.
102
+
103
+ ### Tools with Conditional Validity
104
+
105
+ Each tool has a `validWhen` predicate evaluated against current state. Only valid tools are presented to the model, and the constrained output schema makes it physically impossible for the model to choose an invalid tool. This is least-privilege enforced structurally, not by hoping the model follows instructions.
106
+
107
+ ### Token Budgets
108
+
109
+ You set explicit token budgets per section (instructions, state, history, tools). If any section exceeds its budget, the call is rejected with a `BudgetExceededError` — no silent truncation. This makes context overflow a build-time problem you fix once, not a runtime surprise.
110
+
111
+ ### History
112
+
113
+ You manage history. The library defines the format, validates it, and translates it into provider-native tool-calling messages (exploiting model training on tool-calling patterns). You control what history to include, how to compress it, and when to drop entries.
114
+
115
+ ```typescript
116
+ agent.setHistory([
117
+ {
118
+ tool: "request_info",
119
+ params: { field: "shipping_address" },
120
+ result: "Customer provided: 123 Main St",
121
+ success: true,
122
+ },
123
+ ]);
124
+ ```
125
+
126
+ ### Instructions
127
+
128
+ A function from state to string. Called each turn, so you can provide different instructions for different situations without any framework machinery.
129
+
130
+ ```typescript
131
+ instructions: (s) => {
132
+ if (s.order.riskScore > 0.9) return "This is an extremely high-risk order. Escalate immediately.";
133
+ if (s.order.status === "approved") return "Select carrier based on package weight and destination.";
134
+ return "Evaluate the order against standard fulfillment policy.";
135
+ },
136
+ ```
137
+
138
+ ## Providers
139
+
140
+ | Provider | How | Structured Output |
141
+ |----------|-----|-------------------|
142
+ | OpenAI | OpenAI SDK | `response_format: json_schema` |
143
+ | Anthropic | Raw fetch adapter | `output_config.format: json_schema` |
144
+ | vLLM | OpenAI SDK + custom base URL | Constrained decoding (xgrammar/outlines) |
145
+ | OpenRouter | OpenAI SDK + custom base URL | Depends on upstream model |
146
+
147
+ ```typescript
148
+ // Local vLLM
149
+ provider: { type: "vllm", model: "Qwen/Qwen3.5-4B", apiKey: "not-needed", baseUrl: "http://localhost:8000/v1" }
150
+
151
+ // Anthropic
152
+ provider: { type: "anthropic", model: "claude-haiku-4-5-20251001", apiKey: process.env.ANTHROPIC_API_KEY }
153
+
154
+ // OpenRouter
155
+ provider: { type: "openrouter", model: "anthropic/claude-sonnet-4-5", apiKey: process.env.OPENROUTER_API_KEY }
156
+ ```
157
+
158
+ ## Cost Tracking
159
+
160
+ The library returns token counts in `meta.tokensUsed` (may be `{ input: 0, output: 0 }` if the provider doesn't report usage). For cost estimation, pass your own pricing:
161
+
162
+ ```typescript
163
+ const agent = createAgent({
164
+ // ...
165
+ pricing: { input: 0.05, output: 0.4 }, // per 1M tokens
166
+ });
167
+
168
+ const result = await agent.nextAction();
169
+ result.meta.cost; // number | undefined
170
+ ```
171
+
172
+ ## Timeouts and Cancellation
173
+
174
+ ```typescript
175
+ // Per-call timeout
176
+ const result = await agent.nextAction({ timeout: 10000 });
177
+
178
+ // AbortSignal
179
+ const controller = new AbortController();
180
+ const result = await agent.nextAction({ signal: controller.signal });
181
+ ```
182
+
183
+ ## Verbose Mode
184
+
185
+ For debugging, get the full assembled context:
186
+
187
+ ```typescript
188
+ const result = await agent.nextAction({ verbose: true });
189
+ // result.context.messages — what was sent to the LLM
190
+ // result.context.outputSchema — the JSON schema constraining the output
191
+ // result.context.validTools — which tools were available
192
+ ```
193
+
194
+ ## Errors
195
+
196
+ All errors are typed and actionable:
197
+
198
+ | Error | When |
199
+ |-------|------|
200
+ | `ValidationError` | State doesn't match schema, history format invalid |
201
+ | `BudgetExceededError` | A section exceeds its token budget |
202
+ | `NoValidToolsError` | No tool's `validWhen` returned true |
203
+ | `ProviderError` | Auth failure, rate limit, network error |
204
+ | `OutputError` | Model returned invalid action (shouldn't happen with constrained output) |
205
+ | `AbortError` | Call cancelled or timed out |
206
+
207
+ ## OAuth
208
+
209
+ Built-in device code flows for subscription-based access (ChatGPT Plus, Claude Pro):
210
+
211
+ ```typescript
212
+ import { getOAuthProvider, getOAuthApiKey } from "determinate";
213
+
214
+ // Trigger login flow
215
+ const provider = getOAuthProvider("openai"); // returns undefined if not registered
216
+ await provider?.login(callbacks);
217
+
218
+ // Later, credentials are used automatically
219
+ const agent = createAgent({
220
+ provider: { type: "openai", model: "gpt-5-nano", oauth: true },
221
+ // no apiKey needed — uses stored credentials
222
+ // ...
223
+ });
224
+ ```
225
+
226
+ ## Requirements
227
+
228
+ - **Runtime:** Bun (or Node.js with compatible APIs)
229
+ - **TypeScript:** 5.x
230
+ - **Zod:** >= 4.0.0 (peer dependency)
231
+
232
+ ## Philosophy
233
+
234
+ This library exists because we believe the conversation metaphor is the wrong abstraction for most agentic systems. An LLM making decisions in a dynamic environment is solving a classification problem with context, not having a conversation. The architecture should reflect that.
235
+
236
+ For the full argument: [Beyond the Sacred Conversation](beyond-the-sacred-conversation.md).
@@ -0,0 +1,17 @@
1
+ import { type ValidatedHistoryEntry } from "./schema/history-schema";
2
+ import type { ActionResult, AgentConfig, HistoryEntry, NextActionOptions, VerboseActionResult } from "./types";
3
+ export declare class Agent<TState> {
4
+ private config;
5
+ private state;
6
+ private history;
7
+ private provider;
8
+ private tokenizer;
9
+ constructor(config: AgentConfig<TState>);
10
+ private resolveProvider;
11
+ setState(state: TState): void;
12
+ getState(): TState;
13
+ setHistory(history: HistoryEntry[]): void;
14
+ getHistory(): ValidatedHistoryEntry[];
15
+ nextAction(options?: NextActionOptions): Promise<ActionResult | VerboseActionResult>;
16
+ }
17
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,qBAAqB,EAAmB,MAAM,yBAAyB,CAAC;AACtF,OAAO,KAAK,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,MAAM,SAAS,CAAC;AAEjB,qBAAa,KAAK,CAAC,MAAM;IACxB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,SAAS,CAAY;gBAEjB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;YAUzB,eAAe;IAsB7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAU7B,QAAQ,IAAI,MAAM;IAOlB,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI;IAIzC,UAAU,IAAI,qBAAqB,EAAE;IAI/B,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,GAAG,mBAAmB,CAAC;CA4F1F"}
package/dist/agent.js ADDED
@@ -0,0 +1,131 @@
1
+ import { assembleContext } from "./context/assembler";
2
+ import { createTokenizer } from "./context/tokenizer";
3
+ import { AbortError, OutputError, ProviderError, ValidationError } from "./errors";
4
+ import { getOAuthApiKey } from "./oauth/index";
5
+ import { createProvider } from "./providers/factory";
6
+ import { validateHistory } from "./schema/history-schema";
7
+ export class Agent {
8
+ config;
9
+ state;
10
+ history = [];
11
+ provider;
12
+ tokenizer;
13
+ constructor(config) {
14
+ this.config = config;
15
+ this.tokenizer = createTokenizer(config.provider.type, config.provider.model);
16
+ // Create provider immediately if we have an apiKey or OAuth isn't requested
17
+ if (config.provider.apiKey || !config.provider.oauth) {
18
+ this.provider = createProvider(config.provider);
19
+ }
20
+ }
21
+ async resolveProvider() {
22
+ if (this.provider)
23
+ return this.provider;
24
+ // OAuth is requested but no apiKey — try stored credentials
25
+ const oauthProviderId = this.config.provider.type === "openai" ? "openai" : "anthropic";
26
+ const result = await getOAuthApiKey(oauthProviderId);
27
+ if (!result) {
28
+ throw new ProviderError(this.config.provider.type, `No stored OAuth credentials for ${oauthProviderId}. Run the login flow first using the exported OAuth providers.`);
29
+ }
30
+ this.provider = createProvider({
31
+ ...this.config.provider,
32
+ apiKey: result.apiKey,
33
+ });
34
+ return this.provider;
35
+ }
36
+ setState(state) {
37
+ const result = this.config.state.safeParse(state);
38
+ if (!result.success) {
39
+ throw new ValidationError(`Invalid state: ${result.error.issues.map((i) => i.message).join(", ")}`);
40
+ }
41
+ this.state = result.data;
42
+ }
43
+ getState() {
44
+ if (this.state === undefined) {
45
+ throw new ValidationError("State has not been set");
46
+ }
47
+ return this.state;
48
+ }
49
+ setHistory(history) {
50
+ this.history = validateHistory(history);
51
+ }
52
+ getHistory() {
53
+ return this.history;
54
+ }
55
+ async nextAction(options) {
56
+ const state = this.getState();
57
+ let signal = options?.signal;
58
+ if (options?.timeout) {
59
+ const timeoutSignal = AbortSignal.timeout(options.timeout);
60
+ signal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
61
+ }
62
+ try {
63
+ const assembled = assembleContext({
64
+ state,
65
+ tools: this.config.tools,
66
+ history: this.history,
67
+ instructions: this.config.instructions,
68
+ budgets: this.config.context.budgets,
69
+ tokenizer: this.tokenizer,
70
+ providerType: this.config.provider.type,
71
+ });
72
+ const provider = await this.resolveProvider();
73
+ const start = performance.now();
74
+ const response = await provider.sendRequest({
75
+ messages: assembled.messages,
76
+ outputSchema: assembled.outputSchema,
77
+ model: this.config.provider.model,
78
+ options: this.config.provider.options,
79
+ signal,
80
+ });
81
+ const latency = performance.now() - start;
82
+ if (!assembled.validTools.includes(response.action.tool)) {
83
+ throw new OutputError(`Model returned tool "${response.action.tool}" which is not in the valid set: [${assembled.validTools.join(", ")}]`, JSON.stringify(response.action));
84
+ }
85
+ const toolDef = this.config.tools.find((t) => t.name === response.action.tool);
86
+ if (toolDef) {
87
+ // Strip the tool_name discriminant injected by the output schema
88
+ const { tool_name: _, ...cleanParams } = response.action.params;
89
+ const paramsResult = toolDef.params.safeParse(cleanParams);
90
+ if (!paramsResult.success) {
91
+ throw new OutputError(`Params for tool "${response.action.tool}" failed validation: ${paramsResult.error.issues.map((i) => i.message).join(", ")}`, JSON.stringify(response.action));
92
+ }
93
+ response.action.params = paramsResult.data;
94
+ }
95
+ let cost;
96
+ if (this.config.pricing) {
97
+ const { input, output } = response.meta.tokensUsed;
98
+ cost =
99
+ (input / 1_000_000) * this.config.pricing.input +
100
+ (output / 1_000_000) * this.config.pricing.output;
101
+ }
102
+ const result = {
103
+ action: response.action,
104
+ meta: {
105
+ tokensUsed: response.meta.tokensUsed,
106
+ cost,
107
+ model: response.meta.model,
108
+ latency,
109
+ },
110
+ };
111
+ if (options?.verbose) {
112
+ return {
113
+ ...result,
114
+ context: {
115
+ messages: assembled.messages,
116
+ outputSchema: assembled.outputSchema,
117
+ validTools: assembled.validTools,
118
+ },
119
+ };
120
+ }
121
+ return result;
122
+ }
123
+ catch (err) {
124
+ if (signal?.aborted) {
125
+ throw new AbortError(options?.timeout ? `Timeout after ${options.timeout}ms` : "Operation was aborted");
126
+ }
127
+ throw err;
128
+ }
129
+ }
130
+ }
131
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { HistoryEntry, ProviderConfig, TokenBudgets, ToolDefinition } from "../types";
2
+ import type { Tokenizer } from "./tokenizer";
3
+ interface AssembleInput<TState> {
4
+ state: TState;
5
+ tools: ToolDefinition<TState>[];
6
+ history: HistoryEntry[];
7
+ instructions: (state: TState) => string;
8
+ budgets: TokenBudgets;
9
+ tokenizer: Tokenizer;
10
+ providerType: ProviderConfig["type"];
11
+ }
12
+ interface AssembledPayload {
13
+ messages: unknown[];
14
+ outputSchema: Record<string, unknown>;
15
+ validTools: string[];
16
+ }
17
+ export declare function assembleContext<TState>(input: AssembleInput<TState>): AssembledPayload;
18
+ export {};
19
+ //# sourceMappingURL=assembler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assembler.d.ts","sourceRoot":"","sources":["../../src/context/assembler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE3F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,UAAU,aAAa,CAAC,MAAM;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;IAChC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CACrC;AAED,UAAU,gBAAgB;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,gBAAgB,CA8FtF"}
@@ -0,0 +1,87 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { NoValidToolsError } from "../errors";
3
+ import { generateActionSchema } from "../schema/action-schema";
4
+ import { enforceBudgets } from "./budget";
5
+ export function assembleContext(input) {
6
+ const { state, tools, history, instructions, budgets, tokenizer, providerType } = input;
7
+ // 1. Filter tools by validWhen
8
+ const validTools = tools.filter((t) => t.validWhen(state));
9
+ if (validTools.length === 0) {
10
+ throw new NoValidToolsError();
11
+ }
12
+ // 2. Generate output schema
13
+ const outputSchema = generateActionSchema(validTools);
14
+ // 3. Build instructions text
15
+ const instructionsText = instructions(state);
16
+ const toolInstructions = validTools
17
+ .filter((t) => t.instructions)
18
+ .map((t) => `[${t.name}]: ${t.instructions}`)
19
+ .join("\n");
20
+ const fullInstructions = toolInstructions
21
+ ? `${instructionsText}\n\nTool-specific instructions:\n${toolInstructions}`
22
+ : instructionsText;
23
+ // 4. Build tool descriptions
24
+ const toolDescriptions = validTools.map((t) => `- ${t.name}: ${t.description}`).join("\n");
25
+ // 5. Serialize state
26
+ const stateText = JSON.stringify(state, null, 2);
27
+ // 6. Build history messages (needed for accurate budget counting)
28
+ const historyMessages = [];
29
+ for (const entry of history) {
30
+ const callId = randomUUID();
31
+ if (providerType === "anthropic") {
32
+ historyMessages.push({
33
+ role: "assistant",
34
+ content: [{ type: "tool_use", id: callId, name: entry.tool, input: entry.params }],
35
+ });
36
+ historyMessages.push({
37
+ role: "user",
38
+ content: [
39
+ {
40
+ type: "tool_result",
41
+ tool_use_id: callId,
42
+ content: entry.result,
43
+ is_error: entry.success === false,
44
+ },
45
+ ],
46
+ });
47
+ }
48
+ else {
49
+ historyMessages.push({
50
+ role: "assistant",
51
+ tool_calls: [
52
+ {
53
+ id: callId,
54
+ type: "function",
55
+ function: { name: entry.tool, arguments: JSON.stringify(entry.params) },
56
+ },
57
+ ],
58
+ });
59
+ historyMessages.push({
60
+ role: "tool",
61
+ tool_call_id: callId,
62
+ content: entry.result,
63
+ });
64
+ }
65
+ }
66
+ // 7. Enforce budgets
67
+ const historyText = historyMessages.length > 0 ? JSON.stringify(historyMessages) : "";
68
+ enforceBudgets({
69
+ instructions: fullInstructions,
70
+ state: stateText,
71
+ history: historyText,
72
+ tools: toolDescriptions,
73
+ }, budgets, tokenizer);
74
+ // 8. Build final messages
75
+ const messages = [];
76
+ messages.push({
77
+ role: "system",
78
+ content: `${fullInstructions}\n\nAvailable actions:\n${toolDescriptions}\n\nRespond with a JSON object choosing one action and its parameters.`,
79
+ });
80
+ messages.push(...historyMessages);
81
+ messages.push({
82
+ role: "user",
83
+ content: `Current state:\n${stateText}\n\nChoose the next action.`,
84
+ });
85
+ return { messages, outputSchema, validTools: validTools.map((t) => t.name) };
86
+ }
87
+ //# sourceMappingURL=assembler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assembler.js","sourceRoot":"","sources":["../../src/context/assembler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { TokenBudgets } from "../types";
2
+ import type { Tokenizer } from "./tokenizer";
3
+ export interface SectionContents {
4
+ instructions: string;
5
+ state: string;
6
+ history: string;
7
+ tools: string;
8
+ }
9
+ export declare function enforceBudgets(sections: SectionContents, budgets: TokenBudgets, tokenizer: Tokenizer): Record<keyof TokenBudgets, number>;
10
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/context/budget.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAC7B,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,SAAS,GAClB,MAAM,CAAC,MAAM,YAAY,EAAE,MAAM,CAAC,CAYpC"}
@@ -0,0 +1,13 @@
1
+ import { BudgetExceededError } from "../errors";
2
+ export function enforceBudgets(sections, budgets, tokenizer) {
3
+ const counts = {};
4
+ for (const key of ["instructions", "state", "history", "tools"]) {
5
+ const count = tokenizer.count(sections[key]);
6
+ counts[key] = count;
7
+ if (count > budgets[key]) {
8
+ throw new BudgetExceededError(key, count, budgets[key]);
9
+ }
10
+ }
11
+ return counts;
12
+ }
13
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/context/budget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAWhD,MAAM,UAAU,cAAc,CAC7B,QAAyB,EACzB,OAAqB,EACrB,SAAoB;IAEpB,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAU,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACpB,IAAI,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACzD,CAAC;IACF,CAAC;IAED,OAAO,MAA4C,CAAC;AACrD,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ProviderConfig } from "../types";
2
+ export interface Tokenizer {
3
+ count(input: string | Record<string, unknown>): number;
4
+ }
5
+ export declare function createTokenizer(providerType: ProviderConfig["type"], model: string): Tokenizer;
6
+ //# sourceMappingURL=tokenizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../../src/context/tokenizer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,WAAW,SAAS;IACzB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;CACvD;AA+BD,wBAAgB,eAAe,CAAC,YAAY,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAM9F"}
@@ -0,0 +1,34 @@
1
+ import { encoding_for_model, get_encoding } from "tiktoken";
2
+ function serialize(input) {
3
+ if (typeof input === "string")
4
+ return input;
5
+ return JSON.stringify(input);
6
+ }
7
+ class TiktokenTokenizer {
8
+ encoder;
9
+ constructor(model) {
10
+ try {
11
+ this.encoder = encoding_for_model(model);
12
+ }
13
+ catch {
14
+ this.encoder = get_encoding("cl100k_base");
15
+ }
16
+ }
17
+ count(input) {
18
+ return this.encoder.encode(serialize(input)).length;
19
+ }
20
+ }
21
+ class CharApproximationTokenizer {
22
+ charsPerToken = 3;
23
+ count(input) {
24
+ return Math.ceil(serialize(input).length / this.charsPerToken);
25
+ }
26
+ }
27
+ export function createTokenizer(providerType, model) {
28
+ if (providerType === "openai" || providerType === "openrouter" || providerType === "vllm") {
29
+ return new TiktokenTokenizer(model);
30
+ }
31
+ // Anthropic doesn't use tiktoken — approximate by character count
32
+ return new CharApproximationTokenizer();
33
+ }
34
+ //# sourceMappingURL=tokenizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../src/context/tokenizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAsB,MAAM,UAAU,CAAC;AAOhF,SAAS,SAAS,CAAC,KAAuC;IACzD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,iBAAiB;IACd,OAAO,CAAC;IAEhB,YAAY,KAAa;QACxB,IAAI,CAAC;YACJ,IAAI,CAAC,OAAO,GAAG,kBAAkB,CAAC,KAAsB,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACR,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;QAC5C,CAAC;IACF,CAAC;IAED,KAAK,CAAC,KAAuC;QAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACrD,CAAC;CACD;AAED,MAAM,0BAA0B;IACd,aAAa,GAAG,CAAC,CAAC;IAEnC,KAAK,CAAC,KAAuC;QAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;IAChE,CAAC;CACD;AAED,MAAM,UAAU,eAAe,CAAC,YAAoC,EAAE,KAAa;IAClF,IAAI,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,YAAY,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC3F,OAAO,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IACD,kEAAkE;IAClE,OAAO,IAAI,0BAA0B,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,29 @@
1
+ export declare class ValidationError extends Error {
2
+ name: "ValidationError";
3
+ }
4
+ export declare class BudgetExceededError extends Error {
5
+ readonly section: string;
6
+ readonly actual: number;
7
+ readonly budget: number;
8
+ name: "BudgetExceededError";
9
+ constructor(section: string, actual: number, budget: number);
10
+ }
11
+ export declare class NoValidToolsError extends Error {
12
+ name: "NoValidToolsError";
13
+ constructor();
14
+ }
15
+ export declare class ProviderError extends Error {
16
+ readonly provider: string;
17
+ name: "ProviderError";
18
+ constructor(provider: string, message: string);
19
+ }
20
+ export declare class OutputError extends Error {
21
+ readonly rawOutput: string;
22
+ name: "OutputError";
23
+ constructor(message: string, rawOutput: string);
24
+ }
25
+ export declare class AbortError extends Error {
26
+ name: "AbortError";
27
+ constructor(message?: string);
28
+ }
29
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,eAAgB,SAAQ,KAAK;IAChC,IAAI,EAAG,iBAAiB,CAAU;CAC3C;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAG5B,OAAO,EAAE,MAAM;aACf,MAAM,EAAE,MAAM;aACd,MAAM,EAAE,MAAM;IAJtB,IAAI,EAAG,qBAAqB,CAAU;gBAE9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;CAI/B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAClC,IAAI,EAAG,mBAAmB,CAAU;;CAI7C;AAED,qBAAa,aAAc,SAAQ,KAAK;aAGtB,QAAQ,EAAE,MAAM;IAFxB,IAAI,EAAG,eAAe,CAAU;gBAExB,QAAQ,EAAE,MAAM,EAChC,OAAO,EAAE,MAAM;CAIhB;AAED,qBAAa,WAAY,SAAQ,KAAK;aAIpB,SAAS,EAAE,MAAM;IAHzB,IAAI,EAAG,aAAa,CAAU;gBAEtC,OAAO,EAAE,MAAM,EACC,SAAS,EAAE,MAAM;CAIlC;AAED,qBAAa,UAAW,SAAQ,KAAK;IAC3B,IAAI,EAAG,YAAY,CAAU;gBAC1B,OAAO,GAAE,MAAgC;CAGrD"}