@pikoloo/codex-proxy 1.0.6 → 1.0.7
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/README.md +12 -5
- package/images/dashboard-screenshot.png +0 -0
- package/images/readme-cover.png +0 -0
- package/images/settings-screenshot.png +0 -0
- package/package.json +2 -1
- package/public/css/style.css +247 -0
- package/public/index.html +311 -15
- package/public/js/app.js +275 -14
- package/src/format-converter.js +5 -1
- package/src/index.js +1 -1
- package/src/model-mapper.js +145 -22
- package/src/routes/api-routes.js +21 -1
- package/src/routes/chat-route.js +76 -3
- package/src/routes/messages-route.js +175 -5
- package/src/routes/metrics-route.js +43 -0
- package/src/routes/settings-route.js +148 -2
- package/src/security.js +2 -1
- package/src/server-settings.js +40 -4
- package/src/server.js +27 -2
- package/src/usage-metrics.js +472 -0
package/public/index.html
CHANGED
|
@@ -94,8 +94,8 @@
|
|
|
94
94
|
</a>
|
|
95
95
|
|
|
96
96
|
<button type="button" class="btn btn-ghost btn-xs btn-square text-gray-400 hover:text-white hover:bg-white/5"
|
|
97
|
-
@click="
|
|
98
|
-
<svg class="w-4 h-4" :class="{'animate-spin': loading}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
97
|
+
@click="refreshCurrentView()" :disabled="loading || metricsLoading" title="Refresh data">
|
|
98
|
+
<svg class="w-4 h-4" :class="{'animate-spin': loading || metricsLoading}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
99
99
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
100
100
|
</svg>
|
|
101
101
|
</button>
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
'-translate-x-full': !sidebarOpen
|
|
116
116
|
}">
|
|
117
117
|
<div class="w-64 flex flex-col h-full pt-6 pb-4 flex-shrink-0">
|
|
118
|
-
<div class="px-4 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest hidden lg:block">
|
|
118
|
+
<div class="px-4 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest hidden lg:block">Monitor</div>
|
|
119
119
|
|
|
120
120
|
<nav class="flex flex-col gap-1">
|
|
121
121
|
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
@@ -126,22 +126,32 @@
|
|
|
126
126
|
<span>Dashboard</span>
|
|
127
127
|
</button>
|
|
128
128
|
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
129
|
-
:class="{'active': activeTab === '
|
|
129
|
+
:class="{'active': activeTab === 'metrics'}" @click="setActiveTab('metrics')">
|
|
130
130
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
131
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="
|
|
131
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3v18h18M7 15l3-3 3 2 5-7" />
|
|
132
132
|
</svg>
|
|
133
|
-
<span>
|
|
133
|
+
<span>Metrics</span>
|
|
134
|
+
<span class="nav-count ml-auto" x-text="formatTokenCount(metricsTotals.totalTokens)"></span>
|
|
134
135
|
</button>
|
|
135
|
-
</nav>
|
|
136
|
-
|
|
137
|
-
<div class="px-4 mt-8 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest">System</div>
|
|
138
|
-
<nav class="flex flex-col gap-1">
|
|
139
136
|
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
140
137
|
:class="{'active': activeTab === 'logs'}" @click="setActiveTab('logs')">
|
|
141
138
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
142
139
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
143
140
|
</svg>
|
|
144
141
|
<span>Logs</span>
|
|
142
|
+
<span class="nav-count ml-auto" x-text="logs.length"></span>
|
|
143
|
+
</button>
|
|
144
|
+
</nav>
|
|
145
|
+
|
|
146
|
+
<div class="px-4 mt-8 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest">Manage</div>
|
|
147
|
+
<nav class="flex flex-col gap-1">
|
|
148
|
+
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
149
|
+
:class="{'active': activeTab === 'accounts'}" @click="setActiveTab('accounts')">
|
|
150
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
151
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
152
|
+
</svg>
|
|
153
|
+
<span>Accounts</span>
|
|
154
|
+
<span class="nav-count ml-auto" x-text="stats.total"></span>
|
|
145
155
|
</button>
|
|
146
156
|
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
147
157
|
:class="{'active': activeTab === 'settings'}" @click="setActiveTab('settings')">
|
|
@@ -285,21 +295,224 @@
|
|
|
285
295
|
</div>
|
|
286
296
|
<div class="bg-space-800/50 border border-space-border/30 rounded-lg p-4 font-mono text-sm text-gray-300">
|
|
287
297
|
<div class="text-gray-500 mb-2"># Set environment variables</div>
|
|
288
|
-
<div class="text-neon-cyan">export ANTHROPIC_BASE_URL=http://localhost:8081</div>
|
|
298
|
+
<div class="text-neon-cyan" x-text="'export ANTHROPIC_BASE_URL=' + serverUrl">export ANTHROPIC_BASE_URL=http://localhost:8081</div>
|
|
289
299
|
<div class="text-neon-cyan">export ANTHROPIC_API_KEY=any-key</div>
|
|
290
300
|
<div class="text-gray-500 mt-2 mb-2"># Run Claude</div>
|
|
291
301
|
<div class="text-neon-green">claude</div>
|
|
292
302
|
</div>
|
|
293
303
|
|
|
294
|
-
<div class="mt-4 flex justify-
|
|
304
|
+
<div class="mt-4 flex flex-wrap items-center justify-between gap-3">
|
|
305
|
+
<label class="flex items-center gap-3 rounded-lg border border-space-border/30 bg-space-800/40 px-3 py-2">
|
|
306
|
+
<input type="checkbox"
|
|
307
|
+
class="checkbox checkbox-sm rounded-[3px]"
|
|
308
|
+
x-model="configureClaudeOnStartup"
|
|
309
|
+
@change="setConfigureClaudeOnStartup($event.target.checked)"
|
|
310
|
+
:disabled="claudeProxyStartupSaving">
|
|
311
|
+
<span class="text-sm text-gray-300">Configure on startup</span>
|
|
312
|
+
</label>
|
|
295
313
|
<button class="btn btn-sm bg-neon-purple hover:bg-purple-600 border-none text-white font-sans"
|
|
296
|
-
@click="
|
|
297
|
-
|
|
314
|
+
@click="configureClaudeProxy()"
|
|
315
|
+
:disabled="claudeProxyConfiguring">
|
|
316
|
+
<svg class="w-4 h-4" :class="{'animate-spin': claudeProxyConfiguring}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
317
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7h16M4 12h10M4 17h7m8-4l2 2 4-4"></path>
|
|
318
|
+
</svg>
|
|
319
|
+
<span x-text="claudeProxyConfiguring ? 'Configuring...' : 'Configure Claude Code'">Configure Claude Code</span>
|
|
298
320
|
</button>
|
|
299
321
|
</div>
|
|
300
322
|
</div>
|
|
301
323
|
</div>
|
|
302
324
|
|
|
325
|
+
<div x-show="activeTab === 'metrics'" x-transition class="view-container">
|
|
326
|
+
<div class="flex items-center justify-between gap-4 mb-6">
|
|
327
|
+
<div class="flex flex-wrap items-center gap-4">
|
|
328
|
+
<h1 class="text-2xl font-bold text-white tracking-tight">Token Usage</h1>
|
|
329
|
+
<div class="flex items-center h-6 px-3 rounded-full bg-space-800/80 border border-space-border/50 shadow-sm backdrop-blur-sm">
|
|
330
|
+
<span class="text-[10px] font-mono text-gray-400 uppercase tracking-wider">Request metrics</span>
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
<div class="metrics-range-controls">
|
|
334
|
+
<button class="metrics-range-button" :class="{'active': metricsRange === '24h'}" @click="setMetricsRange('24h')">24h</button>
|
|
335
|
+
<button class="metrics-range-button" :class="{'active': metricsRange === '7d'}" @click="setMetricsRange('7d')">7d</button>
|
|
336
|
+
<button class="metrics-range-button" :class="{'active': metricsRange === '30d'}" @click="setMetricsRange('30d')">30d</button>
|
|
337
|
+
<button class="metrics-range-button" :class="{'active': metricsRange === 'all'}" @click="setMetricsRange('all')">All</button>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<div x-show="metricsError" class="alert alert-error mb-4">
|
|
342
|
+
<span x-text="metricsError"></span>
|
|
343
|
+
</div>
|
|
344
|
+
|
|
345
|
+
<div x-show="metricsStorage && metricsStorage.overLimit" class="metrics-storage-warning mb-4">
|
|
346
|
+
<div>
|
|
347
|
+
<div class="text-sm font-semibold text-red-300">Metrics database is above the configured cap</div>
|
|
348
|
+
<div class="text-xs text-red-200/80 font-mono">
|
|
349
|
+
<span x-text="formatBytes(metricsStorage?.sizeBytes)"></span>
|
|
350
|
+
<span>/</span>
|
|
351
|
+
<span x-text="formatBytes(metricsStorage?.maxBytes)"></span>
|
|
352
|
+
<span>after compact-only maintenance</span>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
<button class="btn btn-xs btn-outline" @click="loadMetrics()" :disabled="metricsLoading">Refresh</button>
|
|
356
|
+
</div>
|
|
357
|
+
|
|
358
|
+
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2 lg:gap-3 mb-6">
|
|
359
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 min-w-0">
|
|
360
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="formatTokenCount(metricsTotals.totalTokens)"></div>
|
|
361
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Total Tokens</div>
|
|
362
|
+
<div class="stat-desc text-cyan-400/60 text-[10px] truncate">Input + output</div>
|
|
363
|
+
</div>
|
|
364
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 min-w-0">
|
|
365
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="metricsTotals.requestCount"></div>
|
|
366
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Requests</div>
|
|
367
|
+
<div class="stat-desc text-green-400/60 text-[10px] truncate"><span x-text="metricsTotals.successCount"></span> successful</div>
|
|
368
|
+
</div>
|
|
369
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 min-w-0">
|
|
370
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="formatTokenCount(metricsTotals.outputTokens)"></div>
|
|
371
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Output Tokens</div>
|
|
372
|
+
<div class="stat-desc text-purple-400/60 text-[10px] truncate"><span x-text="formatTokenCount(metricsTotals.inputTokens)"></span> input</div>
|
|
373
|
+
</div>
|
|
374
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 min-w-0">
|
|
375
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="formatDuration(metricsTotals.averageDurationMs)"></div>
|
|
376
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Avg Latency</div>
|
|
377
|
+
<div class="stat-desc text-yellow-400/60 text-[10px] truncate"><span x-text="metricsTotals.errorCount"></span> errors</div>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
<div class="metrics-grid mb-6">
|
|
382
|
+
<div class="view-card metrics-panel">
|
|
383
|
+
<div class="metrics-panel-header">
|
|
384
|
+
<h3>Token Trend</h3>
|
|
385
|
+
<span x-show="metricsLoading" class="metrics-muted">Loading</span>
|
|
386
|
+
</div>
|
|
387
|
+
<div class="metrics-timeline">
|
|
388
|
+
<template x-for="entry in metricsSummary.timeline" :key="entry.bucket">
|
|
389
|
+
<div class="metrics-timeline-row">
|
|
390
|
+
<span class="metrics-timeline-label" x-text="entry.bucket"></span>
|
|
391
|
+
<div class="metrics-bar-track">
|
|
392
|
+
<div class="metrics-bar-fill" :style="'width:' + metricBarWidth(entry.totalTokens, metricsTimelineMax) + '%'"></div>
|
|
393
|
+
</div>
|
|
394
|
+
<span class="metrics-value" x-text="formatTokenCount(entry.totalTokens)"></span>
|
|
395
|
+
</div>
|
|
396
|
+
</template>
|
|
397
|
+
<div x-show="metricsSummary.timeline.length === 0" class="metrics-empty">No usage recorded for this range</div>
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
<div class="view-card metrics-panel">
|
|
402
|
+
<div class="metrics-panel-header">
|
|
403
|
+
<h3>Storage</h3>
|
|
404
|
+
<span class="metrics-muted" x-text="formatBytes(metricsStorage?.sizeBytes)"></span>
|
|
405
|
+
</div>
|
|
406
|
+
<div class="space-y-3">
|
|
407
|
+
<div class="flex items-center justify-between py-2 border-b border-space-border/30">
|
|
408
|
+
<span class="text-sm text-gray-400">Database</span>
|
|
409
|
+
<span class="font-mono text-xs text-white truncate max-w-[260px]" x-text="metricsStorage?.dbPath || '-'"></span>
|
|
410
|
+
</div>
|
|
411
|
+
<div class="flex items-center justify-between py-2 border-b border-space-border/30">
|
|
412
|
+
<span class="text-sm text-gray-400">Cap</span>
|
|
413
|
+
<span class="font-mono text-sm text-white" x-text="formatBytes(metricsStorage?.maxBytes)"></span>
|
|
414
|
+
</div>
|
|
415
|
+
<div class="flex items-center justify-between py-2">
|
|
416
|
+
<span class="text-sm text-gray-400">Last compact</span>
|
|
417
|
+
<span class="font-mono text-xs text-white" x-text="formatMetricTime(metricsStorage?.lastCompactionAttemptAt)"></span>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<div class="metrics-grid mb-6">
|
|
424
|
+
<div class="view-card metrics-panel">
|
|
425
|
+
<div class="metrics-panel-header">
|
|
426
|
+
<h3>Models</h3>
|
|
427
|
+
<span class="metrics-muted" x-text="metricsSummary.byModel.length"></span>
|
|
428
|
+
</div>
|
|
429
|
+
<div class="metrics-list">
|
|
430
|
+
<template x-for="entry in metricsSummary.byModel" :key="entry.model">
|
|
431
|
+
<div class="metrics-breakdown-row">
|
|
432
|
+
<div class="min-w-0">
|
|
433
|
+
<div class="metrics-breakdown-title" x-text="entry.model"></div>
|
|
434
|
+
<div class="metrics-muted"><span x-text="entry.requestCount"></span> requests</div>
|
|
435
|
+
</div>
|
|
436
|
+
<div class="metrics-breakdown-meter">
|
|
437
|
+
<div class="metrics-bar-track">
|
|
438
|
+
<div class="metrics-bar-fill" :style="'width:' + metricBarWidth(entry.totalTokens, metricsModelMax) + '%'"></div>
|
|
439
|
+
</div>
|
|
440
|
+
<span class="metrics-value" x-text="formatTokenCount(entry.totalTokens)"></span>
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
</template>
|
|
444
|
+
<div x-show="metricsSummary.byModel.length === 0" class="metrics-empty">No model usage</div>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
<div class="view-card metrics-panel">
|
|
449
|
+
<div class="metrics-panel-header">
|
|
450
|
+
<h3>Accounts</h3>
|
|
451
|
+
<span class="metrics-muted" x-text="metricsSummary.byAccount.length"></span>
|
|
452
|
+
</div>
|
|
453
|
+
<div class="metrics-list">
|
|
454
|
+
<template x-for="entry in metricsSummary.byAccount" :key="entry.accountLabel">
|
|
455
|
+
<div class="metrics-breakdown-row">
|
|
456
|
+
<div class="min-w-0">
|
|
457
|
+
<div class="metrics-breakdown-title" x-text="entry.accountLabel"></div>
|
|
458
|
+
<div class="metrics-muted"><span x-text="entry.requestCount"></span> requests</div>
|
|
459
|
+
</div>
|
|
460
|
+
<div class="metrics-breakdown-meter">
|
|
461
|
+
<div class="metrics-bar-track">
|
|
462
|
+
<div class="metrics-bar-fill" :style="'width:' + metricBarWidth(entry.totalTokens, metricsAccountMax) + '%'"></div>
|
|
463
|
+
</div>
|
|
464
|
+
<span class="metrics-value" x-text="formatTokenCount(entry.totalTokens)"></span>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
</template>
|
|
468
|
+
<div x-show="metricsSummary.byAccount.length === 0" class="metrics-empty">No account usage</div>
|
|
469
|
+
</div>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
|
|
473
|
+
<div class="view-card !p-0">
|
|
474
|
+
<div class="metrics-table-toolbar">
|
|
475
|
+
<h3>Recent Requests</h3>
|
|
476
|
+
<div class="metrics-range-controls">
|
|
477
|
+
<button class="metrics-range-button" :class="{'active': metricsStatusFilter === ''}" @click="setMetricsStatusFilter('')">All</button>
|
|
478
|
+
<button class="metrics-range-button" :class="{'active': metricsStatusFilter === 'success'}" @click="setMetricsStatusFilter('success')">Success</button>
|
|
479
|
+
<button class="metrics-range-button" :class="{'active': metricsStatusFilter === 'error'}" @click="setMetricsStatusFilter('error')">Error</button>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
<div class="overflow-x-auto">
|
|
483
|
+
<table id="metrics-recent-events" class="w-full text-sm text-left">
|
|
484
|
+
<thead class="text-xs text-gray-500 uppercase bg-space-800/50 border-b border-space-border/30">
|
|
485
|
+
<tr>
|
|
486
|
+
<th class="px-4 py-3">Time</th>
|
|
487
|
+
<th class="px-4 py-3">Endpoint</th>
|
|
488
|
+
<th class="px-4 py-3">Model</th>
|
|
489
|
+
<th class="px-4 py-3">Account</th>
|
|
490
|
+
<th class="px-4 py-3 text-right">Tokens</th>
|
|
491
|
+
<th class="px-4 py-3">Status</th>
|
|
492
|
+
</tr>
|
|
493
|
+
</thead>
|
|
494
|
+
<tbody class="divide-y divide-space-border/30">
|
|
495
|
+
<template x-for="event in metricsRecent" :key="event.id">
|
|
496
|
+
<tr class="hover:bg-white/[0.03]">
|
|
497
|
+
<td class="px-4 py-3 font-mono text-xs text-gray-400" x-text="formatMetricTime(event.startedAt)"></td>
|
|
498
|
+
<td class="px-4 py-3 font-mono text-xs text-gray-300" x-text="event.endpoint"></td>
|
|
499
|
+
<td class="px-4 py-3 font-mono text-xs text-gray-300" x-text="event.upstreamModel"></td>
|
|
500
|
+
<td class="px-4 py-3 font-mono text-xs text-gray-400" x-text="event.accountLabel || '-'"></td>
|
|
501
|
+
<td class="px-4 py-3 font-mono text-xs text-right text-gray-300" x-text="formatTokenCount(event.totalTokens)"></td>
|
|
502
|
+
<td class="px-4 py-3">
|
|
503
|
+
<span class="metrics-status" :class="metricsStatusClass(event.status)" x-text="event.status"></span>
|
|
504
|
+
</td>
|
|
505
|
+
</tr>
|
|
506
|
+
</template>
|
|
507
|
+
<tr x-show="metricsRecent.length === 0">
|
|
508
|
+
<td colspan="6" class="px-4 py-10 text-center text-sm text-gray-500">No requests recorded</td>
|
|
509
|
+
</tr>
|
|
510
|
+
</tbody>
|
|
511
|
+
</table>
|
|
512
|
+
</div>
|
|
513
|
+
</div>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
303
516
|
<div x-show="activeTab === 'accounts'" x-transition class="view-container">
|
|
304
517
|
<div class="flex items-center justify-between gap-4 mb-6">
|
|
305
518
|
<div class="flex flex-wrap items-center gap-4">
|
|
@@ -596,7 +809,7 @@
|
|
|
596
809
|
<div class="space-y-3">
|
|
597
810
|
<div class="flex items-center justify-between py-2 border-b border-space-border/30">
|
|
598
811
|
<span class="text-sm text-gray-400">Server URL</span>
|
|
599
|
-
<span class="font-mono text-sm text-white">http://localhost:8081</span>
|
|
812
|
+
<span class="font-mono text-sm text-white" x-text="serverUrl">http://localhost:8081</span>
|
|
600
813
|
</div>
|
|
601
814
|
<div class="flex items-center justify-between py-2 border-b border-space-border/30">
|
|
602
815
|
<span class="text-sm text-gray-400">Config Path</span>
|
|
@@ -609,6 +822,89 @@
|
|
|
609
822
|
</div>
|
|
610
823
|
</div>
|
|
611
824
|
|
|
825
|
+
<div class="view-card mt-6">
|
|
826
|
+
<div class="flex items-center gap-2.5 mb-4">
|
|
827
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-cyan">
|
|
828
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7h16M4 12h10M4 17h7m8-4l2 2 4-4"></path>
|
|
829
|
+
</svg>
|
|
830
|
+
<h3 class="text-xs font-mono text-gray-400 uppercase tracking-widest">Claude Model Mapping</h3>
|
|
831
|
+
</div>
|
|
832
|
+
<div class="model-mapping-list">
|
|
833
|
+
<div class="model-mapping-row" data-model-mapping-alias="opus">
|
|
834
|
+
<div class="model-mapping-copy">
|
|
835
|
+
<div class="text-sm text-gray-300">Opus</div>
|
|
836
|
+
<div class="text-xs text-gray-500 font-mono">Default <span x-text="modelOptionName(modelMappingDefaults.opus)"></span> / <span x-text="reasoningOptionName(reasoningMappingDefaults.opus)"></span></div>
|
|
837
|
+
</div>
|
|
838
|
+
<div class="model-mapping-controls">
|
|
839
|
+
<label class="model-mapping-field">
|
|
840
|
+
<span>Model</span>
|
|
841
|
+
<select class="model-mapping-select" :value="modelMappings.opus" @change="setModelMapping('opus', $event.target.value)" :disabled="Boolean(modelMappingSaving)">
|
|
842
|
+
<template x-for="model in openAiModelOptions" :key="model.id">
|
|
843
|
+
<option :value="model.id" x-text="model.name"></option>
|
|
844
|
+
</template>
|
|
845
|
+
</select>
|
|
846
|
+
</label>
|
|
847
|
+
<label class="model-mapping-field">
|
|
848
|
+
<span>Reasoning</span>
|
|
849
|
+
<select class="model-mapping-select" :value="reasoningMappings.opus" @change="setReasoningMapping('opus', $event.target.value)" :disabled="Boolean(reasoningMappingSaving)">
|
|
850
|
+
<template x-for="level in reasoningLevelOptions" :key="level.id">
|
|
851
|
+
<option :value="level.id" x-text="level.name"></option>
|
|
852
|
+
</template>
|
|
853
|
+
</select>
|
|
854
|
+
</label>
|
|
855
|
+
</div>
|
|
856
|
+
</div>
|
|
857
|
+
<div class="model-mapping-row" data-model-mapping-alias="sonnet">
|
|
858
|
+
<div class="model-mapping-copy">
|
|
859
|
+
<div class="text-sm text-gray-300">Sonnet</div>
|
|
860
|
+
<div class="text-xs text-gray-500 font-mono">Default <span x-text="modelOptionName(modelMappingDefaults.sonnet)"></span> / <span x-text="reasoningOptionName(reasoningMappingDefaults.sonnet)"></span></div>
|
|
861
|
+
</div>
|
|
862
|
+
<div class="model-mapping-controls">
|
|
863
|
+
<label class="model-mapping-field">
|
|
864
|
+
<span>Model</span>
|
|
865
|
+
<select class="model-mapping-select" :value="modelMappings.sonnet" @change="setModelMapping('sonnet', $event.target.value)" :disabled="Boolean(modelMappingSaving)">
|
|
866
|
+
<template x-for="model in openAiModelOptions" :key="model.id">
|
|
867
|
+
<option :value="model.id" x-text="model.name"></option>
|
|
868
|
+
</template>
|
|
869
|
+
</select>
|
|
870
|
+
</label>
|
|
871
|
+
<label class="model-mapping-field">
|
|
872
|
+
<span>Reasoning</span>
|
|
873
|
+
<select class="model-mapping-select" :value="reasoningMappings.sonnet" @change="setReasoningMapping('sonnet', $event.target.value)" :disabled="Boolean(reasoningMappingSaving)">
|
|
874
|
+
<template x-for="level in reasoningLevelOptions" :key="level.id">
|
|
875
|
+
<option :value="level.id" x-text="level.name"></option>
|
|
876
|
+
</template>
|
|
877
|
+
</select>
|
|
878
|
+
</label>
|
|
879
|
+
</div>
|
|
880
|
+
</div>
|
|
881
|
+
<div class="model-mapping-row" data-model-mapping-alias="haiku">
|
|
882
|
+
<div class="model-mapping-copy">
|
|
883
|
+
<div class="text-sm text-gray-300">Haiku</div>
|
|
884
|
+
<div class="text-xs text-gray-500 font-mono">Default <span x-text="modelOptionName(modelMappingDefaults.haiku)"></span> / <span x-text="reasoningOptionName(reasoningMappingDefaults.haiku)"></span></div>
|
|
885
|
+
</div>
|
|
886
|
+
<div class="model-mapping-controls">
|
|
887
|
+
<label class="model-mapping-field">
|
|
888
|
+
<span>Model</span>
|
|
889
|
+
<select class="model-mapping-select" :value="modelMappings.haiku" @change="setModelMapping('haiku', $event.target.value)" :disabled="Boolean(modelMappingSaving)">
|
|
890
|
+
<template x-for="model in openAiModelOptions" :key="model.id">
|
|
891
|
+
<option :value="model.id" x-text="model.name"></option>
|
|
892
|
+
</template>
|
|
893
|
+
</select>
|
|
894
|
+
</label>
|
|
895
|
+
<label class="model-mapping-field">
|
|
896
|
+
<span>Reasoning</span>
|
|
897
|
+
<select class="model-mapping-select" :value="reasoningMappings.haiku" @change="setReasoningMapping('haiku', $event.target.value)" :disabled="Boolean(reasoningMappingSaving)">
|
|
898
|
+
<template x-for="level in reasoningLevelOptions" :key="level.id">
|
|
899
|
+
<option :value="level.id" x-text="level.name"></option>
|
|
900
|
+
</template>
|
|
901
|
+
</select>
|
|
902
|
+
</label>
|
|
903
|
+
</div>
|
|
904
|
+
</div>
|
|
905
|
+
</div>
|
|
906
|
+
</div>
|
|
907
|
+
|
|
612
908
|
<div class="view-card mt-6" x-show="kiloEnabled">
|
|
613
909
|
<div class="flex items-center gap-2.5 mb-4">
|
|
614
910
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-purple">
|