@hiper2d/ai-agents 0.2.1 → 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.
- package/README.md +22 -0
- package/dist/index.d.mts +141 -1
- package/dist/index.d.ts +141 -1
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1875,6 +1875,152 @@ function createVoiceAgent(provider, apiKey) {
|
|
|
1875
1875
|
return VoiceAgentFactory.createAgent(provider, apiKey);
|
|
1876
1876
|
}
|
|
1877
1877
|
|
|
1878
|
+
// src/budget/index.ts
|
|
1879
|
+
function round6(n) {
|
|
1880
|
+
return parseFloat((Number(n) || 0).toFixed(6));
|
|
1881
|
+
}
|
|
1882
|
+
function periodKey(timestamp, window) {
|
|
1883
|
+
const d = new Date(timestamp);
|
|
1884
|
+
const y = d.getUTCFullYear();
|
|
1885
|
+
const m = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
1886
|
+
if (window === "month") {
|
|
1887
|
+
return `${y}-${m}`;
|
|
1888
|
+
}
|
|
1889
|
+
const day = String(d.getUTCDate()).padStart(2, "0");
|
|
1890
|
+
return `${y}-${m}-${day}`;
|
|
1891
|
+
}
|
|
1892
|
+
function periodEnd(timestamp, window) {
|
|
1893
|
+
const d = new Date(timestamp);
|
|
1894
|
+
if (window === "month") {
|
|
1895
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);
|
|
1896
|
+
}
|
|
1897
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + 1);
|
|
1898
|
+
}
|
|
1899
|
+
function normalizeLedger(ledger, period) {
|
|
1900
|
+
if (!ledger || ledger.period !== period) {
|
|
1901
|
+
return { period, totalUSD: 0, buckets: {} };
|
|
1902
|
+
}
|
|
1903
|
+
const buckets = {};
|
|
1904
|
+
for (const [k, v] of Object.entries(ledger.buckets ?? {})) {
|
|
1905
|
+
buckets[k] = round6(v);
|
|
1906
|
+
}
|
|
1907
|
+
return { period, totalUSD: round6(ledger.totalUSD ?? 0), buckets };
|
|
1908
|
+
}
|
|
1909
|
+
function applySpend(ledger, input) {
|
|
1910
|
+
const timestamp = input.timestamp ?? Date.now();
|
|
1911
|
+
const period = periodKey(timestamp, input.window);
|
|
1912
|
+
const current2 = normalizeLedger(ledger, period);
|
|
1913
|
+
const amount = round6(input.amountUSD);
|
|
1914
|
+
if (!(amount > 0)) {
|
|
1915
|
+
return current2;
|
|
1916
|
+
}
|
|
1917
|
+
const buckets = { ...current2.buckets };
|
|
1918
|
+
if (input.bucket) {
|
|
1919
|
+
buckets[input.bucket] = round6((buckets[input.bucket] ?? 0) + amount);
|
|
1920
|
+
}
|
|
1921
|
+
return { period, totalUSD: round6(current2.totalUSD + amount), buckets };
|
|
1922
|
+
}
|
|
1923
|
+
function ledgerSpend(ledger, window, timestamp = Date.now(), bucket) {
|
|
1924
|
+
const current2 = normalizeLedger(ledger, periodKey(timestamp, window));
|
|
1925
|
+
return bucket ? current2.buckets[bucket] ?? 0 : current2.totalUSD;
|
|
1926
|
+
}
|
|
1927
|
+
function evaluateBudget(spentUSD, limit, timestamp = Date.now()) {
|
|
1928
|
+
const spent = round6(spentUSD);
|
|
1929
|
+
const unlimited = !Number.isFinite(limit.limitUSD);
|
|
1930
|
+
const remaining = unlimited ? Number.POSITIVE_INFINITY : Math.max(0, round6(limit.limitUSD - spent));
|
|
1931
|
+
return {
|
|
1932
|
+
allowed: unlimited || spent < limit.limitUSD,
|
|
1933
|
+
window: limit.window,
|
|
1934
|
+
...limit.bucket ? { bucket: limit.bucket } : {},
|
|
1935
|
+
limitUSD: limit.limitUSD,
|
|
1936
|
+
spentUSD: spent,
|
|
1937
|
+
remainingUSD: remaining,
|
|
1938
|
+
resetsAt: periodEnd(timestamp, limit.window)
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
function firstRefusal(verdicts) {
|
|
1942
|
+
return verdicts.find((v) => !v.allowed);
|
|
1943
|
+
}
|
|
1944
|
+
var BudgetExceededError = class _BudgetExceededError extends Error {
|
|
1945
|
+
verdict;
|
|
1946
|
+
subject;
|
|
1947
|
+
constructor(verdict, subject, message) {
|
|
1948
|
+
super(message ?? _BudgetExceededError.describe(verdict));
|
|
1949
|
+
this.name = "BudgetExceededError";
|
|
1950
|
+
this.verdict = verdict;
|
|
1951
|
+
this.subject = subject;
|
|
1952
|
+
}
|
|
1953
|
+
static describe(v) {
|
|
1954
|
+
const when = v.window === "day" ? "daily" : "monthly";
|
|
1955
|
+
return `${when} budget of $${v.limitUSD} exhausted ($${v.spentUSD} spent); resets at ${new Date(v.resetsAt).toISOString()}`;
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
function isBudgetExceededError(err) {
|
|
1959
|
+
return err instanceof BudgetExceededError || typeof err === "object" && err !== null && err.name === "BudgetExceededError" && !!err.verdict;
|
|
1960
|
+
}
|
|
1961
|
+
var InMemorySpendStore = class {
|
|
1962
|
+
ledgers = /* @__PURE__ */ new Map();
|
|
1963
|
+
async read(subject) {
|
|
1964
|
+
return { ...this.ledgers.get(subject) ?? {} };
|
|
1965
|
+
}
|
|
1966
|
+
async update(subject, fn) {
|
|
1967
|
+
const next = fn({ ...this.ledgers.get(subject) ?? {} });
|
|
1968
|
+
this.ledgers.set(subject, next);
|
|
1969
|
+
return { ...next };
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
var BudgetController = class {
|
|
1973
|
+
constructor(store, options) {
|
|
1974
|
+
this.store = store;
|
|
1975
|
+
this.limits = options.limits;
|
|
1976
|
+
this.bucket = options.bucket;
|
|
1977
|
+
this.clock = options.clock ?? (() => Date.now());
|
|
1978
|
+
}
|
|
1979
|
+
store;
|
|
1980
|
+
limits;
|
|
1981
|
+
bucket;
|
|
1982
|
+
clock;
|
|
1983
|
+
verdicts(ledgers, now) {
|
|
1984
|
+
return this.limits.map((limit) => {
|
|
1985
|
+
const spent = ledgerSpend(ledgers[limit.window], limit.window, now, limit.bucket ?? this.bucket);
|
|
1986
|
+
return evaluateBudget(spent, limit, now);
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
async check(subject) {
|
|
1990
|
+
return this.verdicts(await this.store.read(subject), this.clock());
|
|
1991
|
+
}
|
|
1992
|
+
async assertWithinBudget(subject) {
|
|
1993
|
+
const refused = firstRefusal(await this.check(subject));
|
|
1994
|
+
if (refused) {
|
|
1995
|
+
throw new BudgetExceededError(refused, subject);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Record `amountUSD` against every limited window. Re-checks the limits on the
|
|
2000
|
+
* ledgers as they are at write time and throws `BudgetExceededError` (writing
|
|
2001
|
+
* nothing) if any window is already exhausted.
|
|
2002
|
+
*/
|
|
2003
|
+
async record(subject, amountUSD) {
|
|
2004
|
+
const now = this.clock();
|
|
2005
|
+
return this.store.update(subject, (current2) => {
|
|
2006
|
+
const refused = firstRefusal(this.verdicts(current2, now));
|
|
2007
|
+
if (refused) {
|
|
2008
|
+
throw new BudgetExceededError(refused, subject);
|
|
2009
|
+
}
|
|
2010
|
+
const next = { ...current2 };
|
|
2011
|
+
for (const limit of this.limits) {
|
|
2012
|
+
next[limit.window] = applySpend(current2[limit.window], {
|
|
2013
|
+
window: limit.window,
|
|
2014
|
+
amountUSD,
|
|
2015
|
+
bucket: limit.bucket ?? this.bucket,
|
|
2016
|
+
timestamp: now
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
return next;
|
|
2020
|
+
});
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
|
|
1878
2024
|
// src/agents/abstract-agent.ts
|
|
1879
2025
|
var AbstractAgent = class {
|
|
1880
2026
|
name;
|
|
@@ -4603,6 +4749,8 @@ export {
|
|
|
4603
4749
|
AbstractAgent,
|
|
4604
4750
|
AgentFactory,
|
|
4605
4751
|
BotResponseError,
|
|
4752
|
+
BudgetController,
|
|
4753
|
+
BudgetExceededError,
|
|
4606
4754
|
CACHE_TIER_MARKER,
|
|
4607
4755
|
ClaudeAgent,
|
|
4608
4756
|
DEEPSEEK_PEAK_SCHEDULE,
|
|
@@ -4620,6 +4768,7 @@ export {
|
|
|
4620
4768
|
GoogleVoiceAgent,
|
|
4621
4769
|
Gpt5Agent,
|
|
4622
4770
|
GrokAgent,
|
|
4771
|
+
InMemorySpendStore,
|
|
4623
4772
|
KimiAgent,
|
|
4624
4773
|
LLM_CONSTANTS,
|
|
4625
4774
|
MESSAGE_ROLE,
|
|
@@ -4646,6 +4795,7 @@ export {
|
|
|
4646
4795
|
VOICE_PROVIDER_API_KEY,
|
|
4647
4796
|
VoiceAgentFactory,
|
|
4648
4797
|
ZodSchemaConverter,
|
|
4798
|
+
applySpend,
|
|
4649
4799
|
buildGoogleTtsPrompt,
|
|
4650
4800
|
calculateAnthropicCost,
|
|
4651
4801
|
calculateCost,
|
|
@@ -4664,6 +4814,7 @@ export {
|
|
|
4664
4814
|
cleanResponse,
|
|
4665
4815
|
createCatalog,
|
|
4666
4816
|
createVoiceAgent,
|
|
4817
|
+
evaluateBudget,
|
|
4667
4818
|
extractAnthropicTokenUsage,
|
|
4668
4819
|
extractTokenUsageFromResponse5 as extractAnthropicTokenUsageFromResponse,
|
|
4669
4820
|
extractDeepSeekTokenUsage,
|
|
@@ -4681,6 +4832,7 @@ export {
|
|
|
4681
4832
|
extractTokenUsageFromResponse as extractOpenAITokenUsageFromResponse,
|
|
4682
4833
|
extractTokenUsage,
|
|
4683
4834
|
extractUsageAndCalculateCost,
|
|
4835
|
+
firstRefusal,
|
|
4684
4836
|
generateGoogleTtsAudio,
|
|
4685
4837
|
generateOpenAiTtsAudio,
|
|
4686
4838
|
generateSchemaInstructions,
|
|
@@ -4689,10 +4841,12 @@ export {
|
|
|
4689
4841
|
getModelProviderName,
|
|
4690
4842
|
getModelTags,
|
|
4691
4843
|
getProviderSignatureFields,
|
|
4844
|
+
isBudgetExceededError,
|
|
4692
4845
|
isHybridThinkingModel,
|
|
4693
4846
|
isInPeakWindow,
|
|
4694
4847
|
isPeakBilling,
|
|
4695
4848
|
isWeekendAt,
|
|
4849
|
+
ledgerSpend,
|
|
4696
4850
|
logger,
|
|
4697
4851
|
mergeThinking,
|
|
4698
4852
|
modelHasTag,
|
|
@@ -4700,6 +4854,8 @@ export {
|
|
|
4700
4854
|
needsPromptBasedSchema,
|
|
4701
4855
|
parseAndValidateLlmJson,
|
|
4702
4856
|
pcmToWav,
|
|
4857
|
+
periodEnd,
|
|
4858
|
+
periodKey,
|
|
4703
4859
|
safeValidateResponse,
|
|
4704
4860
|
setLlmLogger,
|
|
4705
4861
|
stableHashHex,
|