multi-model-flow 0.1.0

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.
Files changed (46) hide show
  1. package/.claude/commands/mmf-analyze.md +49 -0
  2. package/.claude/commands/mmf-codex.md +51 -0
  3. package/.claude/commands/mmf-gemini.md +51 -0
  4. package/.claude/commands/mmf-review.md +53 -0
  5. package/.claude/commands/mmf-workflow.md +104 -0
  6. package/.claude/skills/codex-task/SKILL.md +59 -0
  7. package/.claude/skills/gemini-task/SKILL.md +59 -0
  8. package/.claude/skills/multi-model-task/SKILL.md +94 -0
  9. package/CLAUDE.md +60 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +183 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/client.d.ts +4 -0
  15. package/dist/client.d.ts.map +1 -0
  16. package/dist/client.js +20 -0
  17. package/dist/client.js.map +1 -0
  18. package/dist/completion.d.ts +15 -0
  19. package/dist/completion.d.ts.map +1 -0
  20. package/dist/completion.js +86 -0
  21. package/dist/completion.js.map +1 -0
  22. package/dist/config.d.ts +5 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +64 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/errors.d.ts +3 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +35 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +187 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/session.d.ts +18 -0
  35. package/dist/session.d.ts.map +1 -0
  36. package/dist/session.js +67 -0
  37. package/dist/session.js.map +1 -0
  38. package/dist/task.d.ts +19 -0
  39. package/dist/task.d.ts.map +1 -0
  40. package/dist/task.js +138 -0
  41. package/dist/task.js.map +1 -0
  42. package/dist/types.d.ts +86 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +2 -0
  45. package/dist/types.js.map +1 -0
  46. package/package.json +48 -0
package/dist/cli.js ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+ import { createInterface } from "node:readline";
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, readdirSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const PKG_ROOT = path.resolve(__dirname, "..");
8
+ // ============================================================
9
+ // Readline helpers
10
+ // ============================================================
11
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
12
+ function ask(question) {
13
+ return new Promise((resolve) => rl.question(question, (answer) => resolve(answer.trim())));
14
+ }
15
+ async function askWithDefault(label, defaultVal) {
16
+ const answer = await ask(` ? ${label} (默认: ${defaultVal}): `);
17
+ return answer || defaultVal;
18
+ }
19
+ async function askRequired(label) {
20
+ let answer = "";
21
+ while (!answer) {
22
+ answer = await ask(` ? ${label}: `);
23
+ if (!answer)
24
+ console.log(" ⚠ 此项为必填");
25
+ }
26
+ return answer;
27
+ }
28
+ async function askOptional(label, defaultVal) {
29
+ const hint = defaultVal ? `回车使用默认: ${defaultVal}` : "回车跳过";
30
+ const answer = await ask(` ? ${label} (${hint}): `);
31
+ return answer || defaultVal;
32
+ }
33
+ // PLACEHOLDER_FOR_APPEND_1
34
+ // ============================================================
35
+ // File installation helpers
36
+ // ============================================================
37
+ function copyDir(src, dest) {
38
+ if (!existsSync(src))
39
+ return 0;
40
+ mkdirSync(dest, { recursive: true });
41
+ cpSync(src, dest, { recursive: true, force: true });
42
+ // Count files copied
43
+ let count = 0;
44
+ const entries = readdirSync(src, { withFileTypes: true });
45
+ for (const e of entries) {
46
+ count += e.isDirectory() ? countFiles(path.join(src, e.name)) : 1;
47
+ }
48
+ return count;
49
+ }
50
+ function countFiles(dir) {
51
+ if (!existsSync(dir))
52
+ return 0;
53
+ let count = 0;
54
+ const entries = readdirSync(dir, { withFileTypes: true });
55
+ for (const e of entries) {
56
+ count += e.isDirectory() ? countFiles(path.join(dir, e.name)) : 1;
57
+ }
58
+ return count;
59
+ }
60
+ // ============================================================
61
+ // MCP config helpers
62
+ // ============================================================
63
+ function loadJson(filePath) {
64
+ if (!existsSync(filePath))
65
+ return {};
66
+ try {
67
+ return JSON.parse(readFileSync(filePath, "utf-8"));
68
+ }
69
+ catch {
70
+ return {};
71
+ }
72
+ }
73
+ function saveJson(filePath, data) {
74
+ writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
75
+ }
76
+ function getServerEntryPath() {
77
+ return path.join(PKG_ROOT, "dist", "index.js").replace(/\\/g, "/");
78
+ }
79
+ // PLACEHOLDER_FOR_APPEND_2
80
+ // ============================================================
81
+ // Main
82
+ // ============================================================
83
+ async function main() {
84
+ const command = process.argv[2];
85
+ if (command === "--help" || command === "-h") {
86
+ console.log("用法: mmflow [init]");
87
+ console.log(" 在当前项目中初始化多模型协作工作流");
88
+ process.exit(0);
89
+ }
90
+ console.log();
91
+ console.log(" ╔══════════════════════════════════════╗");
92
+ console.log(" ║ MMFlow - 多模型协作工作流 ║");
93
+ console.log(" ╚══════════════════════════════════════╝");
94
+ console.log();
95
+ // ── Step 1: Codex ──────────────────────────────────────
96
+ console.log(" 步骤 1/3: 配置 Codex (OpenAI)");
97
+ console.log(" ─────────────────────────────────");
98
+ const codexKey = await askRequired("API Key");
99
+ const codexUrl = await askOptional("接口地址", "https://api.openai.com/v1");
100
+ const codexModel = await askWithDefault("模型名称", "gpt-5.4");
101
+ console.log();
102
+ // ── Step 2: Gemini ─────────────────────────────────────
103
+ console.log(" 步骤 2/3: 配置 Gemini");
104
+ console.log(" ─────────────────────────────────");
105
+ const geminiKey = await askRequired("API Key");
106
+ const geminiUrl = await askOptional("接口地址", "https://generativelanguage.googleapis.com/v1beta/openai/");
107
+ const geminiModel = await askWithDefault("模型名称", "gemini-3.1-pro-preview");
108
+ console.log();
109
+ // ── Step 3: Install ────────────────────────────────────
110
+ console.log(" 步骤 3/3: 安装中...");
111
+ console.log(" ─────────────────────────────────");
112
+ const projectRoot = process.cwd();
113
+ const claudeDir = path.join(projectRoot, ".claude");
114
+ // Copy commands
115
+ const cmdSrc = path.join(PKG_ROOT, ".claude", "commands");
116
+ const cmdDest = path.join(claudeDir, "commands");
117
+ const cmdCount = copyDir(cmdSrc, cmdDest);
118
+ console.log(` ✓ 已安装 ${cmdCount} 个命令到 .claude/commands/`);
119
+ // Copy skills
120
+ const skillSrc = path.join(PKG_ROOT, ".claude", "skills");
121
+ const skillDest = path.join(claudeDir, "skills");
122
+ const skillCount = copyDir(skillSrc, skillDest);
123
+ console.log(` ✓ 已安装 ${skillCount} 个技能到 .claude/skills/`);
124
+ // Register MCP server in .mcp.json
125
+ const mcpPath = path.join(projectRoot, ".mcp.json");
126
+ const mcpConfig = loadJson(mcpPath);
127
+ if (!mcpConfig.mcpServers)
128
+ mcpConfig.mcpServers = {};
129
+ mcpConfig.mcpServers["diy-workflow"] = {
130
+ type: "stdio",
131
+ command: "node",
132
+ args: [getServerEntryPath()],
133
+ env: {
134
+ OPENAI_API_KEY: codexKey,
135
+ OPENAI_BASE_URL: codexUrl,
136
+ OPENAI_MODEL: codexModel,
137
+ GEMINI_API_KEY: geminiKey,
138
+ GEMINI_BASE_URL: geminiUrl,
139
+ GEMINI_MODEL: geminiModel,
140
+ },
141
+ };
142
+ saveJson(mcpPath, mcpConfig);
143
+ console.log(" ✓ 已注册 MCP 服务到 .mcp.json");
144
+ // Copy CLAUDE.md
145
+ const claudeMdSrc = path.join(PKG_ROOT, "CLAUDE.md");
146
+ const claudeMdDest = path.join(claudeDir, "CLAUDE.md");
147
+ if (existsSync(claudeMdSrc)) {
148
+ // Append to existing or create new
149
+ if (existsSync(claudeMdDest)) {
150
+ const existing = readFileSync(claudeMdDest, "utf-8");
151
+ if (!existing.includes("Workflow MCP")) {
152
+ const content = readFileSync(claudeMdSrc, "utf-8");
153
+ writeFileSync(claudeMdDest, existing + "\n\n" + content, "utf-8");
154
+ console.log(" ✓ 已追加工作流配置到 .claude/CLAUDE.md");
155
+ }
156
+ else {
157
+ console.log(" - .claude/CLAUDE.md 已包含工作流配置,跳过");
158
+ }
159
+ }
160
+ else {
161
+ mkdirSync(claudeDir, { recursive: true });
162
+ cpSync(claudeMdSrc, claudeMdDest);
163
+ console.log(" ✓ 已创建 .claude/CLAUDE.md");
164
+ }
165
+ }
166
+ console.log();
167
+ console.log(" 完成!重启 Claude Code 即可使用。");
168
+ console.log();
169
+ console.log(" 可用命令:");
170
+ console.log(" /mmf-workflow — 完整多模型开发流程");
171
+ console.log(" /mmf-codex — 单独调 Codex");
172
+ console.log(" /mmf-gemini — 单独调 Gemini");
173
+ console.log(" /mmf-review — 双模型代码审查");
174
+ console.log(" /mmf-analyze — 并行分析");
175
+ console.log();
176
+ rl.close();
177
+ }
178
+ main().catch((err) => {
179
+ console.error("安装失败:", err);
180
+ rl.close();
181
+ process.exit(1);
182
+ });
183
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import OpenAI from "openai";
2
+ import type { ModelRoute } from "./types.js";
3
+ export declare function getClient(route: ModelRoute): OpenAI;
4
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAoBnD"}
package/dist/client.js ADDED
@@ -0,0 +1,20 @@
1
+ import OpenAI from "openai";
2
+ const clients = new Map();
3
+ export function getClient(route) {
4
+ const cached = clients.get(route.configFile);
5
+ if (cached)
6
+ return cached;
7
+ const apiKey = process.env[route.apiKeyEnv] || "";
8
+ if (!apiKey) {
9
+ throw new Error(`${route.apiKeyEnv} is not set. Configure it in MCP server env.`);
10
+ }
11
+ const baseURL = process.env[route.baseUrlEnv] || route.defaultBaseUrl || "";
12
+ const client = new OpenAI({
13
+ apiKey,
14
+ ...(baseURL && { baseURL }),
15
+ maxRetries: 3,
16
+ });
17
+ clients.set(route.configFile, client);
18
+ return client;
19
+ }
20
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE1C,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,CAAC,SAAS,8CAA8C,CACjE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;IAE5E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM;QACN,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,UAAU,EAAE,CAAC;KACd,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type OpenAI from "openai";
2
+ import type { CompletionRequest, CompletionResult, CompletionProvider } from "./types.js";
3
+ export declare class OpenAICompletionProvider implements CompletionProvider {
4
+ private readonly client;
5
+ private readonly options;
6
+ constructor(client: OpenAI, options?: {
7
+ defaultTimeoutMs?: number;
8
+ });
9
+ complete(request: CompletionRequest): Promise<CompletionResult>;
10
+ completeStream(request: CompletionRequest, onChunk: (chunk: string) => void): Promise<CompletionResult>;
11
+ }
12
+ export declare function formatTokens(n: number): string;
13
+ export declare function formatDuration(ms: number): string;
14
+ export declare function formatUsageLine(result: CompletionResult): string;
15
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAI1F,qBAAa,wBAAyB,YAAW,kBAAkB;IAE/D,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAO;IAGxD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgB/D,cAAc,CAClB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAC/B,OAAO,CAAC,gBAAgB,CAAC;CA6B7B;AA6BD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAIhE"}
@@ -0,0 +1,86 @@
1
+ const DEFAULT_TIMEOUT_MS = 60_000;
2
+ export class OpenAICompletionProvider {
3
+ client;
4
+ options;
5
+ constructor(client, options = {}) {
6
+ this.client = client;
7
+ this.options = options;
8
+ }
9
+ async complete(request) {
10
+ const completion = await this.client.chat.completions.create({
11
+ model: request.model,
12
+ messages: request.messages,
13
+ stream: false,
14
+ ...request.extra,
15
+ }, {
16
+ timeout: request.timeoutMs ?? this.options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,
17
+ signal: request.signal ?? undefined,
18
+ });
19
+ return extractResult(completion);
20
+ }
21
+ async completeStream(request, onChunk) {
22
+ const stream = await this.client.chat.completions.create({
23
+ model: request.model,
24
+ messages: request.messages,
25
+ stream: true,
26
+ ...request.extra,
27
+ }, {
28
+ timeout: request.timeoutMs ?? this.options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,
29
+ signal: request.signal ?? undefined,
30
+ });
31
+ let fullContent = "";
32
+ let model = request.model;
33
+ for await (const chunk of stream) {
34
+ const delta = chunk.choices?.[0]?.delta?.content;
35
+ if (delta) {
36
+ fullContent += delta;
37
+ onChunk(delta);
38
+ }
39
+ if (chunk.model)
40
+ model = chunk.model;
41
+ }
42
+ if (!fullContent)
43
+ fullContent = "(empty response)";
44
+ return { content: fullContent, model };
45
+ }
46
+ }
47
+ function extractResult(completion) {
48
+ const choice = completion.choices?.[0];
49
+ if (!choice)
50
+ throw new Error("Model returned no choices");
51
+ const content = typeof choice.message?.content === "string" && choice.message.content.length > 0
52
+ ? choice.message.content
53
+ : "(empty response)";
54
+ const usage = completion.usage;
55
+ return {
56
+ content,
57
+ model: completion.model,
58
+ usage: usage
59
+ ? {
60
+ promptTokens: usage.prompt_tokens,
61
+ completionTokens: usage.completion_tokens,
62
+ totalTokens: usage.total_tokens,
63
+ }
64
+ : undefined,
65
+ };
66
+ }
67
+ // ============================================================
68
+ // Formatting Utilities
69
+ // ============================================================
70
+ export function formatTokens(n) {
71
+ if (n < 1000)
72
+ return String(n);
73
+ return `${(n / 1000).toFixed(1)}k`;
74
+ }
75
+ export function formatDuration(ms) {
76
+ if (ms < 1000)
77
+ return `${ms}ms`;
78
+ return `${(ms / 1000).toFixed(1)}s`;
79
+ }
80
+ export function formatUsageLine(result) {
81
+ if (!result.usage)
82
+ return "";
83
+ const { promptTokens, completionTokens, totalTokens } = result.usage;
84
+ return `\n\n[${result.model} | ${formatTokens(promptTokens)} in + ${formatTokens(completionTokens)} out = ${formatTokens(totalTokens)} tokens]`;
85
+ }
86
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ModelRoute, TaskDomain, RouteDecision } from "./types.js";
2
+ export declare const MODEL_ROUTES: ModelRoute[];
3
+ export declare function resolveModelRoute(model: string): ModelRoute;
4
+ export declare function routeByDomain(domain: TaskDomain): RouteDecision;
5
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMxE,eAAO,MAAM,YAAY,EAAE,UAAU,EAuBpC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAK3D;AAiCD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAK/D"}
package/dist/config.js ADDED
@@ -0,0 +1,64 @@
1
+ // ============================================================
2
+ // Model Route Table
3
+ // ============================================================
4
+ export const MODEL_ROUTES = [
5
+ {
6
+ prefix: "gemini",
7
+ provider: "Gemini",
8
+ configFile: "gemini.json",
9
+ apiKeyEnv: "GEMINI_API_KEY",
10
+ baseUrlEnv: "GEMINI_BASE_URL",
11
+ modelEnv: "GEMINI_MODEL",
12
+ defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai/",
13
+ defaultModel: "gemini-3.1-pro-preview",
14
+ defaultTimeout: 120_000,
15
+ },
16
+ // Default fallback — OpenAI/Codex (must be last)
17
+ {
18
+ prefix: "",
19
+ provider: "Codex",
20
+ configFile: "codex.json",
21
+ apiKeyEnv: "OPENAI_API_KEY",
22
+ baseUrlEnv: "OPENAI_BASE_URL",
23
+ modelEnv: "OPENAI_MODEL",
24
+ defaultModel: "gpt-5.4",
25
+ defaultTimeout: 60_000,
26
+ },
27
+ ];
28
+ export function resolveModelRoute(model) {
29
+ for (const route of MODEL_ROUTES) {
30
+ if (route.prefix && model.startsWith(route.prefix))
31
+ return route;
32
+ }
33
+ return MODEL_ROUTES[MODEL_ROUTES.length - 1];
34
+ }
35
+ // ============================================================
36
+ // Smart Routing (domain → model + system prompt)
37
+ // ============================================================
38
+ /** Get the effective default model for a route (env > hardcoded default) */
39
+ function getDefaultModel(route) {
40
+ return process.env[route.modelEnv] || route.defaultModel;
41
+ }
42
+ const DOMAIN_PROMPTS = {
43
+ frontend: "You are a senior frontend architect. Focus on UI/UX, component architecture, accessibility, responsive design, and performance. " +
44
+ "You have ZERO file write permission — return analysis and Unified Diff patches only. NEVER execute actual modifications.",
45
+ backend: "You are a senior backend architect. Focus on API design, database architecture, security, scalability, and reliability. " +
46
+ "You have ZERO file write permission — return analysis and Unified Diff patches only. NEVER execute actual modifications.",
47
+ review: "You are a senior code reviewer. Review code for bugs, security vulnerabilities, performance issues, and maintainability. " +
48
+ "Rate findings as Critical/Major/Minor/Suggestion with specific line numbers. You have ZERO file write permission.",
49
+ general: "You are a senior software engineer. Analyze context and complete the requested task with specific references. " +
50
+ "If suggesting code changes, return Unified Diff patches. You have ZERO file write permission.",
51
+ };
52
+ const DOMAIN_PROVIDER = {
53
+ frontend: "gemini",
54
+ backend: "",
55
+ review: "",
56
+ general: "",
57
+ };
58
+ export function routeByDomain(domain) {
59
+ const prefix = DOMAIN_PROVIDER[domain];
60
+ const route = MODEL_ROUTES.find((r) => r.prefix === prefix) ?? MODEL_ROUTES[MODEL_ROUTES.length - 1];
61
+ const model = getDefaultModel(route);
62
+ return { model, provider: route.provider, systemPrompt: DOMAIN_PROMPTS[domain] };
63
+ }
64
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC;QACE,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,aAAa;QACzB,SAAS,EAAE,gBAAgB;QAC3B,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,cAAc;QACxB,cAAc,EAAE,0DAA0D;QAC1E,YAAY,EAAE,wBAAwB;QACtC,cAAc,EAAE,OAAO;KACxB;IACD,iDAAiD;IACjD;QACE,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,YAAY;QACxB,SAAS,EAAE,gBAAgB;QAC3B,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,cAAc;QACxB,YAAY,EAAE,SAAS;QACvB,cAAc,EAAE,MAAM;KACvB;CACF,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;IACnE,CAAC;IACD,OAAO,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,iDAAiD;AACjD,+DAA+D;AAE/D,4EAA4E;AAC5E,SAAS,eAAe,CAAC,KAAiB;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC;AAC3D,CAAC;AAED,MAAM,cAAc,GAA+B;IACjD,QAAQ,EACN,kIAAkI;QAClI,0HAA0H;IAC5H,OAAO,EACL,0HAA0H;QAC1H,0HAA0H;IAC5H,MAAM,EACJ,2HAA2H;QAC3H,mHAAmH;IACrH,OAAO,EACL,gHAAgH;QAChH,+FAA+F;CAClG,CAAC;AAEF,MAAM,eAAe,GAA+B;IAClD,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,MAAkB;IAC9C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrG,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;AACnF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolResponse, ErrorContext } from "./types.js";
2
+ export declare function mapErrorToResponse(error: unknown, ctx: ErrorContext): ToolResponse;
3
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,GAAG,YAAY,CAalF"}
package/dist/errors.js ADDED
@@ -0,0 +1,35 @@
1
+ import OpenAI from "openai";
2
+ export function mapErrorToResponse(error, ctx) {
3
+ if (error instanceof Error && error.name === "AbortError") {
4
+ return errorResponse(`${ctx.serviceName} request was cancelled or timed out.`);
5
+ }
6
+ if (error instanceof Error && error.message.includes("is not set")) {
7
+ return errorResponse(`${ctx.serviceName} API key not configured. Check .workflow/ config.`);
8
+ }
9
+ if (error instanceof OpenAI.APIError) {
10
+ return errorResponse(mapApiStatus(error, ctx));
11
+ }
12
+ const msg = error instanceof Error ? error.message : String(error);
13
+ console.error(`[mmf] ${ctx.serviceName} error:`, error);
14
+ return errorResponse(`Unexpected error: ${msg}`);
15
+ }
16
+ function mapApiStatus(error, ctx) {
17
+ const s = ctx.serviceName;
18
+ switch (error.status) {
19
+ case 401:
20
+ return `Invalid or missing ${s} API key.`;
21
+ case 404:
22
+ return `Model not found${ctx.model ? `: ${ctx.model}` : ""}.`;
23
+ case 429:
24
+ return `${s} rate limit exceeded. Please wait and retry.`;
25
+ default:
26
+ if (error.status !== undefined && error.status >= 500) {
27
+ return `${s} service temporarily unavailable (${error.status}).`;
28
+ }
29
+ return `${s} API error (${error.status}): ${error.message}`;
30
+ }
31
+ }
32
+ function errorResponse(text) {
33
+ return { content: [{ type: "text", text }], isError: true };
34
+ }
35
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAE,GAAiB;IAClE,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1D,OAAO,aAAa,CAAC,GAAG,GAAG,CAAC,WAAW,sCAAsC,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnE,OAAO,aAAa,CAAC,GAAG,GAAG,CAAC,WAAW,mDAAmD,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,KAAK,YAAY,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,OAAO,aAAa,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,WAAW,SAAS,EAAE,KAAK,CAAC,CAAC;IACxD,OAAO,aAAa,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,KAA2C,EAAE,GAAiB;IAClF,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC;IAC1B,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,GAAG;YACN,OAAO,sBAAsB,CAAC,WAAW,CAAC;QAC5C,KAAK,GAAG;YACN,OAAO,kBAAkB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QAChE,KAAK,GAAG;YACN,OAAO,GAAG,CAAC,8CAA8C,CAAC;QAC5D;YACE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBACtD,OAAO,GAAG,CAAC,qCAAqC,KAAK,CAAC,MAAM,IAAI,CAAC;YACnE,CAAC;YACD,OAAO,GAAG,CAAC,eAAe,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IAChE,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}