@tyvm/knowhow 0.0.105 → 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 (209) 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 +116 -4
  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 +42 -5
  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 +7 -236
  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 +83 -2
  45. package/src/clients/pricing/xai.ts +121 -65
  46. package/src/clients/types.ts +4 -0
  47. package/src/clients/xai.ts +150 -0
  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/modules/index.ts +11 -2
  55. package/src/types.ts +56 -279
  56. package/src/worker.ts +174 -0
  57. package/tests/clients/pricing.test.ts +37 -0
  58. package/tests/manual/clients/completions.json +838 -226
  59. package/tests/manual/clients/completions.test.ts +46 -31
  60. package/ts_build/package.json +3 -2
  61. package/ts_build/src/agents/base/base.d.ts +17 -1
  62. package/ts_build/src/agents/base/base.js +82 -1
  63. package/ts_build/src/agents/base/base.js.map +1 -1
  64. package/ts_build/src/agents/tools/execCommand.js +3 -0
  65. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  66. package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
  67. package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
  68. package/ts_build/src/agents/tools/index.d.ts +0 -1
  69. package/ts_build/src/agents/tools/index.js +0 -1
  70. package/ts_build/src/agents/tools/index.js.map +1 -1
  71. package/ts_build/src/agents/tools/list.js +3 -38
  72. package/ts_build/src/agents/tools/list.js.map +1 -1
  73. package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
  74. package/ts_build/src/agents/tools/writeFile.js +1 -1
  75. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  76. package/ts_build/src/ai.d.ts +1 -1
  77. package/ts_build/src/auth/browserLogin.d.ts +2 -1
  78. package/ts_build/src/auth/browserLogin.js +10 -3
  79. package/ts_build/src/auth/browserLogin.js.map +1 -1
  80. package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
  81. package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
  82. package/ts_build/src/cli.js +19 -0
  83. package/ts_build/src/cli.js.map +1 -1
  84. package/ts_build/src/clients/anthropic.d.ts +1 -82
  85. package/ts_build/src/clients/cerebras.d.ts +4 -0
  86. package/ts_build/src/clients/cerebras.js +14 -0
  87. package/ts_build/src/clients/cerebras.js.map +1 -0
  88. package/ts_build/src/clients/contextLimits.js +7 -2
  89. package/ts_build/src/clients/contextLimits.js.map +1 -1
  90. package/ts_build/src/clients/copilot.d.ts +4 -0
  91. package/ts_build/src/clients/copilot.js +15 -0
  92. package/ts_build/src/clients/copilot.js.map +1 -0
  93. package/ts_build/src/clients/deepseek.d.ts +4 -0
  94. package/ts_build/src/clients/deepseek.js +15 -0
  95. package/ts_build/src/clients/deepseek.js.map +1 -0
  96. package/ts_build/src/clients/fireworks.d.ts +4 -0
  97. package/ts_build/src/clients/fireworks.js +15 -0
  98. package/ts_build/src/clients/fireworks.js.map +1 -0
  99. package/ts_build/src/clients/gemini.d.ts +1 -0
  100. package/ts_build/src/clients/gemini.js +28 -1
  101. package/ts_build/src/clients/gemini.js.map +1 -1
  102. package/ts_build/src/clients/github.d.ts +4 -0
  103. package/ts_build/src/clients/github.js +15 -0
  104. package/ts_build/src/clients/github.js.map +1 -0
  105. package/ts_build/src/clients/groq.d.ts +4 -0
  106. package/ts_build/src/clients/groq.js +15 -0
  107. package/ts_build/src/clients/groq.js.map +1 -0
  108. package/ts_build/src/clients/http.d.ts +22 -1
  109. package/ts_build/src/clients/http.js +132 -7
  110. package/ts_build/src/clients/http.js.map +1 -1
  111. package/ts_build/src/clients/index.d.ts +14 -0
  112. package/ts_build/src/clients/index.js +94 -4
  113. package/ts_build/src/clients/index.js.map +1 -1
  114. package/ts_build/src/clients/llama.d.ts +4 -0
  115. package/ts_build/src/clients/llama.js +15 -0
  116. package/ts_build/src/clients/llama.js.map +1 -0
  117. package/ts_build/src/clients/mistral.d.ts +4 -0
  118. package/ts_build/src/clients/mistral.js +15 -0
  119. package/ts_build/src/clients/mistral.js.map +1 -0
  120. package/ts_build/src/clients/nvidia.d.ts +4 -0
  121. package/ts_build/src/clients/nvidia.js +15 -0
  122. package/ts_build/src/clients/nvidia.js.map +1 -0
  123. package/ts_build/src/clients/openai.d.ts +4 -206
  124. package/ts_build/src/clients/openai.js +27 -9
  125. package/ts_build/src/clients/openai.js.map +1 -1
  126. package/ts_build/src/clients/openrouter.d.ts +4 -0
  127. package/ts_build/src/clients/openrouter.js +15 -0
  128. package/ts_build/src/clients/openrouter.js.map +1 -0
  129. package/ts_build/src/clients/pricing/anthropic.d.ts +26 -78
  130. package/ts_build/src/clients/pricing/anthropic.js +75 -78
  131. package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
  132. package/ts_build/src/clients/pricing/cerebras.d.ts +4 -0
  133. package/ts_build/src/clients/pricing/cerebras.js +11 -0
  134. package/ts_build/src/clients/pricing/cerebras.js.map +1 -0
  135. package/ts_build/src/clients/pricing/copilot.d.ts +5 -0
  136. package/ts_build/src/clients/pricing/copilot.js +35 -0
  137. package/ts_build/src/clients/pricing/copilot.js.map +1 -0
  138. package/ts_build/src/clients/pricing/deepseek.d.ts +5 -0
  139. package/ts_build/src/clients/pricing/deepseek.js +10 -0
  140. package/ts_build/src/clients/pricing/deepseek.js.map +1 -0
  141. package/ts_build/src/clients/pricing/fireworks.d.ts +5 -0
  142. package/ts_build/src/clients/pricing/fireworks.js +21 -0
  143. package/ts_build/src/clients/pricing/fireworks.js.map +1 -0
  144. package/ts_build/src/clients/pricing/github.d.ts +4 -0
  145. package/ts_build/src/clients/pricing/github.js +58 -0
  146. package/ts_build/src/clients/pricing/github.js.map +1 -0
  147. package/ts_build/src/clients/pricing/google.d.ts +59 -6
  148. package/ts_build/src/clients/pricing/google.js +214 -167
  149. package/ts_build/src/clients/pricing/google.js.map +1 -1
  150. package/ts_build/src/clients/pricing/groq.d.ts +5 -0
  151. package/ts_build/src/clients/pricing/groq.js +41 -0
  152. package/ts_build/src/clients/pricing/groq.js.map +1 -0
  153. package/ts_build/src/clients/pricing/index.d.ts +16 -5
  154. package/ts_build/src/clients/pricing/index.js +62 -7
  155. package/ts_build/src/clients/pricing/index.js.map +1 -1
  156. package/ts_build/src/clients/pricing/llama.d.ts +4 -0
  157. package/ts_build/src/clients/pricing/llama.js +14 -0
  158. package/ts_build/src/clients/pricing/llama.js.map +1 -0
  159. package/ts_build/src/clients/pricing/mistral.d.ts +5 -0
  160. package/ts_build/src/clients/pricing/mistral.js +23 -0
  161. package/ts_build/src/clients/pricing/mistral.js.map +1 -0
  162. package/ts_build/src/clients/pricing/models.d.ts +5 -4
  163. package/ts_build/src/clients/pricing/models.js +8 -162
  164. package/ts_build/src/clients/pricing/models.js.map +1 -1
  165. package/ts_build/src/clients/pricing/nvidia.d.ts +8 -0
  166. package/ts_build/src/clients/pricing/nvidia.js +96 -0
  167. package/ts_build/src/clients/pricing/nvidia.js.map +1 -0
  168. package/ts_build/src/clients/pricing/openai.d.ts +86 -197
  169. package/ts_build/src/clients/pricing/openai.js +294 -168
  170. package/ts_build/src/clients/pricing/openai.js.map +1 -1
  171. package/ts_build/src/clients/pricing/openrouter.d.ts +4 -0
  172. package/ts_build/src/clients/pricing/openrouter.js +29 -0
  173. package/ts_build/src/clients/pricing/openrouter.js.map +1 -0
  174. package/ts_build/src/clients/pricing/types.d.ts +27 -2
  175. package/ts_build/src/clients/pricing/types.js +46 -0
  176. package/ts_build/src/clients/pricing/types.js.map +1 -1
  177. package/ts_build/src/clients/pricing/xai.d.ts +37 -57
  178. package/ts_build/src/clients/pricing/xai.js +92 -59
  179. package/ts_build/src/clients/pricing/xai.js.map +1 -1
  180. package/ts_build/src/clients/types.d.ts +1 -0
  181. package/ts_build/src/clients/xai.d.ts +2 -62
  182. package/ts_build/src/clients/xai.js +121 -0
  183. package/ts_build/src/clients/xai.js.map +1 -1
  184. package/ts_build/src/fileSync.js +7 -2
  185. package/ts_build/src/fileSync.js.map +1 -1
  186. package/ts_build/src/login.js +8 -2
  187. package/ts_build/src/login.js.map +1 -1
  188. package/ts_build/src/services/AgentSyncFs.js +1 -0
  189. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  190. package/ts_build/src/services/KnowhowClient.d.ts +1 -0
  191. package/ts_build/src/services/KnowhowClient.js +7 -0
  192. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  193. package/ts_build/src/services/LazyToolsService.d.ts +1 -0
  194. package/ts_build/src/services/LazyToolsService.js +3 -0
  195. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  196. package/ts_build/src/services/S3.js +0 -7
  197. package/ts_build/src/services/S3.js.map +1 -1
  198. package/ts_build/src/services/modules/index.js +41 -1
  199. package/ts_build/src/services/modules/index.js.map +1 -1
  200. package/ts_build/src/types.d.ts +163 -124
  201. package/ts_build/src/types.js +33 -213
  202. package/ts_build/src/types.js.map +1 -1
  203. package/ts_build/src/worker.d.ts +4 -0
  204. package/ts_build/src/worker.js +140 -0
  205. package/ts_build/src/worker.js.map +1 -1
  206. package/ts_build/tests/clients/pricing.test.js +21 -0
  207. package/ts_build/tests/clients/pricing.test.js.map +1 -1
  208. package/ts_build/tests/manual/clients/completions.test.js +27 -24
  209. 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,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
  }
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" }));
@@ -121,7 +121,11 @@ export class AgentSyncFs {
121
121
  /**
122
122
  * Update metadata file with current agent state
123
123
  */
124
- private async updateMetadata(agent: BaseAgent, inProgress: boolean, result?: string): Promise<void> {
124
+ private async updateMetadata(
125
+ agent: BaseAgent,
126
+ inProgress: boolean,
127
+ result?: string
128
+ ): Promise<void> {
125
129
  if (!this.taskPath) return;
126
130
 
127
131
  try {
@@ -137,7 +141,8 @@ export class AgentSyncFs {
137
141
 
138
142
  metadata.threads = agent.getThreads();
139
143
  metadata.totalCostUsd = agent.getTotalCostUsd();
140
- metadata.agentName = agent.name;
144
+ metadata.tokenUsage = agent.getTokenUsage();
145
+ metadata.agentName = agent.name;
141
146
  metadata.inProgress = inProgress;
142
147
  metadata.lastUpdate = new Date().toISOString();
143
148
 
@@ -147,7 +152,11 @@ export class AgentSyncFs {
147
152
  await this.writeStatus("completed");
148
153
  }
149
154
 
150
- await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2), "utf8");
155
+ await fs.writeFile(
156
+ metadataPath,
157
+ JSON.stringify(metadata, null, 2),
158
+ "utf8"
159
+ );
151
160
  } catch (error) {
152
161
  console.error(`❌ Failed to update metadata:`, error);
153
162
  }
@@ -206,7 +215,9 @@ export class AgentSyncFs {
206
215
  // Check for new input/messages
207
216
  const input = await this.readInput();
208
217
  if (input && input !== this.lastInputContent && input.trim() !== "") {
209
- console.log(`📬 New message received via filesystem for task ${this.taskId}`);
218
+ console.log(
219
+ `📬 New message received via filesystem for task ${this.taskId}`
220
+ );
210
221
  this.lastInputContent = input;
211
222
 
212
223
  agent.addPendingUserMessage({
@@ -234,7 +245,7 @@ export class AgentSyncFs {
234
245
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
235
246
 
236
247
  const status = await this.readStatus();
237
-
248
+
238
249
  if (status === "killed") {
239
250
  console.log(`🛑 Agent task ${this.taskId} killed while paused`);
240
251
  await agent.kill();
@@ -314,7 +325,10 @@ export class AgentSyncFs {
314
325
  console.error(`❌ Error during threadUpdate sync:`, error);
315
326
  }
316
327
  };
317
- agent.agentEvents.on(agent.eventTypes.threadUpdate, this.threadUpdateHandler);
328
+ agent.agentEvents.on(
329
+ agent.eventTypes.threadUpdate,
330
+ this.threadUpdateHandler
331
+ );
318
332
 
319
333
  // Listen to completion event to finalize task (store reference for cleanup)
320
334
  this.doneHandler = (result: string) => {
@@ -323,7 +337,9 @@ export class AgentSyncFs {
323
337
  return;
324
338
  }
325
339
 
326
- console.log(`🎯 [AgentSyncFs] Done event received for task: ${this.taskId}`);
340
+ console.log(
341
+ `🎯 [AgentSyncFs] Done event received for task: ${this.taskId}`
342
+ );
327
343
 
328
344
  // Store finalization promise so callers can await it (same pattern as AgentSyncKnowhowWeb)
329
345
  this.finalizationPromise = (async () => {
@@ -332,7 +348,9 @@ export class AgentSyncFs {
332
348
  // This prevents the race where a pending "inProgress: true" metadata write
333
349
  // overwrites the finalization write.
334
350
  if (this.pendingThreadUpdatePromise) {
335
- console.log(`⏳ [AgentSyncFs] Awaiting pending thread update before finalizing...`);
351
+ console.log(
352
+ `⏳ [AgentSyncFs] Awaiting pending thread update before finalizing...`
353
+ );
336
354
  await this.pendingThreadUpdatePromise.catch(() => {
337
355
  // Ignore errors in pending update — we still want to finalize
338
356
  });
@@ -379,7 +397,7 @@ export class AgentSyncFs {
379
397
  private static async cleanupOldTasks(): Promise<void> {
380
398
  try {
381
399
  const agentsPath = AgentSyncFs.sharedBasePath;
382
-
400
+
383
401
  // Check if directory exists
384
402
  try {
385
403
  await fs.access(agentsPath);
@@ -396,7 +414,7 @@ export class AgentSyncFs {
396
414
  if (!entry.isDirectory()) continue;
397
415
 
398
416
  const taskPath = path.join(agentsPath, entry.name);
399
-
417
+
400
418
  try {
401
419
  const stats = await fs.stat(taskPath);
402
420
  const age = now - stats.mtimeMs;
@@ -449,11 +467,17 @@ export class AgentSyncFs {
449
467
  // Remove old event listeners from the agent before resetting
450
468
  if (this.agent) {
451
469
  if (this.threadUpdateHandler) {
452
- this.agent.agentEvents.removeListener(this.agent.eventTypes.threadUpdate, this.threadUpdateHandler);
470
+ this.agent.agentEvents.removeListener(
471
+ this.agent.eventTypes.threadUpdate,
472
+ this.threadUpdateHandler
473
+ );
453
474
  this.threadUpdateHandler = undefined;
454
475
  }
455
476
  if (this.doneHandler) {
456
- this.agent.agentEvents.removeListener(this.agent.eventTypes.done, this.doneHandler);
477
+ this.agent.agentEvents.removeListener(
478
+ this.agent.eventTypes.done,
479
+ this.doneHandler
480
+ );
457
481
  this.doneHandler = undefined;
458
482
  }
459
483
  this.agent = undefined;