@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.
- package/CONFIG.md +8 -5
- package/package.json +3 -2
- package/scripts/check-model-pricing.ts +509 -0
- package/scripts/compare-openrouter-coverage.ts +576 -0
- package/src/agents/base/base.ts +127 -2
- package/src/agents/tools/execCommand.ts +4 -0
- package/src/agents/tools/executeScript/definition.ts +1 -1
- package/src/agents/tools/index.ts +0 -1
- package/src/agents/tools/list.ts +3 -43
- package/src/agents/tools/writeFile.ts +1 -1
- package/src/auth/browserLogin.ts +9 -4
- package/src/chat/modules/RemoteSyncModule.ts +3 -0
- package/src/cli.ts +31 -1
- package/src/clients/cerebras.ts +10 -0
- package/src/clients/contextLimits.ts +7 -2
- package/src/clients/copilot.ts +23 -0
- package/src/clients/deepseek.ts +16 -0
- package/src/clients/fireworks.ts +15 -0
- package/src/clients/gemini.ts +45 -2
- package/src/clients/github.ts +16 -0
- package/src/clients/groq.ts +15 -0
- package/src/clients/http.ts +190 -6
- package/src/clients/index.ts +215 -9
- package/src/clients/llama.ts +16 -0
- package/src/clients/mistral.ts +16 -0
- package/src/clients/nvidia.ts +16 -0
- package/src/clients/openai.ts +41 -11
- package/src/clients/openrouter.ts +17 -0
- package/src/clients/pricing/anthropic.ts +105 -78
- package/src/clients/pricing/cerebras.ts +11 -0
- package/src/clients/pricing/copilot.ts +60 -0
- package/src/clients/pricing/deepseek.ts +15 -0
- package/src/clients/pricing/fireworks.ts +32 -0
- package/src/clients/pricing/github.ts +69 -0
- package/src/clients/pricing/google.ts +245 -206
- package/src/clients/pricing/groq.ts +56 -0
- package/src/clients/pricing/index.ts +43 -6
- package/src/clients/pricing/llama.ts +18 -0
- package/src/clients/pricing/mistral.ts +34 -0
- package/src/clients/pricing/models.ts +23 -0
- package/src/clients/pricing/nvidia.ts +102 -0
- package/src/clients/pricing/openai.ts +347 -171
- package/src/clients/pricing/openrouter.ts +36 -0
- package/src/clients/pricing/types.ts +110 -0
- package/src/clients/pricing/xai.ts +123 -66
- package/src/clients/types.ts +4 -0
- package/src/clients/xai.ts +152 -2
- package/src/fileSync.ts +8 -2
- package/src/login.ts +11 -3
- package/src/services/AgentSyncFs.ts +36 -12
- package/src/services/KnowhowClient.ts +11 -0
- package/src/services/LazyToolsService.ts +6 -0
- package/src/services/S3.ts +0 -7
- package/src/services/SyncedAgentWatcher.ts +13 -298
- package/src/services/index.ts +1 -0
- package/src/services/modules/index.ts +11 -2
- package/src/services/watchers/FsSyncer.ts +155 -0
- package/src/services/watchers/RemoteSyncer.ts +153 -0
- package/src/services/watchers/index.ts +2 -0
- package/src/types.ts +56 -279
- package/src/worker.ts +174 -0
- package/tests/clients/pricing.test.ts +37 -0
- package/tests/manual/clients/completions.json +838 -226
- package/tests/manual/clients/completions.test.ts +46 -31
- package/ts_build/package.json +3 -2
- package/ts_build/src/agents/base/base.d.ts +17 -1
- package/ts_build/src/agents/base/base.js +82 -1
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/execCommand.js +3 -0
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
- package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
- package/ts_build/src/agents/tools/index.d.ts +0 -1
- package/ts_build/src/agents/tools/index.js +0 -1
- package/ts_build/src/agents/tools/index.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +3 -38
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
- package/ts_build/src/agents/tools/writeFile.js +1 -1
- package/ts_build/src/agents/tools/writeFile.js.map +1 -1
- package/ts_build/src/ai.d.ts +1 -1
- package/ts_build/src/auth/browserLogin.d.ts +2 -1
- package/ts_build/src/auth/browserLogin.js +10 -3
- package/ts_build/src/auth/browserLogin.js.map +1 -1
- package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
- package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
- package/ts_build/src/cli.js +19 -0
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.d.ts +1 -82
- package/ts_build/src/clients/cerebras.d.ts +4 -0
- package/ts_build/src/clients/cerebras.js +14 -0
- package/ts_build/src/clients/cerebras.js.map +1 -0
- package/ts_build/src/clients/contextLimits.js +7 -2
- package/ts_build/src/clients/contextLimits.js.map +1 -1
- package/ts_build/src/clients/copilot.d.ts +4 -0
- package/ts_build/src/clients/copilot.js +15 -0
- package/ts_build/src/clients/copilot.js.map +1 -0
- package/ts_build/src/clients/deepseek.d.ts +4 -0
- package/ts_build/src/clients/deepseek.js +15 -0
- package/ts_build/src/clients/deepseek.js.map +1 -0
- package/ts_build/src/clients/fireworks.d.ts +4 -0
- package/ts_build/src/clients/fireworks.js +15 -0
- package/ts_build/src/clients/fireworks.js.map +1 -0
- package/ts_build/src/clients/gemini.d.ts +1 -0
- package/ts_build/src/clients/gemini.js +28 -1
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/github.d.ts +4 -0
- package/ts_build/src/clients/github.js +15 -0
- package/ts_build/src/clients/github.js.map +1 -0
- package/ts_build/src/clients/groq.d.ts +4 -0
- package/ts_build/src/clients/groq.js +15 -0
- package/ts_build/src/clients/groq.js.map +1 -0
- package/ts_build/src/clients/http.d.ts +22 -1
- package/ts_build/src/clients/http.js +132 -7
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +22 -0
- package/ts_build/src/clients/index.js +150 -5
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/llama.d.ts +4 -0
- package/ts_build/src/clients/llama.js +15 -0
- package/ts_build/src/clients/llama.js.map +1 -0
- package/ts_build/src/clients/mistral.d.ts +4 -0
- package/ts_build/src/clients/mistral.js +15 -0
- package/ts_build/src/clients/mistral.js.map +1 -0
- package/ts_build/src/clients/nvidia.d.ts +4 -0
- package/ts_build/src/clients/nvidia.js +15 -0
- package/ts_build/src/clients/nvidia.js.map +1 -0
- package/ts_build/src/clients/openai.d.ts +4 -206
- package/ts_build/src/clients/openai.js +27 -9
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/openrouter.d.ts +4 -0
- package/ts_build/src/clients/openrouter.js +15 -0
- package/ts_build/src/clients/openrouter.js.map +1 -0
- package/ts_build/src/clients/pricing/anthropic.d.ts +26 -78
- package/ts_build/src/clients/pricing/anthropic.js +75 -78
- package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
- package/ts_build/src/clients/pricing/cerebras.d.ts +4 -0
- package/ts_build/src/clients/pricing/cerebras.js +11 -0
- package/ts_build/src/clients/pricing/cerebras.js.map +1 -0
- package/ts_build/src/clients/pricing/copilot.d.ts +5 -0
- package/ts_build/src/clients/pricing/copilot.js +35 -0
- package/ts_build/src/clients/pricing/copilot.js.map +1 -0
- package/ts_build/src/clients/pricing/deepseek.d.ts +5 -0
- package/ts_build/src/clients/pricing/deepseek.js +10 -0
- package/ts_build/src/clients/pricing/deepseek.js.map +1 -0
- package/ts_build/src/clients/pricing/fireworks.d.ts +5 -0
- package/ts_build/src/clients/pricing/fireworks.js +21 -0
- package/ts_build/src/clients/pricing/fireworks.js.map +1 -0
- package/ts_build/src/clients/pricing/github.d.ts +4 -0
- package/ts_build/src/clients/pricing/github.js +58 -0
- package/ts_build/src/clients/pricing/github.js.map +1 -0
- package/ts_build/src/clients/pricing/google.d.ts +59 -6
- package/ts_build/src/clients/pricing/google.js +214 -167
- package/ts_build/src/clients/pricing/google.js.map +1 -1
- package/ts_build/src/clients/pricing/groq.d.ts +5 -0
- package/ts_build/src/clients/pricing/groq.js +41 -0
- package/ts_build/src/clients/pricing/groq.js.map +1 -0
- package/ts_build/src/clients/pricing/index.d.ts +17 -6
- package/ts_build/src/clients/pricing/index.js +65 -10
- package/ts_build/src/clients/pricing/index.js.map +1 -1
- package/ts_build/src/clients/pricing/llama.d.ts +4 -0
- package/ts_build/src/clients/pricing/llama.js +14 -0
- package/ts_build/src/clients/pricing/llama.js.map +1 -0
- package/ts_build/src/clients/pricing/mistral.d.ts +5 -0
- package/ts_build/src/clients/pricing/mistral.js +23 -0
- package/ts_build/src/clients/pricing/mistral.js.map +1 -0
- package/ts_build/src/clients/pricing/models.d.ts +9 -0
- package/ts_build/src/clients/pricing/models.js +19 -0
- package/ts_build/src/clients/pricing/models.js.map +1 -0
- package/ts_build/src/clients/pricing/nvidia.d.ts +8 -0
- package/ts_build/src/clients/pricing/nvidia.js +96 -0
- package/ts_build/src/clients/pricing/nvidia.js.map +1 -0
- package/ts_build/src/clients/pricing/openai.d.ts +86 -197
- package/ts_build/src/clients/pricing/openai.js +294 -168
- package/ts_build/src/clients/pricing/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/openrouter.d.ts +4 -0
- package/ts_build/src/clients/pricing/openrouter.js +29 -0
- package/ts_build/src/clients/pricing/openrouter.js.map +1 -0
- package/ts_build/src/clients/pricing/types.d.ts +46 -0
- package/ts_build/src/clients/pricing/types.js +49 -0
- package/ts_build/src/clients/pricing/types.js.map +1 -0
- package/ts_build/src/clients/pricing/xai.d.ts +39 -64
- package/ts_build/src/clients/pricing/xai.js +93 -60
- package/ts_build/src/clients/pricing/xai.js.map +1 -1
- package/ts_build/src/clients/types.d.ts +1 -0
- package/ts_build/src/clients/xai.d.ts +2 -58
- package/ts_build/src/clients/xai.js +123 -2
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/fileSync.js +7 -2
- package/ts_build/src/fileSync.js.map +1 -1
- package/ts_build/src/login.js +8 -2
- package/ts_build/src/login.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.js +1 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +1 -0
- package/ts_build/src/services/KnowhowClient.js +7 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +1 -0
- package/ts_build/src/services/LazyToolsService.js +3 -0
- package/ts_build/src/services/LazyToolsService.js.map +1 -1
- package/ts_build/src/services/S3.js +0 -7
- package/ts_build/src/services/S3.js.map +1 -1
- package/ts_build/src/services/SyncedAgentWatcher.d.ts +0 -51
- package/ts_build/src/services/SyncedAgentWatcher.js +1 -282
- package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
- package/ts_build/src/services/index.d.ts +1 -0
- package/ts_build/src/services/index.js +1 -0
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.js +41 -1
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/services/watchers/FsSyncer.d.ts +27 -0
- package/ts_build/src/services/watchers/FsSyncer.js +135 -0
- package/ts_build/src/services/watchers/FsSyncer.js.map +1 -0
- package/ts_build/src/services/watchers/RemoteSyncer.d.ts +28 -0
- package/ts_build/src/services/watchers/RemoteSyncer.js +126 -0
- package/ts_build/src/services/watchers/RemoteSyncer.js.map +1 -0
- package/ts_build/src/services/watchers/index.d.ts +2 -0
- package/ts_build/src/services/watchers/index.js +19 -0
- package/ts_build/src/services/watchers/index.js.map +1 -0
- package/ts_build/src/types.d.ts +163 -124
- package/ts_build/src/types.js +33 -213
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/worker.d.ts +4 -0
- package/ts_build/src/worker.js +140 -0
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/clients/pricing.test.js +21 -0
- package/ts_build/tests/clients/pricing.test.js.map +1 -1
- package/ts_build/tests/manual/clients/completions.test.js +27 -24
- package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
- package/src/clients/pricing/catalog.ts +0 -287
- package/ts_build/src/clients/pricing/catalog.d.ts +0 -28
- package/ts_build/src/clients/pricing/catalog.js +0 -179
- 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
|
-
|
|
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
|
-
|
|
7
|
+
// ─── Model IDs ────────────────────────────────────────────────────────────────
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
70
|
-
|
|
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
|
+
];
|
package/src/clients/types.ts
CHANGED
|
@@ -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 {
|
package/src/clients/xai.ts
CHANGED
|
@@ -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
|
-
|
|
269
|
-
|
|
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
|
-
|
|
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" }));
|