prior-cli 1.3.3 → 1.3.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/bin/prior.js CHANGED
@@ -568,7 +568,7 @@ async function startChat(opts = {}) {
568
568
  terminal: true,
569
569
  historySize: 100,
570
570
  completer: line => {
571
- const cmds = ['/help', '/clear', '/model ', '/tools', '/censored', '/uncensored', '/login', '/logout', '/exit'];
571
+ const cmds = ['/help', '/clear', '/censored', '/uncensored', '/login', '/logout', '/exit'];
572
572
  if (!line.startsWith('/')) return [[], line];
573
573
  const hits = cmds.filter(cmd => cmd.startsWith(line));
574
574
  return [hits, line];
@@ -599,7 +599,7 @@ async function startChat(opts = {}) {
599
599
  console.log(c.ok(' ◉') + c.muted(' Agent mode ') + c.dim('· file web shell image prior-network'));
600
600
 
601
601
  console.log(DIVIDER);
602
- console.log(c.muted(' /help /clear /model <name> /tools /exit'));
602
+ console.log(c.muted(' /help /clear /censored /uncensored /exit'));
603
603
  console.log(DIVIDER);
604
604
  console.log('');
605
605
 
@@ -617,9 +617,7 @@ async function startChat(opts = {}) {
617
617
  const SLASH_CMDS = [
618
618
  { cmd: '/help', desc: 'Show help' },
619
619
  { cmd: '/clear', desc: 'Clear screen' },
620
- { cmd: '/model', desc: 'Switch model' },
621
- { cmd: '/tools', desc: 'List tools' },
622
- { cmd: '/censored', desc: 'Load standard model (qwen)' },
620
+ { cmd: '/censored', desc: 'Load standard model (qwen)' },
623
621
  { cmd: '/uncensored', desc: 'Load uncensored model' },
624
622
  { cmd: '/usage', desc: 'Token usage today' },
625
623
  { cmd: '/learn', desc: 'Learn this directory → prior.md' },
@@ -759,39 +757,6 @@ async function startChat(opts = {}) {
759
757
  console.log(c.warn(' ✓ Prior Uncensored Model Loaded\n'));
760
758
  return loop();
761
759
 
762
- case '/model':
763
- if (args[0]) {
764
- currentModel = args[0];
765
- console.log(c.ok(` ✓ Model → ${currentModel}\n`));
766
- } else {
767
- console.log(c.muted(` Current model: ${currentModel || 'default'}\n`));
768
- }
769
- return loop();
770
-
771
- case '/tools':
772
- console.log('');
773
- console.log(c.bold(' Tools available in agent mode\n'));
774
- const tools = [
775
- ['file_read', 'Read a file'],
776
- ['file_write', 'Create or overwrite a file'],
777
- ['file_append', 'Append to a file'],
778
- ['file_list', 'List directory contents'],
779
- ['file_delete', 'Delete a file'],
780
- ['web_search', 'Search the web (Google)'],
781
- ['url_fetch', 'Fetch a webpage (Puppeteer)'],
782
- ['run_command', 'Execute a shell command'],
783
- ['clipboard_read', 'Read from clipboard'],
784
- ['clipboard_write', 'Write to clipboard'],
785
- ['generate_image', 'Generate an image (Prior Diffusion)'],
786
- ['prior_feed', 'Get Prior Network feed'],
787
- ['prior_profile', 'Get your Prior Network profile'],
788
- ];
789
- tools.forEach(([name, desc]) => {
790
- console.log(` ${c.brand('▸')} ${c.bold(name.padEnd(16))} ${c.muted(desc)}`);
791
- });
792
- console.log('');
793
- return loop();
794
-
795
760
  case '/learn': {
796
761
  // Sanity check — warn if not a project directory
797
762
  const cwdBase = path.basename(process.cwd()).toLowerCase();
@@ -946,8 +911,6 @@ Keep it under 350 words. Write prior.md now.`;
946
911
  console.log(c.muted(' /clear ') + 'Clear screen');
947
912
  console.log(c.muted(' /censored ') + 'Load standard model (qwen)');
948
913
  console.log(c.muted(' /uncensored ') + 'Load uncensored model (dolphin)');
949
- console.log(c.muted(' /model <name> ') + 'Switch to any specific model');
950
- console.log(c.muted(' /tools ') + 'List available tools');
951
914
  console.log(c.muted(' /usage ') + 'Token usage for today');
952
915
  console.log(c.muted(' /learn ') + 'Scan directory and write prior.md context file');
953
916
  console.log(c.muted(' /login ') + 'Sign in to a different account');
package/lib/agent.js CHANGED
@@ -77,6 +77,22 @@ function parseToolCalls(text) {
77
77
  } catch { /* skip */ }
78
78
  }
79
79
 
80
+ // Primary variant: <tool name="X">{"args"}</tool> (name as attribute — used by some models)
81
+ const reAttr = /<tool\s+name="([^"]+)"[^>]*>([\s\S]*?)<\/tool>/g;
82
+ while ((m = reAttr.exec(text)) !== null) {
83
+ const alreadyCaptured = calls.some(c => m.index >= c.offset && m.index < c.offset + c.raw.length);
84
+ if (alreadyCaptured) continue;
85
+ const toolName = m[1];
86
+ try {
87
+ const body = m[2].trim();
88
+ const parsed = body ? JSON.parse(fixJsonLiterals(body)) : {};
89
+ const { args, ...rest } = parsed;
90
+ calls.push({ raw: m[0], offset: m.index, name: toolName, args: args || (Object.keys(rest).length > 0 ? rest : {}) });
91
+ } catch {
92
+ calls.push({ raw: m[0], offset: m.index, name: toolName, args: {} });
93
+ }
94
+ }
95
+
80
96
  // Fallback 1: <tool_name>{...}</tool_name>
81
97
  for (const name of TOOL_NAMES) {
82
98
  const fbRe = new RegExp(`<${name}>([\\s\\S]*?)<\\/${name}>`, 'g');
@@ -109,6 +125,21 @@ function parseToolCalls(text) {
109
125
  }
110
126
  }
111
127
 
128
+ // Fallback 3: <tool_name key="val" ...>...</tool_name> (HTML attribute style — used by dolphin)
129
+ for (const name of TOOL_NAMES) {
130
+ const fbRe = new RegExp(`<${name}((?:\\s+[a-zA-Z_]\\w*="[^"]*")+)\\s*(?:>[\\s\\S]*?<\\/${name}>|/>)`, 'g');
131
+ let fm;
132
+ while ((fm = fbRe.exec(text)) !== null) {
133
+ const alreadyCaptured = calls.some(c => fm.index >= c.offset && fm.index < c.offset + c.raw.length);
134
+ if (alreadyCaptured) continue;
135
+ const args = {};
136
+ const attrRe = /([a-zA-Z_]\w*)="([^"]*)"/g;
137
+ let am;
138
+ while ((am = attrRe.exec(fm[1])) !== null) args[am[1]] = am[2];
139
+ calls.push({ raw: fm[0], offset: fm.index, name, args });
140
+ }
141
+ }
142
+
112
143
  return calls;
113
144
  }
114
145
 
@@ -137,13 +168,31 @@ function stripThink(text) {
137
168
  return text.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
138
169
  }
139
170
 
171
+ // Some models (dolphin) hallucinate fake conversation turns after their response.
172
+ // Truncate at common boundary markers to prevent those being parsed as real tool calls.
173
+ function truncateAtFakeTurn(text) {
174
+ const MARKERS = [
175
+ /\n[-─]{3,}\s*\n+(?:user|human)\b/i,
176
+ /\n+(?:user|human)\s*:\s/i,
177
+ /\n+(?:assistant|prior)\s*:\s/i,
178
+ ];
179
+ let cut = text.length;
180
+ for (const re of MARKERS) {
181
+ const m = re.exec(text);
182
+ if (m && m.index < cut) cut = m.index;
183
+ }
184
+ return text.slice(0, cut);
185
+ }
186
+
140
187
  // Strip any residual tool-call tags the model echoes in its text output
141
188
  function stripToolTags(text) {
142
189
  // <tool>...</tool>
143
190
  let out = text.replace(/<tool>[\s\S]*?<\/tool>/gi, '');
144
- // <tool_name {...}>...</tool_name> AND <tool_name>...</tool_name>
145
191
  const namesPattern = TOOL_NAMES.join('|');
192
+ // <tool_name ...>...</tool_name> (with or without attributes/JSON)
146
193
  out = out.replace(new RegExp(`<(?:${namesPattern})[^>]*>[\\s\\S]*?<\\/(?:${namesPattern})>`, 'gi'), '');
194
+ // Self-closing or unclosed: <tool_name attr="val" /> or <tool_name attr="val">
195
+ out = out.replace(new RegExp(`<(?:${namesPattern})(?:\\s[^>]*)?\\s*/?>`, 'gi'), '');
147
196
  return out.trim();
148
197
  }
149
198
 
@@ -187,8 +236,8 @@ async function runAgent({ messages, model, uncensored, cwd, projectContext, send
187
236
  totalCompletionTokens += result.completionTokens || 0;
188
237
 
189
238
  const raw = result.content;
190
- const cleaned = stripThink(raw)
191
- .replace(/<tool_result[\s\S]*?<\/tool_result>/gi, '')
239
+ const cleaned = truncateAtFakeTurn(stripThink(raw)
240
+ .replace(/<tool_result[\s\S]*?<\/tool_result>/gi, ''))
192
241
  .trim();
193
242
 
194
243
  const calls = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prior-cli",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Prior Network AI — command-line interface",
5
5
  "bin": {
6
6
  "prior": "bin/prior.js"