sphinx-understand 0.1.0 → 0.1.1

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/src/sessions.js CHANGED
@@ -364,5 +364,14 @@ export function createSessionStore({ env = process.env, generate = generateAsses
364
364
  return publicSession(session);
365
365
  });
366
366
  }
367
- return {ensure,approved,prepare,start,retryReview,refreshBudget,answer,pending,read,skip,public:publicSession};
367
+ /** Remove a check that never made a model call or produced a question. Anything with progress is kept. */
368
+ async function discard(id) {
369
+ return withLock(id, env, async () => {
370
+ const session = await readJson(sessionFile(id, env), null);
371
+ if (!session || session.status !== 'pending' || session.calls || session.questions.length || session.reviewerCheckpoint) return false;
372
+ await unlink(sessionFile(id, env)).catch(e => { if (e.code !== 'ENOENT') throw e; });
373
+ return true;
374
+ });
375
+ }
376
+ return {ensure,approved,prepare,start,retryReview,refreshBudget,answer,pending,read,skip,discard,public:publicSession};
368
377
  }
package/src/stream.js ADDED
@@ -0,0 +1,59 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+
3
+ // When a human is watching, transports stream model text into this sink. The
4
+ // final response is still parsed and validated exactly as before.
5
+ const listener = new AsyncLocalStorage();
6
+ export const withTextStream = (sink, operation) => listener.run(sink, operation);
7
+ export const textStream = () => listener.getStore();
8
+
9
+ const ESCAPES = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' };
10
+ /** Decode a JSON string field from a possibly incomplete JSON document. */
11
+ export function partialField(raw, key) {
12
+ const match = new RegExp(`"${key}"\\s*:\\s*"`, 'u').exec(raw);
13
+ if (!match) return null;
14
+ let text = '';
15
+ for (let i = match.index + match[0].length; i < raw.length; i++) {
16
+ const char = raw[i];
17
+ if (char === '"') return { text, complete: true };
18
+ if (char !== '\\') { text += char; continue; }
19
+ const next = raw[i + 1];
20
+ if (next === undefined) break;
21
+ if (next === 'u') {
22
+ const hex = raw.slice(i + 2, i + 6);
23
+ if (!/^[0-9a-fA-F]{4}$/u.test(hex)) break;
24
+ text += String.fromCharCode(parseInt(hex, 16)); i += 5; continue;
25
+ }
26
+ text += ESCAPES[next] ?? next; i++;
27
+ }
28
+ return { text, complete: false };
29
+ }
30
+
31
+ /** Parse an OpenRouter server-sent event stream into one chat completion. */
32
+ export async function readCompletionStream(body, { onContent, signal, maxBytes = 1024 * 1024 } = {}) {
33
+ const decoder = new TextDecoder();
34
+ let buffer = '', content = '', finishReason, usage, error, bytes = 0;
35
+ const handle = line => {
36
+ if (!line.startsWith('data:')) return; // comments keep the connection alive
37
+ const payload = line.slice(5).trim();
38
+ if (!payload || payload === '[DONE]') return;
39
+ let chunk;
40
+ try { chunk = JSON.parse(payload); } catch { return; }
41
+ if (chunk.error) error = chunk.error;
42
+ const choice = chunk.choices?.[0];
43
+ if (choice?.error) error = choice.error;
44
+ const delta = choice?.delta?.content;
45
+ if (typeof delta === 'string' && delta) { content += delta; try { onContent?.(content); } catch {} }
46
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
47
+ if (chunk.usage) usage = chunk.usage;
48
+ };
49
+ for await (const chunk of body) {
50
+ signal?.throwIfAborted();
51
+ bytes += chunk.length;
52
+ if (bytes > maxBytes) throw Object.assign(new Error('Response too large'), { oversized: true });
53
+ buffer += decoder.decode(chunk, { stream: true });
54
+ let newline;
55
+ while ((newline = buffer.indexOf('\n')) >= 0) { handle(buffer.slice(0, newline).replace(/\r$/u, '')); buffer = buffer.slice(newline + 1); }
56
+ }
57
+ handle(buffer);
58
+ return { ...(error ? { error } : {}), choices: [{ message: { content }, finish_reason: finishReason ?? (error ? 'error' : undefined) }], ...(usage ? { usage } : {}) };
59
+ }
package/src/terminal.js CHANGED
@@ -38,19 +38,21 @@ export function wrapText(value, width = 80, indent = '') {
38
38
  }).join('\n');
39
39
  }
40
40
 
41
- // A human face and striped nemes above the lion's body and outstretched paws.
41
+ // The Sphinx mark in half-blocks, matching the SVG logo: crowned nemes with a
42
+ // forehead band, striped lappets, eyes, mouth, and the false beard.
42
43
  export const SPHINX = [
43
- ' .-====-.',
44
- ' / .--. \\',
45
- ' / / \\ \\',
46
- ' | |o o| |',
47
- ' | | __ | |',
48
- " /| '----' |\\",
49
- ' /_|__/| |\\__|_\\',
50
- ' / |__| \\____',
51
- " / ___/____\\___ `-.",
52
- ' /___/ \\________\\',
53
- ' \\___\\____________/___/____/',
44
+ ' ▄██████████▄',
45
+ ' ▄██████████████▄',
46
+ ' ████████████████',
47
+ ' ███▄▄▄▄▄▄▄▄▄▄▄▄███',
48
+ ' ▀▀▀▀▀██ ██▀▀▀▀▀',
49
+ ' ▀▀▀▀██ ▀ ▀ ██▀▀▀▀',
50
+ ' ▀▀▀▀██ ██▀▀▀▀',
51
+ ' ▀▀▀▀██ ▀▀ ██▀▀▀▀',
52
+ ' ▀▀▀▀██▄ ▄██▀▀▀▀',
53
+ ' ▀▀▀▀███ ▄▄ ███▀▀▀▀',
54
+ ' ▀▀▀▀███ ██ ███▀▀▀▀',
55
+ ' ██████████████████',
54
56
  ];
55
57
 
56
58
  export function createTerminal({ stream = process.stdout, env = process.env, width } = {}) {
@@ -79,8 +81,8 @@ export function createTerminal({ stream = process.stdout, env = process.env, wid
79
81
  const banner = () => {
80
82
  write('');
81
83
  if (size >= 65) {
82
- const side = { 2: style.strong('sphinx'), 4: 'Outsource your thinking,', 5: 'not your understanding.' };
83
- SPHINX.forEach((line, index) => write(style.amber(line.padEnd(32)) + (side[index] || '')));
84
+ const side = { 4: style.strong('sphinx'), 6: 'Outsource your thinking,', 7: 'not your understanding.' };
85
+ SPHINX.forEach((line, index) => write(style.amber(line.padEnd(28)) + (side[index] || '')));
84
86
  } else {
85
87
  if (size >= 30) SPHINX.forEach(line => write(style.amber(line)));
86
88
  paragraph(style.strong('sphinx'));
package/src/version.js ADDED
@@ -0,0 +1,4 @@
1
+ import { readFileSync } from 'node:fs';
2
+
3
+ /** The installed package version, read once from package.json so it never drifts. */
4
+ export const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;