tuna-agent 0.1.157 → 0.1.159
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.
|
@@ -407,6 +407,15 @@ Rules:
|
|
|
407
407
|
}
|
|
408
408
|
// Single source of truth for the master-cast prompt block (used by Phase-1
|
|
409
409
|
// and the post-Phase-2 cast reconciliation so the format never drifts).
|
|
410
|
+
//
|
|
411
|
+
// The [CHARACTER CAST LIST] header carries CRITICAL RULES that tell the
|
|
412
|
+
// downstream image generator (Veo3 / FlowKit) how to render the cast. Rule
|
|
413
|
+
// #5 specifically prevents identity-morphing — even when the source video
|
|
414
|
+
// has siblings or look-alike characters, the generated reference sheet
|
|
415
|
+
// must give each character distinctly different facial structures so the
|
|
416
|
+
// per-scene Veo3 renders don't drift into the same face. This rule got
|
|
417
|
+
// lost in a prior refactor; restored to match the reference clone-tool
|
|
418
|
+
// (~/Downloads/if is_character_driven.txt).
|
|
410
419
|
function buildMasterCastPrompt(videoStyle, characters) {
|
|
411
420
|
if (!characters.length)
|
|
412
421
|
return '';
|
|
@@ -414,8 +423,15 @@ function buildMasterCastPrompt(videoStyle, characters) {
|
|
|
414
423
|
const castList = characters.map(c => `- ${c.name}: ${c.description}`).join('\n');
|
|
415
424
|
return (`[AESTHETIC & STYLE]\n${styleLine}\n` +
|
|
416
425
|
`[COMPOSITION & LAYOUT]\nCharacter Reference Sheet. Full-body side-by-side.\n` +
|
|
417
|
-
`[CHARACTER CAST LIST]
|
|
418
|
-
`
|
|
426
|
+
`[CHARACTER CAST LIST] (CRITICAL RULES: ` +
|
|
427
|
+
`1. Max 5 INDIVIDUAL characters. ` +
|
|
428
|
+
`2. STRICTLY PROHIBIT collective nouns, groups, crowds, or plurals. ` +
|
|
429
|
+
`3. If a group exists, pick ONLY the most prominent 1 or 2 individuals. ` +
|
|
430
|
+
`4. Detail unique physical appearance and clothing. ` +
|
|
431
|
+
`5. FORCE UNIQUE facial and physical structures for EVERY character ` +
|
|
432
|
+
`(assign distinct body types, face shapes, wrinkles, or accessories) ` +
|
|
433
|
+
`to prevent identity morphing. List with '- '. English.)\n${castList}\n` +
|
|
434
|
+
`[TECHNICAL SPECIFICATIONS]\nHigh detail, 8k resolution.`);
|
|
419
435
|
}
|
|
420
436
|
// Post-Phase-2 cast RECONCILE. Phase-1 only sees a 30-frame sample so it can
|
|
421
437
|
// miss a recurring character; the per-scene visionDescribe pass, however,
|
package/dist/daemon/index.d.ts
CHANGED
package/dist/daemon/index.js
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
|
+
// ⚠ MUST be first: side-effect import that populates process.env from
|
|
2
|
+
// ~/.tuna-agent/.env BEFORE any other module captures env at its top
|
|
3
|
+
// level. See load-env.ts for the long-form explanation.
|
|
4
|
+
import './load-env.js';
|
|
1
5
|
import fs from 'fs';
|
|
2
6
|
import path from 'path';
|
|
3
7
|
import os from 'os';
|
|
4
|
-
// Load .env from ~/.tuna-agent/.env if exists (ensure OPENAI_API_KEY etc. available)
|
|
5
|
-
const envPath = path.join(os.homedir(), '.tuna-agent', '.env');
|
|
6
|
-
if (fs.existsSync(envPath)) {
|
|
7
|
-
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
8
|
-
for (const line of envContent.split('\n')) {
|
|
9
|
-
const match = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)\s*$/);
|
|
10
|
-
if (match && !process.env[match[1]]) {
|
|
11
|
-
process.env[match[1]] = match[2].replace(/^["']|["']$/g, '');
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
8
|
import { AgentWebSocketClient } from './ws-client.js';
|
|
16
9
|
import { removePid, loadConfig, saveConfig } from '../config/store.js';
|
|
17
10
|
import { validateMessage } from '../utils/message-schemas.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Side-effect module: load ~/.tuna-agent/.env into process.env BEFORE any
|
|
2
|
+
// other daemon module reads process.env at its top level.
|
|
3
|
+
//
|
|
4
|
+
// daemon/index.ts must import this FIRST so the side-effect runs before
|
|
5
|
+
// modules like analyze-video-handler.ts capture `process.env.OPENAI_API_KEY`
|
|
6
|
+
// into a module-top const. ESM imports execute in dependency order, so
|
|
7
|
+
// putting this import line above the analyze-video-handler import (directly
|
|
8
|
+
// or transitively) guarantees the env is populated when those consts are
|
|
9
|
+
// evaluated.
|
|
10
|
+
//
|
|
11
|
+
// Previously the env loader lived inline in daemon/index.ts AFTER the
|
|
12
|
+
// imports — but ES module imports are processed BEFORE any executable code
|
|
13
|
+
// in the file, so analyze-video-handler captured OPENAI_API_KEY='' and the
|
|
14
|
+
// analyze flow died with 'OPENAI_API_KEY not set' even though the .env
|
|
15
|
+
// file was correct.
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
const envPath = path.join(os.homedir(), '.tuna-agent', '.env');
|
|
20
|
+
if (fs.existsSync(envPath)) {
|
|
21
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
22
|
+
for (const line of envContent.split('\n')) {
|
|
23
|
+
const match = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)\s*$/);
|
|
24
|
+
if (match && !process.env[match[1]]) {
|
|
25
|
+
process.env[match[1]] = match[2].replace(/^["']|["']$/g, '');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|