tuna-agent 0.1.34 → 0.1.36
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.
|
@@ -7,7 +7,7 @@ import { planTask, chatWithPM } from '../pm/planner.js';
|
|
|
7
7
|
import { savePMState, clearPMState } from '../daemon/pm-state.js';
|
|
8
8
|
import { simplifyMarkdown, waitForInput, sessionToPayload, executePlanAndReport, } from '../utils/execution-helpers.js';
|
|
9
9
|
import { downloadAttachments, cleanupAttachments } from '../utils/image-download.js';
|
|
10
|
-
import { writeAgentFolderMcpConfig } from '../mcp/setup.js';
|
|
10
|
+
import { writeAgentFolderMcpConfig, fetchMem0Count } from '../mcp/setup.js';
|
|
11
11
|
export class ClaudeCodeAdapter {
|
|
12
12
|
type = 'claude-code';
|
|
13
13
|
displayName = 'Claude Code';
|
|
@@ -119,10 +119,18 @@ export class ClaudeCodeAdapter {
|
|
|
119
119
|
const cwd = task.repoPath || defaultWorkspace;
|
|
120
120
|
if (!fs.existsSync(cwd))
|
|
121
121
|
fs.mkdirSync(cwd, { recursive: true });
|
|
122
|
-
// Write MCP config to agent folder .
|
|
123
|
-
// Claude Code reads
|
|
122
|
+
// Write MCP config to agent folder .mcp.json on first round
|
|
123
|
+
// Claude Code reads .mcp.json automatically for project-level MCPs
|
|
124
124
|
if (round === 0) {
|
|
125
125
|
writeAgentFolderMcpConfig(cwd, this.agentConfig);
|
|
126
|
+
// Seed memoryCount from Mem0 so it survives daemon restarts (non-blocking)
|
|
127
|
+
const agentFolderName = path.basename(cwd);
|
|
128
|
+
fetchMem0Count(agentFolderName).then(count => {
|
|
129
|
+
if (count > this.metrics.memoryCount) {
|
|
130
|
+
this.metrics.memoryCount = count;
|
|
131
|
+
console.log(`[Metrics] Seeded memoryCount=${count} from Mem0 for "${agentFolderName}"`);
|
|
132
|
+
}
|
|
133
|
+
}).catch(() => { });
|
|
126
134
|
}
|
|
127
135
|
// Skills/scheduled tasks use MCP tools (knowledge sync) → disable agentTeam
|
|
128
136
|
// Manual chat tasks may spawn sub-agents → keep agentTeam enabled
|
|
@@ -26,7 +26,7 @@ export interface VideoRecord {
|
|
|
26
26
|
aspectRatio?: string;
|
|
27
27
|
}
|
|
28
28
|
export declare function handleGetHistory(ws: AgentWebSocketClient, code: string, taskId: string): void;
|
|
29
|
-
export declare function handleGenerateIdeas(ws: AgentWebSocketClient, code: string, taskId: string, topic: string, styleName?: string, styleDesc?: string, language?: string): Promise<void>;
|
|
29
|
+
export declare function handleGenerateIdeas(ws: AgentWebSocketClient, code: string, taskId: string, topic: string, styleName?: string, styleDesc?: string, language?: string, count?: number, ideasInstruction?: string): Promise<void>;
|
|
30
30
|
export declare function handleGenerateScript(ws: AgentWebSocketClient, code: string, taskId: string, idea: string, topic: string, style?: string, duration?: number, language?: string, styleName?: string, styleGuidance?: string): Promise<void>;
|
|
31
31
|
export declare function handleRetryVideo(ws: AgentWebSocketClient, code: string, taskId: string, videoId: string): void;
|
|
32
32
|
export declare function handleGenerateScene(ws: AgentWebSocketClient, code: string, taskId: string, sceneIdx: number, prompt: string, aspectRatio: string): Promise<void>;
|
|
@@ -64,7 +64,7 @@ function hasContentCreator() {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
// ─── Handler: generate_ideas ──────────────────────────────────────────────────
|
|
67
|
-
export async function handleGenerateIdeas(ws, code, taskId, topic, styleName, styleDesc, language) {
|
|
67
|
+
export async function handleGenerateIdeas(ws, code, taskId, topic, styleName, styleDesc, language, count, ideasInstruction) {
|
|
68
68
|
if (!hasContentCreator()) {
|
|
69
69
|
const error = 'content-creator agent not found on this machine';
|
|
70
70
|
console.error(`[generate_ideas] ${error}`);
|
|
@@ -86,12 +86,16 @@ export async function handleGenerateIdeas(ws, code, taskId, topic, styleName, st
|
|
|
86
86
|
systemParts.push(`The video style is "${styleName}"${styleDesc ? `: ${styleDesc}` : ''}.`);
|
|
87
87
|
systemParts.push(`Generate ideas that are specifically suited for this style.`);
|
|
88
88
|
}
|
|
89
|
+
if (ideasInstruction && ideasInstruction.trim()) {
|
|
90
|
+
systemParts.push(`\n\nAdditional instructions for idea generation:\n${ideasInstruction.trim()}`);
|
|
91
|
+
}
|
|
89
92
|
const systemPrompt = systemParts.join(' ');
|
|
90
93
|
const langReq = resolvedLang === 'vi'
|
|
91
94
|
? `- Titles must be in Vietnamese, natural and engaging`
|
|
92
95
|
: `- Titles must be in English, natural and engaging`;
|
|
96
|
+
const n = count && count > 0 ? count : 10;
|
|
93
97
|
const prompt = [
|
|
94
|
-
`Generate exactly
|
|
98
|
+
`Generate exactly ${n} viral YouTube Shorts video ideas for the topic: "${topic}".`,
|
|
95
99
|
``,
|
|
96
100
|
`Requirements:`,
|
|
97
101
|
`- Each idea is a catchy, scroll-stopping video title`,
|
|
@@ -100,7 +104,7 @@ export async function handleGenerateIdeas(ws, code, taskId, topic, styleName, st
|
|
|
100
104
|
`- Mix different angles/formats for variety`,
|
|
101
105
|
...(styleName ? [`- Ideas must fit the "${styleName}" video style${styleDesc ? ` (${styleDesc})` : ''}`] : []),
|
|
102
106
|
``,
|
|
103
|
-
`Respond with ONLY a JSON array of
|
|
107
|
+
`Respond with ONLY a JSON array of ${n} strings. No explanation, no markdown, no wrapping.`,
|
|
104
108
|
`Example format: ["title 1","title 2","title 3","title 4","title 5"]`,
|
|
105
109
|
].join('\n');
|
|
106
110
|
try {
|
|
@@ -127,9 +131,9 @@ export async function handleGenerateIdeas(ws, code, taskId, topic, styleName, st
|
|
|
127
131
|
}
|
|
128
132
|
catch { /* skip non-JSON matches */ }
|
|
129
133
|
}
|
|
130
|
-
// Prefer the array closest to
|
|
134
|
+
// Prefer the array closest to n items
|
|
131
135
|
if (arrays.length > 0) {
|
|
132
|
-
ideas = arrays.reduce((best, cur) => Math.abs(cur.length -
|
|
136
|
+
ideas = arrays.reduce((best, cur) => Math.abs(cur.length - n) < Math.abs(best.length - n) ? cur : best);
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
catch { /* fall through to fallback */ }
|
package/dist/daemon/index.js
CHANGED
|
@@ -367,13 +367,13 @@ ${skillContent.slice(0, 15000)}`;
|
|
|
367
367
|
}
|
|
368
368
|
if (extTask === 'generate_ideas') {
|
|
369
369
|
(async () => {
|
|
370
|
-
await handleGenerateIdeas(ws, extCode, extTaskId, msg.topic, msg.styleName, msg.styleDesc, msg.language);
|
|
370
|
+
await handleGenerateIdeas(ws, extCode, extTaskId, msg.topic, msg.styleName, msg.styleDesc, msg.language, msg.count, msg.ideasInstruction);
|
|
371
371
|
})();
|
|
372
372
|
break;
|
|
373
373
|
}
|
|
374
374
|
if (extTask === 'generate_script') {
|
|
375
375
|
(async () => {
|
|
376
|
-
await handleGenerateScript(ws, extCode, extTaskId, msg.idea, msg.topic, msg.style, msg.duration, msg.language, msg.styleName, msg.styleGuidance);
|
|
376
|
+
await handleGenerateScript(ws, extCode, extTaskId, msg.idea, msg.topic, msg.style, msg.duration, msg.language, msg.styleName, (msg.scriptInstruction || msg.styleGuidance));
|
|
377
377
|
})();
|
|
378
378
|
break;
|
|
379
379
|
}
|
package/dist/mcp/setup.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { AgentConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fetch Mem0 memory count for an agent via HTTP API.
|
|
4
|
+
* Used to initialize memoryCount on daemon startup.
|
|
5
|
+
* Returns 0 if MEM0_HTTP_BASE is not set or request fails.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fetchMem0Count(agentName: string): Promise<number>;
|
|
2
8
|
/**
|
|
3
9
|
* Call Mem0 add_memory via mem0-add script (bypasses OpenMemory API).
|
|
4
10
|
* Calls `mem0-add <text>` directly or via SSH — simple, reliable.
|
package/dist/mcp/setup.js
CHANGED
|
@@ -7,9 +7,11 @@ const MCP_CONFIG_DIR = path.join(process.env.HOME || '', '.tuna-agent');
|
|
|
7
7
|
const MCP_CONFIG_PATH = path.join(MCP_CONFIG_DIR, 'mcp-config.json');
|
|
8
8
|
// Mem0 config from environment variables
|
|
9
9
|
// MEM0_SSH_HOST: "local" = run mem0-mcp directly, "user@host" = run via SSH, unset = disabled
|
|
10
|
+
// MEM0_HTTP_BASE: HTTP base URL of OpenMemory API (e.g. http://redrop.ddns.net:8765)
|
|
10
11
|
const MEM0_SSH_HOST = process.env.MEM0_SSH_HOST;
|
|
11
12
|
const MEM0_SSH_PORT = process.env.MEM0_SSH_PORT || '22';
|
|
12
13
|
const MEM0_SSH_KEY = process.env.MEM0_SSH_KEY;
|
|
14
|
+
const MEM0_HTTP_BASE = process.env.MEM0_HTTP_BASE || '';
|
|
13
15
|
const MEM0_ENV_VARS = {
|
|
14
16
|
MEM0_API_BASE: 'http://127.0.0.1:8765',
|
|
15
17
|
MEM0_QDRANT_URL: 'http://127.0.0.1:6333',
|
|
@@ -20,6 +22,27 @@ const MEM0_ENV_VARS = {
|
|
|
20
22
|
MEM0_NEO4J_USER: 'neo4j',
|
|
21
23
|
MEM0_NEO4J_PASSWORD: 'mem0graph',
|
|
22
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Fetch Mem0 memory count for an agent via HTTP API.
|
|
27
|
+
* Used to initialize memoryCount on daemon startup.
|
|
28
|
+
* Returns 0 if MEM0_HTTP_BASE is not set or request fails.
|
|
29
|
+
*/
|
|
30
|
+
export async function fetchMem0Count(agentName) {
|
|
31
|
+
if (!MEM0_HTTP_BASE)
|
|
32
|
+
return 0;
|
|
33
|
+
try {
|
|
34
|
+
const safeName = agentName.replace(/[^a-zA-Z0-9_-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'agent';
|
|
35
|
+
const url = `${MEM0_HTTP_BASE}/api/v1/memories/?user_id=${encodeURIComponent(safeName)}&page=1&page_size=1`;
|
|
36
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
37
|
+
if (!res.ok)
|
|
38
|
+
return 0;
|
|
39
|
+
const data = await res.json();
|
|
40
|
+
return data.total || 0;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
23
46
|
/**
|
|
24
47
|
* Call Mem0 add_memory via mem0-add script (bypasses OpenMemory API).
|
|
25
48
|
* Calls `mem0-add <text>` directly or via SSH — simple, reliable.
|