prior-cli 1.2.5 → 1.2.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/lib/agent.js CHANGED
@@ -77,7 +77,7 @@ function parseToolCalls(text) {
77
77
  } catch { /* skip */ }
78
78
  }
79
79
 
80
- // Fallback: <tool_name>{...}</tool_name>
80
+ // Fallback 1: <tool_name>{...}</tool_name>
81
81
  for (const name of TOOL_NAMES) {
82
82
  const fbRe = new RegExp(`<${name}>([\\s\\S]*?)<\\/${name}>`, 'g');
83
83
  let fm;
@@ -93,6 +93,22 @@ function parseToolCalls(text) {
93
93
  }
94
94
  }
95
95
 
96
+ // Fallback 2: <tool_name {"key":"val"}>...</tool_name> (JSON in opening tag)
97
+ for (const name of TOOL_NAMES) {
98
+ const fbRe = new RegExp(`<${name}\\s*({[\\s\\S]*?})\\s*>[\\s\\S]*?<\\/${name}>`, 'g');
99
+ let fm;
100
+ while ((fm = fbRe.exec(text)) !== null) {
101
+ const alreadyCaptured = calls.some(c => fm.index >= c.offset && fm.index < c.offset + c.raw.length);
102
+ if (alreadyCaptured) continue;
103
+ try {
104
+ const fixed = fixJsonLiterals(fm[1].trim());
105
+ const parsed = JSON.parse(fixed);
106
+ const { args, ...rest } = parsed || {};
107
+ calls.push({ raw: fm[0], offset: fm.index, name, args: args || (parsed && Object.keys(rest).length > 0 ? rest : {}) });
108
+ } catch { /* skip */ }
109
+ }
110
+ }
111
+
96
112
  return calls;
97
113
  }
98
114
 
@@ -121,6 +137,16 @@ function stripThink(text) {
121
137
  return text.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
122
138
  }
123
139
 
140
+ // Strip any residual tool-call tags the model echoes in its text output
141
+ function stripToolTags(text) {
142
+ // <tool>...</tool>
143
+ let out = text.replace(/<tool>[\s\S]*?<\/tool>/gi, '');
144
+ // <tool_name {...}>...</tool_name> AND <tool_name>...</tool_name>
145
+ const namesPattern = TOOL_NAMES.join('|');
146
+ out = out.replace(new RegExp(`<(?:${namesPattern})[^>]*>[\\s\\S]*?<\\/(?:${namesPattern})>`, 'gi'), '');
147
+ return out.trim();
148
+ }
149
+
124
150
  // ── Main agent loop ───────────────────────────────────────────
125
151
 
126
152
  const CONFIRM_TOOLS = new Set(['run_command', 'file_delete', 'file_write']);
@@ -168,13 +194,13 @@ async function runAgent({ messages, model, uncensored, cwd, projectContext, send
168
194
  // ── No tool calls → final answer ──────────────────────────
169
195
  if (calls.length === 0) {
170
196
  await trackTokenUsage(token, totalPromptTokens, totalCompletionTokens);
171
- send({ type: 'text', content: cleaned });
197
+ send({ type: 'text', content: stripToolTags(cleaned) });
172
198
  send({ type: 'done' });
173
199
  return;
174
200
  }
175
201
 
176
202
  // ── Text before first tool call ───────────────────────────
177
- const textBefore = cleaned.slice(0, calls[0].offset).trim();
203
+ const textBefore = stripToolTags(cleaned.slice(0, calls[0].offset)).trim();
178
204
  if (textBefore) send({ type: 'text', content: textBefore });
179
205
 
180
206
  history.push({ role: 'assistant', content: raw });
package/lib/tools.js CHANGED
@@ -225,23 +225,60 @@ const TOOLS = {
225
225
  };
226
226
  },
227
227
 
228
- async generate_image({ prompt, width, height, steps }, { cwd, token }) {
228
+ async generate_image({ prompt, width, height, steps }, { cwd, token, send }) {
229
229
  if (!prompt) throw new Error('"prompt" is required');
230
- // Server handles queuing, polling, and watermarking — returns base64
231
- const res = await fetch(`${CLI_BASE}/api/generate-image`, {
230
+ const totalSteps = steps || 20;
231
+ const authHdr = token ? { Authorization: `Bearer ${token}` } : {};
232
+
233
+ // Step 1: Queue
234
+ const queueRes = await fetch(`${CLI_BASE}/api/generate-image/queue`, {
232
235
  method: 'POST',
233
- headers: {
234
- 'Content-Type': 'application/json',
235
- ...(token ? { Authorization: `Bearer ${token}` } : {}),
236
- },
237
- body: JSON.stringify({ prompt, width: width || 896, height: height || 896, steps: steps || 20 }),
238
- timeout: 360000,
236
+ headers: { 'Content-Type': 'application/json', ...authHdr },
237
+ body: JSON.stringify({ prompt, width: width || 896, height: height || 896, steps: totalSteps }),
238
+ timeout: 15000,
239
239
  });
240
- if (!res.ok) {
241
- const err = await res.json().catch(() => ({}));
242
- throw new Error(err.error || err.message || `HTTP ${res.status}`);
240
+ if (!queueRes.ok) {
241
+ const err = await queueRes.json().catch(() => ({}));
242
+ throw new Error(err.error || err.message || `HTTP ${queueRes.status}`);
243
243
  }
244
- const data = await res.json();
244
+ const { promptId } = await queueRes.json();
245
+ if (!promptId) throw new Error('No promptId returned from image queue');
246
+
247
+ // Step 2: Poll with progress
248
+ let job = null;
249
+ for (let i = 0; i < 240; i++) {
250
+ await new Promise(r => setTimeout(r, 1500));
251
+ try {
252
+ const pr = await fetch(`${CLI_BASE}/api/generate-image/progress/${promptId}`, {
253
+ headers: authHdr, timeout: 5000,
254
+ });
255
+ if (pr.ok) {
256
+ job = await pr.json();
257
+ if (job && send && job.step !== undefined) {
258
+ const pct = job.percent || Math.round((job.step / (job.total || totalSteps)) * 100);
259
+ send({ type: 'tool_progress', step: job.step, total: job.total || totalSteps, percent: pct });
260
+ }
261
+ if (job && (job.status === 'done' || job.status === 'error')) break;
262
+ }
263
+ } catch { /* keep polling */ }
264
+ }
265
+
266
+ if (!job || job.status === 'error') {
267
+ throw new Error(job?.error || 'Image generation failed or timed out');
268
+ }
269
+
270
+ // Step 3: Watermark
271
+ const wmRes = await fetch(`${CLI_BASE}/api/generate-image/watermark`, {
272
+ method: 'POST',
273
+ headers: { 'Content-Type': 'application/json', ...authHdr },
274
+ body: JSON.stringify({ filename: job.filename }),
275
+ timeout: 30000,
276
+ });
277
+ if (!wmRes.ok) {
278
+ const err = await wmRes.json().catch(() => ({}));
279
+ throw new Error(err.error || `Watermark failed: HTTP ${wmRes.status}`);
280
+ }
281
+ const data = await wmRes.json();
245
282
  if (!data.filename || !data.data) throw new Error('Invalid response from image generation service');
246
283
  const savePath = path.join(cwd, data.filename);
247
284
  fs.writeFileSync(savePath, Buffer.from(data.data, 'base64'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prior-cli",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "Prior Network AI — command-line interface",
5
5
  "bin": {
6
6
  "prior": "bin/prior.js"