@acentric/llm 0.0.0-stage → 0.1.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.
Files changed (232) hide show
  1. package/README.md +128 -2
  2. package/dist/catalog/anthropic.d.ts +77 -0
  3. package/dist/catalog/anthropic.d.ts.map +1 -0
  4. package/dist/catalog/anthropic.js +73 -0
  5. package/dist/catalog/anthropic.js.map +1 -0
  6. package/dist/catalog/fireworks.d.ts +93 -0
  7. package/dist/catalog/fireworks.d.ts.map +1 -0
  8. package/dist/catalog/fireworks.js +117 -0
  9. package/dist/catalog/fireworks.js.map +1 -0
  10. package/dist/catalog/openai.d.ts +103 -0
  11. package/dist/catalog/openai.d.ts.map +1 -0
  12. package/dist/catalog/openai.js +102 -0
  13. package/dist/catalog/openai.js.map +1 -0
  14. package/dist/client/anthropic/errors.d.ts +4 -0
  15. package/dist/client/anthropic/errors.d.ts.map +1 -0
  16. package/dist/client/anthropic/errors.js +80 -0
  17. package/dist/client/anthropic/errors.js.map +1 -0
  18. package/dist/client/anthropic/request.d.ts +9 -0
  19. package/dist/client/anthropic/request.d.ts.map +1 -0
  20. package/dist/client/anthropic/request.js +232 -0
  21. package/dist/client/anthropic/request.js.map +1 -0
  22. package/dist/client/anthropic/response.d.ts +13 -0
  23. package/dist/client/anthropic/response.d.ts.map +1 -0
  24. package/dist/client/anthropic/response.js +207 -0
  25. package/dist/client/anthropic/response.js.map +1 -0
  26. package/dist/client/direct.d.ts +18 -0
  27. package/dist/client/direct.d.ts.map +1 -0
  28. package/dist/client/direct.js +104 -0
  29. package/dist/client/direct.js.map +1 -0
  30. package/dist/client/gateway.d.ts +43 -0
  31. package/dist/client/gateway.d.ts.map +1 -0
  32. package/dist/client/gateway.js +72 -0
  33. package/dist/client/gateway.js.map +1 -0
  34. package/dist/client/http.d.ts +41 -0
  35. package/dist/client/http.d.ts.map +1 -0
  36. package/dist/client/http.js +190 -0
  37. package/dist/client/http.js.map +1 -0
  38. package/dist/client/llm.d.ts +41 -0
  39. package/dist/client/llm.d.ts.map +1 -0
  40. package/dist/client/llm.js +100 -0
  41. package/dist/client/llm.js.map +1 -0
  42. package/dist/client/responses/errors.d.ts +13 -0
  43. package/dist/client/responses/errors.d.ts.map +1 -0
  44. package/dist/client/responses/errors.js +144 -0
  45. package/dist/client/responses/errors.js.map +1 -0
  46. package/dist/client/responses/profile.d.ts +50 -0
  47. package/dist/client/responses/profile.d.ts.map +1 -0
  48. package/dist/client/responses/profile.js +4 -0
  49. package/dist/client/responses/profile.js.map +1 -0
  50. package/dist/client/responses/providers.d.ts +4 -0
  51. package/dist/client/responses/providers.d.ts.map +1 -0
  52. package/dist/client/responses/providers.js +75 -0
  53. package/dist/client/responses/providers.js.map +1 -0
  54. package/dist/client/responses/request.d.ts +5 -0
  55. package/dist/client/responses/request.d.ts.map +1 -0
  56. package/dist/client/responses/request.js +248 -0
  57. package/dist/client/responses/request.js.map +1 -0
  58. package/dist/client/responses/response.d.ts +10 -0
  59. package/dist/client/responses/response.d.ts.map +1 -0
  60. package/dist/client/responses/response.js +176 -0
  61. package/dist/client/responses/response.js.map +1 -0
  62. package/dist/client/util.d.ts +21 -0
  63. package/dist/client/util.d.ts.map +1 -0
  64. package/dist/client/util.js +63 -0
  65. package/dist/client/util.js.map +1 -0
  66. package/dist/client.d.ts +9 -0
  67. package/dist/client.d.ts.map +1 -0
  68. package/dist/client.js +10 -0
  69. package/dist/client.js.map +1 -0
  70. package/dist/content.d.ts +38 -0
  71. package/dist/content.d.ts.map +1 -0
  72. package/dist/content.js +5 -0
  73. package/dist/content.js.map +1 -0
  74. package/dist/convert/anthropic.d.ts +3 -0
  75. package/dist/convert/anthropic.d.ts.map +1 -0
  76. package/dist/convert/anthropic.js +114 -0
  77. package/dist/convert/anthropic.js.map +1 -0
  78. package/dist/convert/index.d.ts +12 -0
  79. package/dist/convert/index.d.ts.map +1 -0
  80. package/dist/convert/index.js +221 -0
  81. package/dist/convert/index.js.map +1 -0
  82. package/dist/convert/responses.d.ts +3 -0
  83. package/dist/convert/responses.d.ts.map +1 -0
  84. package/dist/convert/responses.js +197 -0
  85. package/dist/convert/responses.js.map +1 -0
  86. package/dist/convert/types.d.ts +88 -0
  87. package/dist/convert/types.d.ts.map +1 -0
  88. package/dist/convert/types.js +3 -0
  89. package/dist/convert/types.js.map +1 -0
  90. package/dist/cost.d.ts +18 -0
  91. package/dist/cost.d.ts.map +1 -0
  92. package/dist/cost.js +49 -0
  93. package/dist/cost.js.map +1 -0
  94. package/dist/failure.d.ts +90 -0
  95. package/dist/failure.d.ts.map +1 -0
  96. package/dist/failure.js +111 -0
  97. package/dist/failure.js.map +1 -0
  98. package/dist/fields.d.ts +14 -0
  99. package/dist/fields.d.ts.map +1 -0
  100. package/dist/fields.js +3 -0
  101. package/dist/fields.js.map +1 -0
  102. package/dist/formats/anthropic.d.ts +152 -0
  103. package/dist/formats/anthropic.d.ts.map +1 -0
  104. package/dist/formats/anthropic.js +7 -0
  105. package/dist/formats/anthropic.js.map +1 -0
  106. package/dist/formats/responses.d.ts +179 -0
  107. package/dist/formats/responses.d.ts.map +1 -0
  108. package/dist/formats/responses.js +9 -0
  109. package/dist/formats/responses.js.map +1 -0
  110. package/dist/index.d.ts +26 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +11 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/json.d.ts +6 -0
  115. package/dist/json.d.ts.map +1 -0
  116. package/dist/json.js +10 -0
  117. package/dist/json.js.map +1 -0
  118. package/dist/messages.d.ts +82 -0
  119. package/dist/messages.d.ts.map +1 -0
  120. package/dist/messages.js +4 -0
  121. package/dist/messages.js.map +1 -0
  122. package/dist/model.d.ts +36 -0
  123. package/dist/model.d.ts.map +1 -0
  124. package/dist/model.js +4 -0
  125. package/dist/model.js.map +1 -0
  126. package/dist/models.d.ts +9 -0
  127. package/dist/models.d.ts.map +1 -0
  128. package/dist/models.js +19 -0
  129. package/dist/models.js.map +1 -0
  130. package/dist/providers/anthropic.d.ts +130 -0
  131. package/dist/providers/anthropic.d.ts.map +1 -0
  132. package/dist/providers/anthropic.js +5 -0
  133. package/dist/providers/anthropic.js.map +1 -0
  134. package/dist/providers/fireworks.d.ts +108 -0
  135. package/dist/providers/fireworks.d.ts.map +1 -0
  136. package/dist/providers/fireworks.js +6 -0
  137. package/dist/providers/fireworks.js.map +1 -0
  138. package/dist/providers/openai.d.ts +193 -0
  139. package/dist/providers/openai.d.ts.map +1 -0
  140. package/dist/providers/openai.js +4 -0
  141. package/dist/providers/openai.js.map +1 -0
  142. package/dist/providers.d.ts +50 -0
  143. package/dist/providers.d.ts.map +1 -0
  144. package/dist/providers.js +5 -0
  145. package/dist/providers.js.map +1 -0
  146. package/dist/read/anthropic.d.ts +15 -0
  147. package/dist/read/anthropic.d.ts.map +1 -0
  148. package/dist/read/anthropic.js +56 -0
  149. package/dist/read/anthropic.js.map +1 -0
  150. package/dist/read/responses.d.ts +26 -0
  151. package/dist/read/responses.d.ts.map +1 -0
  152. package/dist/read/responses.js +121 -0
  153. package/dist/read/responses.js.map +1 -0
  154. package/dist/read.d.ts +32 -0
  155. package/dist/read.d.ts.map +1 -0
  156. package/dist/read.js +73 -0
  157. package/dist/read.js.map +1 -0
  158. package/dist/request.d.ts +23 -0
  159. package/dist/request.d.ts.map +1 -0
  160. package/dist/request.js +4 -0
  161. package/dist/request.js.map +1 -0
  162. package/dist/response.d.ts +38 -0
  163. package/dist/response.d.ts.map +1 -0
  164. package/dist/response.js +4 -0
  165. package/dist/response.js.map +1 -0
  166. package/dist/secrets.d.ts +22 -0
  167. package/dist/secrets.d.ts.map +1 -0
  168. package/dist/secrets.js +35 -0
  169. package/dist/secrets.js.map +1 -0
  170. package/dist/tool-calls.d.ts +28 -0
  171. package/dist/tool-calls.d.ts.map +1 -0
  172. package/dist/tool-calls.js +4 -0
  173. package/dist/tool-calls.js.map +1 -0
  174. package/dist/tools.d.ts +33 -0
  175. package/dist/tools.d.ts.map +1 -0
  176. package/dist/tools.js +4 -0
  177. package/dist/tools.js.map +1 -0
  178. package/dist/usage.d.ts +31 -0
  179. package/dist/usage.d.ts.map +1 -0
  180. package/dist/usage.js +3 -0
  181. package/dist/usage.js.map +1 -0
  182. package/dist/version.d.ts +2 -0
  183. package/dist/version.d.ts.map +1 -0
  184. package/dist/version.js +6 -0
  185. package/dist/version.js.map +1 -0
  186. package/package.json +33 -3
  187. package/src/catalog/anthropic.ts +83 -0
  188. package/src/catalog/fireworks.ts +121 -0
  189. package/src/catalog/openai.ts +133 -0
  190. package/src/client/anthropic/errors.ts +88 -0
  191. package/src/client/anthropic/request.ts +272 -0
  192. package/src/client/anthropic/response.ts +236 -0
  193. package/src/client/direct.ts +157 -0
  194. package/src/client/gateway.ts +120 -0
  195. package/src/client/http.ts +231 -0
  196. package/src/client/llm.ts +151 -0
  197. package/src/client/responses/errors.ts +166 -0
  198. package/src/client/responses/profile.ts +55 -0
  199. package/src/client/responses/providers.ts +87 -0
  200. package/src/client/responses/request.ts +326 -0
  201. package/src/client/responses/response.ts +203 -0
  202. package/src/client/util.ts +81 -0
  203. package/src/client.ts +20 -0
  204. package/src/content.ts +46 -0
  205. package/src/convert/anthropic.ts +115 -0
  206. package/src/convert/index.ts +275 -0
  207. package/src/convert/responses.ts +203 -0
  208. package/src/convert/types.ts +104 -0
  209. package/src/cost.ts +71 -0
  210. package/src/failure.ts +164 -0
  211. package/src/fields.ts +13 -0
  212. package/src/formats/anthropic.ts +191 -0
  213. package/src/formats/responses.ts +207 -0
  214. package/src/index.ts +44 -0
  215. package/src/json.ts +13 -0
  216. package/src/messages.ts +99 -0
  217. package/src/model.ts +41 -0
  218. package/src/models.ts +23 -0
  219. package/src/providers/anthropic.ts +137 -0
  220. package/src/providers/fireworks.ts +140 -0
  221. package/src/providers/openai.ts +275 -0
  222. package/src/providers.ts +59 -0
  223. package/src/read/anthropic.ts +64 -0
  224. package/src/read/responses.ts +159 -0
  225. package/src/read.ts +108 -0
  226. package/src/request.ts +28 -0
  227. package/src/response.ts +44 -0
  228. package/src/secrets.ts +40 -0
  229. package/src/tool-calls.ts +33 -0
  230. package/src/tools.ts +38 -0
  231. package/src/usage.ts +33 -0
  232. package/src/version.ts +6 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAEA,4FAA4F;AAC5F,MAAM,MAAM,KAAK,GAAG;IAClB,yCAAyC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,SAAS,GAAG;IACtB,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC"}
package/dist/usage.js ADDED
@@ -0,0 +1,3 @@
1
+ // Tokens and cost, the same for every provider.
2
+ export {};
3
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,gDAAgD"}
@@ -0,0 +1,2 @@
1
+ export declare const LLM_VERSION = "0.1.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ // This package's version. The client sends it to the gateway, so a gateway
2
+ // running an older copy can refuse a newer client's request plainly instead
3
+ // of failing on a shape it does not know. A test keeps it equal to
4
+ // package.json's version.
5
+ export const LLM_VERSION = '0.1.0';
6
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,mEAAmE;AACnE,0BAA0B;AAE1B,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "@acentric/llm",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Calls LLM providers from an agent's handlers, directly or through the acentric gateway, with readers for replies that an agent's pure half can use.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./client": {
13
+ "types": "./dist/client.d.ts",
14
+ "default": "./dist/client.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "src"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "dependencies": {
25
+ "@acentric/types": "0.1.0"
26
+ },
27
+ "devDependencies": {
28
+ "@acentric/runner-memory": "0.1.0",
29
+ "@types/node": "^26.6.5",
30
+ "esbuild": "^0.28.2"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc --build",
34
+ "clean": "tsc --build --clean"
35
+ }
6
36
  }
@@ -0,0 +1,83 @@
1
+ // Claude 5 models. Standard prices in US dollars per million tokens, from
2
+ // https://platform.claude.com/docs/en/about-claude/pricing and the model pages,
3
+ // as of October 2026. A cache write costs 1.25 times the input price for five
4
+ // minutes and twice for an hour; reads are priced per model. Only Haiku 5.5
5
+ // has a long-context price: for the whole request, output included, once the
6
+ // prompt is over 100,000 tokens.
7
+
8
+ import type { ModelCost, ModelInfo } from '../model.js';
9
+
10
+ const LIMITS = { contextWindow: 1_000_000, maxOutputTokens: 128_000 } as const;
11
+ const INPUT = ['text', 'image', 'file'] as const;
12
+
13
+ function cost(
14
+ input: number,
15
+ output: number,
16
+ cacheWrite: number,
17
+ cacheWrite1h: number,
18
+ cacheRead: number,
19
+ ): ModelCost {
20
+ return { input, output, cacheWrite, cacheWrite1h, cacheRead };
21
+ }
22
+
23
+ export const ANTHROPIC_MODELS = [
24
+ {
25
+ provider: 'anthropic',
26
+ id: 'claude-fable-5-1',
27
+ name: 'Claude Fable 5.1',
28
+ ...LIMITS,
29
+ input: INPUT,
30
+ pricing: { base: cost(10, 50, 12.5, 20, 0.25) },
31
+ },
32
+ {
33
+ provider: 'anthropic',
34
+ id: 'claude-opus-5-5',
35
+ name: 'Claude Opus 5.5',
36
+ ...LIMITS,
37
+ input: INPUT,
38
+ pricing: { base: cost(4, 20, 5, 8, 0.2) },
39
+ },
40
+ {
41
+ provider: 'anthropic',
42
+ id: 'claude-sonnet-5-5',
43
+ name: 'Claude Sonnet 5.5',
44
+ ...LIMITS,
45
+ input: INPUT,
46
+ pricing: { base: cost(2, 10, 2.5, 4, 0.1) },
47
+ },
48
+ {
49
+ provider: 'anthropic',
50
+ id: 'claude-haiku-5-5',
51
+ name: 'Claude Haiku 5.5',
52
+ ...LIMITS,
53
+ input: INPUT,
54
+ pricing: {
55
+ base: cost(0.1, 0.5, 0.125, 0.2, 0.01),
56
+ tiers: [{ aboveInputTokens: 100_000, cost: cost(0.5, 2.5, 0.625, 1, 0.05) }],
57
+ },
58
+ },
59
+ {
60
+ provider: 'anthropic',
61
+ id: 'claude-fable-5',
62
+ name: 'Claude Fable 5',
63
+ ...LIMITS,
64
+ input: INPUT,
65
+ pricing: { base: cost(10, 50, 12.5, 20, 1) },
66
+ },
67
+ {
68
+ provider: 'anthropic',
69
+ id: 'claude-opus-5',
70
+ name: 'Claude Opus 5',
71
+ ...LIMITS,
72
+ input: INPUT,
73
+ pricing: { base: cost(5, 25, 6.25, 10, 0.5) },
74
+ },
75
+ {
76
+ provider: 'anthropic',
77
+ id: 'claude-sonnet-5',
78
+ name: 'Claude Sonnet 5',
79
+ ...LIMITS,
80
+ input: INPUT,
81
+ pricing: { base: cost(2, 10, 2.5, 4, 0.2) },
82
+ },
83
+ ] as const satisfies readonly ModelInfo<'anthropic'>[];
@@ -0,0 +1,121 @@
1
+ // Fireworks serverless models. Standard prices in US dollars per million
2
+ // tokens, from https://docs.fireworks.ai/serverless/pricing and the model
3
+ // pages, as of October 2026. Fireworks has no long-context prices, charges
4
+ // nothing for cache writes and documents no output limit per model. The
5
+ // "fast" routers are model IDs of their own, with their own prices.
6
+
7
+ import type { ModelPricing, ModelInfo } from '../model.js';
8
+
9
+ const VISION = ['text', 'image'] as const;
10
+ const TEXT = ['text'] as const;
11
+ const MILLION = 1_048_576;
12
+
13
+ function cost(input: number, cacheRead: number, output: number): ModelPricing {
14
+ return { base: { input, cacheRead, output } };
15
+ }
16
+
17
+ export const FIREWORKS_MODELS = [
18
+ {
19
+ provider: 'fireworks',
20
+ id: 'accounts/fireworks/models/kimi-k3',
21
+ name: 'Kimi K3',
22
+ contextWindow: MILLION,
23
+ input: VISION,
24
+ pricing: cost(3, 0.3, 15),
25
+ },
26
+ {
27
+ provider: 'fireworks',
28
+ id: 'accounts/fireworks/routers/kimi-k3-fast',
29
+ name: 'Kimi K3 Fast',
30
+ contextWindow: MILLION,
31
+ input: VISION,
32
+ pricing: cost(4.5, 0.45, 22.5),
33
+ },
34
+ {
35
+ provider: 'fireworks',
36
+ id: 'accounts/fireworks/models/ember-1',
37
+ name: 'Ember-1',
38
+ contextWindow: MILLION,
39
+ input: VISION,
40
+ pricing: cost(3, 0.3, 15),
41
+ },
42
+ {
43
+ provider: 'fireworks',
44
+ id: 'accounts/fireworks/models/deepseek-v4p1-flash',
45
+ name: 'DeepSeek V4.1 Flash',
46
+ contextWindow: MILLION,
47
+ input: VISION,
48
+ pricing: cost(0.3, 0.006, 1.2),
49
+ },
50
+ {
51
+ provider: 'fireworks',
52
+ id: 'accounts/fireworks/models/glm-5p3',
53
+ name: 'GLM 5.3',
54
+ contextWindow: MILLION,
55
+ input: TEXT,
56
+ pricing: cost(1.4, 0.26, 4.4),
57
+ },
58
+ {
59
+ provider: 'fireworks',
60
+ id: 'accounts/fireworks/routers/glm-5p3-fast',
61
+ name: 'GLM 5.3 Fast',
62
+ contextWindow: MILLION,
63
+ input: TEXT,
64
+ pricing: cost(2.1, 0.39, 6.6),
65
+ },
66
+ {
67
+ provider: 'fireworks',
68
+ id: 'accounts/fireworks/models/glm-5p3-flash',
69
+ name: 'GLM 5.3 Flash',
70
+ contextWindow: MILLION,
71
+ input: VISION,
72
+ pricing: cost(0.15, 0.03, 0.5),
73
+ },
74
+ {
75
+ provider: 'fireworks',
76
+ id: 'accounts/fireworks/models/qwen3p8-max',
77
+ name: 'Qwen 3.8 Max',
78
+ input: VISION,
79
+ pricing: cost(2, 0.25, 6),
80
+ },
81
+ {
82
+ provider: 'fireworks',
83
+ id: 'accounts/fireworks/models/minimax-m3',
84
+ name: 'MiniMax M3',
85
+ contextWindow: 512_000,
86
+ input: TEXT,
87
+ pricing: cost(0.3, 0.06, 1.2),
88
+ },
89
+ {
90
+ provider: 'fireworks',
91
+ id: 'accounts/fireworks/models/gpt-oss-120b',
92
+ name: 'gpt-oss-120b',
93
+ contextWindow: 131_072,
94
+ input: TEXT,
95
+ pricing: cost(0.15, 0.015, 0.6),
96
+ },
97
+ {
98
+ provider: 'fireworks',
99
+ id: 'accounts/fireworks/models/nemotron-lightning-3p5-30b-a3b',
100
+ name: 'Nemotron Lightning 3.5 30B A3B',
101
+ contextWindow: 262_144,
102
+ input: TEXT,
103
+ pricing: cost(0.05, 0.01, 0.2),
104
+ },
105
+ {
106
+ provider: 'fireworks',
107
+ id: 'accounts/fireworks/models/nemotron-3-ultra-nvfp4',
108
+ name: 'Nemotron 3 Ultra (Preview)',
109
+ contextWindow: 262_144,
110
+ input: TEXT,
111
+ pricing: cost(0.6, 0.12, 2.4),
112
+ },
113
+ {
114
+ provider: 'fireworks',
115
+ id: 'accounts/fireworks/models/inkling',
116
+ name: 'Inkling',
117
+ contextWindow: MILLION,
118
+ input: VISION,
119
+ pricing: cost(1, 0.17, 4.05),
120
+ },
121
+ ] as const satisfies readonly ModelInfo<'fireworks'>[];
@@ -0,0 +1,133 @@
1
+ // OpenAI models. Standard prices in US dollars per million tokens, and limits,
2
+ // from https://developers.openai.com/api/docs/pricing and the model pages, as
3
+ // of October 2026. Long-context prices are for the whole request once the
4
+ // prompt is over 272,000 tokens.
5
+
6
+ import type { ModelCost, ModelInfo, ModelPricing } from '../model.js';
7
+
8
+ function longContext(base: ModelCost, cost: ModelCost): ModelPricing {
9
+ return { base, tiers: [{ aboveInputTokens: 272_000, cost }] };
10
+ }
11
+
12
+ const GPT_6_LIMITS = { contextWindow: 1_050_000, maxOutputTokens: 128_000 } as const;
13
+ const VISION = ['text', 'image'] as const;
14
+
15
+ export const OPENAI_MODELS = [
16
+ {
17
+ provider: 'openai',
18
+ id: 'gpt-6-astra',
19
+ name: 'GPT-6 Astra',
20
+ ...GPT_6_LIMITS,
21
+ input: VISION,
22
+ pricing: longContext(
23
+ { input: 10, cacheRead: 1, cacheWrite: 12.5, output: 50 },
24
+ { input: 20, cacheRead: 2, output: 75 },
25
+ ),
26
+ },
27
+ {
28
+ provider: 'openai',
29
+ id: 'gpt-6.1-sol',
30
+ name: 'GPT-6.1 Sol',
31
+ ...GPT_6_LIMITS,
32
+ input: VISION,
33
+ pricing: longContext(
34
+ { input: 2, cacheRead: 0.1, cacheWrite: 2.5, output: 10 },
35
+ { input: 4, cacheRead: 0.2, output: 15 },
36
+ ),
37
+ },
38
+ {
39
+ provider: 'openai',
40
+ id: 'gpt-6-sol',
41
+ name: 'GPT-6 Sol',
42
+ ...GPT_6_LIMITS,
43
+ input: VISION,
44
+ pricing: longContext(
45
+ { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 10 },
46
+ { input: 4, cacheRead: 0.4, output: 15 },
47
+ ),
48
+ },
49
+ {
50
+ provider: 'openai',
51
+ id: 'gpt-6-luna',
52
+ name: 'GPT-6 Luna',
53
+ ...GPT_6_LIMITS,
54
+ input: VISION,
55
+ pricing: longContext(
56
+ { input: 0.1, cacheRead: 0.01, cacheWrite: 0.125, output: 0.5 },
57
+ { input: 0.2, cacheRead: 0.02, output: 0.75 },
58
+ ),
59
+ },
60
+ {
61
+ provider: 'openai',
62
+ id: 'gpt-5.6-sol',
63
+ name: 'GPT-5.6 Sol',
64
+ ...GPT_6_LIMITS,
65
+ input: VISION,
66
+ pricing: longContext(
67
+ { input: 4, cacheRead: 0.4, cacheWrite: 5, output: 20 },
68
+ { input: 8, cacheRead: 0.8, output: 30 },
69
+ ),
70
+ },
71
+ {
72
+ provider: 'openai',
73
+ id: 'gpt-5.6-terra',
74
+ name: 'GPT-5.6 Terra',
75
+ ...GPT_6_LIMITS,
76
+ input: VISION,
77
+ pricing: longContext(
78
+ { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 12 },
79
+ { input: 4, cacheRead: 0.4, output: 18 },
80
+ ),
81
+ },
82
+ {
83
+ provider: 'openai',
84
+ id: 'gpt-5.6-luna',
85
+ name: 'GPT-5.6 Luna',
86
+ ...GPT_6_LIMITS,
87
+ input: VISION,
88
+ pricing: longContext(
89
+ { input: 0.2, cacheRead: 0.02, cacheWrite: 0.25, output: 1.2 },
90
+ { input: 0.4, cacheRead: 0.04, output: 1.8 },
91
+ ),
92
+ },
93
+ {
94
+ provider: 'openai',
95
+ id: 'gpt-5.5',
96
+ name: 'GPT-5.5',
97
+ ...GPT_6_LIMITS,
98
+ input: VISION,
99
+ pricing: longContext(
100
+ { input: 5, cacheRead: 0.5, output: 30 },
101
+ { input: 10, cacheRead: 1, output: 45 },
102
+ ),
103
+ },
104
+ {
105
+ provider: 'openai',
106
+ id: 'gpt-5.4',
107
+ name: 'GPT-5.4',
108
+ ...GPT_6_LIMITS,
109
+ input: VISION,
110
+ pricing: longContext(
111
+ { input: 2.5, cacheRead: 0.25, output: 15 },
112
+ { input: 5, cacheRead: 0.5, output: 22.5 },
113
+ ),
114
+ },
115
+ {
116
+ provider: 'openai',
117
+ id: 'gpt-5.4-mini',
118
+ name: 'GPT-5.4 mini',
119
+ contextWindow: 400_000,
120
+ maxOutputTokens: 128_000,
121
+ input: VISION,
122
+ pricing: { base: { input: 0.75, cacheRead: 0.075, output: 4.5 } },
123
+ },
124
+ {
125
+ provider: 'openai',
126
+ id: 'gpt-4.1',
127
+ name: 'GPT-4.1',
128
+ contextWindow: 1_047_576,
129
+ maxOutputTokens: 32_768,
130
+ input: VISION,
131
+ pricing: { base: { input: 2, cacheRead: 0.5, output: 8 } },
132
+ },
133
+ ] as const satisfies readonly ModelInfo<'openai'>[];
@@ -0,0 +1,88 @@
1
+ // Anthropic failures read into LlmErrors. Anthropic answers
2
+ // `{ type: "error", error: { type, message, details? }, request_id }`; a 413
3
+ // and errors from its edge have other shapes, or a text body.
4
+
5
+ import { LlmError } from '../../failure.js';
6
+ import type { LlmFailureKind } from '../../failure.js';
7
+ import { isObject } from '../../json.js';
8
+ import { retryAfter } from '../http.js';
9
+ import type { HttpAnswer } from '../http.js';
10
+ import { cut } from '../util.js';
11
+
12
+ const KIND_BY_TYPE: { readonly [type: string]: LlmFailureKind } = {
13
+ authentication_error: 'auth',
14
+ permission_error: 'auth',
15
+ billing_error: 'quota_exceeded',
16
+ not_found_error: 'not_found',
17
+ rate_limit_error: 'rate_limited',
18
+ request_too_large: 'invalid_request',
19
+ overloaded_error: 'overloaded',
20
+ timeout_error: 'timeout',
21
+ api_error: 'provider_error',
22
+ };
23
+
24
+ /** A validation message starts with the field at fault: `messages.1.content.0: …`. */
25
+ const FIELD_PREFIX = /^([A-Za-z_][\w-]*(?:\.[\w-]+)*): /;
26
+
27
+ export function httpFailure(answer: HttpAnswer): LlmError {
28
+ const { body, status, headers } = answer;
29
+ const error = isObject(body) && isObject(body['error']) ? body['error'] : undefined;
30
+ const type = typeof error?.['type'] === 'string' ? error['type'] : undefined;
31
+ const message = typeof error?.['message'] === 'string' ? error['message'] : undefined;
32
+ const details = isObject(error?.['details']) ? error['details'] : undefined;
33
+ const code = typeof details?.['error_code'] === 'string' ? details['error_code'] : undefined;
34
+ const param = message?.match(FIELD_PREFIX)?.[1];
35
+ const after = retryAfter(headers);
36
+ const shouldRetry = headers.get('x-should-retry');
37
+ return new LlmError(
38
+ message ??
39
+ (typeof body === 'string' && body !== '' ? body : undefined) ??
40
+ `the Anthropic call failed with HTTP ${status}`,
41
+ {
42
+ kind: classify(status, type, message, code),
43
+ provider: 'anthropic',
44
+ httpStatus: status,
45
+ providerError: cut(error ?? body),
46
+ ...(code === undefined ? {} : { providerCode: code }),
47
+ ...(type === undefined ? {} : { providerType: type }),
48
+ ...(param === undefined ? {} : { providerParam: param }),
49
+ ...(after === undefined ? {} : { retryAfterMs: after }),
50
+ ...(shouldRetry === 'true'
51
+ ? { retryable: true }
52
+ : shouldRetry === 'false'
53
+ ? { retryable: false }
54
+ : {}),
55
+ },
56
+ );
57
+ }
58
+
59
+ function classify(
60
+ status: number,
61
+ type: string | undefined,
62
+ message: string | undefined,
63
+ code: string | undefined,
64
+ ): LlmFailureKind {
65
+ // A usage tier's monthly spend cap: a rate limit that lasts until next month.
66
+ if (code === 'enforced_spend_limit_reached') return 'quota_exceeded';
67
+ if (message !== undefined && type === 'invalid_request_error') {
68
+ // "prompt is too long: 205024 tokens > 200000 maximum", with no code.
69
+ if (/^prompt is too long/i.test(message)) return 'context_overflow';
70
+ if (
71
+ /reached your specified (workspace )?API usage limits|credit balance is too low/i.test(
72
+ message,
73
+ )
74
+ ) {
75
+ return 'quota_exceeded';
76
+ }
77
+ }
78
+ const byType = type === undefined ? undefined : KIND_BY_TYPE[type];
79
+ if (byType !== undefined) return byType;
80
+ if (status === 401 || status === 403) return 'auth';
81
+ if (status === 402) return 'quota_exceeded';
82
+ if (status === 404) return 'not_found';
83
+ if (status === 429) return 'rate_limited';
84
+ if (status === 503 || status === 529) return 'overloaded';
85
+ if (status === 504) return 'timeout';
86
+ if (status >= 500) return 'provider_error';
87
+ return 'invalid_request';
88
+ }