@elevasis/core 0.46.0 → 0.48.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.
@@ -2880,6 +2880,138 @@ type Database = {
2880
2880
  };
2881
2881
  Relationships: [];
2882
2882
  };
2883
+ agent_access_grants: {
2884
+ Row: {
2885
+ allowed_origins: string[];
2886
+ branding: Json;
2887
+ capture_fields: Json;
2888
+ code_hash: string | null;
2889
+ code_salt: string | null;
2890
+ created_at: string;
2891
+ disabled_at: string | null;
2892
+ expires_at: string | null;
2893
+ id: string;
2894
+ max_sessions_per_visitor: number;
2895
+ max_turns_per_session: number;
2896
+ mode: string;
2897
+ organization_id: string;
2898
+ resource_id: string;
2899
+ slug: string;
2900
+ tool_policy: Json;
2901
+ updated_at: string;
2902
+ };
2903
+ Insert: {
2904
+ allowed_origins?: string[];
2905
+ branding?: Json;
2906
+ capture_fields?: Json;
2907
+ code_hash?: string | null;
2908
+ code_salt?: string | null;
2909
+ created_at?: string;
2910
+ disabled_at?: string | null;
2911
+ expires_at?: string | null;
2912
+ id?: string;
2913
+ max_sessions_per_visitor?: number;
2914
+ max_turns_per_session?: number;
2915
+ mode?: string;
2916
+ organization_id: string;
2917
+ resource_id: string;
2918
+ slug: string;
2919
+ tool_policy?: Json;
2920
+ updated_at?: string;
2921
+ };
2922
+ Update: {
2923
+ allowed_origins?: string[];
2924
+ branding?: Json;
2925
+ capture_fields?: Json;
2926
+ code_hash?: string | null;
2927
+ code_salt?: string | null;
2928
+ created_at?: string;
2929
+ disabled_at?: string | null;
2930
+ expires_at?: string | null;
2931
+ id?: string;
2932
+ max_sessions_per_visitor?: number;
2933
+ max_turns_per_session?: number;
2934
+ mode?: string;
2935
+ organization_id?: string;
2936
+ resource_id?: string;
2937
+ slug?: string;
2938
+ tool_policy?: Json;
2939
+ updated_at?: string;
2940
+ };
2941
+ Relationships: [
2942
+ {
2943
+ foreignKeyName: "agent_access_grants_organization_id_fkey";
2944
+ columns: ["organization_id"];
2945
+ isOneToOne: false;
2946
+ referencedRelation: "organizations";
2947
+ referencedColumns: ["id"];
2948
+ }
2949
+ ];
2950
+ };
2951
+ agent_chat_capabilities: {
2952
+ Row: {
2953
+ created_at: string;
2954
+ expires_at: string;
2955
+ grant_id: string;
2956
+ id: string;
2957
+ organization_id: string;
2958
+ origin: string | null;
2959
+ resource_id: string;
2960
+ revoked_at: string | null;
2961
+ session_id: string | null;
2962
+ token_hash: string;
2963
+ visitor_id: string | null;
2964
+ };
2965
+ Insert: {
2966
+ created_at?: string;
2967
+ expires_at: string;
2968
+ grant_id: string;
2969
+ id?: string;
2970
+ organization_id: string;
2971
+ origin?: string | null;
2972
+ resource_id: string;
2973
+ revoked_at?: string | null;
2974
+ session_id?: string | null;
2975
+ token_hash: string;
2976
+ visitor_id?: string | null;
2977
+ };
2978
+ Update: {
2979
+ created_at?: string;
2980
+ expires_at?: string;
2981
+ grant_id?: string;
2982
+ id?: string;
2983
+ organization_id?: string;
2984
+ origin?: string | null;
2985
+ resource_id?: string;
2986
+ revoked_at?: string | null;
2987
+ session_id?: string | null;
2988
+ token_hash?: string;
2989
+ visitor_id?: string | null;
2990
+ };
2991
+ Relationships: [
2992
+ {
2993
+ foreignKeyName: "agent_chat_capabilities_grant_id_fkey";
2994
+ columns: ["grant_id"];
2995
+ isOneToOne: false;
2996
+ referencedRelation: "agent_access_grants";
2997
+ referencedColumns: ["id"];
2998
+ },
2999
+ {
3000
+ foreignKeyName: "agent_chat_capabilities_organization_id_fkey";
3001
+ columns: ["organization_id"];
3002
+ isOneToOne: false;
3003
+ referencedRelation: "organizations";
3004
+ referencedColumns: ["id"];
3005
+ },
3006
+ {
3007
+ foreignKeyName: "agent_chat_capabilities_session_id_fkey";
3008
+ columns: ["session_id"];
3009
+ isOneToOne: false;
3010
+ referencedRelation: "sessions";
3011
+ referencedColumns: ["session_id"];
3012
+ }
3013
+ ];
3014
+ };
2883
3015
  organizations: {
2884
3016
  Row: {
2885
3017
  config: Json;
@@ -1538,6 +1538,7 @@ interface OrganizationGraph {
1538
1538
  * @param systemId - The dotted system id (e.g. `sales.crm`).
1539
1539
  */
1540
1540
  declare function bySystem(graph: OrganizationGraph, systemId: string, knowledgeNodes: OrgKnowledgeNode[]): OrgKnowledgeNode[];
1541
+ declare function byOntology(graph: OrganizationGraph, ontologyId: string, knowledgeNodes: OrgKnowledgeNode[]): OrgKnowledgeNode[];
1541
1542
  /**
1542
1543
  * Returns all knowledge nodes whose `kind` matches the given kind.
1543
1544
  *
@@ -1745,5 +1746,5 @@ declare function formatKnowledgeInvocationLabel(invocation: OrganizationModelAct
1745
1746
  declare function resolveKnowledgeInvocationNeighbors(model: OrganizationModel, id: string): KnowledgeInvocationNeighborsResult | undefined;
1746
1747
  declare function formatKnowledgeInvocationNeighbors(result: KnowledgeInvocationNeighborsResult): string;
1747
1748
 
1748
- export { OM_SEARCH_HIT_KINDS, byKind, byOwner, bySystem, formatIdsOnly, formatJson, formatKnowledgeInvocationLabel, formatKnowledgeInvocationNeighbors, formatKnowledgeResourcesList, formatKnowledgeRolesList, formatKnowledgeSystemsList, formatText, governedBy, governs, normalizeKnowledgeNodeId, parseKnowledgeSearchKinds, parseKnowledgeSearchLimit, parsePath, resolveKnowledgeInvocationNeighbors };
1749
+ export { OM_SEARCH_HIT_KINDS, byKind, byOntology, byOwner, bySystem, formatIdsOnly, formatJson, formatKnowledgeInvocationLabel, formatKnowledgeInvocationNeighbors, formatKnowledgeResourcesList, formatKnowledgeRolesList, formatKnowledgeSystemsList, formatText, governedBy, governs, normalizeKnowledgeNodeId, parseKnowledgeSearchKinds, parseKnowledgeSearchLimit, parsePath, resolveKnowledgeInvocationNeighbors };
1749
1750
  export type { KnowledgeInvocationNeighborsResult, KnowledgeInvocationSource, KnowledgeJsonEnvelope, KnowledgeMount, OmSearchHitKind, ParsedKnowledgePath };
@@ -140,6 +140,22 @@ function bySystem(graph, systemId, knowledgeNodes) {
140
140
  }
141
141
  return knowledgeNodes.filter((n) => matchingOmIds.has(n.id));
142
142
  }
143
+ function byOntology(graph, ontologyId, knowledgeNodes) {
144
+ const targetGraphNodeId = toTargetGraphNodeId(ontologyId);
145
+ const governingKnowledgeNodeIds = /* @__PURE__ */ new Set();
146
+ for (const edge of graph.edges) {
147
+ if (edge.kind === "governs" && edge.targetId === targetGraphNodeId && edge.sourceId.startsWith("knowledge:")) {
148
+ governingKnowledgeNodeIds.add(edge.sourceId);
149
+ }
150
+ }
151
+ const sourceIdMap = buildKnowledgeSourceIdMap(graph);
152
+ const matchingOmIds = /* @__PURE__ */ new Set();
153
+ for (const graphNodeId of governingKnowledgeNodeIds) {
154
+ const omId = sourceIdMap.get(graphNodeId);
155
+ if (omId) matchingOmIds.add(omId);
156
+ }
157
+ return knowledgeNodes.filter((n) => matchingOmIds.has(n.id));
158
+ }
143
159
  function byKind(_graph, kind, knowledgeNodes) {
144
160
  return knowledgeNodes.filter((n) => n.kind === kind);
145
161
  }
@@ -433,4 +449,4 @@ function formatKnowledgeInvocationNeighbors(result) {
433
449
  return lines.join("\n");
434
450
  }
435
451
 
436
- export { OM_SEARCH_HIT_KINDS, byKind, byOwner, bySystem, formatIdsOnly, formatJson, formatKnowledgeInvocationLabel, formatKnowledgeInvocationNeighbors, formatKnowledgeResourcesList, formatKnowledgeRolesList, formatKnowledgeSystemsList, formatText, governedBy, governs, normalizeKnowledgeNodeId, parseKnowledgeSearchKinds, parseKnowledgeSearchLimit, parsePath, resolveKnowledgeInvocationNeighbors };
452
+ export { OM_SEARCH_HIT_KINDS, byKind, byOntology, byOwner, bySystem, formatIdsOnly, formatJson, formatKnowledgeInvocationLabel, formatKnowledgeInvocationNeighbors, formatKnowledgeResourcesList, formatKnowledgeRolesList, formatKnowledgeSystemsList, formatText, governedBy, governs, normalizeKnowledgeNodeId, parseKnowledgeSearchKinds, parseKnowledgeSearchLimit, parsePath, resolveKnowledgeInvocationNeighbors };
@@ -2117,6 +2117,138 @@ type Database = {
2117
2117
  };
2118
2118
  Relationships: [];
2119
2119
  };
2120
+ agent_access_grants: {
2121
+ Row: {
2122
+ allowed_origins: string[];
2123
+ branding: Json;
2124
+ capture_fields: Json;
2125
+ code_hash: string | null;
2126
+ code_salt: string | null;
2127
+ created_at: string;
2128
+ disabled_at: string | null;
2129
+ expires_at: string | null;
2130
+ id: string;
2131
+ max_sessions_per_visitor: number;
2132
+ max_turns_per_session: number;
2133
+ mode: string;
2134
+ organization_id: string;
2135
+ resource_id: string;
2136
+ slug: string;
2137
+ tool_policy: Json;
2138
+ updated_at: string;
2139
+ };
2140
+ Insert: {
2141
+ allowed_origins?: string[];
2142
+ branding?: Json;
2143
+ capture_fields?: Json;
2144
+ code_hash?: string | null;
2145
+ code_salt?: string | null;
2146
+ created_at?: string;
2147
+ disabled_at?: string | null;
2148
+ expires_at?: string | null;
2149
+ id?: string;
2150
+ max_sessions_per_visitor?: number;
2151
+ max_turns_per_session?: number;
2152
+ mode?: string;
2153
+ organization_id: string;
2154
+ resource_id: string;
2155
+ slug: string;
2156
+ tool_policy?: Json;
2157
+ updated_at?: string;
2158
+ };
2159
+ Update: {
2160
+ allowed_origins?: string[];
2161
+ branding?: Json;
2162
+ capture_fields?: Json;
2163
+ code_hash?: string | null;
2164
+ code_salt?: string | null;
2165
+ created_at?: string;
2166
+ disabled_at?: string | null;
2167
+ expires_at?: string | null;
2168
+ id?: string;
2169
+ max_sessions_per_visitor?: number;
2170
+ max_turns_per_session?: number;
2171
+ mode?: string;
2172
+ organization_id?: string;
2173
+ resource_id?: string;
2174
+ slug?: string;
2175
+ tool_policy?: Json;
2176
+ updated_at?: string;
2177
+ };
2178
+ Relationships: [
2179
+ {
2180
+ foreignKeyName: "agent_access_grants_organization_id_fkey";
2181
+ columns: ["organization_id"];
2182
+ isOneToOne: false;
2183
+ referencedRelation: "organizations";
2184
+ referencedColumns: ["id"];
2185
+ }
2186
+ ];
2187
+ };
2188
+ agent_chat_capabilities: {
2189
+ Row: {
2190
+ created_at: string;
2191
+ expires_at: string;
2192
+ grant_id: string;
2193
+ id: string;
2194
+ organization_id: string;
2195
+ origin: string | null;
2196
+ resource_id: string;
2197
+ revoked_at: string | null;
2198
+ session_id: string | null;
2199
+ token_hash: string;
2200
+ visitor_id: string | null;
2201
+ };
2202
+ Insert: {
2203
+ created_at?: string;
2204
+ expires_at: string;
2205
+ grant_id: string;
2206
+ id?: string;
2207
+ organization_id: string;
2208
+ origin?: string | null;
2209
+ resource_id: string;
2210
+ revoked_at?: string | null;
2211
+ session_id?: string | null;
2212
+ token_hash: string;
2213
+ visitor_id?: string | null;
2214
+ };
2215
+ Update: {
2216
+ created_at?: string;
2217
+ expires_at?: string;
2218
+ grant_id?: string;
2219
+ id?: string;
2220
+ organization_id?: string;
2221
+ origin?: string | null;
2222
+ resource_id?: string;
2223
+ revoked_at?: string | null;
2224
+ session_id?: string | null;
2225
+ token_hash?: string;
2226
+ visitor_id?: string | null;
2227
+ };
2228
+ Relationships: [
2229
+ {
2230
+ foreignKeyName: "agent_chat_capabilities_grant_id_fkey";
2231
+ columns: ["grant_id"];
2232
+ isOneToOne: false;
2233
+ referencedRelation: "agent_access_grants";
2234
+ referencedColumns: ["id"];
2235
+ },
2236
+ {
2237
+ foreignKeyName: "agent_chat_capabilities_organization_id_fkey";
2238
+ columns: ["organization_id"];
2239
+ isOneToOne: false;
2240
+ referencedRelation: "organizations";
2241
+ referencedColumns: ["id"];
2242
+ },
2243
+ {
2244
+ foreignKeyName: "agent_chat_capabilities_session_id_fkey";
2245
+ columns: ["session_id"];
2246
+ isOneToOne: false;
2247
+ referencedRelation: "sessions";
2248
+ referencedColumns: ["session_id"];
2249
+ }
2250
+ ];
2251
+ };
2120
2252
  organizations: {
2121
2253
  Row: {
2122
2254
  config: Json;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/core",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "license": "MIT",
5
5
  "description": "Minimal shared constants across Elevasis monorepo",
6
6
  "sideEffects": false,
@@ -45,8 +45,8 @@
45
45
  "rollup-plugin-dts": "^6.3.0",
46
46
  "tsup": "^8.0.0",
47
47
  "typescript": "5.9.2",
48
- "@repo/eslint-config": "0.0.0",
49
- "@repo/typescript-config": "0.0.0"
48
+ "@repo/typescript-config": "0.0.0",
49
+ "@repo/eslint-config": "0.0.0"
50
50
  },
51
51
  "dependencies": {
52
52
  "@anthropic-ai/sdk": "^0.62.0",
@@ -75,6 +75,7 @@
75
75
  "lint": "eslint src --max-warnings 0",
76
76
  "check-types": "tsc --noEmit",
77
77
  "test": "vitest run",
78
+ "test:publish-artifacts": "pnpm build:publish && vitest run src/__tests__/publish.test.ts src/__tests__/published-artifact.test.ts",
78
79
  "test:watch": "vitest watch",
79
80
  "clean": "rm -rf dist"
80
81
  }
@@ -1,25 +1,30 @@
1
- import { describe, it, expect } from 'vitest'
2
-
3
- describe('Observability Exports', () => {
4
- it('exports error tracking types from main package', async () => {
5
- // Test that types can be imported from the main package
6
- const {
7
- ErrorRecordSchema,
8
- ErrorDetailFullSchema,
9
- ErrorDistributionSchema,
10
- ErrorTrendSchema
11
- } = await import('../index')
12
-
13
- expect(ErrorRecordSchema).toBeDefined()
14
- expect(ErrorDetailFullSchema).toBeDefined()
15
- expect(ErrorDistributionSchema).toBeDefined()
16
- expect(ErrorTrendSchema).toBeDefined()
17
- })
18
-
19
- it('schemas validate correctly when imported from main package', async () => {
20
- const { ErrorRecordSchema } = await import('../index')
21
-
22
- const validRecord = {
1
+ import { beforeAll, describe, it, expect } from 'vitest'
2
+
3
+ let coreExports: typeof import('../index')
4
+
5
+ describe('Observability Exports', () => {
6
+ beforeAll(async () => {
7
+ coreExports = await import('../index')
8
+ }, 60000)
9
+
10
+ it('exports error tracking types from main package', () => {
11
+ const {
12
+ ErrorRecordSchema,
13
+ ErrorDetailFullSchema,
14
+ ErrorDistributionSchema,
15
+ ErrorTrendSchema
16
+ } = coreExports
17
+
18
+ expect(ErrorRecordSchema).toBeDefined()
19
+ expect(ErrorDetailFullSchema).toBeDefined()
20
+ expect(ErrorDistributionSchema).toBeDefined()
21
+ expect(ErrorTrendSchema).toBeDefined()
22
+ })
23
+
24
+ it('schemas validate correctly when imported from main package', () => {
25
+ const { ErrorRecordSchema } = coreExports
26
+
27
+ const validRecord = {
23
28
  id: '123e4567-e89b-12d3-a456-426614174000',
24
29
  timestamp: '2024-01-15T10:30:00Z',
25
30
  errorType: 'ValidationError',
@@ -0,0 +1,99 @@
1
+ import { afterEach, describe, expect, it } from 'vitest'
2
+ import { execFile } from 'node:child_process'
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+ import { promisify } from 'node:util'
6
+
7
+ const execFileAsync = promisify(execFile)
8
+ const coreRoot = path.resolve(import.meta.dirname, '../..')
9
+ const distRoot = path.resolve(coreRoot, 'dist')
10
+ const packageJsonPath = path.resolve(coreRoot, 'package.json')
11
+ const tempRoots: string[] = []
12
+
13
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as {
14
+ version: string
15
+ type: string
16
+ sideEffects?: boolean | string[]
17
+ publishConfig?: {
18
+ name?: string
19
+ exports?: Record<string, string | { types?: string; import?: string }>
20
+ }
21
+ }
22
+
23
+ function packagePath(target: string): string {
24
+ return path.resolve(coreRoot, target.replace(/^\.\//, ''))
25
+ }
26
+
27
+ function createConsumerPackage(): string {
28
+ const tempRoot = fs.mkdtempSync(path.join(coreRoot, '.tmp-published-core-'))
29
+ tempRoots.push(tempRoot)
30
+
31
+ const packageRoot = path.join(tempRoot, 'node_modules', '@elevasis', 'core')
32
+ fs.mkdirSync(packageRoot, { recursive: true })
33
+ fs.cpSync(distRoot, path.join(packageRoot, 'dist'), { recursive: true })
34
+ fs.writeFileSync(
35
+ path.join(packageRoot, 'package.json'),
36
+ JSON.stringify(
37
+ {
38
+ name: packageJson.publishConfig?.name,
39
+ version: packageJson.version,
40
+ type: packageJson.type,
41
+ sideEffects: packageJson.sideEffects,
42
+ exports: packageJson.publishConfig?.exports
43
+ },
44
+ null,
45
+ 2
46
+ )
47
+ )
48
+
49
+ return tempRoot
50
+ }
51
+
52
+ describe.skipIf(!fs.existsSync(distRoot))('published @elevasis/core artifact', { timeout: 30_000 }, () => {
53
+ afterEach(() => {
54
+ for (const tempRoot of tempRoots.splice(0)) {
55
+ fs.rmSync(tempRoot, { recursive: true, force: true })
56
+ }
57
+ })
58
+
59
+ it('has publish-ready runtime and declaration artifacts for every public export', () => {
60
+ expect(packageJson.publishConfig?.name).toBe('@elevasis/core')
61
+
62
+ for (const [subpath, entry] of Object.entries(packageJson.publishConfig?.exports ?? {})) {
63
+ if (typeof entry === 'string') {
64
+ expect(entry, `${subpath} must point at dist`).toMatch(/^\.\//)
65
+ expect(fs.existsSync(packagePath(entry)), `${subpath} target does not exist: ${entry}`).toBe(true)
66
+ continue
67
+ }
68
+
69
+ expect(entry.types, `${subpath} is missing a types condition`).toBeTruthy()
70
+ expect(entry.import, `${subpath} is missing an import condition`).toBeTruthy()
71
+ expect(fs.existsSync(packagePath(entry.types ?? '')), `${subpath} types do not exist: ${entry.types}`).toBe(true)
72
+ expect(fs.existsSync(packagePath(entry.import ?? '')), `${subpath} runtime does not exist: ${entry.import}`).toBe(
73
+ true
74
+ )
75
+ }
76
+ })
77
+
78
+ it('resolves public runtime subpaths from a temp consumer package', async () => {
79
+ const consumerRoot = createConsumerPackage()
80
+ const smokeScript = `
81
+ const core = await import('@elevasis/core')
82
+ const auth = await import('@elevasis/core/auth')
83
+ const orgModel = await import('@elevasis/core/organization-model')
84
+ const entities = await import('@elevasis/core/entities')
85
+ const knowledge = await import('@elevasis/core/knowledge')
86
+
87
+ if (!core.DEFAULT_ORGANIZATION_MODEL) throw new Error('missing DEFAULT_ORGANIZATION_MODEL')
88
+ if (!auth.AccessKeys) throw new Error('missing AccessKeys')
89
+ if (typeof orgModel.defineOrganizationModel !== 'function') throw new Error('missing defineOrganizationModel')
90
+ if (!entities.BaseProjectSchema) throw new Error('missing BaseProjectSchema')
91
+ if (typeof knowledge.parsePath !== 'function') throw new Error('missing parsePath')
92
+ `
93
+
94
+ await execFileAsync(process.execPath, ['--input-type=module', '--eval', smokeScript], {
95
+ cwd: consumerRoot,
96
+ maxBuffer: 1024 * 1024
97
+ })
98
+ })
99
+ })
@@ -1,10 +1,10 @@
1
- /**
2
- * Model Info Tests
3
- * Verifies registration of gemini-3.1-flash-lite-preview in MODEL_INFO and GoogleConfigSchema
4
- */
5
-
6
- import { describe, it, expect } from 'vitest'
7
- import { MODEL_INFO, GoogleConfigSchema } from '../model-info'
1
+ /**
2
+ * Model Info Tests
3
+ * Verifies model registrations in MODEL_INFO and provider config schemas
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest'
7
+ import { AnthropicConfigSchema, MODEL_INFO, GoogleConfigSchema } from '../model-info'
8
8
 
9
9
  describe('gemini-3.1-flash-lite-preview registration', () => {
10
10
  it('exists in MODEL_INFO with correct pricing', () => {
@@ -46,5 +46,78 @@ describe('gemini-3.1-flash-lite-preview registration', () => {
46
46
  it('GoogleModel type includes gemini-3.1-flash-lite-preview via MODEL_INFO key check', () => {
47
47
  const modelKeys = Object.keys(MODEL_INFO)
48
48
  expect(modelKeys).toContain('gemini-3.1-flash-lite-preview')
49
- })
50
- })
49
+ })
50
+ })
51
+
52
+ describe('current Anthropic model registration', () => {
53
+ it('registers Opus 4.8 with current pricing and token limits', () => {
54
+ const info = MODEL_INFO['claude-opus-4-8']
55
+
56
+ expect(info).toBeDefined()
57
+ expect(info.inputCostPer1M).toBe(500)
58
+ expect(info.outputCostPer1M).toBe(2500)
59
+ expect(info.maxTokens).toBe(1000000)
60
+ expect(info.maxOutputTokens).toBe(128000)
61
+ })
62
+
63
+ it('registers Sonnet 4.6 with current pricing and token limits', () => {
64
+ const info = MODEL_INFO['claude-sonnet-4-6']
65
+
66
+ expect(info).toBeDefined()
67
+ expect(info.inputCostPer1M).toBe(300)
68
+ expect(info.outputCostPer1M).toBe(1500)
69
+ expect(info.maxTokens).toBe(1000000)
70
+ expect(info.maxOutputTokens).toBe(64000)
71
+ })
72
+
73
+ it('registers Haiku 4.5 dated ID and alias with current pricing and token limits', () => {
74
+ const datedInfo = MODEL_INFO['claude-haiku-4-5-20251001']
75
+ const aliasInfo = MODEL_INFO['claude-haiku-4-5']
76
+
77
+ expect(datedInfo).toBeDefined()
78
+ expect(aliasInfo).toBeDefined()
79
+ expect(datedInfo.inputCostPer1M).toBe(100)
80
+ expect(datedInfo.outputCostPer1M).toBe(500)
81
+ expect(datedInfo.maxTokens).toBe(200000)
82
+ expect(datedInfo.maxOutputTokens).toBe(64000)
83
+ expect(aliasInfo).toMatchObject({
84
+ inputCostPer1M: datedInfo.inputCostPer1M,
85
+ outputCostPer1M: datedInfo.outputCostPer1M,
86
+ maxTokens: datedInfo.maxTokens,
87
+ maxOutputTokens: datedInfo.maxOutputTokens
88
+ })
89
+ })
90
+
91
+ it.each(['claude-opus-4-8', 'claude-sonnet-4-6', 'claude-haiku-4-5-20251001', 'claude-haiku-4-5'])(
92
+ 'AnthropicConfigSchema validates %s',
93
+ (model) => {
94
+ const result = AnthropicConfigSchema.safeParse({
95
+ model,
96
+ provider: 'anthropic',
97
+ apiKey: 'test-key',
98
+ maxOutputTokens: 4000
99
+ })
100
+
101
+ expect(result.success).toBe(true)
102
+ }
103
+ )
104
+
105
+ it('rejects non-default Opus 4.8 sampling parameters', () => {
106
+ const temperatureResult = AnthropicConfigSchema.safeParse({
107
+ model: 'claude-opus-4-8',
108
+ provider: 'anthropic',
109
+ apiKey: 'test-key',
110
+ temperature: 0.7
111
+ })
112
+
113
+ const topPResult = AnthropicConfigSchema.safeParse({
114
+ model: 'claude-opus-4-8',
115
+ provider: 'anthropic',
116
+ apiKey: 'test-key',
117
+ topP: 0.9
118
+ })
119
+
120
+ expect(temperatureResult.success).toBe(false)
121
+ expect(topPResult.success).toBe(false)
122
+ })
123
+ })