@lightcone-ai/daemon 0.15.69 → 0.15.70
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/package.json
CHANGED
package/src/mcp-config.js
CHANGED
|
@@ -83,7 +83,6 @@ const SERVER_BACKED_MCP_SERVERS = new Set([
|
|
|
83
83
|
'portfolio-analysis',
|
|
84
84
|
// thin-proxy MCP services migrated to the server (roadmap §4) — every one of
|
|
85
85
|
// these uses startThinProxy() and requires the SERVER_URL/MACHINE_API_KEY/AGENT_ID triple.
|
|
86
|
-
'video-narration-planner',
|
|
87
86
|
'page-understanding',
|
|
88
87
|
'platform-policy-db',
|
|
89
88
|
'keyword-research',
|
|
@@ -39,24 +39,32 @@ function deriveDurationMs(recorderOutput) {
|
|
|
39
39
|
return lastTms > 0 ? lastTms : null;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function planSegments(plan) {
|
|
43
|
+
if (!isPlainObject(plan)) return null;
|
|
44
|
+
for (const key of ['phases', 'sections', 'segments']) {
|
|
45
|
+
if (Array.isArray(plan[key]) && plan[key].length > 0) return plan[key];
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
function derivePhaseCount({ plan, recorderOutput }) {
|
|
43
51
|
const explicit = normalizeNumberOrNull(recorderOutput?.phases);
|
|
44
52
|
if (explicit != null) return explicit;
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return null;
|
|
54
|
+
const segments = planSegments(plan);
|
|
55
|
+
return segments ? segments.length : null;
|
|
49
56
|
}
|
|
50
57
|
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
// record_url_narration is an atomic tool, not the tail of a fixed pipeline.
|
|
59
|
+
// The plan may be hand-written by the scripter or produced by plan_video_segments;
|
|
60
|
+
// it just needs a non-empty list of segments with per-segment visual action + duration
|
|
61
|
+
// so the recording stays in sync with the narration audio.
|
|
53
62
|
function assertPipelineCompliance(plan) {
|
|
54
63
|
if (!isPlainObject(plan)) return;
|
|
55
|
-
if (!plan
|
|
64
|
+
if (!planSegments(plan)) {
|
|
56
65
|
throw new Error(
|
|
57
|
-
'
|
|
58
|
-
+ '
|
|
59
|
-
+ 'Do not hand-write phases or bypass detail_sections.'
|
|
66
|
+
'record_url_narration: `plan` must contain a non-empty `phases` (or `sections` / `segments`) array — '
|
|
67
|
+
+ 'either hand-written or from plan_video_segments. Each entry should carry a visual action and a duration.'
|
|
60
68
|
);
|
|
61
69
|
}
|
|
62
70
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Thin-proxy. Real impl on lightcone server.
|
|
3
|
-
// Source of truth: src/mcp-services/video-narration-planner/
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { startThinProxy } from '../../_thin-proxy/forward.js';
|
|
6
|
-
|
|
7
|
-
await startThinProxy({
|
|
8
|
-
serverId: 'video-narration-planner',
|
|
9
|
-
serverName: 'official-video-narration-planner',
|
|
10
|
-
tools: [
|
|
11
|
-
{
|
|
12
|
-
name: 'plan_video',
|
|
13
|
-
description: 'Stage 2: plan narrative arc + phase plan for URL narration video. Enforces highlights<=3 and phases<=5.',
|
|
14
|
-
inputSchema: {
|
|
15
|
-
understanding: z.record(z.any()).describe('Stage 1 output page_understanding object.'),
|
|
16
|
-
persona: z.string().optional(),
|
|
17
|
-
target_platform: z.string(),
|
|
18
|
-
total_duration_s: z.number().int().min(20).max(90).optional(),
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
name: 'detail_sections',
|
|
23
|
-
description: 'Stage 3: take agent-written sentences, call TTS voiceover for each phase, and fill duration/dwell.',
|
|
24
|
-
inputSchema: {
|
|
25
|
-
strategy: z.record(z.any()),
|
|
26
|
-
sentences: z.array(z.object({
|
|
27
|
-
phase_id: z.string(),
|
|
28
|
-
text: z.string(),
|
|
29
|
-
})),
|
|
30
|
-
workspace_id: z.string().optional(),
|
|
31
|
-
credential_id: z.string().optional(),
|
|
32
|
-
format: z.enum(['mp3', 'wav', 'flac']).optional(),
|
|
33
|
-
strict_tts: z.boolean().optional(),
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "video-narration-planner",
|
|
3
|
-
"name": "Official Video Narration Planner MCP",
|
|
4
|
-
"version": "0.1.0",
|
|
5
|
-
"runtime": "node",
|
|
6
|
-
"entrypoint": "index.js",
|
|
7
|
-
"tool_declarations": [
|
|
8
|
-
{ "name": "plan_video", "classification": "cacheable" },
|
|
9
|
-
{ "name": "detail_sections", "classification": "mandatory" }
|
|
10
|
-
],
|
|
11
|
-
"tool_block_rules": [
|
|
12
|
-
{
|
|
13
|
-
"workspace_id": "ae63cc9e-feff-4d7e-a62e-a7a7c5fd69d9",
|
|
14
|
-
"agent_id": "91a45fd7-ce5f-4da6-9b27-e34bf7b7c0e2",
|
|
15
|
-
"tools": ["plan_video"],
|
|
16
|
-
"message": "plan_video blocked for editor_in_chief in CvMax. In this workspace, @short_video_scripter owns video planning."
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"workspace_id": "ae63cc9e-feff-4d7e-a62e-a7a7c5fd69d9",
|
|
20
|
-
"agent_id": "91a45fd7-ce5f-4da6-9b27-e34bf7b7c0e2",
|
|
21
|
-
"tools": ["detail_sections"],
|
|
22
|
-
"message": "detail_sections blocked for editor_in_chief in CvMax. In this workspace, @short_video_scripter owns video planning."
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
"smoke_test": {
|
|
26
|
-
"tool": "plan_video",
|
|
27
|
-
"arguments": {
|
|
28
|
-
"understanding": {
|
|
29
|
-
"url": "https://example.com/job-detail",
|
|
30
|
-
"core_message": "岗位职责与薪资透明,适合应届生快速判断是否投递",
|
|
31
|
-
"visual_hotspots": [
|
|
32
|
-
{ "id": "hero", "y_range": [120, 320], "weight": 10, "text_excerpt": "岗位标题与薪资" },
|
|
33
|
-
{ "id": "requirements", "y_range": [780, 1080], "weight": 8, "text_excerpt": "学历与经验要求" },
|
|
34
|
-
{ "id": "apply", "y_range": [1420, 1660], "weight": 7, "text_excerpt": "投递入口" }
|
|
35
|
-
],
|
|
36
|
-
"skip_zones": [
|
|
37
|
-
{ "y_range": [2300, 3200], "reason": "广告与推荐位" }
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
|
-
"persona": "校招求职学生",
|
|
41
|
-
"target_platform": "douyin"
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|