tuna-agent 0.1.153 → 0.1.155
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.
|
@@ -247,8 +247,10 @@ Voiceover during this scene: "${voiceoverText || '(none)'}"`;
|
|
|
247
247
|
{ text: promptText },
|
|
248
248
|
...frames.map(b64 => ({ inlineData: { mimeType: 'image/jpeg', data: b64 } })),
|
|
249
249
|
];
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
// Gemini 2.5 Flash (cheapest). geminiGenerate disables thinking for
|
|
251
|
+
// 2.5-flash so the 512 budget isn't starved → non-empty descriptions.
|
|
252
|
+
const { text, usage } = await geminiGenerate(parts, 512, 'gemini-2.5-flash');
|
|
253
|
+
cost?.geminiVision('vision', usage, 'gemini-2.5-flash');
|
|
252
254
|
return text;
|
|
253
255
|
}
|
|
254
256
|
// Phase 1 (the strong part of AI_Video_Clone, ported): ONE gpt-4o call over
|
|
@@ -291,18 +293,18 @@ Rules:
|
|
|
291
293
|
- NO GROUP ENTRIES (CRITICAL): NEVER output a collective/crowd label as a single entry — forbidden: "VILLAGERS", "LADIES GROUP", "KNITTING GROUP", "CROWD", "GROUP OF ...", any "*_GROUP". If 2+ similar secondary people RECUR across scenes, list them as SEPARATE numbered individuals (e.g. WOMAN_1, WOMAN_2, WOMAN_3), each with its OWN distinct face/hair/body/age. Only a truly anonymous one-off background that never recurs may be omitted entirely.
|
|
292
294
|
- characters.description: ENGLISH only, factual, no camera/action words.
|
|
293
295
|
- DISTINCT FACES (CRITICAL): every character MUST have a HIGHLY UNIQUE facial structure, a distinct hairstyle, a specific body type and a clearly different age. NEVER reuse the same or a similar facial description for two characters — they must look completely different from one another.`;
|
|
294
|
-
// Phase-1 on Gemini
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
// so
|
|
296
|
+
// Phase-1 on Gemini 2.5 Flash (cheapest) with a dense 30-frame seed. 1
|
|
297
|
+
// call/video; final cast recall is double-covered by the reconcile pass.
|
|
298
|
+
// geminiGenerate disables thinking for 2.5-flash + generous 3000 output
|
|
299
|
+
// budget so the JSON answer is never starved (was empty without this).
|
|
298
300
|
const parts = [
|
|
299
301
|
{ text: promptText },
|
|
300
302
|
...frames.map(b64 => ({ inlineData: { mimeType: 'image/jpeg', data: b64 } })),
|
|
301
303
|
];
|
|
302
|
-
const { text: rawTxt, usage } = await geminiGenerate(parts, 3000, 'gemini-
|
|
304
|
+
const { text: rawTxt, usage } = await geminiGenerate(parts, 3000, 'gemini-2.5-flash');
|
|
303
305
|
if (!rawTxt)
|
|
304
306
|
return empty;
|
|
305
|
-
cost?.geminiVision('phase1', usage, 'gemini-
|
|
307
|
+
cost?.geminiVision('phase1', usage, 'gemini-2.5-flash');
|
|
306
308
|
let parsed = {};
|
|
307
309
|
try {
|
|
308
310
|
const m = rawTxt.match(/\{[\s\S]*\}/);
|
|
@@ -118,21 +118,26 @@ export async function handleClaudePrompt(ws, code, taskId, prompt, systemPrompt,
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
// ─── Handler: claude_prompt_stream (prompt → streamed text + JSON result) ────
|
|
121
|
-
// Track active stream tasks by
|
|
121
|
+
// Track active stream tasks by taskId (UNIQUE per request). Was keyed by
|
|
122
|
+
// `code` (the shared pair code) which made concurrent claude_prompt_stream
|
|
123
|
+
// calls abort each other — fatal for the batched clone pool (5 parallel
|
|
124
|
+
// chunks → siblings killed → batches hang at 0). taskId is unique so streams
|
|
125
|
+
// run independently; a superseded request gets a fresh taskId anyway.
|
|
122
126
|
const _activeStreamTasks = new Map();
|
|
123
127
|
export async function handleClaudePromptStream(ws, code, taskId, prompt, systemPrompt) {
|
|
124
128
|
console.log(`[claude_prompt_stream] Received: ${prompt.substring(0, 100)}...`);
|
|
125
|
-
//
|
|
126
|
-
|
|
129
|
+
// Per-taskId (unique): never aborts a concurrent sibling. (Re-clicked
|
|
130
|
+
// Regenerate arrives with a new taskId; the old one finishes on its own.)
|
|
131
|
+
const prev = _activeStreamTasks.get(taskId);
|
|
127
132
|
if (prev) {
|
|
128
|
-
console.log(`[claude_prompt_stream] Aborting previous task for
|
|
133
|
+
console.log(`[claude_prompt_stream] Aborting previous task for taskId=${taskId}`);
|
|
129
134
|
prev.abort();
|
|
130
135
|
}
|
|
131
136
|
const abortController = new AbortController();
|
|
132
|
-
_activeStreamTasks.set(
|
|
137
|
+
_activeStreamTasks.set(taskId, abortController);
|
|
133
138
|
if (!hasContentCreator()) {
|
|
134
139
|
const error = 'content-creator agent not found on this machine';
|
|
135
|
-
_activeStreamTasks.delete(
|
|
140
|
+
_activeStreamTasks.delete(taskId);
|
|
136
141
|
ws.sendExtensionDone(code, taskId, { error });
|
|
137
142
|
return;
|
|
138
143
|
}
|
|
@@ -190,11 +195,11 @@ export async function handleClaudePromptStream(ws, code, taskId, prompt, systemP
|
|
|
190
195
|
}
|
|
191
196
|
catch { }
|
|
192
197
|
}
|
|
193
|
-
_activeStreamTasks.delete(
|
|
198
|
+
_activeStreamTasks.delete(taskId);
|
|
194
199
|
ws.sendExtensionDone(code, taskId, { result: parsed, raw: text });
|
|
195
200
|
}
|
|
196
201
|
catch (err) {
|
|
197
|
-
_activeStreamTasks.delete(
|
|
202
|
+
_activeStreamTasks.delete(taskId);
|
|
198
203
|
if (abortController.signal.aborted) {
|
|
199
204
|
console.log(`[claude_prompt_stream] Aborted (replaced by new task)`);
|
|
200
205
|
return; // Don't send error — new task is already running
|