pi-sdk-web 0.5.3 → 0.5.5

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/server.js CHANGED
@@ -581,6 +581,11 @@ export class PiWebServer {
581
581
  break;
582
582
  }
583
583
  case "get_scoped_models":
584
+ // Refresh model catalogs (e.g. pi-deepinfra's lazy catalog swap)
585
+ // before broadcasting, so late-swapped models (zai-org/GLM-5.3-
586
+ // Flash etc.) appear in the list like they do in the TUI. Timeout
587
+ // is bounded by the refresh implementation (network wait).
588
+ await this.session.modelRuntime.refresh().catch(() => { });
584
589
  this.broadcast({
585
590
  type: "scoped_models",
586
591
  data: {
@@ -590,6 +595,11 @@ export class PiWebServer {
590
595
  thinkingLevel: s.thinkingLevel,
591
596
  })),
592
597
  available: this.session.modelRuntime.getAvailableSnapshot(),
598
+ // Settings' enabled-model patterns. TUI's scoped-models selector
599
+ // also shows configured patterns that have no matching provider
600
+ // model (diagnostic no-match) - mirror that so configured models
601
+ // (e.g. deepinfra/zai-org/GLM-5.3-Flash) aren't missing here.
602
+ configured: this.session.settingsManager.getEnabledModels() ?? [],
593
603
  },
594
604
  });
595
605
  break;
@@ -189,6 +189,12 @@ class PiWebClient {
189
189
  this.loadedResourcesEl = document.getElementById('loaded-resources');
190
190
  this.footerEl = document.getElementById('footer-line');
191
191
  this.inputEl = document.getElementById('input');
192
+ // Input history (TUI parity): all submitted inputs (messages, !bash,
193
+ // /commands) plus this session's user messages from history, browsed
194
+ // with the ↑/↓ buttons next to the input box.
195
+ this.inputHistory = [];
196
+ this.historyIndex = -1; // -1 = not browsing (composing new input)
197
+ this.historyDraft = '';
192
198
  this.sendBtn = document.getElementById('send-btn');
193
199
  this.abortBtn = document.getElementById('abort-btn');
194
200
  this.commandMenuEl = document.getElementById('command-menu');
@@ -1117,6 +1123,11 @@ class PiWebClient {
1117
1123
 
1118
1124
  appendUserMessage(message) {
1119
1125
  const text = this.messageText(message);
1126
+ // History population (TUI renderInitialMessages populateHistory):
1127
+ // session user messages seed the input history, deduped.
1128
+ if (text && this.inputHistory[this.inputHistory.length - 1] !== text) {
1129
+ this.inputHistory.push(text);
1130
+ }
1120
1131
  const div = document.createElement('div');
1121
1132
  div.className = 'message user';
1122
1133
  const role = document.createElement('div');
@@ -1570,9 +1581,41 @@ class PiWebClient {
1570
1581
  // Input
1571
1582
  // ------------------------------------------------------------------
1572
1583
 
1584
+ navigateHistory(dir) {
1585
+ // dir: -1 = previous (older), +1 = next (newer). Browsing starts from
1586
+ // the newest entry when the input is empty; editing resets the browse.
1587
+ if (this.inputHistory.length === 0) return;
1588
+ if (this.historyIndex === -1) {
1589
+ // Not browsing yet: stash the current draft, start at newest entry.
1590
+ this.historyDraft = this.inputEl.value;
1591
+ this.historyIndex = this.inputHistory.length - 1;
1592
+ } else {
1593
+ this.historyIndex += dir;
1594
+ }
1595
+ if (this.historyIndex >= this.inputHistory.length) {
1596
+ // Past the newest entry: restore the draft, stop browsing.
1597
+ this.historyIndex = -1;
1598
+ this.inputEl.value = this.historyDraft;
1599
+ } else if (this.historyIndex < 0) {
1600
+ this.historyIndex = 0;
1601
+ this.inputEl.value = this.inputHistory[0];
1602
+ } else {
1603
+ this.inputEl.value = this.inputHistory[this.historyIndex];
1604
+ }
1605
+ // Keep caret at end, keep focus in the box.
1606
+ this.inputEl.setSelectionRange(this.inputEl.value.length, this.inputEl.value.length);
1607
+ }
1608
+
1573
1609
  sendMessage() {
1574
1610
  const text = this.inputEl.value.trim();
1575
1611
  if (!text) return;
1612
+ // Record every submitted input (messages, !bash, /commands) in the
1613
+ // history - TUI parity (handleSubmit addToHistory on all paths).
1614
+ if (this.inputHistory[this.inputHistory.length - 1] !== text) {
1615
+ this.inputHistory.push(text);
1616
+ }
1617
+ this.historyIndex = -1;
1618
+ this.historyDraft = '';
1576
1619
  if (text.startsWith('!')) {
1577
1620
  // TUI parity: "!cmd" runs bash (output goes to LLM context);
1578
1621
  // "!!cmd" runs bash with excludeFromContext (output NOT sent to LLM).
@@ -1682,6 +1725,11 @@ class PiWebClient {
1682
1725
  if (this.sendBtn) {
1683
1726
  this.sendBtn.addEventListener('click', () => this.sendMessage());
1684
1727
  }
1728
+ // Input history navigation (↑/↓ buttons beside the input box)
1729
+ const histPrev = document.getElementById('history-prev');
1730
+ const histNext = document.getElementById('history-next');
1731
+ if (histPrev) histPrev.addEventListener('click', () => this.navigateHistory(-1));
1732
+ if (histNext) histNext.addEventListener('click', () => this.navigateHistory(1));
1685
1733
  if (this.abortBtn) {
1686
1734
  this.abortBtn.addEventListener('click', () => {
1687
1735
  this.send({ type: 'abort' });
@@ -2369,7 +2417,18 @@ class PiWebClient {
2369
2417
 
2370
2418
  handleScopedModels(data) {
2371
2419
  if (this.modalMode !== 'scoped-models') return;
2372
- this.scopedModelsAll = data.available || [];
2420
+ const available = data.available || [];
2421
+ // Merge settings' configured model patterns (e.g. deepinfra/zai-org/
2422
+ // GLM-5.3-Flash) that have no matching provider model - TUI's selector
2423
+ // shows these as configured entries (no-match diagnostics) too.
2424
+ const known = new Set(available.map((m) => `${m.provider}/${m.id}`));
2425
+ const configured = (data.configured || [])
2426
+ .filter((p) => !known.has(p))
2427
+ .map((p) => {
2428
+ const slash = p.indexOf('/');
2429
+ return { provider: p.slice(0, slash), id: p.slice(slash + 1), configured: true };
2430
+ });
2431
+ this.scopedModelsAll = [...available, ...configured];
2373
2432
  this.scopedModelsData = data;
2374
2433
  this.scopedModelsSelected = new Set(
2375
2434
  (data.scoped || []).map((s) => `${s.provider}/${s.id}`),
@@ -2395,7 +2454,7 @@ class PiWebClient {
2395
2454
  return (
2396
2455
  `<div class="modal-item scoped-model ${checked ? 'selected' : ''}" data-key="${key}">` +
2397
2456
  `<span class="modal-check">${checked ? '☑' : '☐'}</span>` +
2398
- `<span class="modal-item-name">${this.escapeHtml(key)}</span>` +
2457
+ `<span class="modal-item-name">${this.escapeHtml(key)}${m.configured ? ' <span class="configured-badge">[configured]</span>' : ''}</span>` +
2399
2458
  `</div>`
2400
2459
  );
2401
2460
  })
@@ -40,6 +40,10 @@
40
40
  <div id="footer-stats"></div>
41
41
  <div id="command-menu"></div>
42
42
  <div class="input-row">
43
+ <div class="history-nav">
44
+ <button id="history-prev" title="Previous input (↑)">↑</button>
45
+ <button id="history-next" title="Next input (↓)">↓</button>
46
+ </div>
43
47
  <textarea id="input" placeholder="Send a message... (Enter to send, Shift+Enter for newline)"></textarea>
44
48
  <button id="send-btn" title="Send (Enter)">Send</button>
45
49
  <button id="abort-btn" title="Abort current operation" style="display:none">Abort</button>
@@ -1475,3 +1475,38 @@ body {
1475
1475
  #usage-close:hover {
1476
1476
  color: var(--text);
1477
1477
  }
1478
+
1479
+ .configured-badge {
1480
+ font-size: 9px;
1481
+ color: var(--dim);
1482
+ background: var(--tool-pending-bg);
1483
+ padding: 1px 4px;
1484
+ border-radius: 3px;
1485
+ margin-left: 4px;
1486
+ vertical-align: middle;
1487
+ }
1488
+
1489
+ /* Input history navigation (↑/↓ buttons beside the input box) */
1490
+ .history-nav {
1491
+ display: flex;
1492
+ flex-direction: column;
1493
+ justify-content: center;
1494
+ gap: 2px;
1495
+ }
1496
+
1497
+ .history-nav button {
1498
+ width: 24px;
1499
+ height: 20px;
1500
+ font-size: 11px;
1501
+ line-height: 1;
1502
+ color: var(--dim);
1503
+ background: transparent;
1504
+ border: 1px solid var(--border);
1505
+ border-radius: 4px;
1506
+ cursor: pointer;
1507
+ }
1508
+
1509
+ .history-nav button:hover {
1510
+ color: var(--text);
1511
+ border-color: var(--accent);
1512
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-sdk-web",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "Browser Web access for Pi (AI coding agent) via the Pi SDK - standalone module, zero modification to Pi itself",
5
5
  "type": "module",
6
6
  "bin": {