@hiper2d/ai-agents 0.2.1 → 0.3.1
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 +31 -0
- package/dist/index.d.mts +150 -1
- package/dist/index.d.ts +150 -1
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1875,7 +1875,157 @@ 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
|
|
2025
|
+
var beforeAskHook;
|
|
2026
|
+
function setBeforeAskHook(hook) {
|
|
2027
|
+
beforeAskHook = hook;
|
|
2028
|
+
}
|
|
1879
2029
|
var AbstractAgent = class {
|
|
1880
2030
|
name;
|
|
1881
2031
|
gameId;
|
|
@@ -1927,6 +2077,7 @@ var AbstractAgent = class {
|
|
|
1927
2077
|
* must NOT override these.
|
|
1928
2078
|
*/
|
|
1929
2079
|
async askWithZodSchema(zodSchema, messages) {
|
|
2080
|
+
if (beforeAskHook) await beforeAskHook(this);
|
|
1930
2081
|
const startedAt = Date.now();
|
|
1931
2082
|
try {
|
|
1932
2083
|
const [result, thinking, usage, signature] = await this.doAskWithZodSchema(zodSchema, messages);
|
|
@@ -1937,6 +2088,7 @@ var AbstractAgent = class {
|
|
|
1937
2088
|
}
|
|
1938
2089
|
}
|
|
1939
2090
|
async askText(messages) {
|
|
2091
|
+
if (beforeAskHook) await beforeAskHook(this);
|
|
1940
2092
|
const startedAt = Date.now();
|
|
1941
2093
|
try {
|
|
1942
2094
|
const [content, thinking, usage, signature] = await this.doAskText(messages);
|
|
@@ -4603,6 +4755,8 @@ export {
|
|
|
4603
4755
|
AbstractAgent,
|
|
4604
4756
|
AgentFactory,
|
|
4605
4757
|
BotResponseError,
|
|
4758
|
+
BudgetController,
|
|
4759
|
+
BudgetExceededError,
|
|
4606
4760
|
CACHE_TIER_MARKER,
|
|
4607
4761
|
ClaudeAgent,
|
|
4608
4762
|
DEEPSEEK_PEAK_SCHEDULE,
|
|
@@ -4620,6 +4774,7 @@ export {
|
|
|
4620
4774
|
GoogleVoiceAgent,
|
|
4621
4775
|
Gpt5Agent,
|
|
4622
4776
|
GrokAgent,
|
|
4777
|
+
InMemorySpendStore,
|
|
4623
4778
|
KimiAgent,
|
|
4624
4779
|
LLM_CONSTANTS,
|
|
4625
4780
|
MESSAGE_ROLE,
|
|
@@ -4646,6 +4801,7 @@ export {
|
|
|
4646
4801
|
VOICE_PROVIDER_API_KEY,
|
|
4647
4802
|
VoiceAgentFactory,
|
|
4648
4803
|
ZodSchemaConverter,
|
|
4804
|
+
applySpend,
|
|
4649
4805
|
buildGoogleTtsPrompt,
|
|
4650
4806
|
calculateAnthropicCost,
|
|
4651
4807
|
calculateCost,
|
|
@@ -4664,6 +4820,7 @@ export {
|
|
|
4664
4820
|
cleanResponse,
|
|
4665
4821
|
createCatalog,
|
|
4666
4822
|
createVoiceAgent,
|
|
4823
|
+
evaluateBudget,
|
|
4667
4824
|
extractAnthropicTokenUsage,
|
|
4668
4825
|
extractTokenUsageFromResponse5 as extractAnthropicTokenUsageFromResponse,
|
|
4669
4826
|
extractDeepSeekTokenUsage,
|
|
@@ -4681,6 +4838,7 @@ export {
|
|
|
4681
4838
|
extractTokenUsageFromResponse as extractOpenAITokenUsageFromResponse,
|
|
4682
4839
|
extractTokenUsage,
|
|
4683
4840
|
extractUsageAndCalculateCost,
|
|
4841
|
+
firstRefusal,
|
|
4684
4842
|
generateGoogleTtsAudio,
|
|
4685
4843
|
generateOpenAiTtsAudio,
|
|
4686
4844
|
generateSchemaInstructions,
|
|
@@ -4689,10 +4847,12 @@ export {
|
|
|
4689
4847
|
getModelProviderName,
|
|
4690
4848
|
getModelTags,
|
|
4691
4849
|
getProviderSignatureFields,
|
|
4850
|
+
isBudgetExceededError,
|
|
4692
4851
|
isHybridThinkingModel,
|
|
4693
4852
|
isInPeakWindow,
|
|
4694
4853
|
isPeakBilling,
|
|
4695
4854
|
isWeekendAt,
|
|
4855
|
+
ledgerSpend,
|
|
4696
4856
|
logger,
|
|
4697
4857
|
mergeThinking,
|
|
4698
4858
|
modelHasTag,
|
|
@@ -4700,7 +4860,10 @@ export {
|
|
|
4700
4860
|
needsPromptBasedSchema,
|
|
4701
4861
|
parseAndValidateLlmJson,
|
|
4702
4862
|
pcmToWav,
|
|
4863
|
+
periodEnd,
|
|
4864
|
+
periodKey,
|
|
4703
4865
|
safeValidateResponse,
|
|
4866
|
+
setBeforeAskHook,
|
|
4704
4867
|
setLlmLogger,
|
|
4705
4868
|
stableHashHex,
|
|
4706
4869
|
stripInlineThinking,
|