@tyvm/knowhow 0.0.104 → 0.0.106

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 (233) 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 +127 -2
  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/cerebras.ts +10 -0
  15. package/src/clients/contextLimits.ts +7 -2
  16. package/src/clients/copilot.ts +23 -0
  17. package/src/clients/deepseek.ts +16 -0
  18. package/src/clients/fireworks.ts +15 -0
  19. package/src/clients/gemini.ts +45 -2
  20. package/src/clients/github.ts +16 -0
  21. package/src/clients/groq.ts +15 -0
  22. package/src/clients/http.ts +190 -6
  23. package/src/clients/index.ts +215 -9
  24. package/src/clients/llama.ts +16 -0
  25. package/src/clients/mistral.ts +16 -0
  26. package/src/clients/nvidia.ts +16 -0
  27. package/src/clients/openai.ts +41 -11
  28. package/src/clients/openrouter.ts +17 -0
  29. package/src/clients/pricing/anthropic.ts +105 -78
  30. package/src/clients/pricing/cerebras.ts +11 -0
  31. package/src/clients/pricing/copilot.ts +60 -0
  32. package/src/clients/pricing/deepseek.ts +15 -0
  33. package/src/clients/pricing/fireworks.ts +32 -0
  34. package/src/clients/pricing/github.ts +69 -0
  35. package/src/clients/pricing/google.ts +245 -206
  36. package/src/clients/pricing/groq.ts +56 -0
  37. package/src/clients/pricing/index.ts +43 -6
  38. package/src/clients/pricing/llama.ts +18 -0
  39. package/src/clients/pricing/mistral.ts +34 -0
  40. package/src/clients/pricing/models.ts +23 -0
  41. package/src/clients/pricing/nvidia.ts +102 -0
  42. package/src/clients/pricing/openai.ts +347 -171
  43. package/src/clients/pricing/openrouter.ts +36 -0
  44. package/src/clients/pricing/types.ts +110 -0
  45. package/src/clients/pricing/xai.ts +123 -66
  46. package/src/clients/types.ts +4 -0
  47. package/src/clients/xai.ts +152 -2
  48. package/src/fileSync.ts +8 -2
  49. package/src/login.ts +11 -3
  50. package/src/services/AgentSyncFs.ts +36 -12
  51. package/src/services/KnowhowClient.ts +11 -0
  52. package/src/services/LazyToolsService.ts +6 -0
  53. package/src/services/S3.ts +0 -7
  54. package/src/services/SyncedAgentWatcher.ts +13 -298
  55. package/src/services/index.ts +1 -0
  56. package/src/services/modules/index.ts +11 -2
  57. package/src/services/watchers/FsSyncer.ts +155 -0
  58. package/src/services/watchers/RemoteSyncer.ts +153 -0
  59. package/src/services/watchers/index.ts +2 -0
  60. package/src/types.ts +56 -279
  61. package/src/worker.ts +174 -0
  62. package/tests/clients/pricing.test.ts +37 -0
  63. package/tests/manual/clients/completions.json +838 -226
  64. package/tests/manual/clients/completions.test.ts +46 -31
  65. package/ts_build/package.json +3 -2
  66. package/ts_build/src/agents/base/base.d.ts +17 -1
  67. package/ts_build/src/agents/base/base.js +82 -1
  68. package/ts_build/src/agents/base/base.js.map +1 -1
  69. package/ts_build/src/agents/tools/execCommand.js +3 -0
  70. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  71. package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
  72. package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
  73. package/ts_build/src/agents/tools/index.d.ts +0 -1
  74. package/ts_build/src/agents/tools/index.js +0 -1
  75. package/ts_build/src/agents/tools/index.js.map +1 -1
  76. package/ts_build/src/agents/tools/list.js +3 -38
  77. package/ts_build/src/agents/tools/list.js.map +1 -1
  78. package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
  79. package/ts_build/src/agents/tools/writeFile.js +1 -1
  80. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  81. package/ts_build/src/ai.d.ts +1 -1
  82. package/ts_build/src/auth/browserLogin.d.ts +2 -1
  83. package/ts_build/src/auth/browserLogin.js +10 -3
  84. package/ts_build/src/auth/browserLogin.js.map +1 -1
  85. package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
  86. package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
  87. package/ts_build/src/cli.js +19 -0
  88. package/ts_build/src/cli.js.map +1 -1
  89. package/ts_build/src/clients/anthropic.d.ts +1 -82
  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 +28 -1
  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 +132 -7
  115. package/ts_build/src/clients/http.js.map +1 -1
  116. package/ts_build/src/clients/index.d.ts +22 -0
  117. package/ts_build/src/clients/index.js +150 -5
  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 +27 -9
  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 +17 -6
  159. package/ts_build/src/clients/pricing/index.js +65 -10
  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 +9 -0
  168. package/ts_build/src/clients/pricing/models.js +19 -0
  169. package/ts_build/src/clients/pricing/models.js.map +1 -0
  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 +294 -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 +46 -0
  180. package/ts_build/src/clients/pricing/types.js +49 -0
  181. package/ts_build/src/clients/pricing/types.js.map +1 -0
  182. package/ts_build/src/clients/pricing/xai.d.ts +39 -64
  183. package/ts_build/src/clients/pricing/xai.js +93 -60
  184. package/ts_build/src/clients/pricing/xai.js.map +1 -1
  185. package/ts_build/src/clients/types.d.ts +1 -0
  186. package/ts_build/src/clients/xai.d.ts +2 -58
  187. package/ts_build/src/clients/xai.js +123 -2
  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/SyncedAgentWatcher.d.ts +0 -51
  204. package/ts_build/src/services/SyncedAgentWatcher.js +1 -282
  205. package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
  206. package/ts_build/src/services/index.d.ts +1 -0
  207. package/ts_build/src/services/index.js +1 -0
  208. package/ts_build/src/services/index.js.map +1 -1
  209. package/ts_build/src/services/modules/index.js +41 -1
  210. package/ts_build/src/services/modules/index.js.map +1 -1
  211. package/ts_build/src/services/watchers/FsSyncer.d.ts +27 -0
  212. package/ts_build/src/services/watchers/FsSyncer.js +135 -0
  213. package/ts_build/src/services/watchers/FsSyncer.js.map +1 -0
  214. package/ts_build/src/services/watchers/RemoteSyncer.d.ts +28 -0
  215. package/ts_build/src/services/watchers/RemoteSyncer.js +126 -0
  216. package/ts_build/src/services/watchers/RemoteSyncer.js.map +1 -0
  217. package/ts_build/src/services/watchers/index.d.ts +2 -0
  218. package/ts_build/src/services/watchers/index.js +19 -0
  219. package/ts_build/src/services/watchers/index.js.map +1 -0
  220. package/ts_build/src/types.d.ts +163 -124
  221. package/ts_build/src/types.js +33 -213
  222. package/ts_build/src/types.js.map +1 -1
  223. package/ts_build/src/worker.d.ts +4 -0
  224. package/ts_build/src/worker.js +140 -0
  225. package/ts_build/src/worker.js.map +1 -1
  226. package/ts_build/tests/clients/pricing.test.js +21 -0
  227. package/ts_build/tests/clients/pricing.test.js.map +1 -1
  228. package/ts_build/tests/manual/clients/completions.test.js +27 -24
  229. package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
  230. package/src/clients/pricing/catalog.ts +0 -287
  231. package/ts_build/src/clients/pricing/catalog.d.ts +0 -28
  232. package/ts_build/src/clients/pricing/catalog.js +0 -179
  233. package/ts_build/src/clients/pricing/catalog.js.map +0 -1
@@ -0,0 +1,36 @@
1
+ /**
2
+ * OpenRouter pricing (USD per 1M tokens)
3
+ * Source: https://openrouter.ai/models
4
+ * Models with `:free` suffix are free. Others are paid.
5
+ * OpenRouter acts as an aggregator — prices may vary from original providers.
6
+ */
7
+ export const OpenRouterTextPricing: Record<string, { input: number; output: number }> = {
8
+ // Free models (`:free` suffix)
9
+ "deepseek/deepseek-r1:free": { input: 0.0, output: 0.0 },
10
+ "deepseek/deepseek-chat-v3-0324:free": { input: 0.0, output: 0.0 },
11
+ "meta-llama/llama-3.3-70b-instruct:free": { input: 0.0, output: 0.0 },
12
+ "meta-llama/llama-4-maverick:free": { input: 0.0, output: 0.0 },
13
+ "meta-llama/llama-4-scout:free": { input: 0.0, output: 0.0 },
14
+ "google/gemma-3-27b-it:free": { input: 0.0, output: 0.0 },
15
+ "google/gemma-3-12b-it:free": { input: 0.0, output: 0.0 },
16
+ "microsoft/phi-4:free": { input: 0.0, output: 0.0 },
17
+ "qwen/qwen3-235b-a22b:free": { input: 0.0, output: 0.0 },
18
+ "qwen/qwen3-30b-a3b:free": { input: 0.0, output: 0.0 },
19
+ "mistralai/mistral-7b-instruct:free": { input: 0.0, output: 0.0 },
20
+ "nousresearch/hermes-3-llama-3.1-405b:free": { input: 0.0, output: 0.0 },
21
+ // Paid models (popular)
22
+ "openai/gpt-4o": { input: 2.5, output: 10.0 },
23
+ "openai/gpt-4o-mini": { input: 0.15, output: 0.6 },
24
+ "anthropic/claude-3.5-sonnet": { input: 3.0, output: 15.0 },
25
+ "anthropic/claude-3-haiku": { input: 0.25, output: 1.25 },
26
+ // Source: openrouter.ai/api/v1/models (2026-04)
27
+ "deepseek/deepseek-r1": { input: 0.7, output: 2.5 },
28
+ "deepseek/deepseek-chat-v3-0324": { input: 0.2, output: 0.77 },
29
+ "meta-llama/llama-3.3-70b-instruct": { input: 0.12, output: 0.3 },
30
+ "google/gemini-2.0-flash-001": { input: 0.1, output: 0.4 },
31
+ // Source: openrouter.ai/api/v1/models (2026-04) — qwen3-235b-a22b = $0.455/$1.82
32
+ // Note: models.dev shows $0.15/$0.85 for dated variant, using OpenRouter live price
33
+ "qwen/qwen3-235b-a22b": { input: 0.455, output: 1.82 },
34
+ "qwen/qwen3-235b-a22b-07-25": { input: 0.15, output: 0.85 },
35
+ "mistralai/mistral-large-2411": { input: 2.0, output: 6.0 },
36
+ };
@@ -0,0 +1,110 @@
1
+ export type ModelType =
2
+ | "completion"
3
+ | "embedding"
4
+ | "image"
5
+ | "audio"
6
+ | "video"
7
+ | "transaction"
8
+ | "live";
9
+
10
+ export interface ModelPricing {
11
+ input?: number;
12
+ output?: number;
13
+ cached_input?: number;
14
+ cache_write?: number;
15
+ cache_hit?: number;
16
+ input_audio?: number;
17
+ output_audio?: number;
18
+ input_gt_200k?: number;
19
+ output_gt_200k?: number;
20
+ image_generation?: number;
21
+ image_generation_per_1m_tokens?: number;
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;
33
+ }
34
+
35
+ export interface ModelCatalogEntry {
36
+ id: string;
37
+ provider: string;
38
+ type: ModelType;
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
+ };
110
+ }
@@ -1,73 +1,130 @@
1
- import { Models } 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";
2
6
 
3
- export const XaiTextPricing = {
7
+ // ─── Model IDs ────────────────────────────────────────────────────────────────
4
8
 
5
- [Models.xai.Grok_4_20_Reasoning]: {
6
- input: 2.0,
7
- cache_hit: 0.20,
8
- output: 6.0,
9
- },
10
- [Models.xai.Grok_4_20_NonReasoning]: {
11
- input: 2.0,
12
- cache_hit: 0.20,
13
- output: 6.0,
14
- },
15
- [Models.xai.Grok4_1_Fast_NonReasoning]: {
16
- input: 0.2,
17
- cache_hit: 0.05,
18
- output: 0.5,
19
- },
20
- [Models.xai.Grok4_1_Fast_Reasoning]: {
21
- input: 0.2,
22
- cache_hit: 0.05,
23
- output: 0.5,
24
- },
25
- [Models.xai.GrokCodeFast]: {
26
- input: 0.2,
27
- cache_hit: 0.02,
28
- output: 1.5,
29
- },
30
- [Models.xai.Grok4]: {
31
- input: 3.0,
32
- output: 15.0,
33
- },
34
- [Models.xai.Grok3Beta]: {
35
- input: 3.0,
36
- output: 15.0,
37
- },
38
- [Models.xai.Grok3MiniBeta]: {
39
- input: 0.3,
40
- output: 0.5,
41
- },
42
- [Models.xai.Grok3FastBeta]: {
43
- input: 5.0,
44
- output: 25.0,
45
- },
46
- [Models.xai.Grok3MiniFastBeta]: {
47
- input: 0.6,
48
- output: 4.0,
49
- },
50
- [Models.xai.Grok21212]: {
51
- input: 2.0,
52
- output: 10.0,
53
- },
54
- [Models.xai.Grok2Vision1212]: {
55
- input: 2.0,
56
- output: 10.0,
57
- image_input: 2.0,
58
- },
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 },
59
111
  };
60
112
 
61
- // Image generation pricing: per image
62
- // Based on https://docs.x.ai/developers/models
63
- export const XaiImagePricing = {
64
- "grok-imagine-image-pro": 0.07,
65
- "grok-imagine-image": 0.02,
66
- "grok-2-image-1212": 0.07,
113
+ export const XaiImagePricing: Record<string, ModelPricing> = {
114
+ "grok-imagine-image-pro": { image_generation: 0.07 },
115
+ [XaiModels.GrokImagineImage]: { image_generation: 0.02 },
116
+ [XaiModels.Grok2Image1212]: { image_generation: 0.07 },
67
117
  };
68
118
 
69
- // Video generation pricing: $0.05 per second
70
- // Based on https://docs.x.ai/developers/models
71
- export const XaiVideoPricing = {
72
- "grok-imagine-video": 0.05, // per second
119
+ export const XaiVideoPricing: Record<string, ModelPricing> = {
120
+ [XaiModels.GrokImagineVideo]: { video_generation: 0.05 },
73
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,10 @@ 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";
60
64
  }
61
65
 
62
66
  export interface CompletionResponse {
@@ -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",
@@ -94,6 +104,146 @@ export class GenericXAIClient implements GenericClient {
94
104
  };
95
105
  }
96
106
 
107
+ /**
108
+ * Creates a completion using the xAI Responses API (/v1/responses).
109
+ * Used for grok-4.20 reasoning/non-reasoning and multi-agent models.
110
+ * Translates Chat Completions message format to Responses API format.
111
+ */
112
+ async createChatResponse(
113
+ options: CompletionOptions
114
+ ): Promise<CompletionResponse> {
115
+ const apiKey = this.apiKey || process.env.XAI_API_KEY;
116
+ if (!apiKey) {
117
+ throw new Error("XAI API key not set");
118
+ }
119
+
120
+ // Extract system messages as instructions
121
+ const systemMessages = options.messages.filter((m) => m.role === "system");
122
+ const nonSystemMessages = options.messages.filter((m) => m.role !== "system");
123
+ const instructions = systemMessages
124
+ .map((m) => (typeof m.content === "string" ? m.content : ""))
125
+ .join("\n")
126
+ .trim() || undefined;
127
+
128
+ // Convert chat messages to Responses API input items
129
+ const input: any[] = nonSystemMessages.map((msg) => {
130
+ if (msg.role === "tool") {
131
+ return {
132
+ type: "function_call_output",
133
+ call_id: msg.tool_call_id,
134
+ output: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
135
+ };
136
+ }
137
+ if (msg.role === "assistant" && msg.tool_calls?.length) {
138
+ return msg.tool_calls.map((tc) => ({
139
+ type: "function_call",
140
+ id: tc.id.startsWith("fc") ? tc.id : `fc_${tc.id}`,
141
+ call_id: tc.id,
142
+ name: tc.function.name,
143
+ arguments: tc.function.arguments,
144
+ }));
145
+ }
146
+ return {
147
+ role: msg.role,
148
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
149
+ };
150
+ }).flat();
151
+
152
+ // Convert tool definitions to Responses API format
153
+ const tools = options.tools?.map((tool) => ({
154
+ type: "function" as const,
155
+ name: tool.function.name,
156
+ description: tool.function.description,
157
+ parameters: tool.function.parameters as Record<string, unknown>,
158
+ strict: false,
159
+ }));
160
+
161
+ // Resolve reasoning effort, clamping to supported levels if defined in pricing
162
+ const pricing = XaiTextPricing[options.model];
163
+ const supportedLevels = pricing?.reasoningLevels;
164
+ let reasoningEffort: string | undefined = options.reasoning_effort;
165
+ if (supportedLevels?.length) {
166
+ if (!reasoningEffort || !supportedLevels.includes(reasoningEffort)) {
167
+ reasoningEffort = supportedLevels[0];
168
+ }
169
+ }
170
+
171
+ const body: any = {
172
+ model: options.model,
173
+ input,
174
+ ...(instructions && { instructions }),
175
+ ...(options.max_tokens && { max_output_tokens: Math.max(options.max_tokens, 16_000) }),
176
+ ...(reasoningEffort && { reasoning: { effort: reasoningEffort } }),
177
+ ...(tools?.length && { tools, tool_choice: "auto" }),
178
+ store: false,
179
+ };
180
+
181
+ const response = await fetch("https://api.x.ai/v1/responses", {
182
+ method: "POST",
183
+ headers: {
184
+ "Content-Type": "application/json",
185
+ Authorization: `Bearer ${apiKey}`,
186
+ },
187
+ body: JSON.stringify(body),
188
+ });
189
+
190
+ if (!response.ok) {
191
+ const errorText = await response.text();
192
+ throw new Error(`XAI Responses API error: ${response.status} ${errorText}`);
193
+ }
194
+
195
+ const data = await response.json();
196
+
197
+ // Map usage
198
+ const usage = data.usage
199
+ ? {
200
+ prompt_tokens: data.usage.input_tokens,
201
+ completion_tokens: data.usage.output_tokens,
202
+ total_tokens: data.usage.input_tokens + data.usage.output_tokens,
203
+ }
204
+ : undefined;
205
+
206
+ const usdCost = usage ? this.calculateCost(options.model, usage) : undefined;
207
+
208
+ // Collect text content and tool calls from output items
209
+ let textContent: string | null = null;
210
+ const toolCalls: any[] = [];
211
+
212
+ for (const item of data.output ?? []) {
213
+ if (item.type === "message") {
214
+ for (const part of item.content ?? []) {
215
+ if (part.type === "output_text") {
216
+ textContent = (textContent ?? "") + part.text;
217
+ }
218
+ }
219
+ } else if (item.type === "function_call") {
220
+ toolCalls.push({
221
+ id: item.call_id,
222
+ type: "function",
223
+ function: {
224
+ name: item.name,
225
+ arguments: item.arguments,
226
+ },
227
+ });
228
+ }
229
+ }
230
+
231
+ return {
232
+ choices: [
233
+ {
234
+ message: {
235
+ role: "assistant",
236
+ content: textContent,
237
+ ...(toolCalls.length > 0 && { tool_calls: toolCalls }),
238
+ },
239
+ },
240
+ ],
241
+ model: options.model,
242
+ usage,
243
+ usd_cost: usdCost,
244
+ };
245
+ }
246
+
97
247
  pricesPerMillion() {
98
248
  return XaiTextPricing;
99
249
  }
@@ -175,7 +325,7 @@ export class GenericXAIClient implements GenericClient {
175
325
  // Calculate cost based on model name
176
326
  const imageModel = options.model || "grok-imagine-image";
177
327
  const costPerImage =
178
- XaiImagePricing[imageModel as keyof typeof XaiImagePricing] || 0.02;
328
+ XaiImagePricing[imageModel as keyof typeof XaiImagePricing]?.image_generation || 0.02;
179
329
  const usdCost = (options.n || 1) * costPerImage;
180
330
 
181
331
  return {
@@ -250,7 +400,7 @@ export class GenericXAIClient implements GenericClient {
250
400
  // Return immediately with the jobId – do NOT poll here.
251
401
  // Use getVideoStatus() to poll and downloadVideo() to fetch the result.
252
402
  const duration = options.duration || 5;
253
- const pricePerSecond = XaiVideoPricing[model] || 0.07;
403
+ const pricePerSecond = XaiVideoPricing[model]?.video_generation || 0.07;
254
404
  const usdCost = duration * pricePerSecond;
255
405
 
256
406
  return {
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" }));