mulmocast 2.6.20 → 2.6.22
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/README.md +36 -0
- package/lib/actions/audio.js +3 -0
- package/lib/actions/image_references.js +3 -0
- package/lib/actions/images.js +3 -0
- package/lib/actions/translate.d.ts +2 -0
- package/lib/actions/translate.js +5 -0
- package/lib/agents/image_genai_agent.js +12 -3
- package/lib/agents/image_openai_agent.js +20 -5
- package/lib/agents/image_replicate_agent.js +9 -3
- package/lib/agents/lipsync_replicate_agent.js +10 -5
- package/lib/agents/movie_genai_agent.js +22 -4
- package/lib/agents/movie_replicate_agent.js +16 -5
- package/lib/agents/sound_effect_replicate_agent.js +4 -4
- package/lib/agents/tts_elevenlabs_agent.js +12 -1
- package/lib/agents/tts_gemini_agent.js +59 -32
- package/lib/agents/tts_google_agent.js +9 -1
- package/lib/agents/tts_kotodama_agent.js +9 -1
- package/lib/agents/tts_openai_agent.js +9 -1
- package/lib/cli/commands/audio/handler.js +2 -1
- package/lib/cli/commands/bundle/handler.js +2 -1
- package/lib/cli/commands/html/handler.js +2 -1
- package/lib/cli/commands/image/handler.js +2 -1
- package/lib/cli/commands/markdown/handler.js +2 -1
- package/lib/cli/commands/movie/handler.js +2 -1
- package/lib/cli/commands/pdf/handler.js +2 -1
- package/lib/cli/commands/tool/whisper/handler.js +60 -37
- package/lib/cli/commands/translate/handler.js +2 -1
- package/lib/cli/helpers.d.ts +1 -0
- package/lib/cli/helpers.js +46 -0
- package/lib/tools/create_mulmo_script_from_url.d.ts +2 -2
- package/lib/tools/create_mulmo_script_from_url.js +5 -2
- package/lib/tools/create_mulmo_script_interactively.d.ts +1 -1
- package/lib/tools/create_mulmo_script_interactively.js +6 -3
- package/lib/tools/deep_research.d.ts +2 -1
- package/lib/tools/deep_research.js +3 -1
- package/lib/tools/story_to_script.d.ts +3 -1
- package/lib/tools/story_to_script.js +3 -1
- package/lib/types/agent.d.ts +2 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/lib/types/type.d.ts +3 -0
- package/lib/types/usage.d.ts +32 -0
- package/lib/types/usage.js +1 -0
- package/lib/utils/context.d.ts +2 -0
- package/lib/utils/context.js +2 -0
- package/lib/utils/filters.js +3 -6
- package/lib/utils/replicate_usage.d.ts +5 -0
- package/lib/utils/replicate_usage.js +11 -0
- package/lib/utils/usage_callback.d.ts +4 -0
- package/lib/utils/usage_callback.js +93 -0
- package/lib/utils/usage_collector.d.ts +12 -0
- package/lib/utils/usage_collector.js +18 -0
- package/package.json +6 -6
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type Replicate from "replicate";
|
|
2
|
+
export declare const runReplicateWithMetrics: (replicate: Replicate, identifier: `${string}/${string}` | `${string}/${string}:${string}`, input: object, signal?: AbortSignal) => Promise<{
|
|
3
|
+
output: unknown;
|
|
4
|
+
predictSec?: number;
|
|
5
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Capture Replicate's exact billed seconds (`metrics.predict_time`) via the
|
|
2
|
+
// progress callback on `replicate.run()`. Avoids switching the four
|
|
3
|
+
// replicate agents from `.run()` to `predictions.create()` + poll, which
|
|
4
|
+
// would be a much bigger blast radius.
|
|
5
|
+
export const runReplicateWithMetrics = async (replicate, identifier, input, signal) => {
|
|
6
|
+
let lastPrediction;
|
|
7
|
+
const output = await replicate.run(identifier, { input, signal }, (prediction) => {
|
|
8
|
+
lastPrediction = prediction;
|
|
9
|
+
});
|
|
10
|
+
return { output, predictSec: lastPrediction?.metrics?.predict_time };
|
|
11
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CallbackFunction } from "graphai";
|
|
2
|
+
import type { MulmoStudioContext } from "../types/type.js";
|
|
3
|
+
import type { UsageCollectorAPI } from "../types/usage.js";
|
|
4
|
+
export declare const createUsageCallback: (target: MulmoStudioContext | UsageCollectorAPI | undefined) => CallbackFunction;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { NodeState } from "graphai";
|
|
2
|
+
// @graphai/* LLM agents (openAIAgent / geminiAgent / anthropicAgent / groqAgent)
|
|
3
|
+
// return usage in the OpenAI chat-completions wire shape:
|
|
4
|
+
// { prompt_tokens, completion_tokens, total_tokens }
|
|
5
|
+
// without provider/model on the usage object. We derive provider from the
|
|
6
|
+
// node's agentId and model from the node's params or the spread response.
|
|
7
|
+
const LLM_AGENT_TO_PROVIDER = {
|
|
8
|
+
openAIAgent: "openai",
|
|
9
|
+
geminiAgent: "google",
|
|
10
|
+
anthropicAgent: "anthropic",
|
|
11
|
+
groqAgent: "groq",
|
|
12
|
+
};
|
|
13
|
+
const isAgentUsage = (value) => {
|
|
14
|
+
if (!value || typeof value !== "object")
|
|
15
|
+
return false;
|
|
16
|
+
const { provider, model } = value;
|
|
17
|
+
return typeof provider === "string" && typeof model === "string";
|
|
18
|
+
};
|
|
19
|
+
const extractLLMUsage = (log) => {
|
|
20
|
+
const provider = log.agentId ? LLM_AGENT_TO_PROVIDER[log.agentId] : undefined;
|
|
21
|
+
if (!provider)
|
|
22
|
+
return undefined;
|
|
23
|
+
const result = log.result;
|
|
24
|
+
const u = result?.usage;
|
|
25
|
+
if (!u || typeof u.prompt_tokens !== "number" || typeof u.total_tokens !== "number")
|
|
26
|
+
return undefined;
|
|
27
|
+
const pickModel = () => {
|
|
28
|
+
const fromParams = log.params?.model;
|
|
29
|
+
if (typeof fromParams === "string")
|
|
30
|
+
return fromParams;
|
|
31
|
+
if (typeof result?.model === "string")
|
|
32
|
+
return result.model;
|
|
33
|
+
return "unknown";
|
|
34
|
+
};
|
|
35
|
+
const model = pickModel();
|
|
36
|
+
return {
|
|
37
|
+
provider,
|
|
38
|
+
model,
|
|
39
|
+
inputTokens: u.prompt_tokens,
|
|
40
|
+
outputTokens: u.completion_tokens,
|
|
41
|
+
totalTokens: u.total_tokens,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const extractUsage = (log) => {
|
|
45
|
+
// 1. mulmocast AgentUsage shape (image/TTS agents in this repo).
|
|
46
|
+
if (log.result && typeof log.result === "object") {
|
|
47
|
+
const { usage } = log.result;
|
|
48
|
+
if (isAgentUsage(usage))
|
|
49
|
+
return usage;
|
|
50
|
+
}
|
|
51
|
+
// 2. @graphai/* LLM shape — derive provider/model from log metadata.
|
|
52
|
+
return extractLLMUsage(log);
|
|
53
|
+
};
|
|
54
|
+
const resolveCollector = (target) => {
|
|
55
|
+
if (!target)
|
|
56
|
+
return undefined;
|
|
57
|
+
// A MulmoStudioContext has the optional `usageCollector` slot; the API itself
|
|
58
|
+
// doesn't. Distinguishing on the slot name lets either form pass through.
|
|
59
|
+
if ("usageCollector" in target)
|
|
60
|
+
return target.usageCollector;
|
|
61
|
+
return target;
|
|
62
|
+
};
|
|
63
|
+
// GraphAI callback that pushes any agent's reported usage into the given
|
|
64
|
+
// UsageCollector when the node completes successfully. No-op when the
|
|
65
|
+
// collector is absent (either undefined directly or `context.usageCollector`
|
|
66
|
+
// undefined), the node fails, or the result has no `usage`.
|
|
67
|
+
export const createUsageCallback = (target) => {
|
|
68
|
+
return (log, isUpdate) => {
|
|
69
|
+
if (isUpdate)
|
|
70
|
+
return;
|
|
71
|
+
if (log.state !== NodeState.Completed)
|
|
72
|
+
return;
|
|
73
|
+
const collector = resolveCollector(target);
|
|
74
|
+
if (!collector)
|
|
75
|
+
return;
|
|
76
|
+
const usage = extractUsage(log);
|
|
77
|
+
if (!usage)
|
|
78
|
+
return;
|
|
79
|
+
collector.add({
|
|
80
|
+
agent: log.agentId ?? "unknown",
|
|
81
|
+
provider: usage.provider,
|
|
82
|
+
model: usage.model,
|
|
83
|
+
beatIndex: log.mapIndex,
|
|
84
|
+
inputTokens: usage.inputTokens,
|
|
85
|
+
outputTokens: usage.outputTokens,
|
|
86
|
+
totalTokens: usage.totalTokens,
|
|
87
|
+
predictSec: usage.predictSec,
|
|
88
|
+
inputChars: usage.inputChars,
|
|
89
|
+
cached: false,
|
|
90
|
+
retryAttempt: log.retryCount,
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { UsageRecord, UsageCollectorAPI } from "../types/usage.js";
|
|
2
|
+
export type { UsageRecord, UsageCollectorAPI } from "../types/usage.js";
|
|
3
|
+
export declare class UsageCollector implements UsageCollectorAPI {
|
|
4
|
+
private readonly records;
|
|
5
|
+
add(record: Omit<UsageRecord, "timestamp"> & {
|
|
6
|
+
timestamp?: string;
|
|
7
|
+
}): void;
|
|
8
|
+
snapshot(): UsageRecord[];
|
|
9
|
+
merge(other: UsageCollectorAPI): void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
get size(): number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class UsageCollector {
|
|
2
|
+
records = [];
|
|
3
|
+
add(record) {
|
|
4
|
+
this.records.push({ ...record, timestamp: record.timestamp ?? new Date().toISOString() });
|
|
5
|
+
}
|
|
6
|
+
snapshot() {
|
|
7
|
+
return this.records.map((record) => ({ ...record }));
|
|
8
|
+
}
|
|
9
|
+
merge(other) {
|
|
10
|
+
other.snapshot().forEach((record) => this.records.push({ ...record }));
|
|
11
|
+
}
|
|
12
|
+
clear() {
|
|
13
|
+
this.records.length = 0;
|
|
14
|
+
}
|
|
15
|
+
get size() {
|
|
16
|
+
return this.records.length;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mulmocast",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.22",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.node.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"resolutions": {
|
|
27
27
|
"minimatch": "^10.2.5",
|
|
28
|
-
"tar": "7.5.
|
|
28
|
+
"tar": "7.5.16",
|
|
29
29
|
"yauzl": "^3.3.1"
|
|
30
30
|
},
|
|
31
31
|
"bin": {
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"@inquirer/input": "^5.0.13",
|
|
103
103
|
"@inquirer/select": "^5.1.5",
|
|
104
104
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
105
|
-
"@modernized/fluent-ffmpeg": "^1.0.
|
|
105
|
+
"@modernized/fluent-ffmpeg": "^1.0.1",
|
|
106
106
|
"@mozilla/readability": "^0.6.0",
|
|
107
107
|
"@mulmocast/deck": "^1.1.0",
|
|
108
108
|
"@tavily/core": "^0.7.3",
|
|
@@ -127,16 +127,16 @@
|
|
|
127
127
|
"@types/jsdom": "^28.0.3",
|
|
128
128
|
"@types/yargs": "^17.0.35",
|
|
129
129
|
"cross-env": "^10.1.0",
|
|
130
|
-
"eslint": "^10.
|
|
130
|
+
"eslint": "^10.5.0",
|
|
131
131
|
"eslint-config-prettier": "^10.1.8",
|
|
132
132
|
"eslint-plugin-import": "^2.32.0",
|
|
133
133
|
"eslint-plugin-prettier": "^5.5.6",
|
|
134
134
|
"eslint-plugin-sonarjs": "^4.0.3",
|
|
135
135
|
"globals": "^17.6.0",
|
|
136
|
-
"prettier": "^3.8.
|
|
136
|
+
"prettier": "^3.8.4",
|
|
137
137
|
"tsx": "^4.22.4",
|
|
138
138
|
"typescript": "6.0.3",
|
|
139
|
-
"typescript-eslint": "^8.
|
|
139
|
+
"typescript-eslint": "^8.61.1"
|
|
140
140
|
},
|
|
141
141
|
"engines": {
|
|
142
142
|
"node": ">=22.0.0"
|