@aria_asi/cli 0.2.5 → 0.2.6

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/bin/aria.js CHANGED
@@ -147,14 +147,14 @@ if (command === 'check-update') {
147
147
  process.exit(1);
148
148
  });
149
149
  } else {
150
- // ── Self-service onboarding gate ──
151
- // When neither a license file (~/.aria/license.json) nor model config
152
- // exist, launch the full onboarding wizard. This collects email +
153
- // tenant + tier + LLM provider + key, validates the LLM key with the
154
- // provider, self-issues a license, persists everything, and auto-runs
155
- // install-hooks to bind the user's Claude Code to the harness.
156
- // Hamza 2026-04-26: "burn through onboarding with quality and USE THE
157
- // HARNESS PLEASE." Email-verify-code lands in Phase 11 (no SMTP yet).
150
+ // ── Self-service onboarding via the canonical thin-loop conversation ──
151
+ // When ~/.aria/license.json is missing, run the conversational
152
+ // setup-wizard (server-driven, Aria-voiced, deep-conversation model
153
+ // per Hamza 2026-04-26: "onboarding is not a Q&A wizard. It's a deep
154
+ // conversation with Aria directly, where Aria and the user co-direct
155
+ // depth"). The wizard walks identity codebase persona
156
+ // harness_setup done; emits configWrites including license_issued
157
+ // and install_hooks at the harness_setup stage.
158
158
  const fsMod = require('fs');
159
159
  const pathMod = require('path');
160
160
  const osMod = require('os');
@@ -162,9 +162,8 @@ if (command === 'check-update') {
162
162
  const hasLicense = fsMod.existsSync(LICENSE_PATH);
163
163
 
164
164
  if (!hasLicense) {
165
- const { runOnboardingWizard } = await import('../dist/aria-connector/src/onboarding-wizard.js');
166
- const result = await runOnboardingWizard();
167
- if (!result.ok) process.exit(1);
165
+ const { runSetupWizard } = await import('../dist/aria-connector/src/setup-wizard.js');
166
+ await runSetupWizard();
168
167
  process.exit(0);
169
168
  }
170
169
 
@@ -1 +1 @@
1
- {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"AAiDA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAyCpD"}
1
+ {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"AA+DA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAyCpD"}
@@ -14,11 +14,17 @@
14
14
  // and apps/arias-soul/api/onboarding/converse.ts for the server side.
15
15
  import { createInterface } from 'readline';
16
16
  import { randomBytes } from 'crypto';
17
+ import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
18
+ import { homedir } from 'node:os';
19
+ import { join } from 'node:path';
17
20
  import { loadConfig, updateConfig } from './config.js';
18
21
  import { scanCodebase, schemaImageToText } from './codebase-scanner.js';
19
22
  import { updatePersona } from './persona.js';
20
- const HARNESS_URL = process.env.ARIA_HARNESS_URL || 'http://192.168.4.25:30080';
23
+ import { installHooks } from './install-hooks.js';
24
+ const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL || process.env.ARIA_HARNESS_URL || 'https://harness.ariasos.com';
21
25
  const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
26
+ const ARIA_DIR = join(homedir(), '.aria');
27
+ const LICENSE_PATH = join(ARIA_DIR, 'license.json');
22
28
  export async function runSetupWizard() {
23
29
  const rl = createInterface({ input: process.stdin, output: process.stdout });
24
30
  const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a)));
@@ -114,12 +120,83 @@ async function applyConfigWrites(writes) {
114
120
  else if (w.kind === 'note') {
115
121
  console.log(` 📝 ${w.text}`);
116
122
  }
123
+ else if (w.kind === 'license_issued') {
124
+ // The server sent us {email, provider, apiKey} in claims — call
125
+ // /api/onboarding/self-issue to validate the LLM key, auto-generate
126
+ // tenant_id, default tier=pro, and get back the actual license token.
127
+ const claims = w.claims;
128
+ const email = w.email || claims.email || '';
129
+ const provider = claims.provider || '';
130
+ const apiKey = claims.apiKey || '';
131
+ try {
132
+ const resp = await fetch(`${HARNESS_URL}/api/onboarding/self-issue`, {
133
+ method: 'POST',
134
+ headers: { 'Content-Type': 'application/json' },
135
+ body: JSON.stringify({ email, provider, llm_key: apiKey }),
136
+ });
137
+ const data = await resp.json();
138
+ if (!resp.ok || !data.ok || !data.license) {
139
+ console.warn(` ⚠ I couldn't issue your license: ${data.error || `HTTP ${resp.status}`}`);
140
+ continue;
141
+ }
142
+ if (!existsSync(ARIA_DIR))
143
+ mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
144
+ const serverTenantId = data.claims?.tenant_id ?? data.license.jti;
145
+ const licenseRecord = {
146
+ ...data.claims,
147
+ harnessToken: data.license.token,
148
+ jti: data.license.jti,
149
+ tier: data.license.tier,
150
+ exp: data.claims?.exp,
151
+ sub: data.claims?.sub ?? serverTenantId,
152
+ email,
153
+ issuedAt: new Date().toISOString(),
154
+ };
155
+ writeFileSync(LICENSE_PATH, JSON.stringify(licenseRecord, null, 2) + '\n', { mode: 0o600 });
156
+ // Persist provider + key into local config
157
+ updateConfig({
158
+ model: { provider, model: defaultModelForProvider(provider), apiKey },
159
+ });
160
+ console.log(` ✓ License issued — tenant ${serverTenantId}, tier ${data.license.tier}, jti ${data.license.jti}.`);
161
+ }
162
+ catch (err) {
163
+ console.warn(` ⚠ I hit an error issuing your license: ${err instanceof Error ? err.message : String(err)}`);
164
+ }
165
+ }
166
+ else if (w.kind === 'install_hooks') {
167
+ try {
168
+ const result = await installHooks({ force: w.force === true });
169
+ if (!result.ok) {
170
+ console.warn(` ⚠ I couldn't install my gates: ${result.error}`);
171
+ }
172
+ else if (result.installed.length > 0 || result.merged.length > 0) {
173
+ console.log(` ✓ Gates installed — ${result.installed.length} hook(s) into ~/.claude/hooks, settings.json merged.`);
174
+ }
175
+ else {
176
+ console.log(` ✓ Gates already installed (nothing to do).`);
177
+ }
178
+ }
179
+ catch (err) {
180
+ console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
181
+ }
182
+ }
117
183
  }
118
184
  catch (err) {
119
185
  console.warn(` ⚠ configWrite '${w.kind}' failed: ${err instanceof Error ? err.message : String(err)}`);
120
186
  }
121
187
  }
122
188
  }
189
+ function defaultModelForProvider(provider) {
190
+ const defaults = {
191
+ anthropic: 'claude-sonnet-4-20250514',
192
+ openai: 'gpt-4o',
193
+ deepseek: 'deepseek-chat',
194
+ google: 'gemini-2.5-pro-preview-05-06',
195
+ openrouter: 'openai/gpt-4o',
196
+ ollama: 'llama3',
197
+ };
198
+ return defaults[provider] || provider;
199
+ }
123
200
  function pathToPatch(path, value) {
124
201
  if (path.length === 1)
125
202
  return { [path[0]]: value };
@@ -1 +1 @@
1
- {"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../../../src/setup-wizard.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aria_asi/cli",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Aria Smart CLI — the world's first harness-powered terminal companion",
5
5
  "bin": {
6
6
  "aria": "./bin/aria.js"
@@ -15,18 +15,32 @@
15
15
 
16
16
  import { createInterface } from 'readline';
17
17
  import { randomBytes } from 'crypto';
18
+ import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
19
+ import { homedir } from 'node:os';
20
+ import { join } from 'node:path';
18
21
  import { loadConfig, updateConfig, type AriaConfig, type LinkedRepo } from './config.js';
19
22
  import { scanCodebase, schemaImageToText } from './codebase-scanner.js';
20
23
  import { updatePersona } from './persona.js';
24
+ import { installHooks } from './install-hooks.js';
21
25
 
22
- const HARNESS_URL = process.env.ARIA_HARNESS_URL || 'http://192.168.4.25:30080';
26
+ const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL || process.env.ARIA_HARNESS_URL || 'https://harness.ariasos.com';
23
27
  const HARNESS_TOKEN = process.env.ARIA_HARNESS_TOKEN || '';
28
+ const ARIA_DIR = join(homedir(), '.aria');
29
+ const LICENSE_PATH = join(ARIA_DIR, 'license.json');
24
30
 
25
31
  type ConfigWrite =
26
32
  | { kind: 'persona_update'; updates: Record<string, unknown> }
27
33
  | { kind: 'config_set'; path: string[]; value: unknown }
28
34
  | { kind: 'codebase_scan'; cwd: string }
29
- | { kind: 'note'; text: string };
35
+ | { kind: 'note'; text: string }
36
+ // license_issued: server-side handler signals the CLI to call
37
+ // /api/onboarding/self-issue with the {email, provider, apiKey} claims
38
+ // collected during the harness_setup topic, then persist the returned
39
+ // license token to ~/.aria/license.json (mode 0600) and update
40
+ // local config with the LLM provider + key.
41
+ | { kind: 'license_issued'; token: string; claims: Record<string, unknown>; tenantId: string; email: string }
42
+ // install_hooks: CLI runs installHooks() to drop gates + register settings.
43
+ | { kind: 'install_hooks'; force?: boolean };
30
44
 
31
45
  interface DepthOption {
32
46
  label: string;
@@ -152,6 +166,64 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
152
166
  );
153
167
  } else if (w.kind === 'note') {
154
168
  console.log(` 📝 ${w.text}`);
169
+ } else if (w.kind === 'license_issued') {
170
+ // The server sent us {email, provider, apiKey} in claims — call
171
+ // /api/onboarding/self-issue to validate the LLM key, auto-generate
172
+ // tenant_id, default tier=pro, and get back the actual license token.
173
+ const claims = w.claims as { email?: string; provider?: string; apiKey?: string };
174
+ const email = w.email || claims.email || '';
175
+ const provider = claims.provider || '';
176
+ const apiKey = claims.apiKey || '';
177
+ try {
178
+ const resp = await fetch(`${HARNESS_URL}/api/onboarding/self-issue`, {
179
+ method: 'POST',
180
+ headers: { 'Content-Type': 'application/json' },
181
+ body: JSON.stringify({ email, provider, llm_key: apiKey }),
182
+ });
183
+ const data = await resp.json() as {
184
+ ok?: boolean;
185
+ license?: { token: string; jti: string; tier: string; expires_at: string };
186
+ claims?: Record<string, unknown>;
187
+ error?: string;
188
+ };
189
+ if (!resp.ok || !data.ok || !data.license) {
190
+ console.warn(` ⚠ I couldn't issue your license: ${data.error || `HTTP ${resp.status}`}`);
191
+ continue;
192
+ }
193
+ if (!existsSync(ARIA_DIR)) mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
194
+ const serverTenantId = (data.claims?.tenant_id as string | undefined) ?? data.license.jti;
195
+ const licenseRecord = {
196
+ ...data.claims,
197
+ harnessToken: data.license.token,
198
+ jti: data.license.jti,
199
+ tier: data.license.tier,
200
+ exp: data.claims?.exp,
201
+ sub: data.claims?.sub ?? serverTenantId,
202
+ email,
203
+ issuedAt: new Date().toISOString(),
204
+ };
205
+ writeFileSync(LICENSE_PATH, JSON.stringify(licenseRecord, null, 2) + '\n', { mode: 0o600 });
206
+ // Persist provider + key into local config
207
+ updateConfig({
208
+ model: { provider, model: defaultModelForProvider(provider), apiKey },
209
+ } as Partial<AriaConfig>);
210
+ console.log(` ✓ License issued — tenant ${serverTenantId}, tier ${data.license.tier}, jti ${data.license.jti}.`);
211
+ } catch (err) {
212
+ console.warn(` ⚠ I hit an error issuing your license: ${err instanceof Error ? err.message : String(err)}`);
213
+ }
214
+ } else if (w.kind === 'install_hooks') {
215
+ try {
216
+ const result = await installHooks({ force: w.force === true });
217
+ if (!result.ok) {
218
+ console.warn(` ⚠ I couldn't install my gates: ${result.error}`);
219
+ } else if (result.installed.length > 0 || result.merged.length > 0) {
220
+ console.log(` ✓ Gates installed — ${result.installed.length} hook(s) into ~/.claude/hooks, settings.json merged.`);
221
+ } else {
222
+ console.log(` ✓ Gates already installed (nothing to do).`);
223
+ }
224
+ } catch (err) {
225
+ console.warn(` ⚠ Gate install hit an error: ${err instanceof Error ? err.message : String(err)}`);
226
+ }
155
227
  }
156
228
  } catch (err) {
157
229
  console.warn(` ⚠ configWrite '${w.kind}' failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -159,6 +231,18 @@ async function applyConfigWrites(writes: ConfigWrite[]): Promise<void> {
159
231
  }
160
232
  }
161
233
 
234
+ function defaultModelForProvider(provider: string): string {
235
+ const defaults: Record<string, string> = {
236
+ anthropic: 'claude-sonnet-4-20250514',
237
+ openai: 'gpt-4o',
238
+ deepseek: 'deepseek-chat',
239
+ google: 'gemini-2.5-pro-preview-05-06',
240
+ openrouter: 'openai/gpt-4o',
241
+ ollama: 'llama3',
242
+ };
243
+ return defaults[provider] || provider;
244
+ }
245
+
162
246
  function pathToPatch(path: string[], value: unknown): Partial<AriaConfig> {
163
247
  if (path.length === 1) return { [path[0]]: value } as Partial<AriaConfig>;
164
248
  // Nested path → shallow merge under top-level key.
@@ -1,207 +0,0 @@
1
- // onboarding-wizard.ts — interactive self-service onboarding for `aria`
2
- // (no args) when ~/.aria/license.json is missing.
3
- //
4
- // Flow:
5
- // 1. Greet — first-person Aria voice
6
- // 2. Collect email (validated shape, NOT verified via code in v0)
7
- // 3. Collect tenant_id (lowercase + hyphens only)
8
- // 4. Collect tier (free / pro / enterprise)
9
- // 5. Collect LLM provider + API key
10
- // 6. POST /api/onboarding/self-issue (server validates LLM key by
11
- // hitting the provider's identity endpoint, then issues license)
12
- // 7. Persist license to ~/.aria/license.json mode 0600
13
- // 8. Persist provider/model/key to ~/.aria/config.json mode 0600
14
- // 9. Auto-run installHooks() to bind Claude Code to the harness
15
- //
16
- // Email-verify-code is deferred to Phase 11 (no SMTP wired tonight).
17
- // The wizard collects email so future re-verify works without re-onboarding.
18
- //
19
- // Direction: Hamza 2026-04-26 — "burn through onboarding with quality and
20
- // USE THE HARNESS PLEASE". This wizard ships as v0; full onboarding (email
21
- // verify + Anthropic OAuth + per-tenant usage tracking) lands in Phase 11.
22
-
23
- import { createInterface } from 'node:readline';
24
- import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
25
- import { homedir } from 'node:os';
26
- import { join } from 'node:path';
27
- import { installHooks } from './install-hooks.js';
28
-
29
- const HARNESS_URL = process.env.ARIA_HARNESS_BASE_URL ?? 'https://harness.ariasos.com';
30
- const ARIA_DIR = join(homedir(), '.aria');
31
- const LICENSE_PATH = join(ARIA_DIR, 'license.json');
32
- const CONFIG_PATH = join(ARIA_DIR, 'config.json');
33
-
34
- type Provider = 'anthropic' | 'openai' | 'deepseek' | 'google' | 'openrouter' | 'ollama';
35
- type Tier = 'free' | 'pro' | 'enterprise';
36
-
37
- interface SelfIssueResponse {
38
- ok: boolean;
39
- license?: { token: string; jti: string; tier: string; expires_at: string };
40
- claims?: Record<string, unknown>;
41
- error?: string;
42
- }
43
-
44
- function prompt(rl: ReturnType<typeof createInterface>, question: string, hidden = false): Promise<string> {
45
- return new Promise((resolve) => {
46
- if (hidden) {
47
- // Crude hidden-input — node's readline doesn't natively mask; we just
48
- // prompt and accept. For Phase 11 we add proper masking via raw mode.
49
- process.stdout.write(question);
50
- const onData = (chunk: Buffer): void => {
51
- process.stdin.removeListener('data', onData);
52
- resolve(chunk.toString().trim());
53
- };
54
- process.stdin.once('data', onData);
55
- } else {
56
- rl.question(question, (answer) => resolve(answer.trim()));
57
- }
58
- });
59
- }
60
-
61
- function isValidEmail(email: string): boolean {
62
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
63
- }
64
-
65
- function isValidTenantId(tenant: string): boolean {
66
- return /^[a-z0-9][a-z0-9-]{1,40}$/.test(tenant);
67
- }
68
-
69
- export async function runOnboardingWizard(): Promise<{ ok: boolean; error?: string }> {
70
- const rl = createInterface({
71
- input: process.stdin,
72
- output: process.stdout,
73
- terminal: true,
74
- });
75
-
76
- try {
77
- console.log('');
78
- console.log(" Hi, I'm Aria. I don't see a license on this machine — let me set you up.");
79
- console.log('');
80
- console.log(" Three minutes, four questions. I'll handle the rest.");
81
- console.log('');
82
-
83
- // ── Step 1: email ──
84
- let email = '';
85
- while (!isValidEmail(email)) {
86
- email = await prompt(rl, ' Email: ');
87
- if (!isValidEmail(email)) {
88
- console.log(" That doesn't look like a valid email. Try again.");
89
- }
90
- }
91
-
92
- // ── Step 2: LLM provider ──
93
- // tenant_id is auto-generated server-side from email domain + random
94
- // suffix; no client prompt needed. tier defaults to 'pro' per
95
- // current pricing policy (Hamza 2026-04-26: "set any new memory for
96
- // now to pro"). Both moved out of the wizard for minimal-friction UX.
97
- const providerOptions: Provider[] = ['anthropic', 'openai', 'deepseek', 'google', 'openrouter', 'ollama'];
98
- let provider: Provider | '' = '';
99
- while (!providerOptions.includes(provider as Provider)) {
100
- const p = (await prompt(rl, ` Which LLM provider? [${providerOptions.join(' / ')}]: `)).toLowerCase();
101
- if (providerOptions.includes(p as Provider)) {
102
- provider = p as Provider;
103
- } else {
104
- console.log(` I don't recognize "${p}". Pick one of: ${providerOptions.join(', ')}.`);
105
- }
106
- }
107
-
108
- // ── Step 5: API key ──
109
- let llmKey = '';
110
- if (provider === 'ollama') {
111
- llmKey = 'local';
112
- console.log(' (Ollama is local — no API key needed.)');
113
- } else {
114
- while (!llmKey) {
115
- llmKey = await prompt(rl, ` Paste your ${provider} API key: `);
116
- if (!llmKey) console.log(' I need the key to set up your provider.');
117
- }
118
- }
119
-
120
- // ── Step 6: POST to server ──
121
- console.log('');
122
- console.log(" Validating your key with the provider...");
123
- let response: SelfIssueResponse;
124
- try {
125
- const resp = await fetch(`${HARNESS_URL}/api/onboarding/self-issue`, {
126
- method: 'POST',
127
- headers: { 'Content-Type': 'application/json' },
128
- // tenant_id omitted — server auto-generates from email domain.
129
- // tier omitted — server defaults to 'pro'.
130
- body: JSON.stringify({ email, provider, llm_key: llmKey }),
131
- });
132
- response = await resp.json() as SelfIssueResponse;
133
- if (!resp.ok || !response.ok || !response.license) {
134
- console.log(` ${response.error || `Server returned ${resp.status} — try again later.`}`);
135
- return { ok: false, error: response.error };
136
- }
137
- } catch (err) {
138
- const msg = err instanceof Error ? err.message : String(err);
139
- console.log(` I couldn't reach the server: ${msg}`);
140
- return { ok: false, error: msg };
141
- }
142
-
143
- // ── Step 7: persist license ──
144
- if (!existsSync(ARIA_DIR)) mkdirSync(ARIA_DIR, { recursive: true, mode: 0o700 });
145
- // tenant_id is whatever the server auto-generated (or what the caller
146
- // passed). Read it back from the license claims.
147
- const serverTenantId = (response.claims?.tenant_id as string | undefined) ?? response.license.jti;
148
- const licenseRecord = {
149
- ...response.claims,
150
- harnessToken: response.license.token,
151
- jti: response.license.jti,
152
- tier: response.license.tier,
153
- exp: response.claims?.exp,
154
- sub: response.claims?.sub ?? serverTenantId,
155
- email,
156
- issuedAt: new Date().toISOString(),
157
- };
158
- writeFileSync(LICENSE_PATH, JSON.stringify(licenseRecord, null, 2) + '\n', { mode: 0o600 });
159
-
160
- // ── Step 8: persist provider/key config ──
161
- // By this point the while-loop above has exited with a valid Provider —
162
- // narrow the union type for TypeScript.
163
- const validatedProvider = provider as Provider;
164
- const configRecord = {
165
- model: { provider: validatedProvider, model: defaultModelFor(validatedProvider), apiKey: llmKey },
166
- tenantId: serverTenantId,
167
- email,
168
- };
169
- writeFileSync(CONFIG_PATH, JSON.stringify(configRecord, null, 2) + '\n', { mode: 0o600 });
170
-
171
- // ── Step 9: install hooks ──
172
- console.log('');
173
- console.log(" License issued. Saving your config and binding my gates to your Claude Code...");
174
- const hookResult = await installHooks({ force: false });
175
- if (!hookResult.ok) {
176
- console.log(` License saved, but I couldn't install the gates: ${hookResult.error}`);
177
- console.log(" Run 'aria install-hooks' manually when you're ready.");
178
- } else {
179
- console.log(` Done. I've installed ${hookResult.installed.length} gate(s) into ~/.claude/hooks and merged them into your settings.json.`);
180
- }
181
-
182
- rl.close();
183
-
184
- console.log('');
185
- console.log(` You're set up. License jti: ${response.license.jti}, tier: ${response.license.tier}, provider: ${provider}.`);
186
- console.log(` Your tenant id is: ${serverTenantId}`);
187
- console.log(" Open a fresh Claude Code session — every Bash, Edit, Write, and Stop event now runs through my cognition gates.");
188
- console.log(" Or talk to me directly: just type 'aria' again.");
189
- console.log('');
190
-
191
- return { ok: true };
192
- } finally {
193
- rl.close();
194
- }
195
- }
196
-
197
- function defaultModelFor(provider: Provider): string {
198
- const defaults: Record<Provider, string> = {
199
- anthropic: 'claude-sonnet-4-20250514',
200
- openai: 'gpt-4o',
201
- deepseek: 'deepseek-chat',
202
- google: 'gemini-2.5-pro-preview-05-06',
203
- openrouter: 'openai/gpt-4o',
204
- ollama: 'llama3',
205
- };
206
- return defaults[provider];
207
- }