@ebowwa/coder 0.7.64 → 0.7.66
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/dist/index.js +36233 -32
- package/dist/interfaces/ui/terminal/cli/index.js +34318 -158
- package/dist/interfaces/ui/terminal/native/README.md +53 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
- package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
- package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
- package/dist/interfaces/ui/terminal/native/index.js +43 -0
- package/dist/interfaces/ui/terminal/native/index.node +0 -0
- package/dist/interfaces/ui/terminal/native/package.json +34 -0
- package/dist/native/README.md +53 -0
- package/dist/native/claude_code_native.darwin-x64.node +0 -0
- package/dist/native/claude_code_native.dylib +0 -0
- package/dist/native/index.d.ts +0 -480
- package/dist/native/index.darwin-arm64.node +0 -0
- package/dist/native/index.js +43 -1625
- package/dist/native/index.node +0 -0
- package/dist/native/package.json +34 -0
- package/native/index.darwin-arm64.node +0 -0
- package/native/index.js +33 -19
- package/package.json +3 -2
- package/packages/src/core/agent-loop/__tests__/compaction.test.ts +17 -14
- package/packages/src/core/agent-loop/compaction.ts +6 -2
- package/packages/src/core/agent-loop/index.ts +2 -0
- package/packages/src/core/agent-loop/loop-state.ts +1 -1
- package/packages/src/core/agent-loop/turn-executor.ts +4 -0
- package/packages/src/core/agent-loop/types.ts +4 -0
- package/packages/src/core/api-client-impl.ts +377 -176
- package/packages/src/core/cognitive-security/hooks.ts +2 -1
- package/packages/src/core/config/todo +7 -0
- package/packages/src/core/context/__tests__/integration.test.ts +334 -0
- package/packages/src/core/context/compaction.ts +170 -0
- package/packages/src/core/context/constants.ts +58 -0
- package/packages/src/core/context/extraction.ts +85 -0
- package/packages/src/core/context/index.ts +66 -0
- package/packages/src/core/context/summarization.ts +251 -0
- package/packages/src/core/context/token-estimation.ts +98 -0
- package/packages/src/core/context/types.ts +59 -0
- package/packages/src/core/models.ts +81 -4
- package/packages/src/core/normalizers/todo +5 -1
- package/packages/src/core/providers/README.md +230 -0
- package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
- package/packages/src/core/providers/index.ts +419 -0
- package/packages/src/core/providers/types.ts +132 -0
- package/packages/src/core/retry.ts +10 -0
- package/packages/src/ecosystem/tools/index.ts +174 -0
- package/packages/src/index.ts +23 -2
- package/packages/src/interfaces/ui/index.ts +17 -20
- package/packages/src/interfaces/ui/spinner.ts +2 -2
- package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
- package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
- package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
- package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
- package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
- package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
- package/packages/src/interfaces/ui/terminal/cli/index.ts +200 -13
- package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +402 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
- package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
- package/packages/src/interfaces/ui/terminal/shared/index.ts +13 -0
- package/packages/src/interfaces/ui/terminal/shared/query.ts +9 -3
- package/packages/src/interfaces/ui/terminal/shared/setup.ts +5 -1
- package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
- package/packages/src/interfaces/ui/terminal/shared/status-line.ts +10 -2
- package/packages/src/native/index.ts +404 -27
- package/packages/src/native/tui_v2_types.ts +39 -0
- package/packages/src/teammates/coordination.test.ts +279 -0
- package/packages/src/teammates/coordination.ts +646 -0
- package/packages/src/teammates/index.ts +95 -25
- package/packages/src/teammates/integration.test.ts +272 -0
- package/packages/src/teammates/runner.test.ts +235 -0
- package/packages/src/teammates/runner.ts +750 -0
- package/packages/src/teammates/schemas.ts +673 -0
- package/packages/src/types/index.ts +1 -0
- package/packages/src/core/context-compaction.ts +0 -578
- package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
- package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
- package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +0 -262
- package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +0 -232
- package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +0 -62
- package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +0 -537
- package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +0 -107
- package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +0 -240
- package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +0 -54
- package/packages/src/interfaces/ui/terminal/tui/commands.ts +0 -438
- package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +0 -584
- package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +0 -614
- package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +0 -333
- package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +0 -604
- package/packages/src/interfaces/ui/terminal/tui/components/index.ts +0 -118
- package/packages/src/interfaces/ui/terminal/tui/console.ts +0 -49
- package/packages/src/interfaces/ui/terminal/tui/index.ts +0 -90
- package/packages/src/interfaces/ui/terminal/tui/run.tsx +0 -42
- package/packages/src/interfaces/ui/terminal/tui/spinner.ts +0 -69
- package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +0 -390
- package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +0 -422
- package/packages/src/interfaces/ui/terminal/tui/types.ts +0 -186
- package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +0 -104
- package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +0 -239
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Provider System
|
|
2
|
+
|
|
3
|
+
Multi-provider architecture for Coder CLI supporting multiple LLM backends.
|
|
4
|
+
|
|
5
|
+
## Supported Providers
|
|
6
|
+
|
|
7
|
+
| Provider | Models | Format | Endpoint |
|
|
8
|
+
|----------|--------|--------|----------|
|
|
9
|
+
| **Zhipu (Z.AI)** | GLM-5, GLM-4.7, GLM-4.6, GLM-4.5V, GLM-4.5, GLM-4.5-air | OpenAI | `https://api.z.ai/api/coding/paas/v4` |
|
|
10
|
+
| **MiniMax** | MiniMax-M2.5 | Anthropic | `https://api.minimax.io/anthropic` |
|
|
11
|
+
| **OpenAI** | GPT-4, GPT-4-turbo | OpenAI | `https://api.openai.com/v1` |
|
|
12
|
+
| **Anthropic** | Claude Opus 4.6, Sonnet 4.6 | Anthropic | *Not implemented (stub)* |
|
|
13
|
+
|
|
14
|
+
## Z.AI Endpoints
|
|
15
|
+
|
|
16
|
+
Z.AI provides **two different endpoints**:
|
|
17
|
+
|
|
18
|
+
| Endpoint | Format | Auth | Use Case |
|
|
19
|
+
|----------|--------|------|----------|
|
|
20
|
+
| `https://api.z.ai/api/coding/paas/v4` | OpenAI | `Z_AI_API_KEY` | **Coding plan** (default) |
|
|
21
|
+
| `https://api.z.ai/api/anthropic` | Anthropic | `ANTHROPIC_AUTH_TOKEN` | Anthropic-compatible |
|
|
22
|
+
|
|
23
|
+
Our implementation uses the **coding plan endpoint** with shared quotas.
|
|
24
|
+
|
|
25
|
+
### GLM Models (Coding Plan - Shared Quota)
|
|
26
|
+
|
|
27
|
+
| Model | Context | Max Output | Vision | Thinking | Quota |
|
|
28
|
+
|-------|---------|------------|--------|----------|-------|
|
|
29
|
+
| **GLM-5** | 200K | 128K | Yes | Yes | 3x peak, 2x off-peak |
|
|
30
|
+
| **GLM-4.7** | 128K | 8K | Yes | Yes | 1x |
|
|
31
|
+
| **GLM-4.6** | 128K | 8K | Yes | Yes | 1x |
|
|
32
|
+
| **GLM-4.5V** | 128K | 4K | Yes | No | 1x |
|
|
33
|
+
| **GLM-4.5** | 128K | 4K | No | No | 1x |
|
|
34
|
+
| **GLM-4.5-Air** | 128K | 4K | No | No | 1x (fast/cheap) |
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
### Environment Variables
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Z.AI / GLM (Coding Plan)
|
|
42
|
+
Z_AI_API_KEY=xxx # Single key
|
|
43
|
+
Z_AI_API_KEYS='["key1","key2"]' # Rolling keys (JSON array)
|
|
44
|
+
ZHIPU_BASE_URL=https://api.z.ai/api/coding/paas/v4 # Optional override
|
|
45
|
+
|
|
46
|
+
# MiniMax
|
|
47
|
+
MINIMAX_API_KEY=xxx
|
|
48
|
+
MINIMAX_BASE_URL=https://api.minimax.io/anthropic # Optional: use minimaxi.com for China
|
|
49
|
+
|
|
50
|
+
# OpenAI (Future)
|
|
51
|
+
OPENAI_API_KEY=xxx
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Doppler Configuration
|
|
55
|
+
|
|
56
|
+
Add keys to your Doppler project:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
doppler secrets set Z_AI_API_KEY=xxx
|
|
60
|
+
doppler secrets set Z_AI_API_KEYS='["key1","key2"]' # For rolling keys
|
|
61
|
+
doppler secrets set MINIMAX_API_KEY=xxx
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
### Model Selection
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Use GLM-5 (Zhipu)
|
|
70
|
+
coder --model glm-5
|
|
71
|
+
|
|
72
|
+
# Use MiniMax M2.5
|
|
73
|
+
coder --model minimax-m2.5
|
|
74
|
+
|
|
75
|
+
# Use GLM-4.5-air (fast/cheap)
|
|
76
|
+
coder --model glm-4.5-air
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Model Aliases
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// In code
|
|
83
|
+
import { MODEL_ALIASES } from "@ebowwa/coder";
|
|
84
|
+
|
|
85
|
+
MODEL_ALIASES.glm // → "glm-5"
|
|
86
|
+
MODEL_ALIASES.glm4 // → "glm-4.5-air"
|
|
87
|
+
MODEL_ALIASES.minimax // → "minimax-m2.5"
|
|
88
|
+
MODEL_ALIASES.m25 // → "minimax-m2.5"
|
|
89
|
+
MODEL_ALIASES.fast // → "glm-4.5-air"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Provider Resolution
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { resolveProvider, getProviderForModel } from "@ebowwa/coder";
|
|
96
|
+
|
|
97
|
+
// Detect provider from model name
|
|
98
|
+
const provider = getProviderForModel("glm-5"); // → "zhipu"
|
|
99
|
+
|
|
100
|
+
// Resolve full provider info
|
|
101
|
+
const resolved = resolveProvider("glm-5");
|
|
102
|
+
// {
|
|
103
|
+
// config: ProviderConfig,
|
|
104
|
+
// apiKey: string,
|
|
105
|
+
// endpoint: string,
|
|
106
|
+
// model: string
|
|
107
|
+
// }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Health Tracking
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import {
|
|
114
|
+
isProviderHealthy,
|
|
115
|
+
getHealthyProviders,
|
|
116
|
+
recordProviderSuccess,
|
|
117
|
+
recordProviderFailure,
|
|
118
|
+
} from "@ebowwa/coder";
|
|
119
|
+
|
|
120
|
+
// Check if provider is healthy
|
|
121
|
+
if (isProviderHealthy("zhipu")) {
|
|
122
|
+
// Use zhipu
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Get all healthy providers
|
|
126
|
+
const healthy = getHealthyProviders(); // ["zhipu", "minimax"]
|
|
127
|
+
|
|
128
|
+
// Track success (auto-called by API client)
|
|
129
|
+
recordProviderSuccess("zhipu", 1500); // 1.5s latency
|
|
130
|
+
|
|
131
|
+
// Track failure (auto-called on retry)
|
|
132
|
+
recordProviderFailure("zhipu");
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Architecture
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
┌─────────────────────────────────────────────────────┐
|
|
139
|
+
│ Model Request │
|
|
140
|
+
│ (model: "glm-5") │
|
|
141
|
+
└─────────────────────────────────────────────────────┘
|
|
142
|
+
│
|
|
143
|
+
▼
|
|
144
|
+
┌─────────────────────────┐
|
|
145
|
+
│ resolveProvider() │
|
|
146
|
+
│ - Detect from name │
|
|
147
|
+
│ - Load API key │
|
|
148
|
+
│ - Build endpoint │
|
|
149
|
+
└─────────────────────────┘
|
|
150
|
+
│
|
|
151
|
+
┌───────────┴───────────┐
|
|
152
|
+
│ │
|
|
153
|
+
▼ ▼
|
|
154
|
+
┌───────────────┐ ┌───────────────┐
|
|
155
|
+
│ Zhipu (Z.AI) │ │ MiniMax │
|
|
156
|
+
│ OpenAI format │ │ Anthropic fmt │
|
|
157
|
+
│ /chat/ │ │ /v1/messages │
|
|
158
|
+
│ completions │ │ │
|
|
159
|
+
└───────────────┘ └───────────────┘
|
|
160
|
+
│ │
|
|
161
|
+
└───────────┬───────────┘
|
|
162
|
+
▼
|
|
163
|
+
┌─────────────────────────┐
|
|
164
|
+
│ Health Tracking │
|
|
165
|
+
│ - Latency metrics │
|
|
166
|
+
│ - Failure backoff │
|
|
167
|
+
│ - Rolling key rotation │
|
|
168
|
+
└─────────────────────────┘
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Rolling Keys
|
|
172
|
+
|
|
173
|
+
The provider system supports multiple API keys with round-robin rotation:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Set multiple keys as JSON array
|
|
177
|
+
Z_AI_API_KEYS='["key1","key2","key3"]'
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Features:
|
|
181
|
+
- **Round-robin rotation** - Cycles through keys on each request
|
|
182
|
+
- **Exponential backoff** - Keys that fail are temporarily disabled
|
|
183
|
+
- **Health tracking** - Keys are tracked per-provider
|
|
184
|
+
|
|
185
|
+
## Fallback Chain
|
|
186
|
+
|
|
187
|
+
Default fallback order:
|
|
188
|
+
1. `zhipu` (Z.AI / GLM)
|
|
189
|
+
2. `minimax` (MiniMax)
|
|
190
|
+
|
|
191
|
+
Configure via environment:
|
|
192
|
+
```bash
|
|
193
|
+
MODEL_FALLBACK_CHAIN='["zhipu","minimax","openai"]'
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Adding New Providers
|
|
197
|
+
|
|
198
|
+
1. Add provider config to `providers/index.ts`:
|
|
199
|
+
```typescript
|
|
200
|
+
PROVIDERS.newprovider = {
|
|
201
|
+
name: "newprovider",
|
|
202
|
+
displayName: "New Provider",
|
|
203
|
+
endpoint: "https://api.newprovider.com/v1",
|
|
204
|
+
authHeader: "Authorization",
|
|
205
|
+
apiKeyEnv: ["NEWPROVIDER_API_KEY"],
|
|
206
|
+
format: "openai", // or "anthropic"
|
|
207
|
+
defaultModel: "newprovider-1",
|
|
208
|
+
models: ["newprovider-1", "newprovider-2"],
|
|
209
|
+
supportsStreaming: true,
|
|
210
|
+
supportsToolCalling: true,
|
|
211
|
+
supportsVision: true,
|
|
212
|
+
supportsThinking: false,
|
|
213
|
+
};
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
2. Add model to `models.ts`:
|
|
217
|
+
```typescript
|
|
218
|
+
"newprovider-1": {
|
|
219
|
+
id: "newprovider-1",
|
|
220
|
+
name: "NP-1",
|
|
221
|
+
fullName: "NewProvider 1",
|
|
222
|
+
provider: "newprovider",
|
|
223
|
+
// ...
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
3. Add to fallback chain (optional):
|
|
228
|
+
```typescript
|
|
229
|
+
DEFAULT_ROUTING_CONFIG.fallbackChain.push("newprovider");
|
|
230
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
getProvider,
|
|
4
|
+
getProviderForModel,
|
|
5
|
+
resolveProvider,
|
|
6
|
+
isProviderHealthy,
|
|
7
|
+
getHealthyProviders,
|
|
8
|
+
getNextHealthyProvider,
|
|
9
|
+
PROVIDERS,
|
|
10
|
+
type ProviderName,
|
|
11
|
+
} from "../index.js";
|
|
12
|
+
|
|
13
|
+
describe("Provider Registry", () => {
|
|
14
|
+
describe("getProvider", () => {
|
|
15
|
+
test("returns zhipu provider config", () => {
|
|
16
|
+
const provider = getProvider("zhipu");
|
|
17
|
+
expect(provider).toBeDefined();
|
|
18
|
+
expect(provider?.name).toBe("zhipu");
|
|
19
|
+
expect(provider?.displayName).toBe("Z.AI (GLM)");
|
|
20
|
+
expect(provider?.format).toBe("openai");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("returns minimax provider config", () => {
|
|
24
|
+
const provider = getProvider("minimax");
|
|
25
|
+
expect(provider).toBeDefined();
|
|
26
|
+
expect(provider?.name).toBe("minimax");
|
|
27
|
+
expect(provider?.displayName).toBe("MiniMax");
|
|
28
|
+
expect(provider?.format).toBe("anthropic");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("returns undefined for unknown provider", () => {
|
|
32
|
+
const provider = getProvider("unknown" as any);
|
|
33
|
+
expect(provider).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("getProviderForModel", () => {
|
|
38
|
+
test("detects zhipu from glm-5", () => {
|
|
39
|
+
expect(getProviderForModel("glm-5")).toBe("zhipu");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("detects zhipu from GLM-4.7 (case insensitive)", () => {
|
|
43
|
+
expect(getProviderForModel("GLM-4.7")).toBe("zhipu");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("detects minimax from minimax-m2.5", () => {
|
|
47
|
+
expect(getProviderForModel("minimax-m2.5")).toBe("minimax");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("detects minimax from MiniMax-M2.5 (case insensitive)", () => {
|
|
51
|
+
expect(getProviderForModel("MiniMax-M2.5")).toBe("minimax");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("defaults to zhipu for unknown models", () => {
|
|
55
|
+
expect(getProviderForModel("unknown-model")).toBe("zhipu");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("isProviderHealthy", () => {
|
|
60
|
+
test("zhipu starts healthy", () => {
|
|
61
|
+
expect(isProviderHealthy("zhipu")).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("minimax starts healthy", () => {
|
|
65
|
+
expect(isProviderHealthy("minimax")).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("anthropic is marked unhealthy (not implemented)", () => {
|
|
69
|
+
expect(isProviderHealthy("anthropic")).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("getHealthyProviders", () => {
|
|
74
|
+
test("returns list of healthy providers", () => {
|
|
75
|
+
const healthy = getHealthyProviders();
|
|
76
|
+
expect(healthy).toContain("zhipu");
|
|
77
|
+
expect(healthy).toContain("minimax");
|
|
78
|
+
expect(healthy).not.toContain("anthropic");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("getNextHealthyProvider", () => {
|
|
83
|
+
test("returns first healthy provider from fallback chain", () => {
|
|
84
|
+
const provider = getNextHealthyProvider();
|
|
85
|
+
expect(provider).toBe("zhipu");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("can exclude provider", () => {
|
|
89
|
+
const provider = getNextHealthyProvider("zhipu");
|
|
90
|
+
expect(provider).toBe("minimax");
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("resolveProvider", () => {
|
|
95
|
+
test("returns null when no API key configured", () => {
|
|
96
|
+
// Clear env for this test
|
|
97
|
+
const originalKey = process.env.Z_AI_API_KEY;
|
|
98
|
+
delete process.env.Z_AI_API_KEY;
|
|
99
|
+
|
|
100
|
+
const result = resolveProvider("glm-5");
|
|
101
|
+
// May return null or use fallback
|
|
102
|
+
// This depends on whether keys are loaded
|
|
103
|
+
|
|
104
|
+
// Restore
|
|
105
|
+
if (originalKey) {
|
|
106
|
+
process.env.Z_AI_API_KEY = originalKey;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("Provider Configuration", () => {
|
|
113
|
+
test("zhipu uses OpenAI format", () => {
|
|
114
|
+
expect(PROVIDERS.zhipu.format).toBe("openai");
|
|
115
|
+
expect(PROVIDERS.zhipu.endpoint).toContain("z.ai");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("minimax uses Anthropic format", () => {
|
|
119
|
+
expect(PROVIDERS.minimax.format).toBe("anthropic");
|
|
120
|
+
expect(PROVIDERS.minimax.endpoint).toContain("minimax");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("providers have required fields", () => {
|
|
124
|
+
for (const name of Object.keys(PROVIDERS) as ProviderName[]) {
|
|
125
|
+
const config = PROVIDERS[name];
|
|
126
|
+
expect(config.name).toBe(name);
|
|
127
|
+
expect(config.displayName).toBeTruthy();
|
|
128
|
+
expect(config.endpoint).toBeTruthy();
|
|
129
|
+
expect(config.apiKeyEnv).toBeInstanceOf(Array);
|
|
130
|
+
expect(config.apiKeyEnv.length).toBeGreaterThan(0);
|
|
131
|
+
expect(config.defaultModel).toBeTruthy();
|
|
132
|
+
expect(config.models).toBeInstanceOf(Array);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|