@juspay/neurolink 11.13.2 → 11.15.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/CHANGELOG.md +3 -3
- package/dist/browser/neurolink.min.js +365 -363
- package/dist/core/geminiLoopAdapter.js +13 -7
- package/dist/proxy/accountLedger.d.ts +39 -0
- package/dist/proxy/accountLedger.js +299 -0
- package/dist/proxy/proxyTranslationEngine.js +21 -3
- package/dist/server/routes/claudeProxyRoutes.d.ts +7 -8
- package/dist/server/routes/claudeProxyRoutes.js +247 -0
- package/dist/types/loopEngine.d.ts +17 -1
- package/dist/types/proxyClient.d.ts +81 -0
- package/package.json +2 -36
|
@@ -5759,6 +5759,59 @@ function buildEarlyClaudeRequestError(args) {
|
|
|
5759
5759
|
* @param basePath - Base path prefix (default: "" since Claude API uses /v1/...).
|
|
5760
5760
|
* @returns RouteGroup with Claude-compatible endpoints.
|
|
5761
5761
|
*/
|
|
5762
|
+
/**
|
|
5763
|
+
* Quota timestamps arrive in two units. `sessionResetAt`, `weeklyResetAt` and
|
|
5764
|
+
* each window's `resetsAt` are unix SECONDS; `lastUpdated`, `updatedAt` and
|
|
5765
|
+
* `coolingUntil` are already MILLISECONDS. Blanket-multiplying would push the
|
|
5766
|
+
* millisecond fields tens of thousands of years into the future, so only the
|
|
5767
|
+
* seconds fields are converted, and 0 becomes null rather than epoch zero.
|
|
5768
|
+
*/
|
|
5769
|
+
/**
|
|
5770
|
+
* Account types that represent a real credential rather than proxy plumbing.
|
|
5771
|
+
* Mirrors the Anthropic pool's own account types.
|
|
5772
|
+
*/
|
|
5773
|
+
const REAL_ACCOUNT_TYPES = new Set(["oauth", "api_key"]);
|
|
5774
|
+
function toMillis(value) {
|
|
5775
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
5776
|
+
? Math.round(value * 1000)
|
|
5777
|
+
: null;
|
|
5778
|
+
}
|
|
5779
|
+
/**
|
|
5780
|
+
* Normalise one account's quota for a dashboard consumer.
|
|
5781
|
+
*
|
|
5782
|
+
* `severity` and `isActive` are absent on header-sourced windows — a
|
|
5783
|
+
* structural property of how those rows are parsed, not a transient gap — so
|
|
5784
|
+
* every consumer would otherwise need the same fallback branch.
|
|
5785
|
+
*/
|
|
5786
|
+
function normalizeQuotaForAccounts(quota) {
|
|
5787
|
+
if (!quota || typeof quota !== "object") {
|
|
5788
|
+
return null;
|
|
5789
|
+
}
|
|
5790
|
+
const q = { ...quota };
|
|
5791
|
+
q.sessionResetAtMs = toMillis(q.sessionResetAt);
|
|
5792
|
+
q.weeklyResetAtMs = toMillis(q.weeklyResetAt);
|
|
5793
|
+
if (Array.isArray(q.windows)) {
|
|
5794
|
+
q.windows = q.windows.map((raw) => {
|
|
5795
|
+
const w = { ...raw };
|
|
5796
|
+
w.resetsAtMs = toMillis(w.resetsAt);
|
|
5797
|
+
w.severity =
|
|
5798
|
+
w.severity ?? (w.status === "rejected" ? "critical" : "normal");
|
|
5799
|
+
w.isActive = w.isActive ?? false;
|
|
5800
|
+
return w;
|
|
5801
|
+
});
|
|
5802
|
+
}
|
|
5803
|
+
return q;
|
|
5804
|
+
}
|
|
5805
|
+
/** "rejected" and "throttled" both mean degraded; unknown strings stay unknown. */
|
|
5806
|
+
function quotaHealth(status) {
|
|
5807
|
+
if (status === "allowed") {
|
|
5808
|
+
return "ok";
|
|
5809
|
+
}
|
|
5810
|
+
if (status === "rejected" || status === "throttled") {
|
|
5811
|
+
return "degraded";
|
|
5812
|
+
}
|
|
5813
|
+
return "unknown";
|
|
5814
|
+
}
|
|
5762
5815
|
export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrategy = "fill-first", passthroughMode = false, primaryAccountKey, accountAllowlistOrRuntimeOptions) {
|
|
5763
5816
|
const accountAllowlist = isClaudeProxyRouteRuntimeOptions(accountAllowlistOrRuntimeOptions)
|
|
5764
5817
|
? accountAllowlistOrRuntimeOptions.accountAllowlist
|
|
@@ -5991,6 +6044,199 @@ export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrat
|
|
|
5991
6044
|
"?account=<label> for one account, ?snapshot=true for stored state",
|
|
5992
6045
|
tags: ["claude-proxy", "limits"],
|
|
5993
6046
|
},
|
|
6047
|
+
// =====================================================================
|
|
6048
|
+
// GET /accounts -- One dashboard-shaped row per account
|
|
6049
|
+
// =====================================================================
|
|
6050
|
+
// Joins what previously took two calls with incompatible schemas plus a
|
|
6051
|
+
// client-side merge: request counters from the usage snapshot, quota from
|
|
6052
|
+
// the limits snapshot, and today's tokens and cost from the request log.
|
|
6053
|
+
{
|
|
6054
|
+
method: "GET",
|
|
6055
|
+
path: `${basePath}/accounts`,
|
|
6056
|
+
handler: async (ctx) => {
|
|
6057
|
+
const routing = runtimeConfigProvider?.();
|
|
6058
|
+
const effectiveAllowlist = routing?.accountAllowlist ?? accountAllowlist;
|
|
6059
|
+
// Cached by default. This endpoint is built to be polled, and a live
|
|
6060
|
+
// refresh spends the user's own OAuth credentials against Anthropic's
|
|
6061
|
+
// usage API — one dashboard on a short interval would hammer it.
|
|
6062
|
+
const live = ctx.query?.refresh === "true";
|
|
6063
|
+
// A live refresh reconciles cooldowns from the fetched quota, so it
|
|
6064
|
+
// makes the same overage judgement the request path does and needs
|
|
6065
|
+
// the same operator policy in scope — exactly as /limits sets it.
|
|
6066
|
+
if (live) {
|
|
6067
|
+
setOveragePolicy(routing?.useOverage);
|
|
6068
|
+
}
|
|
6069
|
+
// Every other source in this handler degrades to a partial row on
|
|
6070
|
+
// failure; quota must too, or one upstream hiccup 500s a dashboard.
|
|
6071
|
+
let limits = {
|
|
6072
|
+
fetchedAt: Date.now(),
|
|
6073
|
+
snapshot: !live,
|
|
6074
|
+
results: [],
|
|
6075
|
+
};
|
|
6076
|
+
let quotaError = null;
|
|
6077
|
+
try {
|
|
6078
|
+
limits = await refreshAccountLimits({
|
|
6079
|
+
accountAllowlist: effectiveAllowlist,
|
|
6080
|
+
snapshotOnly: !live,
|
|
6081
|
+
});
|
|
6082
|
+
}
|
|
6083
|
+
catch (error) {
|
|
6084
|
+
quotaError = error instanceof Error ? error.message : String(error);
|
|
6085
|
+
}
|
|
6086
|
+
const { getUsageSnapshot } = await import("../../proxy/usageStats.js");
|
|
6087
|
+
const statsAccounts = getUsageSnapshot().stats.accounts;
|
|
6088
|
+
// `cooling` is the field an operator actually acts on, and one small
|
|
6089
|
+
// file read answers it. `allowed`/`expired` additionally need the
|
|
6090
|
+
// token store, which /status guards behind its own timeouts — this
|
|
6091
|
+
// route reports them as null rather than taking that latency.
|
|
6092
|
+
const now = Date.now();
|
|
6093
|
+
// Typed from the loader, NOT re-asserted into a local shape. The
|
|
6094
|
+
// first version cast this to `{ until?: number }` and read
|
|
6095
|
+
// `.until` — a field PersistedAccountCooldown does not have, so
|
|
6096
|
+
// every row reported cooling: false and the assertion is precisely
|
|
6097
|
+
// what stopped the compiler from saying so.
|
|
6098
|
+
let cooldowns = {};
|
|
6099
|
+
try {
|
|
6100
|
+
cooldowns = await loadAccountCooldowns();
|
|
6101
|
+
}
|
|
6102
|
+
catch {
|
|
6103
|
+
// Non-fatal: every row simply reports cooling: false.
|
|
6104
|
+
}
|
|
6105
|
+
const isCooling = (key) => {
|
|
6106
|
+
if (!key) {
|
|
6107
|
+
return false;
|
|
6108
|
+
}
|
|
6109
|
+
const until = cooldowns[key]?.coolingUntil;
|
|
6110
|
+
return typeof until === "number" && until > now;
|
|
6111
|
+
};
|
|
6112
|
+
let usageByAccount = new Map();
|
|
6113
|
+
let usageError = null;
|
|
6114
|
+
let usageDate = "";
|
|
6115
|
+
try {
|
|
6116
|
+
const { readAccountUsage, currentUsageDate } = await import("../../proxy/accountLedger.js");
|
|
6117
|
+
usageDate = currentUsageDate();
|
|
6118
|
+
usageByAccount = await readAccountUsage(usageDate);
|
|
6119
|
+
}
|
|
6120
|
+
catch (error) {
|
|
6121
|
+
// Usage is the optional half; quota and status must still render.
|
|
6122
|
+
usageError = error instanceof Error ? error.message : String(error);
|
|
6123
|
+
}
|
|
6124
|
+
const statsByLabel = new Map();
|
|
6125
|
+
for (const entry of Object.values(statsAccounts)) {
|
|
6126
|
+
statsByLabel.set(entry.label, entry);
|
|
6127
|
+
}
|
|
6128
|
+
const rows = [];
|
|
6129
|
+
const claimed = new Set();
|
|
6130
|
+
// Real logins drive the row set. Building it from the log instead
|
|
6131
|
+
// would silently drop any account that happened to serve no traffic
|
|
6132
|
+
// today, which is exactly when an operator most wants to see it.
|
|
6133
|
+
for (const result of limits.results) {
|
|
6134
|
+
const label = result.account;
|
|
6135
|
+
claimed.add(label);
|
|
6136
|
+
const stat = statsByLabel.get(label);
|
|
6137
|
+
const quota = normalizeQuotaForAccounts(result.quota);
|
|
6138
|
+
const cooling = isCooling(result.key ?? null);
|
|
6139
|
+
rows.push({
|
|
6140
|
+
label,
|
|
6141
|
+
key: result.key ?? null,
|
|
6142
|
+
kind: "account",
|
|
6143
|
+
type: result.type ?? stat?.type ?? "oauth",
|
|
6144
|
+
// result.status describes how the quota was obtained
|
|
6145
|
+
// ("snapshot"/"fetched"), not the account's health, so it must
|
|
6146
|
+
// not leak into a field consumers read as health.
|
|
6147
|
+
// BOTH quota windows, not just the weekly one. A session
|
|
6148
|
+
// window that is rejected or throttled stops the account
|
|
6149
|
+
// serving right now — this same file gates routing on
|
|
6150
|
+
// `sessionStatus` (see the overage checks above) — so an
|
|
6151
|
+
// account with a healthy weekly window and a degraded session
|
|
6152
|
+
// window would otherwise be reported "active" while being
|
|
6153
|
+
// unable to take work.
|
|
6154
|
+
status: cooling
|
|
6155
|
+
? "cooling"
|
|
6156
|
+
: quotaHealth(quota?.weeklyStatus) === "degraded" ||
|
|
6157
|
+
quotaHealth(quota?.sessionStatus) === "degraded"
|
|
6158
|
+
? "exhausted"
|
|
6159
|
+
: "active",
|
|
6160
|
+
cooling,
|
|
6161
|
+
allowed: null,
|
|
6162
|
+
expired: null,
|
|
6163
|
+
isPrimary: false,
|
|
6164
|
+
requests: stat ? stat.successCount + stat.errorCount : null,
|
|
6165
|
+
errors: stat?.errorCount ?? null,
|
|
6166
|
+
rateLimits: stat?.rateLimitCount ?? null,
|
|
6167
|
+
quotaRateLimits: stat?.quotaRateLimitCount ?? null,
|
|
6168
|
+
quota: quota
|
|
6169
|
+
? {
|
|
6170
|
+
...quota,
|
|
6171
|
+
sessionHealth: quotaHealth(quota.sessionStatus),
|
|
6172
|
+
weeklyHealth: quotaHealth(quota.weeklyStatus),
|
|
6173
|
+
}
|
|
6174
|
+
: null,
|
|
6175
|
+
usage: usageByAccount.get(label) ?? null,
|
|
6176
|
+
});
|
|
6177
|
+
}
|
|
6178
|
+
// Plumbing rows are still reported, but tagged, so a consumer can
|
|
6179
|
+
// show or hide them rather than rendering them as credentials.
|
|
6180
|
+
//
|
|
6181
|
+
// A real login can land here too: listAnthropicAccountsForUsage
|
|
6182
|
+
// skips accounts the token store has disabled or the allowlist
|
|
6183
|
+
// excludes, so an account with real usage history but no current
|
|
6184
|
+
// route is absent from limits.results. Tagging that as plumbing hid
|
|
6185
|
+
// the one account an operator is looking for when they ask why
|
|
6186
|
+
// traffic stopped — the docs tell consumers to filter internal rows
|
|
6187
|
+
// out. It stays kind "account", with a status saying why it has no
|
|
6188
|
+
// quota block.
|
|
6189
|
+
for (const entry of Object.values(statsAccounts)) {
|
|
6190
|
+
if (claimed.has(entry.label)) {
|
|
6191
|
+
continue;
|
|
6192
|
+
}
|
|
6193
|
+
const isRealAccount = REAL_ACCOUNT_TYPES.has(entry.type);
|
|
6194
|
+
rows.push({
|
|
6195
|
+
label: entry.label,
|
|
6196
|
+
key: null,
|
|
6197
|
+
kind: isRealAccount
|
|
6198
|
+
? "account"
|
|
6199
|
+
: entry.type === "translation"
|
|
6200
|
+
? "translation"
|
|
6201
|
+
: "internal",
|
|
6202
|
+
type: entry.type,
|
|
6203
|
+
status: isRealAccount ? "unrouted" : null,
|
|
6204
|
+
cooling: false,
|
|
6205
|
+
allowed: null,
|
|
6206
|
+
expired: null,
|
|
6207
|
+
isPrimary: false,
|
|
6208
|
+
requests: entry.successCount + entry.errorCount,
|
|
6209
|
+
errors: entry.errorCount,
|
|
6210
|
+
rateLimits: entry.rateLimitCount,
|
|
6211
|
+
quotaRateLimits: entry.quotaRateLimitCount,
|
|
6212
|
+
quota: null,
|
|
6213
|
+
// Looked up the same way the routed rows do. These accounts are
|
|
6214
|
+
// built FROM today's usage stats, so an account that served
|
|
6215
|
+
// requests and was then disabled or excluded still has tokens
|
|
6216
|
+
// and cost in the ledger — hardcoding null here discarded
|
|
6217
|
+
// exactly the usage an operator is looking for when they ask
|
|
6218
|
+
// why traffic stopped.
|
|
6219
|
+
usage: usageByAccount.get(entry.label) ?? null,
|
|
6220
|
+
});
|
|
6221
|
+
}
|
|
6222
|
+
const response = {
|
|
6223
|
+
generatedAt: Date.now(),
|
|
6224
|
+
usageDate,
|
|
6225
|
+
quotaFromSnapshot: !live,
|
|
6226
|
+
usageError,
|
|
6227
|
+
quotaError,
|
|
6228
|
+
// Pooled accounts bill by subscription. This is what the recorded
|
|
6229
|
+
// tokens would have cost at published rates — a value estimate, not
|
|
6230
|
+
// an invoice — and consumers must label it that way.
|
|
6231
|
+
costBasis: "api-equivalent",
|
|
6232
|
+
accounts: rows,
|
|
6233
|
+
};
|
|
6234
|
+
return response;
|
|
6235
|
+
},
|
|
6236
|
+
description: "One row per account: status, quota, and today's tokens and " +
|
|
6237
|
+
"API-equivalent cost. ?refresh=true forces a live quota fetch",
|
|
6238
|
+
tags: ["claude-proxy", "accounts"],
|
|
6239
|
+
},
|
|
5994
6240
|
],
|
|
5995
6241
|
};
|
|
5996
6242
|
}
|
|
@@ -6354,6 +6600,7 @@ export function redactProviderErrorMessage(message) {
|
|
|
6354
6600
|
// spinning up a full proxy. Keep this surface small.
|
|
6355
6601
|
// ---------------------------------------------------------------------------
|
|
6356
6602
|
export const __testHooks = {
|
|
6603
|
+
normalizeQuotaForAccounts,
|
|
6357
6604
|
resolveHomeIndex,
|
|
6358
6605
|
maybeResetPrimaryToHome,
|
|
6359
6606
|
planCooldownFor429,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import type { Tool } from "./tools.js";
|
|
3
|
-
import type { NativeFunctionCall, NativeToolDeclarationsResult } from "./providers.js";
|
|
3
|
+
import type { CollectedChunkResult, NativeFunctionCall, NativeToolDeclarationsResult } from "./providers.js";
|
|
4
4
|
/**
|
|
5
5
|
* One chunk on the engine's stream.
|
|
6
6
|
*
|
|
@@ -240,6 +240,22 @@ export type GeminiLoopAdapterCoreConfig = {
|
|
|
240
240
|
* step with that step's real token counts.
|
|
241
241
|
*/
|
|
242
242
|
noteUsage?: (inputTokens: number, outputTokens: number) => void;
|
|
243
|
+
/**
|
|
244
|
+
* Fold one step's raw stream into the shape the adapter reports.
|
|
245
|
+
*
|
|
246
|
+
* Defaults to `collectStreamChunksIncremental`, which is what AI Studio and
|
|
247
|
+
* any provider sharing the googleNativeGemini3 helpers want. Vertex does
|
|
248
|
+
* NOT share them: its loop drains the stream itself, folding cumulative
|
|
249
|
+
* usage counts as deltas and capturing thought signatures in its own way,
|
|
250
|
+
* and that behaviour is characterized rather than incidental.
|
|
251
|
+
*
|
|
252
|
+
* So the collector is a hook rather than a hard-coded call. A provider
|
|
253
|
+
* whose drain differs supplies its own and keeps its measured behaviour;
|
|
254
|
+
* one that matches the shared helper passes nothing.
|
|
255
|
+
*/
|
|
256
|
+
collectStep?: (stream: unknown, channel: {
|
|
257
|
+
push(chunk: AgenticLoopChunk): void;
|
|
258
|
+
}) => Promise<CollectedChunkResult>;
|
|
243
259
|
};
|
|
244
260
|
/**
|
|
245
261
|
* Opt in to the single MALFORMED_FUNCTION_CALL retry.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JsonObject } from "./common.js";
|
|
1
2
|
/**
|
|
2
3
|
* One AI coding CLI the proxy can point at itself.
|
|
3
4
|
*
|
|
@@ -52,3 +53,83 @@ export type CliProxyClientRestoreResult = {
|
|
|
52
53
|
* key the user has set, including ones this repo does not know about.
|
|
53
54
|
*/
|
|
54
55
|
export type CliQwenSettings = Record<string, unknown>;
|
|
56
|
+
/**
|
|
57
|
+
* Per-account token and cost totals derived from the proxy's own request log.
|
|
58
|
+
*
|
|
59
|
+
* `costUsd` is an **API-equivalent** figure: what the recorded tokens would
|
|
60
|
+
* have cost at published per-token rates. Pooled OAuth accounts are billed by
|
|
61
|
+
* subscription, so this is a value estimate, never an invoice. Consumers must
|
|
62
|
+
* label it as such.
|
|
63
|
+
*/
|
|
64
|
+
export type CliAccountUsageTotals = {
|
|
65
|
+
requests: number;
|
|
66
|
+
inputTokens: number;
|
|
67
|
+
outputTokens: number;
|
|
68
|
+
cacheReadTokens: number;
|
|
69
|
+
cacheCreationTokens: number;
|
|
70
|
+
costUsd: number;
|
|
71
|
+
/** Requests whose model carried no pricing row, so contributed no cost. */
|
|
72
|
+
unpricedRequests: number;
|
|
73
|
+
/** Distinct models with no pricing row, so an operator can chase them. */
|
|
74
|
+
unpricedModels: string[];
|
|
75
|
+
};
|
|
76
|
+
/** One row of GET /accounts. */
|
|
77
|
+
export type CliAccountsRow = {
|
|
78
|
+
/** Bare label, e.g. "someone@example.com". The join key across all sources. */
|
|
79
|
+
label: string;
|
|
80
|
+
/** Full pool key, e.g. "anthropic:someone@example.com". */
|
|
81
|
+
key: string | null;
|
|
82
|
+
/**
|
|
83
|
+
* What this row actually is. Only "account" rows are real logins; the proxy
|
|
84
|
+
* also tracks internal and translation pseudo-accounts, which have no quota
|
|
85
|
+
* and should not be rendered as credentials.
|
|
86
|
+
*/
|
|
87
|
+
kind: "account" | "internal" | "translation";
|
|
88
|
+
type: string;
|
|
89
|
+
status: string | null;
|
|
90
|
+
cooling: boolean;
|
|
91
|
+
allowed: boolean | null;
|
|
92
|
+
expired: boolean | null;
|
|
93
|
+
isPrimary: boolean;
|
|
94
|
+
requests: number | null;
|
|
95
|
+
errors: number | null;
|
|
96
|
+
rateLimits: number | null;
|
|
97
|
+
quotaRateLimits: number | null;
|
|
98
|
+
/** Quota block from the limits snapshot, timestamps normalised to ms. */
|
|
99
|
+
quota: JsonObject | null;
|
|
100
|
+
/** Today's usage from the request log, or null when the log is unreadable. */
|
|
101
|
+
usage: CliAccountUsageTotals | null;
|
|
102
|
+
};
|
|
103
|
+
/** Response body of GET /accounts. */
|
|
104
|
+
export type CliAccountsResponse = {
|
|
105
|
+
generatedAt: number;
|
|
106
|
+
/** UTC date whose request log the usage totals cover. */
|
|
107
|
+
usageDate: string;
|
|
108
|
+
/** True when quota came from the stored snapshot rather than a live fetch. */
|
|
109
|
+
quotaFromSnapshot: boolean;
|
|
110
|
+
/** Set when the usage totals could not be read at all. */
|
|
111
|
+
usageError: string | null;
|
|
112
|
+
/** Set when the quota snapshot could not be read; rows still carry status. */
|
|
113
|
+
quotaError: string | null;
|
|
114
|
+
costBasis: "api-equivalent";
|
|
115
|
+
accounts: CliAccountsRow[];
|
|
116
|
+
};
|
|
117
|
+
/** One request as recorded in the proxy request log, reduced to what costing needs. */
|
|
118
|
+
export type ProxyLedgerEntry = {
|
|
119
|
+
account: string;
|
|
120
|
+
accountType: string;
|
|
121
|
+
model: string;
|
|
122
|
+
provider?: string;
|
|
123
|
+
inputTokens: number;
|
|
124
|
+
outputTokens: number;
|
|
125
|
+
cacheReadTokens: number;
|
|
126
|
+
cacheCreationTokens: number;
|
|
127
|
+
};
|
|
128
|
+
/** Incremental read position and accumulated entries for one request-log file. */
|
|
129
|
+
export type ProxyLedgerFileCursor = {
|
|
130
|
+
/** Byte offset just past the last complete line consumed. */
|
|
131
|
+
offset: number;
|
|
132
|
+
size: number;
|
|
133
|
+
/** requestId -> latest known entry, so a re-logged request cannot double count. */
|
|
134
|
+
entries: Map<string, ProxyLedgerEntry>;
|
|
135
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.15.0",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|
|
@@ -32,8 +32,6 @@
|
|
|
32
32
|
"build:browser": "node scripts/build-browser.mjs",
|
|
33
33
|
"build:browser:dev": "node scripts/build-browser.mjs --dev",
|
|
34
34
|
"build:cli": "echo 'Building CLI...' && svelte-kit sync && tsc --project tsconfig.cli.json && node scripts/collapse-cli-lib-duplicate.mjs",
|
|
35
|
-
"build:cli:bundle": "node scripts/bundle-cli.mjs",
|
|
36
|
-
"build:cli:bundle:minify": "node scripts/bundle-cli.mjs --minify",
|
|
37
35
|
"build:action": "ncc build src/action/index.ts -o action-dist --source-map",
|
|
38
36
|
"build:cli:link": "pnpm run build:cli && pnpm link --global",
|
|
39
37
|
"check:deps": "tsx scripts/check-banned-deps.ts",
|
|
@@ -154,9 +152,6 @@
|
|
|
154
152
|
"// Documentation Automation (Legacy MkDocs)": "",
|
|
155
153
|
"docs:api": "typedoc",
|
|
156
154
|
"docs:sync": "bash scripts/sync-readme.sh",
|
|
157
|
-
"docs:build:mkdocs": "pnpm run docs:api && bash scripts/sync-readme.sh && mkdocs build --strict --clean",
|
|
158
|
-
"docs:serve:mkdocs": "bash scripts/sync-readme.sh && mkdocs serve",
|
|
159
|
-
"docs:gh-deploy:mkdocs": "bash scripts/sync-readme.sh && mkdocs gh-deploy --force",
|
|
160
155
|
"docs:validate": "tsx tools/content/documentationSync.ts --validate",
|
|
161
156
|
"docs:generate": "pnpm run docs:validate",
|
|
162
157
|
"// Documentation (Docusaurus)": "",
|
|
@@ -200,7 +195,6 @@
|
|
|
200
195
|
"validate:commit": "tsx scripts/commit-validation.ts",
|
|
201
196
|
"quality:metrics": "tsx scripts/quality-metrics.ts",
|
|
202
197
|
"quality:report": "pnpm run quality:metrics && echo 'Quality metrics saved to quality-metrics.json'",
|
|
203
|
-
"pre-commit": "lint-staged",
|
|
204
198
|
"pre-push": "pnpm run check:deps && pnpm run build && pnpm run test:providers-mocked && pnpm run test:provider-structure && pnpm run test:model-manifests",
|
|
205
199
|
"check:all": "pnpm run lint && pnpm run format --check && pnpm run validate && pnpm run validate:commit",
|
|
206
200
|
"test:file-formats": "npx tsx test/continuous-test-suite-file-formats.ts",
|
|
@@ -383,9 +377,7 @@
|
|
|
383
377
|
"js-yaml": "^4.3.1",
|
|
384
378
|
"json-schema-to-zod": "^2.7.0",
|
|
385
379
|
"jsonrepair": "^3.14.0",
|
|
386
|
-
"minisearch": "^7.2.0",
|
|
387
380
|
"nanoid": "^5.1.16",
|
|
388
|
-
"open": "^11.0.0",
|
|
389
381
|
"ora": "^9.3.0",
|
|
390
382
|
"p-limit": "^7.3.0",
|
|
391
383
|
"redis": "^5.11.0",
|
|
@@ -424,9 +416,7 @@
|
|
|
424
416
|
"@fastify/cors": "^11.2.0",
|
|
425
417
|
"@fastify/rate-limit": "^10.3.0",
|
|
426
418
|
"@google-cloud/text-to-speech": "^6.4.0",
|
|
427
|
-
"@google-cloud/vertexai": "^1.10.0",
|
|
428
419
|
"@hono/node-server": "^1.19.15",
|
|
429
|
-
"@huggingface/inference": "^4.13.14",
|
|
430
420
|
"@koa/cors": "^5.0.0",
|
|
431
421
|
"@koa/router": "^15.3.1",
|
|
432
422
|
"@langfuse/otel": "^5.0.1",
|
|
@@ -463,7 +453,6 @@
|
|
|
463
453
|
"@actions/core": "^3.0.0",
|
|
464
454
|
"@actions/exec": "^3.0.0",
|
|
465
455
|
"@actions/github": "^9.0.0",
|
|
466
|
-
"@biomejs/biome": "^2.4.4",
|
|
467
456
|
"@changesets/changelog-github": "^0.6.0",
|
|
468
457
|
"@changesets/cli": "^2.29.8",
|
|
469
458
|
"@electric-sql/pglite": "^0.4.6",
|
|
@@ -474,7 +463,6 @@
|
|
|
474
463
|
"@opentelemetry/sdk-trace-node": "^2.6.0",
|
|
475
464
|
"@semantic-release/changelog": "^6.0.3",
|
|
476
465
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
477
|
-
"@semantic-release/git": "^10.0.1",
|
|
478
466
|
"@semantic-release/github": "^12.0.6",
|
|
479
467
|
"@semantic-release/npm": "^13.1.4",
|
|
480
468
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
@@ -483,11 +471,9 @@
|
|
|
483
471
|
"@sveltejs/kit": "^2.70.3",
|
|
484
472
|
"@sveltejs/package": "^2.5.7",
|
|
485
473
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
486
|
-
"@types/adm-zip": "^0.5.7",
|
|
487
474
|
"@types/cors": "^2.8.19",
|
|
488
475
|
"@types/express": "^5.0.6",
|
|
489
476
|
"@types/fluent-ffmpeg": "^2.1.28",
|
|
490
|
-
"@types/inquirer": "^9.0.9",
|
|
491
477
|
"@types/js-yaml": "^4.0.9",
|
|
492
478
|
"@types/koa": "^3.0.1",
|
|
493
479
|
"@types/koa-bodyparser": "^4.3.13",
|
|
@@ -500,32 +486,25 @@
|
|
|
500
486
|
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
|
501
487
|
"@typescript-eslint/parser": "^8.57.2",
|
|
502
488
|
"@vercel/ncc": "^0.38.4",
|
|
503
|
-
"@vitest/coverage-v8": "^4.1.0",
|
|
504
489
|
"concurrently": "^9.2.1",
|
|
505
490
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
506
491
|
"esbuild": "^0.28.1",
|
|
507
492
|
"eslint": "^10.0.2",
|
|
508
493
|
"husky": "^9.1.7",
|
|
509
|
-
"lint-staged": "^16.3.0",
|
|
510
494
|
"playwright": "^1.58.2",
|
|
511
495
|
"prettier": "^3.8.1",
|
|
512
496
|
"publint": "^0.3.17",
|
|
513
|
-
"puppeteer": "^24.37.5",
|
|
514
497
|
"react": "^19.2.4",
|
|
515
498
|
"react-dom": "^19.2.4",
|
|
516
499
|
"semantic-release": "^25.0.3",
|
|
517
|
-
"shell-quote": "^1.9.0",
|
|
518
500
|
"svelte": "^5.55.7",
|
|
519
501
|
"svelte-check": "^4.4.4",
|
|
520
|
-
"ts-morph": "^24.0.0",
|
|
521
|
-
"tslib": "^2.8.1",
|
|
522
502
|
"tsx": "^4.21.0",
|
|
523
503
|
"typedoc": "^0.28.17",
|
|
524
504
|
"typedoc-plugin-markdown": "^4.10.0",
|
|
525
505
|
"typescript": "^5.9.3",
|
|
526
506
|
"vite": "^8.2.2",
|
|
527
|
-
"vitest": "^4.1.0"
|
|
528
|
-
"why-is-node-running": "^3.2.2"
|
|
507
|
+
"vitest": "^4.1.0"
|
|
529
508
|
},
|
|
530
509
|
"keywords": [
|
|
531
510
|
"ai",
|
|
@@ -650,18 +629,5 @@
|
|
|
650
629
|
"tabWidth": 2,
|
|
651
630
|
"useTabs": false,
|
|
652
631
|
"proseWrap": "preserve"
|
|
653
|
-
},
|
|
654
|
-
"lint-staged": {
|
|
655
|
-
"src/**/*.{ts,tsx}": [
|
|
656
|
-
"eslint --fix --max-warnings=50",
|
|
657
|
-
"prettier --write"
|
|
658
|
-
],
|
|
659
|
-
"test/**/*.{ts,tsx}": [
|
|
660
|
-
"eslint --fix --max-warnings=0",
|
|
661
|
-
"prettier --write"
|
|
662
|
-
],
|
|
663
|
-
"*.{json,md}": [
|
|
664
|
-
"prettier --write"
|
|
665
|
-
]
|
|
666
632
|
}
|
|
667
633
|
}
|