@symerian/symi 3.5.11 → 3.5.13

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.5.11",
3
- "commit": "0b0214f0883885802eb1f14b3287222b044689f2",
4
- "builtAt": "2026-05-06T02:28:12.827Z"
2
+ "version": "3.5.13",
3
+ "commit": "33e6d6051e6f74ada770ca1941c409ce7ba65cd2",
4
+ "builtAt": "2026-05-06T02:46:17.820Z"
5
5
  }
@@ -1 +1 @@
1
- 1191210216ce547e23cadf39bf60dc8d937eb3b4357c931c6ab5afdad1515eef
1
+ b6b358862b350355c1027203e25ea1b0380203d1ceff6fb6a17ee5d3259e905e
@@ -397,49 +397,21 @@ body {
397
397
  letter-spacing: 0.05em;
398
398
  }
399
399
 
400
- /* ── Model Toggle ─────────────────────────────────────────────────── */
401
- .model-toggle {
402
- display: flex;
403
- gap: 6px;
400
+ /* ── Model Routing select ──────────────────────────────────────────── */
401
+ .model-routing-select {
402
+ width: 100%;
403
+ display: block;
404
+ padding: 8px 22px 8px 8px;
404
405
  margin-bottom: 6px;
405
- }
406
- .model-toggle-btn {
407
- flex: 1;
408
- padding: 8px 4px;
409
406
  border: 1px solid var(--glass-border);
410
407
  border-radius: 6px;
411
408
  background: rgba(255, 255, 255, 0.03);
412
- color: var(--text-dim);
413
- font-family: var(--font-mono);
414
- font-size: 10px;
415
- letter-spacing: 0.04em;
416
- cursor: pointer;
417
- transition: all 0.2s ease;
418
- white-space: nowrap;
419
- }
420
- .model-toggle-btn:hover {
421
- border-color: var(--accent-cyan);
422
409
  color: var(--text);
423
- }
424
- .model-toggle-btn.active {
425
- background: rgba(0, 212, 255, 0.08);
426
- border-color: var(--accent-cyan);
427
- color: var(--accent-cyan);
428
- box-shadow: 0 0 8px rgba(0, 212, 255, 0.12);
429
- }
430
- .model-toggle-select {
431
- flex: 1;
432
- padding: 8px 22px 8px 8px;
433
- border: 1px solid var(--glass-border);
434
- border-radius: 6px;
435
- background: rgba(255, 255, 255, 0.03);
436
- color: var(--text-dim);
437
410
  font-family: var(--font-mono);
438
411
  font-size: 10px;
439
412
  letter-spacing: 0.04em;
440
413
  cursor: pointer;
441
414
  transition: all 0.2s ease;
442
- white-space: nowrap;
443
415
  appearance: none;
444
416
  -webkit-appearance: none;
445
417
  background-image:
@@ -452,24 +424,31 @@ body {
452
424
  4px 4px,
453
425
  4px 4px;
454
426
  background-repeat: no-repeat;
427
+ text-overflow: ellipsis;
428
+ overflow: hidden;
455
429
  }
456
- .model-toggle-select:hover {
430
+ .model-routing-select:hover {
457
431
  border-color: var(--accent-cyan);
458
432
  color: var(--text);
459
433
  }
460
- .model-toggle-select.active {
461
- background-color: rgba(0, 212, 255, 0.08);
462
- border-color: var(--accent-cyan);
463
- color: var(--accent-cyan);
464
- box-shadow: 0 0 8px rgba(0, 212, 255, 0.12);
465
- }
466
- .model-toggle-select:focus {
434
+ .model-routing-select:focus {
467
435
  outline: none;
468
436
  border-color: var(--accent-cyan);
437
+ box-shadow: 0 0 8px rgba(0, 212, 255, 0.12);
469
438
  }
470
- .model-toggle-select option {
439
+ .model-routing-select option {
471
440
  background: #0a0a0a;
472
441
  color: var(--text);
442
+ padding: 4px 0;
443
+ }
444
+ .model-routing-select optgroup {
445
+ background: #0a0a0a;
446
+ color: var(--accent-cyan);
447
+ font-style: normal;
448
+ font-weight: 600;
449
+ letter-spacing: 0.08em;
450
+ text-transform: uppercase;
451
+ font-size: 10px;
473
452
  }
474
453
  .model-status {
475
454
  font-size: 10px;
@@ -120,22 +120,23 @@
120
120
 
121
121
  <div class="glass-panel" id="model-routing-panel">
122
122
  <div class="panel-label">MODEL ROUTING</div>
123
- <div class="model-toggle" id="model-toggle">
124
- <select class="model-toggle-select" id="model-toggle-spider" data-model="spider">
125
- <option value="" disabled selected>Spider ▾</option>
123
+ <select class="model-routing-select" id="model-toggle">
124
+ <option value="" disabled selected>Select model…</option>
125
+ <optgroup label="SPIDER">
126
126
  <option value="spider-gemma4">Gemma 4 31B Uncensored</option>
127
127
  <option value="spider-qwen35">Qwen 3.5 35B</option>
128
128
  <option value="spider-qwen35-uncen">Qwen 3.5 Uncensored</option>
129
129
  <option value="spider-qwen36">Qwen 3.6 35B</option>
130
- </select>
131
- <select class="model-toggle-select" id="model-toggle-coreweave" data-model="coreweave">
132
- <option value="" disabled selected>CoreWeave ▾</option>
130
+ </optgroup>
131
+ <optgroup label="COREWEAVE">
133
132
  <option value="coreweave1">CoreWeave 1 (Qwen 3.5 35B)</option>
134
133
  <option value="coreweave2">CoreWeave 2 (Qwen 3.6 35B)</option>
135
134
  <option value="coreweave3">CoreWeave 3 (Qwen 3.6 27B)</option>
136
- </select>
137
- <button class="model-toggle-btn" data-model="api">API</button>
138
- </div>
135
+ </optgroup>
136
+ <optgroup label="API">
137
+ <option value="api">Anthropic Claude Sonnet 4.6</option>
138
+ </optgroup>
139
+ </select>
139
140
  <div class="model-status" id="model-status">loading…</div>
140
141
  </div>
141
142
 
@@ -1,77 +1,50 @@
1
- // ── Model Routing Toggle ─────────────────────────────────────────────
2
- // Spider dropdown (4 models) CoreWeave dropdown (3 endpoints) API (Anthropic).
3
- // Each <select> maps an option value (the provider key) to a fully
4
- // qualified model id; clicking switches `agents.defaults.model.primary`
5
- // via config.patch.
1
+ // ── Model Routing select ─────────────────────────────────────────────
2
+ // Single <select> with three <optgroup>s (SPIDER / COREWEAVE / API).
3
+ // Picking an option switches `agents.defaults.model.primary` via
4
+ // config.patch. Compact one-row presentation no horizontal scroll,
5
+ // no vertical bloat from listing every option in the panel.
6
6
 
7
7
  (function () {
8
- // Button keysfull model id (single-button surfaces)
9
- const BUTTON_MODELS = {
10
- api: "anthropic/claude-sonnet-4-6",
11
- };
12
-
13
- // Spider option values → full model id. The option value is the
14
- // provider key in symi.json; the model id includes the HuggingFace
15
- // path after the provider prefix (parseModelRef splits on the first
16
- // slash only, so slashes in the model id survive).
17
- const SPIDER_MODELS = {
8
+ // <option value>fully-qualified model id understood by the gateway
9
+ // (provider/model split on first "/"; later slashes survive and are
10
+ // part of the model id, e.g. for HuggingFace paths).
11
+ const MODEL_IDS = {
12
+ // SPIDER
18
13
  "spider-gemma4": "spider-gemma4/TrevorJS/gemma-4-31B-it-uncensored",
19
14
  "spider-qwen35": "spider-qwen35/Qwen/Qwen3.5-35B-A3B-FP8",
20
15
  "spider-qwen35-uncen":
21
16
  "spider-qwen35-uncen/Li101/Qwen3.5-35B-A3B-Uncensored-Aggressive-safetensors",
22
17
  "spider-qwen36": "spider-qwen36/Qwen/Qwen3.6-35B-A3B-FP8",
23
- };
24
-
25
- // CoreWeave option values → full model id. Same shape as SPIDER_MODELS;
26
- // each entry corresponds to a provider block in symi.json
27
- // (qwen-cw / qwen-cw2 / qwen-cw3) all hosted at *.coreweave.app.
28
- const COREWEAVE_MODELS = {
18
+ // COREWEAVE
29
19
  coreweave1: "qwen-cw/qwen35-35b-fp8",
30
20
  coreweave2: "qwen-cw2/qwen36-35b-fp8",
31
21
  coreweave3: "qwen-cw3/qwen36-27b-fp8",
22
+ // API
23
+ api: "anthropic/claude-sonnet-4-6",
32
24
  };
33
25
 
34
- const buttons = document.querySelectorAll("#model-toggle .model-toggle-btn");
35
- const spiderSelect = document.getElementById("model-toggle-spider");
36
- const coreweaveSelect = document.getElementById("model-toggle-coreweave");
26
+ // Reverse: model id → option value (for setActive lookup).
27
+ const idToValue = {};
28
+ for (const [value, id] of Object.entries(MODEL_IDS)) {
29
+ idToValue[id] = value;
30
+ }
31
+
32
+ const select = document.getElementById("model-toggle");
37
33
  const statusEl = document.getElementById("model-status");
38
34
 
39
- if (!buttons.length && !spiderSelect && !coreweaveSelect) {
35
+ if (!select) {
40
36
  return;
41
37
  }
42
38
 
43
39
  let currentHash = null;
44
40
 
45
- // Reverse lookups: model id → option value, per surface
46
- const idToButtonKey = {};
47
- for (const [key, id] of Object.entries(BUTTON_MODELS)) {
48
- idToButtonKey[id] = key;
49
- }
50
- const idToSpiderKey = {};
51
- for (const [key, id] of Object.entries(SPIDER_MODELS)) {
52
- idToSpiderKey[id] = key;
53
- }
54
- const idToCoreweaveKey = {};
55
- for (const [key, id] of Object.entries(COREWEAVE_MODELS)) {
56
- idToCoreweaveKey[id] = key;
57
- }
58
-
59
41
  function setActive(primaryId) {
60
- const buttonKey = idToButtonKey[primaryId];
61
- buttons.forEach((btn) => {
62
- btn.classList.toggle("active", btn.dataset.model === buttonKey);
63
- });
64
-
65
- const spiderKey = idToSpiderKey[primaryId];
66
- if (spiderSelect) {
67
- spiderSelect.classList.toggle("active", Boolean(spiderKey));
68
- spiderSelect.value = spiderKey ?? "";
69
- }
70
-
71
- const coreweaveKey = idToCoreweaveKey[primaryId];
72
- if (coreweaveSelect) {
73
- coreweaveSelect.classList.toggle("active", Boolean(coreweaveKey));
74
- coreweaveSelect.value = coreweaveKey ?? "";
42
+ const value = idToValue[primaryId];
43
+ if (value) {
44
+ select.value = value;
45
+ } else {
46
+ // Unknown model id — leave the placeholder visible.
47
+ select.value = "";
75
48
  }
76
49
  }
77
50
 
@@ -131,33 +104,13 @@
131
104
  }
132
105
  });
133
106
 
134
- buttons.forEach((btn) => {
135
- btn.addEventListener("click", () => {
136
- const id = BUTTON_MODELS[btn.dataset.model];
137
- if (id) {
138
- void switchToModelId(id);
139
- }
140
- });
107
+ select.addEventListener("change", () => {
108
+ const id = MODEL_IDS[select.value];
109
+ if (id) {
110
+ void switchToModelId(id);
111
+ }
141
112
  });
142
113
 
143
- if (spiderSelect) {
144
- spiderSelect.addEventListener("change", () => {
145
- const id = SPIDER_MODELS[spiderSelect.value];
146
- if (id) {
147
- void switchToModelId(id);
148
- }
149
- });
150
- }
151
-
152
- if (coreweaveSelect) {
153
- coreweaveSelect.addEventListener("change", () => {
154
- const id = COREWEAVE_MODELS[coreweaveSelect.value];
155
- if (id) {
156
- void switchToModelId(id);
157
- }
158
- });
159
- }
160
-
161
114
  window.addEventListener("gateway:connected", () => init());
162
115
  if (window.gateway && window.gateway.connected) {
163
116
  void init();
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import fs, { constants, readFileSync } from "node:fs";
5
5
  import os from "node:os";
6
6
  import { Logger } from "tslog";
7
- import JSON5 from "json5";
7
+ import json5 from "json5";
8
8
  import chalk, { Chalk } from "chalk";
9
9
  import fs$1, { mkdtemp, rm } from "node:fs/promises";
10
10
  import { z } from "zod";
@@ -294,7 +294,7 @@ function readLoggingConfig() {
294
294
  try {
295
295
  if (!fs.existsSync(configPath)) return;
296
296
  const raw = fs.readFileSync(configPath, "utf-8");
297
- const logging = JSON5.parse(raw)?.logging;
297
+ const logging = json5.parse(raw)?.logging;
298
298
  if (!logging || typeof logging !== "object" || Array.isArray(logging)) return;
299
299
  return logging;
300
300
  } catch {
@@ -7392,7 +7392,7 @@ function safeRealpath(target) {
7392
7392
  }
7393
7393
  const defaultResolver = {
7394
7394
  readFile: (p) => fs.readFileSync(p, "utf-8"),
7395
- parseJson: (raw) => JSON5.parse(raw)
7395
+ parseJson: (raw) => json5.parse(raw)
7396
7396
  };
7397
7397
  /**
7398
7398
  * Resolves all $include directives in a parsed config object.
@@ -10623,7 +10623,7 @@ function resolveConfigPathForDeps(deps) {
10623
10623
  function normalizeDeps(overrides = {}) {
10624
10624
  return {
10625
10625
  fs: overrides.fs ?? fs,
10626
- json5: overrides.json5 ?? JSON5,
10626
+ json5: overrides.json5 ?? json5,
10627
10627
  env: overrides.env ?? process.env,
10628
10628
  homedir: overrides.homedir ?? (() => resolveRequiredHomeDir(overrides.env ?? process.env, os.homedir)),
10629
10629
  configPath: overrides.configPath ?? "",
@@ -10634,11 +10634,11 @@ function maybeLoadDotEnvForConfig(env) {
10634
10634
  if (env !== process.env) return;
10635
10635
  loadDotEnv({ quiet: true });
10636
10636
  }
10637
- function parseConfigJson5(raw, json5 = JSON5) {
10637
+ function parseConfigJson5(raw, json5$1 = json5) {
10638
10638
  try {
10639
10639
  return {
10640
10640
  ok: true,
10641
- parsed: json5.parse(raw)
10641
+ parsed: json5$1.parse(raw)
10642
10642
  };
10643
10643
  } catch (err) {
10644
10644
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symerian/symi",
3
- "version": "3.5.11",
3
+ "version": "3.5.13",
4
4
  "description": "Multi-channel AI gateway with extensible messaging integrations",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/jaysteelmind/symi#readme",