@tyvm/knowhow 0.0.105 → 0.0.107

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 (219) hide show
  1. package/CONFIG.md +8 -5
  2. package/package.json +3 -2
  3. package/scripts/check-model-pricing.ts +509 -0
  4. package/scripts/compare-openrouter-coverage.ts +576 -0
  5. package/src/agents/base/base.ts +169 -5
  6. package/src/agents/tools/execCommand.ts +4 -0
  7. package/src/agents/tools/executeScript/definition.ts +1 -1
  8. package/src/agents/tools/index.ts +0 -1
  9. package/src/agents/tools/list.ts +3 -43
  10. package/src/agents/tools/writeFile.ts +1 -1
  11. package/src/auth/browserLogin.ts +9 -4
  12. package/src/chat/modules/RemoteSyncModule.ts +3 -0
  13. package/src/cli.ts +31 -1
  14. package/src/clients/anthropic.ts +8 -2
  15. package/src/clients/cerebras.ts +10 -0
  16. package/src/clients/contextLimits.ts +7 -2
  17. package/src/clients/copilot.ts +23 -0
  18. package/src/clients/deepseek.ts +16 -0
  19. package/src/clients/fireworks.ts +15 -0
  20. package/src/clients/gemini.ts +59 -4
  21. package/src/clients/github.ts +16 -0
  22. package/src/clients/groq.ts +15 -0
  23. package/src/clients/http.ts +194 -6
  24. package/src/clients/index.ts +116 -4
  25. package/src/clients/llama.ts +16 -0
  26. package/src/clients/mistral.ts +16 -0
  27. package/src/clients/nvidia.ts +16 -0
  28. package/src/clients/openai.ts +53 -12
  29. package/src/clients/openrouter.ts +17 -0
  30. package/src/clients/pricing/anthropic.ts +105 -78
  31. package/src/clients/pricing/cerebras.ts +11 -0
  32. package/src/clients/pricing/copilot.ts +60 -0
  33. package/src/clients/pricing/deepseek.ts +15 -0
  34. package/src/clients/pricing/fireworks.ts +32 -0
  35. package/src/clients/pricing/github.ts +69 -0
  36. package/src/clients/pricing/google.ts +245 -206
  37. package/src/clients/pricing/groq.ts +56 -0
  38. package/src/clients/pricing/index.ts +42 -5
  39. package/src/clients/pricing/llama.ts +18 -0
  40. package/src/clients/pricing/mistral.ts +34 -0
  41. package/src/clients/pricing/models.ts +7 -236
  42. package/src/clients/pricing/nvidia.ts +102 -0
  43. package/src/clients/pricing/openai.ts +348 -171
  44. package/src/clients/pricing/openrouter.ts +36 -0
  45. package/src/clients/pricing/types.ts +83 -2
  46. package/src/clients/pricing/xai.ts +121 -65
  47. package/src/clients/types.ts +28 -1
  48. package/src/clients/xai.ts +161 -1
  49. package/src/fileSync.ts +8 -2
  50. package/src/login.ts +11 -3
  51. package/src/services/AgentSyncFs.ts +36 -12
  52. package/src/services/KnowhowClient.ts +11 -0
  53. package/src/services/LazyToolsService.ts +6 -0
  54. package/src/services/S3.ts +0 -7
  55. package/src/services/modules/index.ts +11 -2
  56. package/src/types.ts +56 -279
  57. package/src/worker.ts +174 -0
  58. package/tests/clients/AIClient.test.ts +1 -1
  59. package/tests/clients/anthropic.test.ts +202 -0
  60. package/tests/clients/pricing.test.ts +37 -0
  61. package/tests/manual/clients/completions.json +838 -226
  62. package/tests/manual/clients/completions.test.ts +46 -31
  63. package/ts_build/package.json +3 -2
  64. package/ts_build/src/agents/base/base.d.ts +18 -1
  65. package/ts_build/src/agents/base/base.js +111 -4
  66. package/ts_build/src/agents/base/base.js.map +1 -1
  67. package/ts_build/src/agents/tools/execCommand.js +3 -0
  68. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  69. package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
  70. package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
  71. package/ts_build/src/agents/tools/index.d.ts +0 -1
  72. package/ts_build/src/agents/tools/index.js +0 -1
  73. package/ts_build/src/agents/tools/index.js.map +1 -1
  74. package/ts_build/src/agents/tools/list.js +3 -38
  75. package/ts_build/src/agents/tools/list.js.map +1 -1
  76. package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
  77. package/ts_build/src/agents/tools/writeFile.js +1 -1
  78. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  79. package/ts_build/src/ai.d.ts +1 -1
  80. package/ts_build/src/auth/browserLogin.d.ts +2 -1
  81. package/ts_build/src/auth/browserLogin.js +10 -3
  82. package/ts_build/src/auth/browserLogin.js.map +1 -1
  83. package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
  84. package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
  85. package/ts_build/src/cli.js +19 -0
  86. package/ts_build/src/cli.js.map +1 -1
  87. package/ts_build/src/clients/anthropic.d.ts +1 -82
  88. package/ts_build/src/clients/anthropic.js +8 -2
  89. package/ts_build/src/clients/anthropic.js.map +1 -1
  90. package/ts_build/src/clients/cerebras.d.ts +4 -0
  91. package/ts_build/src/clients/cerebras.js +14 -0
  92. package/ts_build/src/clients/cerebras.js.map +1 -0
  93. package/ts_build/src/clients/contextLimits.js +7 -2
  94. package/ts_build/src/clients/contextLimits.js.map +1 -1
  95. package/ts_build/src/clients/copilot.d.ts +4 -0
  96. package/ts_build/src/clients/copilot.js +15 -0
  97. package/ts_build/src/clients/copilot.js.map +1 -0
  98. package/ts_build/src/clients/deepseek.d.ts +4 -0
  99. package/ts_build/src/clients/deepseek.js +15 -0
  100. package/ts_build/src/clients/deepseek.js.map +1 -0
  101. package/ts_build/src/clients/fireworks.d.ts +4 -0
  102. package/ts_build/src/clients/fireworks.js +15 -0
  103. package/ts_build/src/clients/fireworks.js.map +1 -0
  104. package/ts_build/src/clients/gemini.d.ts +1 -0
  105. package/ts_build/src/clients/gemini.js +38 -2
  106. package/ts_build/src/clients/gemini.js.map +1 -1
  107. package/ts_build/src/clients/github.d.ts +4 -0
  108. package/ts_build/src/clients/github.js +15 -0
  109. package/ts_build/src/clients/github.js.map +1 -0
  110. package/ts_build/src/clients/groq.d.ts +4 -0
  111. package/ts_build/src/clients/groq.js +15 -0
  112. package/ts_build/src/clients/groq.js.map +1 -0
  113. package/ts_build/src/clients/http.d.ts +22 -1
  114. package/ts_build/src/clients/http.js +135 -7
  115. package/ts_build/src/clients/http.js.map +1 -1
  116. package/ts_build/src/clients/index.d.ts +14 -0
  117. package/ts_build/src/clients/index.js +94 -4
  118. package/ts_build/src/clients/index.js.map +1 -1
  119. package/ts_build/src/clients/llama.d.ts +4 -0
  120. package/ts_build/src/clients/llama.js +15 -0
  121. package/ts_build/src/clients/llama.js.map +1 -0
  122. package/ts_build/src/clients/mistral.d.ts +4 -0
  123. package/ts_build/src/clients/mistral.js +15 -0
  124. package/ts_build/src/clients/mistral.js.map +1 -0
  125. package/ts_build/src/clients/nvidia.d.ts +4 -0
  126. package/ts_build/src/clients/nvidia.js +15 -0
  127. package/ts_build/src/clients/nvidia.js.map +1 -0
  128. package/ts_build/src/clients/openai.d.ts +4 -206
  129. package/ts_build/src/clients/openai.js +38 -10
  130. package/ts_build/src/clients/openai.js.map +1 -1
  131. package/ts_build/src/clients/openrouter.d.ts +4 -0
  132. package/ts_build/src/clients/openrouter.js +15 -0
  133. package/ts_build/src/clients/openrouter.js.map +1 -0
  134. package/ts_build/src/clients/pricing/anthropic.d.ts +26 -78
  135. package/ts_build/src/clients/pricing/anthropic.js +75 -78
  136. package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
  137. package/ts_build/src/clients/pricing/cerebras.d.ts +4 -0
  138. package/ts_build/src/clients/pricing/cerebras.js +11 -0
  139. package/ts_build/src/clients/pricing/cerebras.js.map +1 -0
  140. package/ts_build/src/clients/pricing/copilot.d.ts +5 -0
  141. package/ts_build/src/clients/pricing/copilot.js +35 -0
  142. package/ts_build/src/clients/pricing/copilot.js.map +1 -0
  143. package/ts_build/src/clients/pricing/deepseek.d.ts +5 -0
  144. package/ts_build/src/clients/pricing/deepseek.js +10 -0
  145. package/ts_build/src/clients/pricing/deepseek.js.map +1 -0
  146. package/ts_build/src/clients/pricing/fireworks.d.ts +5 -0
  147. package/ts_build/src/clients/pricing/fireworks.js +21 -0
  148. package/ts_build/src/clients/pricing/fireworks.js.map +1 -0
  149. package/ts_build/src/clients/pricing/github.d.ts +4 -0
  150. package/ts_build/src/clients/pricing/github.js +58 -0
  151. package/ts_build/src/clients/pricing/github.js.map +1 -0
  152. package/ts_build/src/clients/pricing/google.d.ts +59 -6
  153. package/ts_build/src/clients/pricing/google.js +214 -167
  154. package/ts_build/src/clients/pricing/google.js.map +1 -1
  155. package/ts_build/src/clients/pricing/groq.d.ts +5 -0
  156. package/ts_build/src/clients/pricing/groq.js +41 -0
  157. package/ts_build/src/clients/pricing/groq.js.map +1 -0
  158. package/ts_build/src/clients/pricing/index.d.ts +16 -5
  159. package/ts_build/src/clients/pricing/index.js +62 -7
  160. package/ts_build/src/clients/pricing/index.js.map +1 -1
  161. package/ts_build/src/clients/pricing/llama.d.ts +4 -0
  162. package/ts_build/src/clients/pricing/llama.js +14 -0
  163. package/ts_build/src/clients/pricing/llama.js.map +1 -0
  164. package/ts_build/src/clients/pricing/mistral.d.ts +5 -0
  165. package/ts_build/src/clients/pricing/mistral.js +23 -0
  166. package/ts_build/src/clients/pricing/mistral.js.map +1 -0
  167. package/ts_build/src/clients/pricing/models.d.ts +5 -4
  168. package/ts_build/src/clients/pricing/models.js +8 -162
  169. package/ts_build/src/clients/pricing/models.js.map +1 -1
  170. package/ts_build/src/clients/pricing/nvidia.d.ts +8 -0
  171. package/ts_build/src/clients/pricing/nvidia.js +96 -0
  172. package/ts_build/src/clients/pricing/nvidia.js.map +1 -0
  173. package/ts_build/src/clients/pricing/openai.d.ts +86 -197
  174. package/ts_build/src/clients/pricing/openai.js +295 -168
  175. package/ts_build/src/clients/pricing/openai.js.map +1 -1
  176. package/ts_build/src/clients/pricing/openrouter.d.ts +4 -0
  177. package/ts_build/src/clients/pricing/openrouter.js +29 -0
  178. package/ts_build/src/clients/pricing/openrouter.js.map +1 -0
  179. package/ts_build/src/clients/pricing/types.d.ts +27 -2
  180. package/ts_build/src/clients/pricing/types.js +46 -0
  181. package/ts_build/src/clients/pricing/types.js.map +1 -1
  182. package/ts_build/src/clients/pricing/xai.d.ts +37 -57
  183. package/ts_build/src/clients/pricing/xai.js +92 -59
  184. package/ts_build/src/clients/pricing/xai.js.map +1 -1
  185. package/ts_build/src/clients/types.d.ts +12 -1
  186. package/ts_build/src/clients/xai.d.ts +2 -62
  187. package/ts_build/src/clients/xai.js +132 -1
  188. package/ts_build/src/clients/xai.js.map +1 -1
  189. package/ts_build/src/fileSync.js +7 -2
  190. package/ts_build/src/fileSync.js.map +1 -1
  191. package/ts_build/src/login.js +8 -2
  192. package/ts_build/src/login.js.map +1 -1
  193. package/ts_build/src/services/AgentSyncFs.js +1 -0
  194. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  195. package/ts_build/src/services/KnowhowClient.d.ts +1 -0
  196. package/ts_build/src/services/KnowhowClient.js +7 -0
  197. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  198. package/ts_build/src/services/LazyToolsService.d.ts +1 -0
  199. package/ts_build/src/services/LazyToolsService.js +3 -0
  200. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  201. package/ts_build/src/services/S3.js +0 -7
  202. package/ts_build/src/services/S3.js.map +1 -1
  203. package/ts_build/src/services/modules/index.js +41 -1
  204. package/ts_build/src/services/modules/index.js.map +1 -1
  205. package/ts_build/src/types.d.ts +163 -124
  206. package/ts_build/src/types.js +33 -213
  207. package/ts_build/src/types.js.map +1 -1
  208. package/ts_build/src/worker.d.ts +4 -0
  209. package/ts_build/src/worker.js +140 -0
  210. package/ts_build/src/worker.js.map +1 -1
  211. package/ts_build/tests/clients/AIClient.test.js +1 -1
  212. package/ts_build/tests/clients/AIClient.test.js.map +1 -1
  213. package/ts_build/tests/clients/anthropic.test.d.ts +1 -0
  214. package/ts_build/tests/clients/anthropic.test.js +159 -0
  215. package/ts_build/tests/clients/anthropic.test.js.map +1 -0
  216. package/ts_build/tests/clients/pricing.test.js +21 -0
  217. package/ts_build/tests/clients/pricing.test.js.map +1 -1
  218. package/ts_build/tests/manual/clients/completions.test.js +27 -24
  219. package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
@@ -4,7 +4,8 @@ export type ModelType =
4
4
  | "image"
5
5
  | "audio"
6
6
  | "video"
7
- | "transaction";
7
+ | "transaction"
8
+ | "live";
8
9
 
9
10
  export interface ModelPricing {
10
11
  input?: number;
@@ -17,13 +18,93 @@ export interface ModelPricing {
17
18
  input_gt_200k?: number;
18
19
  output_gt_200k?: number;
19
20
  image_generation?: number;
21
+ image_generation_per_1m_tokens?: number;
20
22
  video_generation?: number;
23
+ output_image_per_1m_tokens?: number;
24
+ // Optional metadata — when set on a pricing entry, the catalog picks them up automatically
25
+ deprecated?: boolean;
26
+ deprecationDate?: string;
27
+ limitedAvailability?: boolean;
28
+ replacedBy?: string;
29
+ /** Supported reasoning effort levels for this model (ordered low→high). If set, effort will be clamped to these values. */
30
+ reasoningLevels?: string[];
31
+ /** If true, this model must be called via the Responses API (/v1/responses) instead of /v1/chat/completions */
32
+ useResponsesApi?: boolean;
21
33
  }
22
34
 
23
35
  export interface ModelCatalogEntry {
24
36
  id: string;
25
37
  provider: string;
26
38
  type: ModelType;
27
- displayName: string;
28
39
  pricing: ModelPricing;
40
+ deprecated?: boolean;
41
+ deprecationDate?: string;
42
+ /** Model exists but is not generally available (e.g. Live API only, limited access, or returns empty responses) */
43
+ limitedAvailability?: boolean;
44
+ /** Recommended replacement model ID when this model is deprecated */
45
+ replacedBy?: string;
46
+ }
47
+
48
+ // ─── Bulk catalog helpers ─────────────────────────────────────────────────────
49
+
50
+ export interface DeprecationOptions {
51
+ deprecated?: boolean;
52
+ deprecationDate?: string;
53
+ limitedAvailability?: boolean;
54
+ replacedBy?: string;
55
+ }
56
+
57
+ function makeEntries(
58
+ type: ModelType,
59
+ ids: string[],
60
+ provider: string,
61
+ pricing: Record<string, ModelPricing>,
62
+ deprecation?: DeprecationOptions
63
+ ): ModelCatalogEntry[] {
64
+ return ids.map((id) => {
65
+ const p = pricing[id] ?? {};
66
+ // Explicit dep options take precedence; fall back to metadata embedded in the pricing entry
67
+ const deprecated = deprecation?.deprecated ?? p.deprecated;
68
+ const deprecationDate = deprecation?.deprecationDate ?? p.deprecationDate;
69
+ const limitedAvailability = deprecation?.limitedAvailability ?? p.limitedAvailability;
70
+ const replacedBy = deprecation?.replacedBy ?? p.replacedBy;
71
+ // Strip metadata fields before storing as pricing
72
+ const { deprecated: _d, deprecationDate: _dd, limitedAvailability: _la, replacedBy: _rb, reasoningLevels: _rl, useResponsesApi: _ura, ...pricingOnly } = p;
73
+ return {
74
+ id,
75
+ provider,
76
+ type,
77
+ pricing: { input: 0, output: 0, ...pricingOnly },
78
+ deprecated,
79
+ deprecationDate,
80
+ limitedAvailability,
81
+ replacedBy,
82
+ };
83
+ });
84
+ }
85
+
86
+ export const completions = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("completion", ids, provider, pricing, dep);
87
+ export const embeddings = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("embedding", ids, provider, pricing, dep);
88
+ export const images = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("image", ids, provider, pricing, dep);
89
+ export const videos = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("video", ids, provider, pricing, dep);
90
+ export const audios = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("audio", ids, provider, pricing, dep);
91
+ export const transactions = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("transaction", ids, provider, pricing, dep);
92
+ export const liveApi = (ids: string[], provider: string, pricing: Record<string, ModelPricing>, dep?: DeprecationOptions) => makeEntries("live", ids, provider, pricing, dep);
93
+
94
+ // ─── Single-entry helpers (for deprecated/special cases) ─────────────────────
95
+
96
+ export function completion(
97
+ id: string,
98
+ provider: string,
99
+ pricing: Partial<ModelPricing> = {},
100
+ deprecation?: DeprecationOptions
101
+ ): ModelCatalogEntry {
102
+ return {
103
+ id, provider, type: "completion",
104
+ pricing: { input: 0, output: 0, ...pricing },
105
+ deprecated: deprecation?.deprecated,
106
+ deprecationDate: deprecation?.deprecationDate,
107
+ limitedAvailability: deprecation?.limitedAvailability,
108
+ replacedBy: deprecation?.replacedBy,
109
+ };
29
110
  }
@@ -1,74 +1,130 @@
1
- import { Models } from "../../types";
2
- import { ModelPricing } from "./types";
1
+ /**
2
+ * xAI model IDs, pricing, and catalog.
3
+ * Single source of truth for all xAI/Grok models.
4
+ */
5
+ import { completions, images, videos, ModelCatalogEntry, ModelPricing } from "./types";
3
6
 
4
- export const XaiTextPricing = {
7
+ // ─── Model IDs ────────────────────────────────────────────────────────────────
5
8
 
6
- [Models.xai.Grok_4_20_Reasoning]: {
7
- input: 2.0,
8
- cache_hit: 0.20,
9
- output: 6.0,
10
- },
11
- [Models.xai.Grok_4_20_NonReasoning]: {
12
- input: 2.0,
13
- cache_hit: 0.20,
14
- output: 6.0,
15
- },
16
- [Models.xai.Grok4_1_Fast_NonReasoning]: {
17
- input: 0.2,
18
- cache_hit: 0.05,
19
- output: 0.5,
20
- },
21
- [Models.xai.Grok4_1_Fast_Reasoning]: {
22
- input: 0.2,
23
- cache_hit: 0.05,
24
- output: 0.5,
25
- },
26
- [Models.xai.GrokCodeFast]: {
27
- input: 0.2,
28
- cache_hit: 0.02,
29
- output: 1.5,
30
- },
31
- [Models.xai.Grok4]: {
32
- input: 3.0,
33
- output: 15.0,
34
- },
35
- [Models.xai.Grok3Beta]: {
36
- input: 3.0,
37
- output: 15.0,
38
- },
39
- [Models.xai.Grok3MiniBeta]: {
40
- input: 0.3,
41
- output: 0.5,
42
- },
43
- [Models.xai.Grok3FastBeta]: {
44
- input: 5.0,
45
- output: 25.0,
46
- },
47
- [Models.xai.Grok3MiniFastBeta]: {
48
- input: 0.6,
49
- output: 4.0,
50
- },
51
- [Models.xai.Grok21212]: {
52
- input: 2.0,
53
- output: 10.0,
54
- },
55
- [Models.xai.Grok2Vision1212]: {
56
- input: 2.0,
57
- output: 10.0,
58
- image_input: 2.0,
59
- },
9
+ export const XaiModels = {
10
+ Grok_4_20_Reasoning: "grok-4.20-0309-reasoning",
11
+ Grok_4_20_NonReasoning: "grok-4.20-0309-non-reasoning",
12
+ Grok_4_20_MultiAgent: "grok-4.20-multi-agent-0309",
13
+ Grok4_1_Fast_Reasoning: "grok-4-1-fast-reasoning",
14
+ Grok4_1_Fast_NonReasoning: "grok-4-1-fast-non-reasoning",
15
+ GrokCodeFast: "grok-code-fast-1",
16
+ Grok4: "grok-4-0709",
17
+ Grok3Beta: "grok-3-beta",
18
+ Grok3MiniBeta: "grok-3-mini-beta",
19
+ Grok3FastBeta: "grok-3-fast-beta",
20
+ Grok3MiniFastBeta: "grok-3-mini-fast-beta",
21
+ // Deprecated alias IDs used by models.dev (latest aliases and older beta names)
22
+ Grok2Latest: "grok-2-latest",
23
+ Grok2VisionLatest: "grok-2-vision-latest",
24
+ Grok3Latest: "grok-3-latest",
25
+ Grok3FastLatest: "grok-3-fast-latest",
26
+ Grok3MiniLatest: "grok-3-mini-latest",
27
+ Grok3MiniFastLatest: "grok-3-mini-fast-latest",
28
+ GrokBeta: "grok-beta",
29
+ GrokVisionBeta: "grok-vision-beta",
30
+ // grok-4-1-fast variants (aliases for grok-4-1-fast-reasoning/non-reasoning)
31
+ Grok4_1_Fast: "grok-4-1-fast",
32
+ Grok4Fast: "grok-4-fast",
33
+ Grok4FastNonReasoning: "grok-4-fast-non-reasoning",
34
+ Grok21212: "grok-2-1212",
35
+ Grok2Vision1212: "grok-2-vision-1212",
36
+ GrokImagineImage: "grok-imagine-image",
37
+ GrokImagineVideo: "grok-imagine-video",
38
+ Grok2Image1212: "grok-2-image-1212",
39
+ } as const;
40
+
41
+ // ─── Modality arrays ──────────────────────────────────────────────────────────
42
+
43
+ export const XaiTextModels: string[] = [
44
+ XaiModels.Grok_4_20_Reasoning, XaiModels.Grok_4_20_NonReasoning,
45
+ XaiModels.Grok_4_20_MultiAgent,
46
+ XaiModels.Grok4_1_Fast_Reasoning, XaiModels.Grok4_1_Fast_NonReasoning,
47
+ XaiModels.GrokCodeFast, XaiModels.Grok4,
48
+ XaiModels.Grok3Beta, XaiModels.Grok3MiniBeta, XaiModels.Grok3FastBeta, XaiModels.Grok3MiniFastBeta,
49
+ ];
50
+
51
+ // Models that require the Responses API (/v1/responses) instead of /v1/chat/completions
52
+ // The xAI reasoning variants and multi-agent model use the Responses API
53
+ export const XaiResponsesOnlyModels: string[] = [
54
+ XaiModels.Grok_4_20_Reasoning,
55
+ XaiModels.Grok_4_20_NonReasoning,
56
+ XaiModels.Grok_4_20_MultiAgent,
57
+ XaiModels.Grok4_1_Fast_Reasoning,
58
+ XaiModels.Grok4_1_Fast_NonReasoning,
59
+ ];
60
+
61
+ // Models that support the reasoning_effort parameter
62
+ // grok-3-mini variants support reasoning_effort; grok-3-beta, grok-4 etc. do NOT
63
+ export const XaiReasoningModels: string[] = [
64
+ XaiModels.Grok_4_20_MultiAgent,
65
+ XaiModels.Grok3MiniBeta,
66
+ XaiModels.Grok3MiniFastBeta,
67
+ ];
68
+
69
+ // Deprecated xAI models — "Model not found" (400) when called
70
+ export const XaiDeprecatedTextModels: string[] = [
71
+ XaiModels.Grok21212, XaiModels.Grok2Vision1212,
72
+ // Alias IDs from models.dev that map to deprecated/versioned models
73
+ XaiModels.Grok2Latest, XaiModels.Grok2VisionLatest,
74
+ XaiModels.Grok3Latest, XaiModels.Grok3FastLatest,
75
+ XaiModels.Grok3MiniLatest, XaiModels.Grok3MiniFastLatest,
76
+ XaiModels.GrokBeta, XaiModels.GrokVisionBeta,
77
+ XaiModels.Grok4_1_Fast, XaiModels.Grok4Fast, XaiModels.Grok4FastNonReasoning,
78
+ ];
79
+ export const XaiImageModels: string[] = [XaiModels.GrokImagineImage, XaiModels.Grok2Image1212];
80
+ export const XaiVideoModels: string[] = [XaiModels.GrokImagineVideo];
81
+
82
+ // ─── Pricing (USD per 1M tokens / per-image / per-second) ────────────────────
83
+
84
+ export const XaiTextPricing: Record<string, ModelPricing> = {
85
+ [XaiModels.Grok_4_20_Reasoning]: { input: 2.0, cache_hit: 0.20, output: 6.0, useResponsesApi: true },
86
+ [XaiModels.Grok_4_20_NonReasoning]: { input: 2.0, cache_hit: 0.20, output: 6.0, useResponsesApi: true },
87
+ [XaiModels.Grok_4_20_MultiAgent]: { input: 2.0, cache_hit: 0.20, output: 6.0, reasoningLevels: ["low", "medium", "high", "xhigh"], useResponsesApi: true },
88
+ [XaiModels.Grok4_1_Fast_Reasoning]: { input: 0.2, cache_hit: 0.05, output: 0.5, useResponsesApi: true },
89
+ [XaiModels.Grok4_1_Fast_NonReasoning]: { input: 0.2, cache_hit: 0.05, output: 0.5, useResponsesApi: true },
90
+ [XaiModels.GrokCodeFast]: { input: 0.2, cache_hit: 0.02, output: 1.5 },
91
+ [XaiModels.Grok4]: { input: 3.0, output: 15.0 },
92
+ [XaiModels.Grok3Beta]: { input: 3.0, output: 15.0 },
93
+ [XaiModels.Grok3MiniBeta]: { input: 0.3, output: 0.5 },
94
+ [XaiModels.Grok3FastBeta]: { input: 5.0, output: 25.0 },
95
+ [XaiModels.Grok3MiniFastBeta]: { input: 0.6, output: 4.0 },
96
+ [XaiModels.Grok21212]: { input: 2.0, output: 10.0, deprecated: true },
97
+ [XaiModels.Grok2Vision1212]: { input: 2.0, output: 10.0, deprecated: true },
98
+ // Deprecated alias IDs (models.dev uses these; they map to versioned/beta models above)
99
+ [XaiModels.Grok2Latest]: { input: 2.0, output: 10.0, deprecated: true },
100
+ [XaiModels.Grok2VisionLatest]: { input: 2.0, output: 10.0, deprecated: true },
101
+ [XaiModels.Grok3Latest]: { input: 3.0, output: 15.0, deprecated: true },
102
+ [XaiModels.Grok3FastLatest]: { input: 5.0, output: 25.0, deprecated: true },
103
+ [XaiModels.Grok3MiniLatest]: { input: 0.3, output: 0.5, deprecated: true },
104
+ [XaiModels.Grok3MiniFastLatest]: { input: 0.6, output: 4.0, deprecated: true },
105
+ [XaiModels.GrokBeta]: { input: 5.0, output: 15.0, deprecated: true },
106
+ [XaiModels.GrokVisionBeta]: { input: 5.0, output: 15.0, deprecated: true },
107
+ // grok-4-1-fast / grok-4-fast aliases — deprecated in favor of versioned reasoning/non-reasoning variants
108
+ [XaiModels.Grok4_1_Fast]: { input: 0.2, output: 0.5, deprecated: true },
109
+ [XaiModels.Grok4Fast]: { input: 0.2, output: 0.5, deprecated: true },
110
+ [XaiModels.Grok4FastNonReasoning]:{ input: 0.2, output: 0.5, deprecated: true },
60
111
  };
61
112
 
62
- // Image generation pricing: per image
63
- // Based on https://docs.x.ai/developers/models
64
113
  export const XaiImagePricing: Record<string, ModelPricing> = {
65
- "grok-imagine-image-pro": { image_generation: 0.07 },
66
- "grok-imagine-image": { image_generation: 0.02 },
67
- "grok-2-image-1212": { image_generation: 0.07 },
114
+ "grok-imagine-image-pro": { image_generation: 0.07 },
115
+ [XaiModels.GrokImagineImage]: { image_generation: 0.02 },
116
+ [XaiModels.Grok2Image1212]: { image_generation: 0.07 },
68
117
  };
69
118
 
70
- // Video generation pricing: $0.05 per second
71
- // Based on https://docs.x.ai/developers/models
72
119
  export const XaiVideoPricing: Record<string, ModelPricing> = {
73
- "grok-imagine-video": { video_generation: 0.05 }, // per second
120
+ [XaiModels.GrokImagineVideo]: { video_generation: 0.05 },
74
121
  };
122
+
123
+ // ─── Catalog ──────────────────────────────────────────────────────────────────
124
+ // Metadata (deprecated, useResponsesApi) is read directly from XaiTextPricing entries.
125
+
126
+ export const XAI_MODEL_CATALOG: ModelCatalogEntry[] = [
127
+ ...completions([...XaiTextModels, ...XaiDeprecatedTextModels], "xai", XaiTextPricing),
128
+ ...images(XaiImageModels, "xai", XaiImagePricing),
129
+ ...videos(XaiVideoModels, "xai", XaiVideoPricing),
130
+ ];
@@ -57,6 +57,33 @@ export interface CompletionOptions {
57
57
  tools?: Tool[];
58
58
  tool_choice?: "auto" | "none";
59
59
  max_tokens?: number;
60
+ /** Reasoning effort level for models that support it.
61
+ * Maps to: OpenAI reasoning_effort, xAI reasoning.effort, Gemini thinkingLevel/thinkingBudget, Anthropic thinking budget.
62
+ * "low" = minimal thinking, "medium" = balanced, "high" = maximum reasoning */
63
+ reasoning_effort?: "low" | "medium" | "high";
64
+ }
65
+
66
+ /**
67
+ * Normalised token-usage shape that every client must return.
68
+ * All clients must map their provider-specific field names into this structure
69
+ * so that base.ts can accurately track input/output and cache utilization.
70
+ */
71
+ export interface TokenUsage {
72
+ /** Total input/prompt tokens consumed */
73
+ prompt_tokens: number;
74
+ /** Total output/completion tokens generated */
75
+ completion_tokens: number;
76
+ /** Convenience total (prompt + completion) */
77
+ total_tokens?: number;
78
+ /** Cache details */
79
+ prompt_tokens_details?: {
80
+ /** Tokens served from the prompt cache (reduces cost) */
81
+ cached_tokens: number;
82
+ };
83
+ /** Anthropic-style cache write tokens */
84
+ cache_creation_input_tokens?: number;
85
+ /** Anthropic-style cache read tokens (alternative field name) */
86
+ cache_read_input_tokens?: number;
60
87
  }
61
88
 
62
89
  export interface CompletionResponse {
@@ -65,7 +92,7 @@ export interface CompletionResponse {
65
92
  }[];
66
93
 
67
94
  model: string;
68
- usage: any;
95
+ usage: TokenUsage | undefined;
69
96
  usd_cost?: number;
70
97
  }
71
98
 
@@ -29,6 +29,7 @@ import {
29
29
 
30
30
  import { Models, XaiImageModels, XaiVideoModels } from "../types";
31
31
  import { ModelModality } from "./types";
32
+ import { XaiReasoningModels, XaiResponsesOnlyModels } from "./pricing/xai";
32
33
 
33
34
  export class GenericXAIClient implements GenericClient {
34
35
  private client: OpenAI;
@@ -54,6 +55,11 @@ export class GenericXAIClient implements GenericClient {
54
55
  async createChatCompletion(
55
56
  options: CompletionOptions
56
57
  ): Promise<CompletionResponse> {
58
+ // Route to Responses API for models that require it
59
+ if (XaiResponsesOnlyModels.includes(options.model)) {
60
+ return this.createChatResponse(options);
61
+ }
62
+
57
63
  const xaiMessages = options.messages.map((msg) => {
58
64
  if (msg.role === "tool") {
59
65
  return {
@@ -70,6 +76,10 @@ export class GenericXAIClient implements GenericClient {
70
76
  model: options.model,
71
77
  messages: xaiMessages,
72
78
  max_tokens: options.max_tokens,
79
+ ...(XaiReasoningModels.includes(options.model) && options.reasoning_effort && {
80
+ // grok-3-mini models support reasoning_effort: "low" | "medium" | "high"
81
+ reasoning_effort: options.reasoning_effort,
82
+ }),
73
83
  ...(options.tools && {
74
84
  tools: options.tools,
75
85
  tool_choice: "auto",
@@ -89,7 +99,157 @@ export class GenericXAIClient implements GenericClient {
89
99
  })),
90
100
 
91
101
  model: options.model,
92
- usage: response.usage,
102
+ usage: response.usage ? {
103
+ prompt_tokens: response.usage.prompt_tokens ?? 0,
104
+ completion_tokens: response.usage.completion_tokens ?? 0,
105
+ total_tokens: response.usage.total_tokens,
106
+ prompt_tokens_details: {
107
+ cached_tokens: response.usage.prompt_tokens_details?.cached_tokens ?? 0,
108
+ },
109
+ } : undefined,
110
+ usd_cost: usdCost,
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Creates a completion using the xAI Responses API (/v1/responses).
116
+ * Used for grok-4.20 reasoning/non-reasoning and multi-agent models.
117
+ * Translates Chat Completions message format to Responses API format.
118
+ */
119
+ async createChatResponse(
120
+ options: CompletionOptions
121
+ ): Promise<CompletionResponse> {
122
+ const apiKey = this.apiKey || process.env.XAI_API_KEY;
123
+ if (!apiKey) {
124
+ throw new Error("XAI API key not set");
125
+ }
126
+
127
+ // Extract system messages as instructions
128
+ const systemMessages = options.messages.filter((m) => m.role === "system");
129
+ const nonSystemMessages = options.messages.filter((m) => m.role !== "system");
130
+ const instructions = systemMessages
131
+ .map((m) => (typeof m.content === "string" ? m.content : ""))
132
+ .join("\n")
133
+ .trim() || undefined;
134
+
135
+ // Convert chat messages to Responses API input items
136
+ const input: any[] = nonSystemMessages.map((msg) => {
137
+ if (msg.role === "tool") {
138
+ return {
139
+ type: "function_call_output",
140
+ call_id: msg.tool_call_id,
141
+ output: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
142
+ };
143
+ }
144
+ if (msg.role === "assistant" && msg.tool_calls?.length) {
145
+ return msg.tool_calls.map((tc) => ({
146
+ type: "function_call",
147
+ id: tc.id.startsWith("fc") ? tc.id : `fc_${tc.id}`,
148
+ call_id: tc.id,
149
+ name: tc.function.name,
150
+ arguments: tc.function.arguments,
151
+ }));
152
+ }
153
+ return {
154
+ role: msg.role,
155
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
156
+ };
157
+ }).flat();
158
+
159
+ // Convert tool definitions to Responses API format
160
+ const tools = options.tools?.map((tool) => ({
161
+ type: "function" as const,
162
+ name: tool.function.name,
163
+ description: tool.function.description,
164
+ parameters: tool.function.parameters as Record<string, unknown>,
165
+ strict: false,
166
+ }));
167
+
168
+ // Resolve reasoning effort, clamping to supported levels if defined in pricing
169
+ const pricing = XaiTextPricing[options.model];
170
+ const supportedLevels = pricing?.reasoningLevels;
171
+ let reasoningEffort: string | undefined = options.reasoning_effort;
172
+ if (supportedLevels?.length) {
173
+ if (!reasoningEffort || !supportedLevels.includes(reasoningEffort)) {
174
+ reasoningEffort = supportedLevels[0];
175
+ }
176
+ }
177
+
178
+ const body: any = {
179
+ model: options.model,
180
+ input,
181
+ ...(instructions && { instructions }),
182
+ ...(options.max_tokens && { max_output_tokens: Math.max(options.max_tokens, 16_000) }),
183
+ ...(reasoningEffort && { reasoning: { effort: reasoningEffort } }),
184
+ ...(tools?.length && { tools, tool_choice: "auto" }),
185
+ store: false,
186
+ };
187
+
188
+ const response = await fetch("https://api.x.ai/v1/responses", {
189
+ method: "POST",
190
+ headers: {
191
+ "Content-Type": "application/json",
192
+ Authorization: `Bearer ${apiKey}`,
193
+ },
194
+ body: JSON.stringify(body),
195
+ });
196
+
197
+ if (!response.ok) {
198
+ const errorText = await response.text();
199
+ throw new Error(`XAI Responses API error: ${response.status} ${errorText}`);
200
+ }
201
+
202
+ const data = await response.json();
203
+
204
+ // Map usage
205
+ const usage = data.usage
206
+ ? {
207
+ prompt_tokens: data.usage.input_tokens,
208
+ completion_tokens: data.usage.output_tokens,
209
+ total_tokens: data.usage.input_tokens + data.usage.output_tokens,
210
+ prompt_tokens_details: {
211
+ cached_tokens: data.usage.input_tokens_details?.cached_tokens ?? 0,
212
+ },
213
+ }
214
+ : undefined;
215
+
216
+ const usdCost = usage ? this.calculateCost(options.model, usage) : undefined;
217
+
218
+ // Collect text content and tool calls from output items
219
+ let textContent: string | null = null;
220
+ const toolCalls: any[] = [];
221
+
222
+ for (const item of data.output ?? []) {
223
+ if (item.type === "message") {
224
+ for (const part of item.content ?? []) {
225
+ if (part.type === "output_text") {
226
+ textContent = (textContent ?? "") + part.text;
227
+ }
228
+ }
229
+ } else if (item.type === "function_call") {
230
+ toolCalls.push({
231
+ id: item.call_id,
232
+ type: "function",
233
+ function: {
234
+ name: item.name,
235
+ arguments: item.arguments,
236
+ },
237
+ });
238
+ }
239
+ }
240
+
241
+ return {
242
+ choices: [
243
+ {
244
+ message: {
245
+ role: "assistant",
246
+ content: textContent,
247
+ ...(toolCalls.length > 0 && { tool_calls: toolCalls }),
248
+ },
249
+ },
250
+ ],
251
+ model: options.model,
252
+ usage,
93
253
  usd_cost: usdCost,
94
254
  };
95
255
  }
package/src/fileSync.ts CHANGED
@@ -265,8 +265,14 @@ export async function uploadDirectory(
265
265
  for (const relFile of localFiles) {
266
266
  const localFilePath = localDir + relFile;
267
267
  const remoteFilePath = remoteDir + relFile;
268
- await uploadFile(client, s3Service, remoteFilePath, localFilePath, dryRun);
269
- count++;
268
+ try {
269
+ await uploadFile(client, s3Service, remoteFilePath, localFilePath, dryRun);
270
+ count++;
271
+ } catch (error) {
272
+ console.error(
273
+ ` ❌ Failed to upload ${localFilePath}, skipping: ${error.message}`
274
+ );
275
+ }
270
276
  }
271
277
  return count;
272
278
  }
package/src/login.ts CHANGED
@@ -29,7 +29,10 @@ export async function login(jwtFlag?: boolean): Promise<void> {
29
29
  // Use browser login as default method
30
30
  console.log("Starting browser-based authentication...");
31
31
  try {
32
- const browserLoginService = new BrowserLoginService();
32
+ // Pass existing orgId from config (if any) so the browser pre-selects the right org
33
+ const existingConfig = await getConfig();
34
+ const existingOrgId = existingConfig?.orgId;
35
+ const browserLoginService = new BrowserLoginService(undefined, existingOrgId);
33
36
  await browserLoginService.login();
34
37
  console.log("Successfully authenticated via browser!");
35
38
  } catch (error) {
@@ -43,6 +46,7 @@ export async function login(jwtFlag?: boolean): Promise<void> {
43
46
  try {
44
47
  const storedJwt = await loadJwt();
45
48
  const { user, currentOrg } = await checkJwt(storedJwt);
49
+ const orgId = currentOrg?.organizationId;
46
50
 
47
51
  console.log(
48
52
  `Current user: ${user.email}, \nOrganization: ${currentOrg?.organization?.name} - ${currentOrg?.organization?.id}`
@@ -61,9 +65,13 @@ export async function login(jwtFlag?: boolean): Promise<void> {
61
65
  config.modelProviders.push({
62
66
  provider: "knowhow",
63
67
  });
64
-
65
- await updateConfig(config);
66
68
  }
69
+ // Save orgId to config so sync:remote and other features use the correct org
70
+ if (orgId) {
71
+ config.orgId = orgId;
72
+ }
73
+
74
+ await updateConfig(config);
67
75
  } catch (error) {
68
76
  if (http.isHttpError(error) && error.response) {
69
77
  const errData = await error.response.json().catch(() => ({ message: "Unknown error" }));