@agenticprimitives/model-gateway 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/adapters/anthropic.d.ts +13 -0
- package/dist/adapters/anthropic.d.ts.map +1 -0
- package/dist/adapters/anthropic.js +59 -0
- package/dist/adapters/anthropic.js.map +1 -0
- package/dist/adapters/openai-compat.d.ts +17 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -0
- package/dist/adapters/openai-compat.js +66 -0
- package/dist/adapters/openai-compat.js.map +1 -0
- package/dist/budget.d.ts +86 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +98 -0
- package/dist/budget.js.map +1 -0
- package/dist/contract.d.ts +268 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +128 -0
- package/dist/contract.js.map +1 -0
- package/dist/handler.d.ts +24 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +124 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/openai-compat/translate.d.ts +122 -0
- package/dist/openai-compat/translate.d.ts.map +1 -0
- package/dist/openai-compat/translate.js +72 -0
- package/dist/openai-compat/translate.js.map +1 -0
- package/dist/ops.d.ts +6 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +38 -0
- package/dist/ops.js.map +1 -0
- package/dist/policy.d.ts +26 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +83 -0
- package/dist/policy.js.map +1 -0
- package/dist/ports.d.ts +95 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +43 -0
- package/dist/ports.js.map +1 -0
- package/dist/usage.d.ts +23 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +16 -0
- package/dist/usage.js.map +1 -0
- package/package.json +32 -0
- package/spec.md +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Agentic Trust Labs
|
|
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,29 @@
|
|
|
1
|
+
# @agenticprimitives/model-gateway
|
|
2
|
+
|
|
3
|
+
The contract half of the AP Model Gateway (spec 434). One request shape — `GenerateRequestV1` — that a typed client and an
|
|
4
|
+
OpenAI-compatible endpoint both produce; profiles over a model catalog with one switch per model; a reserve-then-settle
|
|
5
|
+
budget algebra; usage normalized in one place; declared, receipted fallback; provider adapters over the substrate's
|
|
6
|
+
existing fetch clients; and `createGatewayHandler(ports)`, which the town's inference Worker mounts.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { createGatewayHandler, anthropicAdapter, openAiCompatAdapter } from '@agenticprimitives/model-gateway';
|
|
10
|
+
import { createFetchAnthropicClient } from '@agenticprimitives/orchestration-anthropic';
|
|
11
|
+
import { createFetchOpenAiCompatClient } from '@agenticprimitives/orchestration-openai-compat';
|
|
12
|
+
|
|
13
|
+
const handler = createGatewayHandler({
|
|
14
|
+
resolver, // app key → the app's Service SA; session wire → the delegator SA (never `context.agent`)
|
|
15
|
+
policy, // profiles + catalog + entitlements (the Worker's KV cache over the service's vault records)
|
|
16
|
+
meter, // BudgetDO: reserve → settle
|
|
17
|
+
ledger, // receipts into inference.svc's vault
|
|
18
|
+
adapters: {
|
|
19
|
+
anthropic: anthropicAdapter({ client: createFetchAnthropicClient({ apiKey }) }),
|
|
20
|
+
'openai-compat': openAiCompatAdapter({ clientFor: (endpoint) => createFetchOpenAiCompatClient({ baseUrl: endpoint!, apiKey: keyFor(endpoint) }) }),
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
const out = await handler.generate({ profile: 'planner-fast', messages, context: { purpose: 'plan', runRef } }, { kind: 'app-key', key });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A caller names a profile, never a model. The gateway establishes the principal; what the caller says it acts for is
|
|
27
|
+
recorded as asserted. A profile with no enabled model fails closed. Every attempt leaves a receipt; a fallback is a
|
|
28
|
+
second attempt inside the same profile on a failure class the profile named — never on a content error, never silently.
|
|
29
|
+
Receipts are the record; the budget state is rebuilt from them.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AnthropicLike, AnthropicMessageCreateParams } from '@agenticprimitives/orchestration-anthropic';
|
|
2
|
+
import type { ProviderAdapter } from '../ports.js';
|
|
3
|
+
import type { MessageV1 } from '../contract.js';
|
|
4
|
+
export interface AnthropicAdapterOpts {
|
|
5
|
+
client: AnthropicLike;
|
|
6
|
+
}
|
|
7
|
+
/** The Messages API wants one system string and alternating user/assistant turns; tool results ride as user text. */
|
|
8
|
+
export declare function foldForAnthropic(messages: MessageV1[]): {
|
|
9
|
+
system: string | undefined;
|
|
10
|
+
messages: AnthropicMessageCreateParams['messages'];
|
|
11
|
+
};
|
|
12
|
+
export declare function anthropicAdapter(opts: AnthropicAdapterOpts): ProviderAdapter;
|
|
13
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,4BAA4B,EAAuB,MAAM,4CAA4C,CAAC;AACnI,OAAO,KAAK,EAAqC,eAAe,EAAE,MAAM,aAAa,CAAC;AAGtF,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,gBAAgB,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,qHAAqH;AACrH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,4BAA4B,CAAC,UAAU,CAAC,CAAA;CAAE,CAY1I;AAKD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,eAAe,CA8B5E"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { classifyStatus, ProviderFailure } from '../ports.js';
|
|
2
|
+
import { normalizeAnthropicUsage } from '../usage.js';
|
|
3
|
+
/** The Messages API wants one system string and alternating user/assistant turns; tool results ride as user text. */
|
|
4
|
+
export function foldForAnthropic(messages) {
|
|
5
|
+
const system = messages.filter((m) => m.role === 'system').map((m) => m.content).join('\n\n') || undefined;
|
|
6
|
+
const turns = [];
|
|
7
|
+
for (const m of messages) {
|
|
8
|
+
if (m.role === 'system')
|
|
9
|
+
continue;
|
|
10
|
+
const role = m.role === 'assistant' ? 'assistant' : 'user';
|
|
11
|
+
const content = m.role === 'tool' ? `[tool result ${m.toolCallId}]\n${m.content}` : m.role === 'assistant' && m.toolCalls?.length ? `${m.content}${m.content ? '\n' : ''}[called ${m.toolCalls.map((c) => `${c.name}(${JSON.stringify(c.args)})`).join('; ')}]` : m.content;
|
|
12
|
+
const last = turns[turns.length - 1];
|
|
13
|
+
if (last && last.role === role)
|
|
14
|
+
last.content = `${last.content}\n\n${content}`;
|
|
15
|
+
else
|
|
16
|
+
turns.push({ role, content });
|
|
17
|
+
}
|
|
18
|
+
if (turns.length === 0 || turns[0].role !== 'user')
|
|
19
|
+
turns.unshift({ role: 'user', content: '(continue)' });
|
|
20
|
+
return { system, messages: turns };
|
|
21
|
+
}
|
|
22
|
+
const stopOf = (reason, hadTool) => reason === 'max_tokens' ? 'length' : reason === 'tool_use' || hadTool ? 'tool' : reason === 'refusal' ? 'filtered' : 'end';
|
|
23
|
+
export function anthropicAdapter(opts) {
|
|
24
|
+
return {
|
|
25
|
+
provider: 'anthropic',
|
|
26
|
+
async generate(req) {
|
|
27
|
+
const folded = foldForAnthropic(req.messages);
|
|
28
|
+
const toolChoice = !req.tools?.length ? undefined : req.toolChoice === 'required' ? { type: 'any' } : req.toolChoice && typeof req.toolChoice === 'object' ? { type: 'tool', name: req.toolChoice.name } : req.toolChoice === 'none' ? undefined : { type: 'auto' };
|
|
29
|
+
const params = {
|
|
30
|
+
model: req.model, max_tokens: req.maxOutputTokens, ...(folded.system ? { system: folded.system } : {}), messages: folded.messages,
|
|
31
|
+
...(req.tools?.length && req.toolChoice !== 'none' ? { tools: req.tools.map((t) => ({ name: t.name, ...(t.description ? { description: t.description } : {}), input_schema: t.inputSchema })) } : {}),
|
|
32
|
+
...(toolChoice ? { tool_choice: toolChoice } : {}),
|
|
33
|
+
};
|
|
34
|
+
const timer = setTimeout(() => { }, req.timeoutMs);
|
|
35
|
+
let res;
|
|
36
|
+
try {
|
|
37
|
+
res = await Promise.race([
|
|
38
|
+
opts.client.messages.create(params),
|
|
39
|
+
new Promise((_, reject) => setTimeout(() => reject(new ProviderFailure('timeout', `anthropic ${req.model} did not answer within ${req.timeoutMs} ms`)), req.timeoutMs)),
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
if (e instanceof ProviderFailure)
|
|
44
|
+
throw e;
|
|
45
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
46
|
+
const m = /HTTP (\d{3})/.exec(msg);
|
|
47
|
+
throw new ProviderFailure(m ? classifyStatus(Number(m[1])) : /stream error|no body/.test(msg) ? 'unavailable' : 'unavailable', msg, m ? Number(m[1]) : undefined);
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
const text = res.content.filter((b) => b.type === 'text' && typeof b.text === 'string').map((b) => b.text).join('');
|
|
53
|
+
const toolCalls = res.content.filter((b) => b.type === 'tool_use' && typeof b.name === 'string').map((b) => ({ ...(b.id ? { id: b.id } : {}), name: b.name, args: (b.input ?? {}) }));
|
|
54
|
+
const usage = normalizeAnthropicUsage(res.usage);
|
|
55
|
+
return { content: text, toolCalls, stopReason: stopOf(res.stop_reason, toolCalls.length > 0), ...(usage ? { usage } : {}), ...(res.usage ? { providerUsage: res.usage } : {}) };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OpenAiCompatLike, OpenAiCompatChatCreateParams } from '@agenticprimitives/orchestration-openai-compat';
|
|
2
|
+
import type { ProviderAdapter } from '../ports.js';
|
|
3
|
+
import type { MessageV1, ToolCallV1 } from '../contract.js';
|
|
4
|
+
export interface OpenAiCompatAdapterOpts {
|
|
5
|
+
/** One client per endpoint: the Worker builds `createFetchOpenAiCompatClient({ baseUrl, apiKey })` per catalog endpoint. */
|
|
6
|
+
clientFor: (endpoint: string | undefined) => OpenAiCompatLike;
|
|
7
|
+
}
|
|
8
|
+
export declare function foldForOpenAi(messages: MessageV1[]): OpenAiCompatChatCreateParams['messages'];
|
|
9
|
+
export declare function parseToolCalls(calls: Array<{
|
|
10
|
+
id?: string;
|
|
11
|
+
function: {
|
|
12
|
+
name: string;
|
|
13
|
+
arguments: string;
|
|
14
|
+
};
|
|
15
|
+
}> | undefined): ToolCallV1[];
|
|
16
|
+
export declare function openAiCompatAdapter(opts: OpenAiCompatAdapterOpts): ProviderAdapter;
|
|
17
|
+
//# sourceMappingURL=openai-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compat.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-compat.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,4BAA4B,EAA0B,MAAM,gDAAgD,CAAC;AAC7I,OAAO,KAAK,EAAqC,eAAe,EAAE,MAAM,aAAa,CAAC;AAGtF,OAAO,KAAK,EAAE,SAAS,EAAgB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE1E,MAAM,WAAW,uBAAuB;IACtC,4HAA4H;IAC5H,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,gBAAgB,CAAC;CAC/D;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAM7F;AAKD,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,UAAU,EAAE,CAOrI;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,uBAAuB,GAAG,eAAe,CAkClF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { classifyStatus, ProviderFailure } from '../ports.js';
|
|
2
|
+
import { normalizeOpenAiUsage } from '../usage.js';
|
|
3
|
+
export function foldForOpenAi(messages) {
|
|
4
|
+
return messages.map((m) => {
|
|
5
|
+
if (m.role === 'tool')
|
|
6
|
+
return { role: 'user', content: `[tool result ${m.toolCallId}]\n${m.content}` };
|
|
7
|
+
if (m.role === 'assistant' && m.toolCalls?.length)
|
|
8
|
+
return { role: 'assistant', content: `${m.content}${m.content ? '\n' : ''}[called ${m.toolCalls.map((c) => `${c.name}(${JSON.stringify(c.args)})`).join('; ')}]` };
|
|
9
|
+
return { role: m.role, content: m.content };
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
const stopOf = (reason, hadTool) => reason === 'length' ? 'length' : reason === 'tool_calls' || hadTool ? 'tool' : reason === 'content_filter' ? 'filtered' : 'end';
|
|
13
|
+
export function parseToolCalls(calls) {
|
|
14
|
+
return (calls ?? []).map((c) => {
|
|
15
|
+
let args = {};
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(c.function.arguments || '{}');
|
|
18
|
+
if (parsed && typeof parsed === 'object')
|
|
19
|
+
args = parsed;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new ProviderFailure('malformed', `the model's tool call "${c.function.name}" carried arguments that are not JSON`);
|
|
23
|
+
}
|
|
24
|
+
return { ...(c.id ? { id: c.id } : {}), name: c.function.name, args };
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function openAiCompatAdapter(opts) {
|
|
28
|
+
return {
|
|
29
|
+
provider: 'openai-compat',
|
|
30
|
+
async generate(req) {
|
|
31
|
+
const client = opts.clientFor(req.endpoint);
|
|
32
|
+
const toolChoice = !req.tools?.length ? undefined : req.toolChoice === 'required' ? 'required' : req.toolChoice === 'none' ? 'none' : req.toolChoice && typeof req.toolChoice === 'object' ? { type: 'function', function: { name: req.toolChoice.name } } : 'auto';
|
|
33
|
+
const params = {
|
|
34
|
+
model: req.model, max_tokens: req.maxOutputTokens, messages: foldForOpenAi(req.messages),
|
|
35
|
+
...(req.tools?.length && req.toolChoice !== 'none' ? { tools: req.tools.map((t) => ({ type: 'function', function: { name: t.name, ...(t.description ? { description: t.description } : {}), parameters: t.inputSchema } })) } : {}),
|
|
36
|
+
...(toolChoice ? { tool_choice: toolChoice } : {}),
|
|
37
|
+
...(req.temperature !== undefined ? { temperature: req.temperature } : {}),
|
|
38
|
+
};
|
|
39
|
+
let res;
|
|
40
|
+
try {
|
|
41
|
+
res = await Promise.race([
|
|
42
|
+
client.chat.completions.create(params),
|
|
43
|
+
new Promise((_, reject) => setTimeout(() => reject(new ProviderFailure('timeout', `${req.endpoint ?? 'openai-compat'} ${req.model} did not answer within ${req.timeoutMs} ms`)), req.timeoutMs)),
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
if (e instanceof ProviderFailure)
|
|
48
|
+
throw e;
|
|
49
|
+
const status = e.status;
|
|
50
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
51
|
+
if (typeof status === 'number')
|
|
52
|
+
throw new ProviderFailure(classifyStatus(status), msg, status);
|
|
53
|
+
const m = /HTTP (\d{3})|\b(\d{3})\b/.exec(msg);
|
|
54
|
+
const code = m ? Number(m[1] ?? m[2]) : undefined;
|
|
55
|
+
throw new ProviderFailure(code ? classifyStatus(code) : 'unavailable', msg, code);
|
|
56
|
+
}
|
|
57
|
+
const choice = res.choices[0];
|
|
58
|
+
if (!choice)
|
|
59
|
+
throw new ProviderFailure('malformed', 'the host answered with no choices');
|
|
60
|
+
const toolCalls = parseToolCalls(choice.message.tool_calls);
|
|
61
|
+
const usage = normalizeOpenAiUsage(res.usage);
|
|
62
|
+
return { content: choice.message.content ?? '', toolCalls, stopReason: stopOf(choice.finish_reason, toolCalls.length > 0), ...(usage ? { usage } : {}), ...(res.usage ? { providerUsage: res.usage } : {}) };
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=openai-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compat.js","sourceRoot":"","sources":["../../src/adapters/openai-compat.ts"],"names":[],"mappings":"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"}
|
package/dist/budget.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { BudgetLimitsV1, ModelPricingV1, ModelUsageV1 } from './contract.js';
|
|
2
|
+
export interface ProfileCountersV1 {
|
|
3
|
+
tokens: number;
|
|
4
|
+
microUsd: number;
|
|
5
|
+
/** Requests started in the current minute. */
|
|
6
|
+
requestsThisMinute: number;
|
|
7
|
+
minute: number;
|
|
8
|
+
inFlight: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ReservationV1 {
|
|
11
|
+
id: string;
|
|
12
|
+
profile: string;
|
|
13
|
+
at: number;
|
|
14
|
+
estimateTokens: number;
|
|
15
|
+
estimateMicroUsd: number;
|
|
16
|
+
}
|
|
17
|
+
export interface BudgetStateV1 {
|
|
18
|
+
/** `YYYY-MM-DD` (UTC) — counters roll at 00:00 UTC. */
|
|
19
|
+
day: string;
|
|
20
|
+
counters: Record<string, ProfileCountersV1>;
|
|
21
|
+
reservations: Record<string, ReservationV1>;
|
|
22
|
+
}
|
|
23
|
+
export declare const dayOf: (now: number) => string;
|
|
24
|
+
export declare const minuteOf: (now: number) => number;
|
|
25
|
+
export declare const emptyBudget: (now: number) => BudgetStateV1;
|
|
26
|
+
/** A new day resets the day counters; reservations survive (they are settled or expired by id). */
|
|
27
|
+
export declare function rollDay(s: BudgetStateV1, now: number): BudgetStateV1;
|
|
28
|
+
/** Prompt tokens are counted here as ~4 chars per token — an estimate the settle corrects; it only sizes the reservation. */
|
|
29
|
+
export declare const estimateTokens: (chars: number) => number;
|
|
30
|
+
export declare function estimateCostMicroUsd(tokensIn: number, tokensOut: number, pricing: ModelPricingV1): number;
|
|
31
|
+
export declare function costMicroUsd(usage: ModelUsageV1, pricing: ModelPricingV1): number;
|
|
32
|
+
export type ReserveResult = {
|
|
33
|
+
ok: true;
|
|
34
|
+
state: BudgetStateV1;
|
|
35
|
+
reservationId: string;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
state: BudgetStateV1;
|
|
39
|
+
reason: 'tokens_per_day' | 'micro_usd_per_day' | 'requests_per_minute' | 'concurrency';
|
|
40
|
+
detail: string;
|
|
41
|
+
};
|
|
42
|
+
export declare function reserve(state: BudgetStateV1, input: {
|
|
43
|
+
id: string;
|
|
44
|
+
profile: string;
|
|
45
|
+
estimateTokens: number;
|
|
46
|
+
estimateMicroUsd: number;
|
|
47
|
+
limits: BudgetLimitsV1;
|
|
48
|
+
now: number;
|
|
49
|
+
}): ReserveResult;
|
|
50
|
+
/** Replace the estimate with what actually happened. Unknown or already-settled ids are a no-op (settle twice is safe). */
|
|
51
|
+
export declare function settle(state: BudgetStateV1, input: {
|
|
52
|
+
reservationId: string;
|
|
53
|
+
usage: ModelUsageV1;
|
|
54
|
+
costMicroUsd: number;
|
|
55
|
+
now: number;
|
|
56
|
+
}): {
|
|
57
|
+
state: BudgetStateV1;
|
|
58
|
+
settled: boolean;
|
|
59
|
+
};
|
|
60
|
+
/** Nothing came back: the reservation is charged AS RESERVED. Never zero — an unknown cost is the estimate, not a refund. */
|
|
61
|
+
export declare function expire(state: BudgetStateV1, input: {
|
|
62
|
+
reservationId: string;
|
|
63
|
+
now: number;
|
|
64
|
+
}): {
|
|
65
|
+
state: BudgetStateV1;
|
|
66
|
+
expired: boolean;
|
|
67
|
+
chargedMicroUsd: number;
|
|
68
|
+
};
|
|
69
|
+
/** Reservations older than `maxAgeMs` — the alarm sweeps these: reconcile the ones whose usage can be read back, expire the rest. */
|
|
70
|
+
export declare function stale(state: BudgetStateV1, now: number, maxAgeMs: number): ReservationV1[];
|
|
71
|
+
/** Receipts are the record; a wiped store is rebuilt from the day's receipts (settled cost + expired reservations). */
|
|
72
|
+
export declare function rebuildFromReceipts(now: number, receipts: ReadonlyArray<{
|
|
73
|
+
profile: string;
|
|
74
|
+
usage: ModelUsageV1;
|
|
75
|
+
costMicroUsd: number;
|
|
76
|
+
at: string;
|
|
77
|
+
reconciliation: 'settled' | 'pending' | 'expired';
|
|
78
|
+
}>): BudgetStateV1;
|
|
79
|
+
/** Utilisation of each limit, 0..1 (or null where no limit is set) — what the Pulse draws against the line. */
|
|
80
|
+
export declare function utilisation(state: BudgetStateV1, profile: string, limits: BudgetLimitsV1, now: number): {
|
|
81
|
+
tokens: number | null;
|
|
82
|
+
microUsd: number | null;
|
|
83
|
+
requestsPerMinute: number | null;
|
|
84
|
+
concurrency: number | null;
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"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"}
|
package/dist/budget.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export const dayOf = (now) => new Date(now).toISOString().slice(0, 10);
|
|
2
|
+
export const minuteOf = (now) => Math.floor(now / 60_000);
|
|
3
|
+
export const emptyBudget = (now) => ({ day: dayOf(now), counters: {}, reservations: {} });
|
|
4
|
+
const counters = (s, profile, now) => {
|
|
5
|
+
const c = s.counters[profile] ?? { tokens: 0, microUsd: 0, requestsThisMinute: 0, minute: minuteOf(now), inFlight: 0 };
|
|
6
|
+
return c.minute === minuteOf(now) ? c : { ...c, requestsThisMinute: 0, minute: minuteOf(now) };
|
|
7
|
+
};
|
|
8
|
+
/** A new day resets the day counters; reservations survive (they are settled or expired by id). */
|
|
9
|
+
export function rollDay(s, now) {
|
|
10
|
+
const d = dayOf(now);
|
|
11
|
+
if (s.day === d)
|
|
12
|
+
return s;
|
|
13
|
+
const next = {};
|
|
14
|
+
for (const [k, c] of Object.entries(s.counters))
|
|
15
|
+
next[k] = { ...c, tokens: 0, microUsd: 0, requestsThisMinute: 0, minute: minuteOf(now) };
|
|
16
|
+
return { day: d, counters: next, reservations: s.reservations };
|
|
17
|
+
}
|
|
18
|
+
/** Prompt tokens are counted here as ~4 chars per token — an estimate the settle corrects; it only sizes the reservation. */
|
|
19
|
+
export const estimateTokens = (chars) => Math.ceil(chars / 4);
|
|
20
|
+
export function estimateCostMicroUsd(tokensIn, tokensOut, pricing) {
|
|
21
|
+
return Math.ceil((tokensIn * pricing.inputMicroUsdPerMtok + tokensOut * pricing.outputMicroUsdPerMtok) / 1_000_000);
|
|
22
|
+
}
|
|
23
|
+
export function costMicroUsd(usage, pricing) {
|
|
24
|
+
const cached = usage.cachedIn ?? 0;
|
|
25
|
+
const uncached = Math.max(0, usage.tokensIn - cached);
|
|
26
|
+
const cachedRate = pricing.cachedInputMicroUsdPerMtok ?? pricing.inputMicroUsdPerMtok;
|
|
27
|
+
return Math.ceil((uncached * pricing.inputMicroUsdPerMtok + cached * cachedRate + usage.tokensOut * pricing.outputMicroUsdPerMtok) / 1_000_000);
|
|
28
|
+
}
|
|
29
|
+
export function reserve(state, input) {
|
|
30
|
+
const s = rollDay(state, input.now);
|
|
31
|
+
const c = counters(s, input.profile, input.now);
|
|
32
|
+
const l = input.limits;
|
|
33
|
+
const refuse = (reason, detail) => ({ ok: false, state: s, reason, detail });
|
|
34
|
+
if (l.concurrency !== undefined && c.inFlight >= l.concurrency)
|
|
35
|
+
return refuse('concurrency', `${c.inFlight} in flight, limit ${l.concurrency}`);
|
|
36
|
+
if (l.requestsPerMinute !== undefined && c.requestsThisMinute >= l.requestsPerMinute)
|
|
37
|
+
return refuse('requests_per_minute', `${c.requestsThisMinute} this minute, limit ${l.requestsPerMinute}`);
|
|
38
|
+
if (l.tokensPerDay !== undefined && c.tokens + input.estimateTokens > l.tokensPerDay)
|
|
39
|
+
return refuse('tokens_per_day', `${c.tokens} used + ${input.estimateTokens} reserved > ${l.tokensPerDay} today`);
|
|
40
|
+
if (l.microUsdPerDay !== undefined && c.microUsd + input.estimateMicroUsd > l.microUsdPerDay)
|
|
41
|
+
return refuse('micro_usd_per_day', `${c.microUsd} µUSD used + ${input.estimateMicroUsd} reserved > ${l.microUsdPerDay} today`);
|
|
42
|
+
const next = { ...c, tokens: c.tokens + input.estimateTokens, microUsd: c.microUsd + input.estimateMicroUsd, requestsThisMinute: c.requestsThisMinute + 1, inFlight: c.inFlight + 1 };
|
|
43
|
+
return {
|
|
44
|
+
ok: true, reservationId: input.id,
|
|
45
|
+
state: { ...s, counters: { ...s.counters, [input.profile]: next }, reservations: { ...s.reservations, [input.id]: { id: input.id, profile: input.profile, at: input.now, estimateTokens: input.estimateTokens, estimateMicroUsd: input.estimateMicroUsd } } },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Replace the estimate with what actually happened. Unknown or already-settled ids are a no-op (settle twice is safe). */
|
|
49
|
+
export function settle(state, input) {
|
|
50
|
+
const s = rollDay(state, input.now);
|
|
51
|
+
const r = s.reservations[input.reservationId];
|
|
52
|
+
if (!r)
|
|
53
|
+
return { state: s, settled: false };
|
|
54
|
+
const c = counters(s, r.profile, input.now);
|
|
55
|
+
const actualTokens = input.usage.tokensIn + input.usage.tokensOut;
|
|
56
|
+
// If the day rolled between reserve and settle the estimate was zeroed with the day; add the actual, do not subtract.
|
|
57
|
+
const sameDay = s.day === dayOf(r.at);
|
|
58
|
+
const next = {
|
|
59
|
+
...c,
|
|
60
|
+
tokens: Math.max(0, c.tokens - (sameDay ? r.estimateTokens : 0) + actualTokens),
|
|
61
|
+
microUsd: Math.max(0, c.microUsd - (sameDay ? r.estimateMicroUsd : 0) + input.costMicroUsd),
|
|
62
|
+
inFlight: Math.max(0, c.inFlight - 1),
|
|
63
|
+
};
|
|
64
|
+
const { [input.reservationId]: _gone, ...rest } = s.reservations;
|
|
65
|
+
return { state: { ...s, counters: { ...s.counters, [r.profile]: next }, reservations: rest }, settled: true };
|
|
66
|
+
}
|
|
67
|
+
/** Nothing came back: the reservation is charged AS RESERVED. Never zero — an unknown cost is the estimate, not a refund. */
|
|
68
|
+
export function expire(state, input) {
|
|
69
|
+
const s = rollDay(state, input.now);
|
|
70
|
+
const r = s.reservations[input.reservationId];
|
|
71
|
+
if (!r)
|
|
72
|
+
return { state: s, expired: false, chargedMicroUsd: 0 };
|
|
73
|
+
const c = counters(s, r.profile, input.now);
|
|
74
|
+
const { [input.reservationId]: _gone, ...rest } = s.reservations;
|
|
75
|
+
return { state: { ...s, counters: { ...s.counters, [r.profile]: { ...c, inFlight: Math.max(0, c.inFlight - 1) } }, reservations: rest }, expired: true, chargedMicroUsd: r.estimateMicroUsd };
|
|
76
|
+
}
|
|
77
|
+
/** Reservations older than `maxAgeMs` — the alarm sweeps these: reconcile the ones whose usage can be read back, expire the rest. */
|
|
78
|
+
export function stale(state, now, maxAgeMs) {
|
|
79
|
+
return Object.values(state.reservations).filter((r) => now - r.at > maxAgeMs);
|
|
80
|
+
}
|
|
81
|
+
/** Receipts are the record; a wiped store is rebuilt from the day's receipts (settled cost + expired reservations). */
|
|
82
|
+
export function rebuildFromReceipts(now, receipts) {
|
|
83
|
+
const s = emptyBudget(now);
|
|
84
|
+
for (const r of receipts) {
|
|
85
|
+
if (dayOf(Date.parse(r.at)) !== s.day)
|
|
86
|
+
continue;
|
|
87
|
+
const c = s.counters[r.profile] ?? { tokens: 0, microUsd: 0, requestsThisMinute: 0, minute: minuteOf(now), inFlight: 0 };
|
|
88
|
+
s.counters[r.profile] = { ...c, tokens: c.tokens + r.usage.tokensIn + r.usage.tokensOut, microUsd: c.microUsd + r.costMicroUsd };
|
|
89
|
+
}
|
|
90
|
+
return s;
|
|
91
|
+
}
|
|
92
|
+
/** Utilisation of each limit, 0..1 (or null where no limit is set) — what the Pulse draws against the line. */
|
|
93
|
+
export function utilisation(state, profile, limits, now) {
|
|
94
|
+
const c = counters(rollDay(state, now), profile, now);
|
|
95
|
+
const r = (used, limit) => (limit === undefined || limit === 0 ? null : Math.min(1, used / limit));
|
|
96
|
+
return { tokens: r(c.tokens, limits.tokensPerDay), microUsd: r(c.microUsd, limits.microUsdPerDay), requestsPerMinute: r(c.requestsThisMinute, limits.requestsPerMinute), concurrency: r(c.inFlight, limits.concurrency) };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.js","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"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"}
|