@genesislcap/foundation-ai 15.33.1 → 15.34.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/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/tiers/ai-tiers.d.ts +154 -0
- package/dist/dts/tiers/ai-tiers.d.ts.map +1 -0
- package/dist/dts/tiers/build-tier-providers.d.ts +67 -0
- package/dist/dts/tiers/build-tier-providers.d.ts.map +1 -0
- package/dist/dts/utils/token-cost.d.ts +14 -0
- package/dist/dts/utils/token-cost.d.ts.map +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/tiers/ai-tiers.js +173 -0
- package/dist/esm/tiers/build-tier-providers.js +72 -0
- package/dist/esm/utils/token-cost.js +14 -0
- package/dist/foundation-ai.api.json +1128 -263
- package/dist/foundation-ai.d.ts +191 -0
- package/package.json +10 -10
package/dist/dts/index.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ export { GeminiTransport, MalformedFunctionCallError } from './transports/gemini
|
|
|
10
10
|
export { DEFAULT_PROVIDER_REFUSED_MESSAGE, PROVIDER_REFUSED_CODE, ProviderRefusedError, } from './transports/provider-refused';
|
|
11
11
|
export type { ProviderRefusalKind } from './transports/provider-refused';
|
|
12
12
|
export { ContextOverflowError, contextOverflowOf, DEFAULT_CONTEXT_OVERFLOW_MESSAGE, } from './transports/context-overflow-error';
|
|
13
|
+
export { AI_TIER_IDS, AI_TIER_VENDORS, DEFAULT_AI_TIERS, resolveAITiers } from './tiers/ai-tiers';
|
|
14
|
+
export type { AITierId, AITierOverrides, AITiers, AITierVendor, AnthropicTierConfig, GeminiTierConfig, } from './tiers/ai-tiers';
|
|
15
|
+
export { buildTierProviders } from './tiers/build-tier-providers';
|
|
16
|
+
export type { BuildTierProvidersOptions } from './tiers/build-tier-providers';
|
|
13
17
|
export { AI_FEATURE_FLAG, isAIFeatureEnabled } from './utils/feature-flags';
|
|
14
18
|
export { ChatTemperature } from './utils/temperature';
|
|
15
19
|
export { ANTHROPIC_CACHE_READ_MULTIPLIER, ANTHROPIC_CACHE_WRITE_1H_MULTIPLIER, ANTHROPIC_CACHE_WRITE_5M_MULTIPLIER, anthropicRatesFor, anthropicTokenCost, GEMINI_CACHED_INPUT_MULTIPLIER, GEMINI_LONG_CONTEXT_THRESHOLD, geminiRatesFor, geminiTokenCost, } from './utils/token-cost';
|
package/dist/dts/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,8BAA8B,EAC9B,yBAAyB,EACzB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,eAAe,CAAC;AAKvB,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC9F,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,gCAAgC,EAChC,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAK5F,OAAO,EACL,gCAAgC,EAChC,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,gCAAgC,GACjC,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { AnthropicModelId, GeminiModelId } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* The platform's tier → model table (GENC-1610).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Pure data, and deliberately so: this module imports nothing but types, never
|
|
7
|
+
* `ai-provider-di` (the one `@microsoft/fast-foundation` importer) and never
|
|
8
|
+
* `@genesislcap/web-core`, so it loads in bare Node. It is re-exported by name from
|
|
9
|
+
* `@genesislcap/ai-assistant/chat-driver`, which a server-side host requires at runtime —
|
|
10
|
+
* an `export *` or a DOM import anywhere in its closure crashes that host at require time.
|
|
11
|
+
* Provider construction lives next door in `build-tier-providers.ts`, which is browser-only.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Every tier id, in ascending capability order.
|
|
17
|
+
*
|
|
18
|
+
* This array is the source of truth and {@link AITierId} is derived from it, so the two cannot
|
|
19
|
+
* drift: a tier exists exactly when it is listed here. That matters because the provider
|
|
20
|
+
* builders and the table's tests all loop over this array — a tier missing from it would get
|
|
21
|
+
* no provider and no test, with nothing to say so.
|
|
22
|
+
*
|
|
23
|
+
* @beta
|
|
24
|
+
*/
|
|
25
|
+
export declare const AI_TIER_IDS: readonly ["low", "high", "reasoning"];
|
|
26
|
+
/**
|
|
27
|
+
* The tier a caller asks for, rather than a model id.
|
|
28
|
+
*
|
|
29
|
+
* Tier-shaped names are what let an app swap vendor (or re-bench a tier onto a
|
|
30
|
+
* newer model) without touching a single agent config — agents resolve `'high'`,
|
|
31
|
+
* not `claude-sonnet-5`. Derived from {@link AI_TIER_IDS}.
|
|
32
|
+
*
|
|
33
|
+
* @beta
|
|
34
|
+
*/
|
|
35
|
+
export type AITierId = (typeof AI_TIER_IDS)[number];
|
|
36
|
+
/**
|
|
37
|
+
* Every vendor in the table — the two the platform's proxy meters. The source of truth for
|
|
38
|
+
* {@link AITierVendor}, for the same reason as {@link AI_TIER_IDS}.
|
|
39
|
+
*
|
|
40
|
+
* @beta
|
|
41
|
+
*/
|
|
42
|
+
export declare const AI_TIER_VENDORS: readonly ["anthropic", "gemini"];
|
|
43
|
+
/**
|
|
44
|
+
* The cloud vendors the tier table covers. Derived from {@link AI_TIER_VENDORS}.
|
|
45
|
+
*
|
|
46
|
+
* @beta
|
|
47
|
+
*/
|
|
48
|
+
export type AITierVendor = (typeof AI_TIER_VENDORS)[number];
|
|
49
|
+
/**
|
|
50
|
+
* What one tier is worth on Anthropic: the model, its output ceiling, and the two clocks.
|
|
51
|
+
*
|
|
52
|
+
* @beta
|
|
53
|
+
*/
|
|
54
|
+
export interface AnthropicTierConfig {
|
|
55
|
+
model: AnthropicModelId;
|
|
56
|
+
/**
|
|
57
|
+
* `max_tokens` for every request on this tier. Part of the tier, not an optional
|
|
58
|
+
* extra: Anthropic requires the field and the transport defaults it to 4096, which
|
|
59
|
+
* truncates a large single-call file write mid-stream (`stop_reason: max_tokens`)
|
|
60
|
+
* and leaves the tool input unparseable. Values sit inside each model's documented
|
|
61
|
+
* output ceiling.
|
|
62
|
+
*/
|
|
63
|
+
maxTokens: number;
|
|
64
|
+
/** Inactivity window on a stream that has started. */
|
|
65
|
+
stallTimeoutMs: number;
|
|
66
|
+
/** Ceiling on the wait for the FIRST byte — a different clock from the stall one. */
|
|
67
|
+
timeoutMs: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What one tier is worth on Gemini.
|
|
71
|
+
*
|
|
72
|
+
* No `maxTokens`: `GeminiAIConfig` has no such field and the provider's own (much
|
|
73
|
+
* larger) default applies, so Gemini writes never hit the Anthropic wall above.
|
|
74
|
+
*
|
|
75
|
+
* @beta
|
|
76
|
+
*/
|
|
77
|
+
export interface GeminiTierConfig {
|
|
78
|
+
model: GeminiModelId;
|
|
79
|
+
/** Inactivity window on a stream that has started. */
|
|
80
|
+
stallTimeoutMs: number;
|
|
81
|
+
/** Ceiling on the wait for the FIRST byte — a different clock from the stall one. */
|
|
82
|
+
timeoutMs: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The whole table: every tier, for every vendor.
|
|
86
|
+
*
|
|
87
|
+
* Total records, not partials — a tier a vendor cannot serve is not a tier, it is a
|
|
88
|
+
* gap that only shows up when an agent resolves it at runtime.
|
|
89
|
+
*
|
|
90
|
+
* @beta
|
|
91
|
+
*/
|
|
92
|
+
export interface AITiers {
|
|
93
|
+
anthropic: Record<AITierId, AnthropicTierConfig>;
|
|
94
|
+
gemini: Record<AITierId, GeminiTierConfig>;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The platform's default tier table.
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
* Frozen, because it is shared by every app in the process: {@link resolveAITiers} returns
|
|
101
|
+
* a fresh object for callers that override, and hands this back untouched for callers that
|
|
102
|
+
* do not.
|
|
103
|
+
*
|
|
104
|
+
* The models are the ones Genesis Create has been running these tiers on in production — except
|
|
105
|
+
* Anthropic's `reasoning`, moved to `claude-opus-4-8` (see its entry) — and they are a
|
|
106
|
+
* **benchmark result, not a preference**: re-bench before moving one. Two of the Gemini
|
|
107
|
+
* defaults carry a caveat recorded beside them, a preview model and an introductory rate. Two dates
|
|
108
|
+
* are already on the calendar for that: `gemini-3.8-flash` sits on an introductory rate that
|
|
109
|
+
* doubles on 2027-01-01 (at which point it is dearer on input than the model it replaced),
|
|
110
|
+
* and `token-cost.test.ts` fails the build that day; `ai-tiers.test.ts` fails alongside it
|
|
111
|
+
* saying the High tier is the thing to re-bench.
|
|
112
|
+
*
|
|
113
|
+
* Every model here must be in `SUPPORTED_*_MODEL_IDS` with a context limit and a price —
|
|
114
|
+
* pinned by tests, because an unpriced model silently bills at nothing.
|
|
115
|
+
*
|
|
116
|
+
* @beta
|
|
117
|
+
*/
|
|
118
|
+
export declare const DEFAULT_AI_TIERS: AITiers;
|
|
119
|
+
/**
|
|
120
|
+
* Per-tier overrides, shallow-merged field by field over the defaults.
|
|
121
|
+
*
|
|
122
|
+
* @beta
|
|
123
|
+
*/
|
|
124
|
+
export interface AITierOverrides {
|
|
125
|
+
anthropic?: Partial<Record<AITierId, Partial<AnthropicTierConfig>>>;
|
|
126
|
+
gemini?: Partial<Record<AITierId, Partial<GeminiTierConfig>>>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The table an app should actually use: {@link DEFAULT_AI_TIERS} with `overrides` applied
|
|
130
|
+
* per field, so an app that wants one model moved says only that and keeps the platform's
|
|
131
|
+
* clocks and ceilings.
|
|
132
|
+
*
|
|
133
|
+
* @remarks
|
|
134
|
+
* An override field set to `undefined` is skipped, exactly as if it had been left out. The
|
|
135
|
+
* common caller passes an optional config value straight through
|
|
136
|
+
* (`{ high: { model: appConfig.model } }`), and copying `undefined` over the default would
|
|
137
|
+
* hand the transport no model at all — it then quietly falls back to its own default, with
|
|
138
|
+
* nothing logged.
|
|
139
|
+
*
|
|
140
|
+
* The result is frozen whether or not anything was overridden, so whether mutating it throws
|
|
141
|
+
* does not depend on what the caller passed. The default itself is returned untouched when
|
|
142
|
+
* there is nothing to override, and is never mutated, which matters because it is shared
|
|
143
|
+
* across every app in the process.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* // Keep everything, but run the reasoning tier on Fable.
|
|
148
|
+
* const tiers = resolveAITiers({ anthropic: { reasoning: { model: 'claude-fable-5' } } });
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* @beta
|
|
152
|
+
*/
|
|
153
|
+
export declare function resolveAITiers(overrides?: AITierOverrides): AITiers;
|
|
154
|
+
//# sourceMappingURL=ai-tiers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-tiers.d.ts","sourceRoot":"","sources":["../../../src/tiers/ai-tiers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhE;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,uCAAwC,CAAC;AAEjE;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,kCAAmC,CAAC;AAEhE;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,CAAC;IACrB,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAsBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAsD7B,CAAC;AAEH;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,eAAe,GAAG,OAAO,CAMnE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type AIProvider } from '../ai-provider';
|
|
2
|
+
import type { AnthropicAIConfig, GeminiAIConfig } from '../types';
|
|
3
|
+
import { type AITierId, type AITiers, type AITierVendor } from './ai-tiers';
|
|
4
|
+
/**
|
|
5
|
+
* Turns the tier table into live providers (GENC-1610).
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Split from `ai-tiers.ts` because this half is **browser-only**: `createAIProvider` checks
|
|
9
|
+
* the AI feature flag, which reads `window.location`. The table is what a Node host needs
|
|
10
|
+
* (model ids and pricing); provider construction is not, so only the table is re-exported
|
|
11
|
+
* from the `@genesislcap/ai-assistant/chat-driver` Node entry.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Options for {@link buildTierProviders}.
|
|
17
|
+
*
|
|
18
|
+
* @beta
|
|
19
|
+
*/
|
|
20
|
+
export interface BuildTierProvidersOptions {
|
|
21
|
+
/** Which vendor's models to build. */
|
|
22
|
+
vendor: AITierVendor;
|
|
23
|
+
/**
|
|
24
|
+
* The proxy endpoint every tier posts to — a string, or a function of the vendor for a
|
|
25
|
+
* caller that builds more than one vendor from one rule (see the example below).
|
|
26
|
+
*
|
|
27
|
+
* Always a server endpoint, never an API key: these providers are meant for an app whose
|
|
28
|
+
* keys stay on its server. An empty endpoint throws here rather than at the first turn.
|
|
29
|
+
*/
|
|
30
|
+
serverEndpoint: string | ((vendor: AITierVendor) => string);
|
|
31
|
+
/** The table to build from. Defaults to {@link DEFAULT_AI_TIERS}. */
|
|
32
|
+
tiers?: AITiers;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Builds one {@link AIProvider} per tier for a vendor, ready to register under the tier
|
|
36
|
+
* names agents resolve (`low` / `high` / `reasoning`).
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* Each provider carries its tier's model, output ceiling (Anthropic) and both clocks, so no
|
|
40
|
+
* tier can silently fall back to the transport defaults — which is how a large tool write
|
|
41
|
+
* ends up truncated at 4096 tokens.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* registerAIProviders(
|
|
46
|
+
* container,
|
|
47
|
+
* buildTierProviders({ vendor: 'gemini', serverEndpoint: (v) => `/gwf/ai-service/${v}/chat` }),
|
|
48
|
+
* { default: 'high' },
|
|
49
|
+
* );
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @beta
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildTierProviders(options: BuildTierProvidersOptions): Record<AITierId, AIProvider>;
|
|
55
|
+
/**
|
|
56
|
+
* The provider configs {@link buildTierProviders} builds from, before they reach
|
|
57
|
+
* `createAIProvider`.
|
|
58
|
+
*
|
|
59
|
+
* A seam rather than an inline literal, because what is being asserted is exactly what a
|
|
60
|
+
* constructed provider hides: a transport keeps `maxTokens` and both clocks private, so a
|
|
61
|
+
* tier silently falling back to the 4096-token default would be invisible from the outside
|
|
62
|
+
* — which is the failure this table exists to prevent.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
export declare function tierProviderConfigs(options: BuildTierProvidersOptions): Record<AITierId, AnthropicAIConfig | GeminiAIConfig>;
|
|
67
|
+
//# sourceMappingURL=build-tier-providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-tier-providers.d.ts","sourceRoot":"","sources":["../../../src/tiers/build-tier-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,MAAM,EAAE,YAAY,CAAC;IACrB;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC,CAAC;IAC5D,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAO9B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,yBAAyB,GACjC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,cAAc,CAAC,CAkCtD"}
|
|
@@ -144,6 +144,20 @@ export declare const GEMINI_LONG_CONTEXT_THRESHOLD = 200000;
|
|
|
144
144
|
* @beta
|
|
145
145
|
*/
|
|
146
146
|
export declare const GEMINI_CACHED_INPUT_MULTIPLIER = 0.1;
|
|
147
|
+
/**
|
|
148
|
+
* The day `gemini-3.8-flash` leaves its introductory rate (see `GEMINI_PRICING` below).
|
|
149
|
+
*
|
|
150
|
+
* A constant rather than a literal in the test that enforces it, because a SECOND dated
|
|
151
|
+
* assertion now hangs off the same day: the High tier picked that model while it was the
|
|
152
|
+
* cheaper one, so the flip is also the trigger to re-bench the tier (`tiers/ai-tiers.test.ts`).
|
|
153
|
+
* Two hand-copied dates would drift the moment either is corrected, and a re-bench reminder
|
|
154
|
+
* that fires on the wrong day is no reminder at all.
|
|
155
|
+
*
|
|
156
|
+
* Not part of the package's public surface — it exists for those two tests.
|
|
157
|
+
*
|
|
158
|
+
* @internal
|
|
159
|
+
*/
|
|
160
|
+
export declare const GEMINI_3_8_FLASH_INTRO_RATE_ENDS: number;
|
|
147
161
|
/**
|
|
148
162
|
* Resolve the per-million-token rates for a model given the request's prompt size,
|
|
149
163
|
* selecting the long-context tier for tiered models when the prompt exceeds
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-cost.d.ts","sourceRoot":"","sources":["../../../src/utils/token-cost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAkDhE;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;CACtB;AAiCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,UAAU,CAErE;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,YAAY;AACZ,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,YAAY;AACZ,eAAO,MAAM,mCAAmC,IAAI,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;;;OASG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,oBAAoB,GAC1B,SAAS,CAiCX;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"token-cost.d.ts","sourceRoot":"","sources":["../../../src/utils/token-cost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAkDhE;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;CACtB;AAiCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,UAAU,CAErE;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,YAAY;AACZ,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,YAAY;AACZ,eAAO,MAAM,mCAAmC,IAAI,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;;;OASG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,oBAAoB,GAC1B,SAAS,CAiCX;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gCAAgC,QAAqC,CAAC;AAsDnF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,UAAU,CAMrF;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,GAAG,SAAS,CAuBzF"}
|
package/dist/esm/index.js
CHANGED
|
@@ -15,6 +15,13 @@ export { GeminiTransport, MalformedFunctionCallError } from './transports/gemini
|
|
|
15
15
|
// first reword.
|
|
16
16
|
export { DEFAULT_PROVIDER_REFUSED_MESSAGE, PROVIDER_REFUSED_CODE, ProviderRefusedError, } from './transports/provider-refused';
|
|
17
17
|
export { ContextOverflowError, contextOverflowOf, DEFAULT_CONTEXT_OVERFLOW_MESSAGE, } from './transports/context-overflow-error';
|
|
18
|
+
// The platform tier table (GENC-1610) — what a `low` / `high` / `reasoning` slot resolves to
|
|
19
|
+
// per vendor, including the Anthropic output ceiling and both timeout clocks. Named exports,
|
|
20
|
+
// and the data half is deliberately free of DOM and DI imports so it also rides the
|
|
21
|
+
// `@genesislcap/ai-assistant/chat-driver` Node bundle; `buildTierProviders` does NOT, because
|
|
22
|
+
// it constructs providers through the feature-flag gate (see `tiers/build-tier-providers.ts`).
|
|
23
|
+
export { AI_TIER_IDS, AI_TIER_VENDORS, DEFAULT_AI_TIERS, resolveAITiers } from './tiers/ai-tiers';
|
|
24
|
+
export { buildTierProviders } from './tiers/build-tier-providers';
|
|
18
25
|
export { AI_FEATURE_FLAG, isAIFeatureEnabled } from './utils/feature-flags';
|
|
19
26
|
export { ChatTemperature } from './utils/temperature';
|
|
20
27
|
// Request pricing. Exported so a host that prices its own calls — a server proxy, a usage ledger,
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The platform's tier → model table (GENC-1610).
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Pure data, and deliberately so: this module imports nothing but types, never
|
|
6
|
+
* `ai-provider-di` (the one `@microsoft/fast-foundation` importer) and never
|
|
7
|
+
* `@genesislcap/web-core`, so it loads in bare Node. It is re-exported by name from
|
|
8
|
+
* `@genesislcap/ai-assistant/chat-driver`, which a server-side host requires at runtime —
|
|
9
|
+
* an `export *` or a DOM import anywhere in its closure crashes that host at require time.
|
|
10
|
+
* Provider construction lives next door in `build-tier-providers.ts`, which is browser-only.
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Every tier id, in ascending capability order.
|
|
16
|
+
*
|
|
17
|
+
* This array is the source of truth and {@link AITierId} is derived from it, so the two cannot
|
|
18
|
+
* drift: a tier exists exactly when it is listed here. That matters because the provider
|
|
19
|
+
* builders and the table's tests all loop over this array — a tier missing from it would get
|
|
20
|
+
* no provider and no test, with nothing to say so.
|
|
21
|
+
*
|
|
22
|
+
* @beta
|
|
23
|
+
*/
|
|
24
|
+
export const AI_TIER_IDS = ['low', 'high', 'reasoning'];
|
|
25
|
+
/**
|
|
26
|
+
* Every vendor in the table — the two the platform's proxy meters. The source of truth for
|
|
27
|
+
* {@link AITierVendor}, for the same reason as {@link AI_TIER_IDS}.
|
|
28
|
+
*
|
|
29
|
+
* @beta
|
|
30
|
+
*/
|
|
31
|
+
export const AI_TIER_VENDORS = ['anthropic', 'gemini'];
|
|
32
|
+
/**
|
|
33
|
+
* 60s inactivity backstop on a stream that has already started.
|
|
34
|
+
*
|
|
35
|
+
* `foundation-ai` defaults this to 30s, which is TIGHTER than the platform proxy's own
|
|
36
|
+
* 45s mid-stream watchdog — so the client won every race and aborted the request before
|
|
37
|
+
* the server could notice, classify or log the stall. A stall is not retried; it surfaces
|
|
38
|
+
* as a dead turn. 60s puts the proxy back in charge of detecting upstream stalls.
|
|
39
|
+
*/
|
|
40
|
+
const AI_STALL_TIMEOUT_MS = 60000;
|
|
41
|
+
/**
|
|
42
|
+
* 300s ceiling on the wait for the first byte — nothing has arrived yet.
|
|
43
|
+
*
|
|
44
|
+
* Distinct from {@link AI_STALL_TIMEOUT_MS}, which is only armed once the body starts.
|
|
45
|
+
* It stays generous because on the legacy (unframed) proxy path the response is buffered,
|
|
46
|
+
* so the first byte only lands when generation is complete; a tight value there would cap
|
|
47
|
+
* total generation time. Set explicitly rather than inherited, so it is a decision on the record.
|
|
48
|
+
*/
|
|
49
|
+
const AI_NO_RESPONSE_TIMEOUT_MS = 300000;
|
|
50
|
+
/**
|
|
51
|
+
* The platform's default tier table.
|
|
52
|
+
*
|
|
53
|
+
* @remarks
|
|
54
|
+
* Frozen, because it is shared by every app in the process: {@link resolveAITiers} returns
|
|
55
|
+
* a fresh object for callers that override, and hands this back untouched for callers that
|
|
56
|
+
* do not.
|
|
57
|
+
*
|
|
58
|
+
* The models are the ones Genesis Create has been running these tiers on in production — except
|
|
59
|
+
* Anthropic's `reasoning`, moved to `claude-opus-4-8` (see its entry) — and they are a
|
|
60
|
+
* **benchmark result, not a preference**: re-bench before moving one. Two of the Gemini
|
|
61
|
+
* defaults carry a caveat recorded beside them, a preview model and an introductory rate. Two dates
|
|
62
|
+
* are already on the calendar for that: `gemini-3.8-flash` sits on an introductory rate that
|
|
63
|
+
* doubles on 2027-01-01 (at which point it is dearer on input than the model it replaced),
|
|
64
|
+
* and `token-cost.test.ts` fails the build that day; `ai-tiers.test.ts` fails alongside it
|
|
65
|
+
* saying the High tier is the thing to re-bench.
|
|
66
|
+
*
|
|
67
|
+
* Every model here must be in `SUPPORTED_*_MODEL_IDS` with a context limit and a price —
|
|
68
|
+
* pinned by tests, because an unpriced model silently bills at nothing.
|
|
69
|
+
*
|
|
70
|
+
* @beta
|
|
71
|
+
*/
|
|
72
|
+
export const DEFAULT_AI_TIERS = Object.freeze({
|
|
73
|
+
anthropic: Object.freeze({
|
|
74
|
+
low: Object.freeze({
|
|
75
|
+
model: 'claude-haiku-4-5-20251001',
|
|
76
|
+
maxTokens: 16000,
|
|
77
|
+
stallTimeoutMs: AI_STALL_TIMEOUT_MS,
|
|
78
|
+
timeoutMs: AI_NO_RESPONSE_TIMEOUT_MS,
|
|
79
|
+
}),
|
|
80
|
+
// The heavy tier: whole-file writes, and adaptive thinking out of the same budget
|
|
81
|
+
// wherever a caller leaves thinking on — hence Sonnet 5's full 128K ceiling rather
|
|
82
|
+
// than a figure that only fits one of the two.
|
|
83
|
+
high: Object.freeze({
|
|
84
|
+
model: 'claude-sonnet-5',
|
|
85
|
+
maxTokens: 128000,
|
|
86
|
+
stallTimeoutMs: AI_STALL_TIMEOUT_MS,
|
|
87
|
+
timeoutMs: AI_NO_RESPONSE_TIMEOUT_MS,
|
|
88
|
+
}),
|
|
89
|
+
// One-shot judgement calls rather than tool loops, so a smaller ceiling is ample:
|
|
90
|
+
// `max_tokens` is only a cap, and this tier never emits a whole file.
|
|
91
|
+
//
|
|
92
|
+
// Opus 4.8 rather than the 4.7 Create benched: the same price ($5 / $25) and the same 1M
|
|
93
|
+
// window, but 4.8 supports native structured output where 4.7 takes the forced-tool
|
|
94
|
+
// fallback — and structured judgement is what this tier is asked for most (review of #2540).
|
|
95
|
+
reasoning: Object.freeze({
|
|
96
|
+
model: 'claude-opus-4-8',
|
|
97
|
+
maxTokens: 32000,
|
|
98
|
+
stallTimeoutMs: AI_STALL_TIMEOUT_MS,
|
|
99
|
+
timeoutMs: AI_NO_RESPONSE_TIMEOUT_MS,
|
|
100
|
+
}),
|
|
101
|
+
}),
|
|
102
|
+
gemini: Object.freeze({
|
|
103
|
+
low: Object.freeze({
|
|
104
|
+
model: 'gemini-3.1-flash-lite',
|
|
105
|
+
stallTimeoutMs: AI_STALL_TIMEOUT_MS,
|
|
106
|
+
timeoutMs: AI_NO_RESPONSE_TIMEOUT_MS,
|
|
107
|
+
}),
|
|
108
|
+
// On an INTRODUCTORY rate that doubles to $1.50 / $7.50 on 2027-01-01, from which point it
|
|
109
|
+
// is dearer on input than the gemini-3.5-flash it replaced. Chosen at the introductory rate
|
|
110
|
+
// knowingly; `ai-tiers.test.ts` fails that day to force the re-bench.
|
|
111
|
+
high: Object.freeze({
|
|
112
|
+
model: 'gemini-3.8-flash',
|
|
113
|
+
stallTimeoutMs: AI_STALL_TIMEOUT_MS,
|
|
114
|
+
timeoutMs: AI_NO_RESPONSE_TIMEOUT_MS,
|
|
115
|
+
}),
|
|
116
|
+
// A PREVIEW model: no stability guarantee, and it may be withdrawn at short notice (its
|
|
117
|
+
// transport warns on every construction). Accepted knowingly as the platform default because
|
|
118
|
+
// no stable Gemini Pro was on offer when the tiers were benched; revisit as soon as Google
|
|
119
|
+
// promotes, deprecates or withdraws it, since every app on this default inherits the risk.
|
|
120
|
+
reasoning: Object.freeze({
|
|
121
|
+
model: 'gemini-3.1-pro-preview',
|
|
122
|
+
stallTimeoutMs: AI_STALL_TIMEOUT_MS,
|
|
123
|
+
timeoutMs: AI_NO_RESPONSE_TIMEOUT_MS,
|
|
124
|
+
}),
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
/**
|
|
128
|
+
* The table an app should actually use: {@link DEFAULT_AI_TIERS} with `overrides` applied
|
|
129
|
+
* per field, so an app that wants one model moved says only that and keeps the platform's
|
|
130
|
+
* clocks and ceilings.
|
|
131
|
+
*
|
|
132
|
+
* @remarks
|
|
133
|
+
* An override field set to `undefined` is skipped, exactly as if it had been left out. The
|
|
134
|
+
* common caller passes an optional config value straight through
|
|
135
|
+
* (`{ high: { model: appConfig.model } }`), and copying `undefined` over the default would
|
|
136
|
+
* hand the transport no model at all — it then quietly falls back to its own default, with
|
|
137
|
+
* nothing logged.
|
|
138
|
+
*
|
|
139
|
+
* The result is frozen whether or not anything was overridden, so whether mutating it throws
|
|
140
|
+
* does not depend on what the caller passed. The default itself is returned untouched when
|
|
141
|
+
* there is nothing to override, and is never mutated, which matters because it is shared
|
|
142
|
+
* across every app in the process.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* // Keep everything, but run the reasoning tier on Fable.
|
|
147
|
+
* const tiers = resolveAITiers({ anthropic: { reasoning: { model: 'claude-fable-5' } } });
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @beta
|
|
151
|
+
*/
|
|
152
|
+
export function resolveAITiers(overrides) {
|
|
153
|
+
if (!(overrides === null || overrides === void 0 ? void 0 : overrides.anthropic) && !(overrides === null || overrides === void 0 ? void 0 : overrides.gemini))
|
|
154
|
+
return DEFAULT_AI_TIERS;
|
|
155
|
+
return Object.freeze({
|
|
156
|
+
anthropic: mergeVendor(DEFAULT_AI_TIERS.anthropic, overrides.anthropic),
|
|
157
|
+
gemini: mergeVendor(DEFAULT_AI_TIERS.gemini, overrides.gemini),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function mergeVendor(defaults, overrides) {
|
|
161
|
+
var _a;
|
|
162
|
+
const merged = {};
|
|
163
|
+
for (const tier of AI_TIER_IDS) {
|
|
164
|
+
const defined = Object.fromEntries(Object.entries((_a = overrides === null || overrides === void 0 ? void 0 : overrides[tier]) !== null && _a !== void 0 ? _a : {}).filter(([, value]) => value !== undefined));
|
|
165
|
+
// Frozen in place rather than through `Object.freeze`'s return value, whose overloads
|
|
166
|
+
// widen a generic `T` to an index signature; the typed reference is the one we keep.
|
|
167
|
+
const entry = Object.assign(Object.assign({}, defaults[tier]), defined);
|
|
168
|
+
Object.freeze(entry);
|
|
169
|
+
merged[tier] = entry;
|
|
170
|
+
}
|
|
171
|
+
Object.freeze(merged);
|
|
172
|
+
return merged;
|
|
173
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createAIProvider } from '../ai-provider';
|
|
2
|
+
import { AI_TIER_IDS, DEFAULT_AI_TIERS, } from './ai-tiers';
|
|
3
|
+
/**
|
|
4
|
+
* Builds one {@link AIProvider} per tier for a vendor, ready to register under the tier
|
|
5
|
+
* names agents resolve (`low` / `high` / `reasoning`).
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Each provider carries its tier's model, output ceiling (Anthropic) and both clocks, so no
|
|
9
|
+
* tier can silently fall back to the transport defaults — which is how a large tool write
|
|
10
|
+
* ends up truncated at 4096 tokens.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* registerAIProviders(
|
|
15
|
+
* container,
|
|
16
|
+
* buildTierProviders({ vendor: 'gemini', serverEndpoint: (v) => `/gwf/ai-service/${v}/chat` }),
|
|
17
|
+
* { default: 'high' },
|
|
18
|
+
* );
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @beta
|
|
22
|
+
*/
|
|
23
|
+
export function buildTierProviders(options) {
|
|
24
|
+
const configs = tierProviderConfigs(options);
|
|
25
|
+
const providers = {};
|
|
26
|
+
for (const tier of AI_TIER_IDS) {
|
|
27
|
+
providers[tier] = createAIProvider(configs[tier]);
|
|
28
|
+
}
|
|
29
|
+
return providers;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The provider configs {@link buildTierProviders} builds from, before they reach
|
|
33
|
+
* `createAIProvider`.
|
|
34
|
+
*
|
|
35
|
+
* A seam rather than an inline literal, because what is being asserted is exactly what a
|
|
36
|
+
* constructed provider hides: a transport keeps `maxTokens` and both clocks private, so a
|
|
37
|
+
* tier silently falling back to the 4096-token default would be invisible from the outside
|
|
38
|
+
* — which is the failure this table exists to prevent.
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export function tierProviderConfigs(options) {
|
|
43
|
+
const { vendor, tiers = DEFAULT_AI_TIERS } = options;
|
|
44
|
+
const serverEndpoint = typeof options.serverEndpoint === 'function'
|
|
45
|
+
? options.serverEndpoint(vendor)
|
|
46
|
+
: options.serverEndpoint;
|
|
47
|
+
if (!serverEndpoint) {
|
|
48
|
+
throw new Error(`buildTierProviders: no serverEndpoint for '${vendor}'. Every tier posts to your app's ` +
|
|
49
|
+
'AI proxy; there is no browser-key mode here.');
|
|
50
|
+
}
|
|
51
|
+
const configs = {};
|
|
52
|
+
for (const tier of AI_TIER_IDS) {
|
|
53
|
+
configs[tier] =
|
|
54
|
+
vendor === 'anthropic'
|
|
55
|
+
? {
|
|
56
|
+
providerType: 'anthropic',
|
|
57
|
+
model: tiers.anthropic[tier].model,
|
|
58
|
+
maxTokens: tiers.anthropic[tier].maxTokens,
|
|
59
|
+
serverEndpoint,
|
|
60
|
+
stallTimeout: tiers.anthropic[tier].stallTimeoutMs,
|
|
61
|
+
timeout: tiers.anthropic[tier].timeoutMs,
|
|
62
|
+
}
|
|
63
|
+
: {
|
|
64
|
+
providerType: 'gemini',
|
|
65
|
+
model: tiers.gemini[tier].model,
|
|
66
|
+
serverEndpoint,
|
|
67
|
+
stallTimeout: tiers.gemini[tier].stallTimeoutMs,
|
|
68
|
+
timeout: tiers.gemini[tier].timeoutMs,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return configs;
|
|
72
|
+
}
|
|
@@ -161,6 +161,20 @@ export const GEMINI_LONG_CONTEXT_THRESHOLD = 200000;
|
|
|
161
161
|
* @beta
|
|
162
162
|
*/
|
|
163
163
|
export const GEMINI_CACHED_INPUT_MULTIPLIER = 0.1;
|
|
164
|
+
/**
|
|
165
|
+
* The day `gemini-3.8-flash` leaves its introductory rate (see `GEMINI_PRICING` below).
|
|
166
|
+
*
|
|
167
|
+
* A constant rather than a literal in the test that enforces it, because a SECOND dated
|
|
168
|
+
* assertion now hangs off the same day: the High tier picked that model while it was the
|
|
169
|
+
* cheaper one, so the flip is also the trigger to re-bench the tier (`tiers/ai-tiers.test.ts`).
|
|
170
|
+
* Two hand-copied dates would drift the moment either is corrected, and a re-bench reminder
|
|
171
|
+
* that fires on the wrong day is no reminder at all.
|
|
172
|
+
*
|
|
173
|
+
* Not part of the package's public surface — it exists for those two tests.
|
|
174
|
+
*
|
|
175
|
+
* @internal
|
|
176
|
+
*/
|
|
177
|
+
export const GEMINI_3_8_FLASH_INTRO_RATE_ENDS = Date.parse('2027-01-01T00:00:00Z');
|
|
164
178
|
/**
|
|
165
179
|
* Paid Standard tier rates (USD per million tokens) —
|
|
166
180
|
* https://ai.google.dev/gemini-api/docs/pricing
|