whale-code 6.4.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.
- package/README.md +95 -0
- package/bin/swag-agent.js +9 -0
- package/bin/swagmanager-mcp.js +321 -0
- package/dist/cli/app.d.ts +26 -0
- package/dist/cli/app.js +64 -0
- package/dist/cli/chat/AgentSelector.d.ts +14 -0
- package/dist/cli/chat/AgentSelector.js +14 -0
- package/dist/cli/chat/ChatApp.d.ts +9 -0
- package/dist/cli/chat/ChatApp.js +267 -0
- package/dist/cli/chat/ChatInput.d.ts +39 -0
- package/dist/cli/chat/ChatInput.js +509 -0
- package/dist/cli/chat/MarkdownText.d.ts +10 -0
- package/dist/cli/chat/MarkdownText.js +20 -0
- package/dist/cli/chat/MessageList.d.ts +37 -0
- package/dist/cli/chat/MessageList.js +80 -0
- package/dist/cli/chat/ModelSelector.d.ts +20 -0
- package/dist/cli/chat/ModelSelector.js +73 -0
- package/dist/cli/chat/RewindViewer.d.ts +26 -0
- package/dist/cli/chat/RewindViewer.js +185 -0
- package/dist/cli/chat/StoreSelector.d.ts +14 -0
- package/dist/cli/chat/StoreSelector.js +24 -0
- package/dist/cli/chat/StreamingText.d.ts +12 -0
- package/dist/cli/chat/StreamingText.js +12 -0
- package/dist/cli/chat/SubagentPanel.d.ts +45 -0
- package/dist/cli/chat/SubagentPanel.js +110 -0
- package/dist/cli/chat/TeamPanel.d.ts +21 -0
- package/dist/cli/chat/TeamPanel.js +42 -0
- package/dist/cli/chat/ToolIndicator.d.ts +25 -0
- package/dist/cli/chat/ToolIndicator.js +436 -0
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
- package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
- package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
- package/dist/cli/commands/config-cmd.d.ts +10 -0
- package/dist/cli/commands/config-cmd.js +99 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +172 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.js +278 -0
- package/dist/cli/commands/mcp.d.ts +12 -0
- package/dist/cli/commands/mcp.js +162 -0
- package/dist/cli/login/LoginApp.d.ts +7 -0
- package/dist/cli/login/LoginApp.js +157 -0
- package/dist/cli/print-mode.d.ts +31 -0
- package/dist/cli/print-mode.js +202 -0
- package/dist/cli/serve-mode.d.ts +37 -0
- package/dist/cli/serve-mode.js +636 -0
- package/dist/cli/services/agent-definitions.d.ts +25 -0
- package/dist/cli/services/agent-definitions.js +91 -0
- package/dist/cli/services/agent-events.d.ts +178 -0
- package/dist/cli/services/agent-events.js +175 -0
- package/dist/cli/services/agent-loop.d.ts +90 -0
- package/dist/cli/services/agent-loop.js +762 -0
- package/dist/cli/services/agent-worker-base.d.ts +97 -0
- package/dist/cli/services/agent-worker-base.js +220 -0
- package/dist/cli/services/auth-service.d.ts +30 -0
- package/dist/cli/services/auth-service.js +160 -0
- package/dist/cli/services/background-processes.d.ts +126 -0
- package/dist/cli/services/background-processes.js +318 -0
- package/dist/cli/services/browser-auth.d.ts +24 -0
- package/dist/cli/services/browser-auth.js +180 -0
- package/dist/cli/services/claude-md-loader.d.ts +16 -0
- package/dist/cli/services/claude-md-loader.js +58 -0
- package/dist/cli/services/config-store.d.ts +47 -0
- package/dist/cli/services/config-store.js +79 -0
- package/dist/cli/services/debug-log.d.ts +10 -0
- package/dist/cli/services/debug-log.js +52 -0
- package/dist/cli/services/error-logger.d.ts +58 -0
- package/dist/cli/services/error-logger.js +269 -0
- package/dist/cli/services/file-history.d.ts +21 -0
- package/dist/cli/services/file-history.js +83 -0
- package/dist/cli/services/format-server-response.d.ts +16 -0
- package/dist/cli/services/format-server-response.js +440 -0
- package/dist/cli/services/git-context.d.ts +11 -0
- package/dist/cli/services/git-context.js +66 -0
- package/dist/cli/services/hooks.d.ts +85 -0
- package/dist/cli/services/hooks.js +258 -0
- package/dist/cli/services/interactive-tools.d.ts +125 -0
- package/dist/cli/services/interactive-tools.js +260 -0
- package/dist/cli/services/keybinding-manager.d.ts +52 -0
- package/dist/cli/services/keybinding-manager.js +115 -0
- package/dist/cli/services/local-tools.d.ts +22 -0
- package/dist/cli/services/local-tools.js +697 -0
- package/dist/cli/services/lsp-manager.d.ts +18 -0
- package/dist/cli/services/lsp-manager.js +717 -0
- package/dist/cli/services/mcp-client.d.ts +48 -0
- package/dist/cli/services/mcp-client.js +157 -0
- package/dist/cli/services/memory-manager.d.ts +16 -0
- package/dist/cli/services/memory-manager.js +57 -0
- package/dist/cli/services/model-manager.d.ts +18 -0
- package/dist/cli/services/model-manager.js +71 -0
- package/dist/cli/services/model-router.d.ts +26 -0
- package/dist/cli/services/model-router.js +149 -0
- package/dist/cli/services/permission-modes.d.ts +13 -0
- package/dist/cli/services/permission-modes.js +43 -0
- package/dist/cli/services/rewind.d.ts +84 -0
- package/dist/cli/services/rewind.js +194 -0
- package/dist/cli/services/ripgrep.d.ts +28 -0
- package/dist/cli/services/ripgrep.js +138 -0
- package/dist/cli/services/sandbox.d.ts +29 -0
- package/dist/cli/services/sandbox.js +97 -0
- package/dist/cli/services/server-tools.d.ts +61 -0
- package/dist/cli/services/server-tools.js +543 -0
- package/dist/cli/services/session-persistence.d.ts +23 -0
- package/dist/cli/services/session-persistence.js +99 -0
- package/dist/cli/services/subagent-worker.d.ts +19 -0
- package/dist/cli/services/subagent-worker.js +41 -0
- package/dist/cli/services/subagent.d.ts +47 -0
- package/dist/cli/services/subagent.js +647 -0
- package/dist/cli/services/system-prompt.d.ts +7 -0
- package/dist/cli/services/system-prompt.js +198 -0
- package/dist/cli/services/team-lead.d.ts +73 -0
- package/dist/cli/services/team-lead.js +512 -0
- package/dist/cli/services/team-state.d.ts +77 -0
- package/dist/cli/services/team-state.js +398 -0
- package/dist/cli/services/teammate.d.ts +31 -0
- package/dist/cli/services/teammate.js +689 -0
- package/dist/cli/services/telemetry.d.ts +61 -0
- package/dist/cli/services/telemetry.js +209 -0
- package/dist/cli/services/tools/agent-tools.d.ts +14 -0
- package/dist/cli/services/tools/agent-tools.js +347 -0
- package/dist/cli/services/tools/file-ops.d.ts +15 -0
- package/dist/cli/services/tools/file-ops.js +487 -0
- package/dist/cli/services/tools/search-tools.d.ts +8 -0
- package/dist/cli/services/tools/search-tools.js +186 -0
- package/dist/cli/services/tools/shell-exec.d.ts +10 -0
- package/dist/cli/services/tools/shell-exec.js +168 -0
- package/dist/cli/services/tools/task-manager.d.ts +28 -0
- package/dist/cli/services/tools/task-manager.js +209 -0
- package/dist/cli/services/tools/web-tools.d.ts +11 -0
- package/dist/cli/services/tools/web-tools.js +395 -0
- package/dist/cli/setup/SetupApp.d.ts +9 -0
- package/dist/cli/setup/SetupApp.js +191 -0
- package/dist/cli/shared/MatrixIntro.d.ts +4 -0
- package/dist/cli/shared/MatrixIntro.js +83 -0
- package/dist/cli/shared/Theme.d.ts +74 -0
- package/dist/cli/shared/Theme.js +127 -0
- package/dist/cli/shared/WhaleBanner.d.ts +10 -0
- package/dist/cli/shared/WhaleBanner.js +12 -0
- package/dist/cli/shared/markdown.d.ts +21 -0
- package/dist/cli/shared/markdown.js +756 -0
- package/dist/cli/status/StatusApp.d.ts +4 -0
- package/dist/cli/status/StatusApp.js +105 -0
- package/dist/cli/stores/StoreApp.d.ts +7 -0
- package/dist/cli/stores/StoreApp.js +81 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +538 -0
- package/dist/local-agent/connection.d.ts +48 -0
- package/dist/local-agent/connection.js +332 -0
- package/dist/local-agent/discovery.d.ts +18 -0
- package/dist/local-agent/discovery.js +146 -0
- package/dist/local-agent/executor.d.ts +34 -0
- package/dist/local-agent/executor.js +241 -0
- package/dist/local-agent/index.d.ts +14 -0
- package/dist/local-agent/index.js +198 -0
- package/dist/node/adapters/base.d.ts +35 -0
- package/dist/node/adapters/base.js +10 -0
- package/dist/node/adapters/discord.d.ts +29 -0
- package/dist/node/adapters/discord.js +299 -0
- package/dist/node/adapters/email.d.ts +23 -0
- package/dist/node/adapters/email.js +218 -0
- package/dist/node/adapters/imessage.d.ts +17 -0
- package/dist/node/adapters/imessage.js +118 -0
- package/dist/node/adapters/slack.d.ts +26 -0
- package/dist/node/adapters/slack.js +259 -0
- package/dist/node/adapters/sms.d.ts +23 -0
- package/dist/node/adapters/sms.js +161 -0
- package/dist/node/adapters/telegram.d.ts +17 -0
- package/dist/node/adapters/telegram.js +101 -0
- package/dist/node/adapters/webchat.d.ts +27 -0
- package/dist/node/adapters/webchat.js +160 -0
- package/dist/node/adapters/whatsapp.d.ts +28 -0
- package/dist/node/adapters/whatsapp.js +230 -0
- package/dist/node/cli.d.ts +2 -0
- package/dist/node/cli.js +325 -0
- package/dist/node/config.d.ts +17 -0
- package/dist/node/config.js +31 -0
- package/dist/node/runtime.d.ts +50 -0
- package/dist/node/runtime.js +351 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
- package/dist/server/handlers/analytics.d.ts +17 -0
- package/dist/server/handlers/analytics.js +266 -0
- package/dist/server/handlers/api-keys.d.ts +6 -0
- package/dist/server/handlers/api-keys.js +221 -0
- package/dist/server/handlers/billing.d.ts +33 -0
- package/dist/server/handlers/billing.js +272 -0
- package/dist/server/handlers/browser.d.ts +10 -0
- package/dist/server/handlers/browser.js +517 -0
- package/dist/server/handlers/catalog.d.ts +99 -0
- package/dist/server/handlers/catalog.js +976 -0
- package/dist/server/handlers/comms.d.ts +254 -0
- package/dist/server/handlers/comms.js +588 -0
- package/dist/server/handlers/creations.d.ts +6 -0
- package/dist/server/handlers/creations.js +479 -0
- package/dist/server/handlers/crm.d.ts +89 -0
- package/dist/server/handlers/crm.js +538 -0
- package/dist/server/handlers/discovery.d.ts +6 -0
- package/dist/server/handlers/discovery.js +288 -0
- package/dist/server/handlers/embeddings.d.ts +92 -0
- package/dist/server/handlers/embeddings.js +197 -0
- package/dist/server/handlers/enrichment.d.ts +8 -0
- package/dist/server/handlers/enrichment.js +768 -0
- package/dist/server/handlers/image-gen.d.ts +6 -0
- package/dist/server/handlers/image-gen.js +409 -0
- package/dist/server/handlers/inventory.d.ts +319 -0
- package/dist/server/handlers/inventory.js +447 -0
- package/dist/server/handlers/kali.d.ts +10 -0
- package/dist/server/handlers/kali.js +210 -0
- package/dist/server/handlers/llm-providers.d.ts +6 -0
- package/dist/server/handlers/llm-providers.js +673 -0
- package/dist/server/handlers/local-agent.d.ts +6 -0
- package/dist/server/handlers/local-agent.js +118 -0
- package/dist/server/handlers/meta-ads.d.ts +111 -0
- package/dist/server/handlers/meta-ads.js +2279 -0
- package/dist/server/handlers/nodes.d.ts +33 -0
- package/dist/server/handlers/nodes.js +699 -0
- package/dist/server/handlers/operations.d.ts +138 -0
- package/dist/server/handlers/operations.js +131 -0
- package/dist/server/handlers/platform.d.ts +23 -0
- package/dist/server/handlers/platform.js +227 -0
- package/dist/server/handlers/supply-chain.d.ts +19 -0
- package/dist/server/handlers/supply-chain.js +327 -0
- package/dist/server/handlers/transcription.d.ts +17 -0
- package/dist/server/handlers/transcription.js +121 -0
- package/dist/server/handlers/video-gen.d.ts +6 -0
- package/dist/server/handlers/video-gen.js +466 -0
- package/dist/server/handlers/voice.d.ts +8 -0
- package/dist/server/handlers/voice.js +1146 -0
- package/dist/server/handlers/workflow-steps.d.ts +86 -0
- package/dist/server/handlers/workflow-steps.js +2349 -0
- package/dist/server/handlers/workflows.d.ts +7 -0
- package/dist/server/handlers/workflows.js +989 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +2427 -0
- package/dist/server/lib/batch-client.d.ts +80 -0
- package/dist/server/lib/batch-client.js +467 -0
- package/dist/server/lib/code-worker-pool.d.ts +31 -0
- package/dist/server/lib/code-worker-pool.js +224 -0
- package/dist/server/lib/code-worker.d.ts +1 -0
- package/dist/server/lib/code-worker.js +188 -0
- package/dist/server/lib/compaction-service.d.ts +32 -0
- package/dist/server/lib/compaction-service.js +162 -0
- package/dist/server/lib/logger.d.ts +19 -0
- package/dist/server/lib/logger.js +46 -0
- package/dist/server/lib/otel.d.ts +38 -0
- package/dist/server/lib/otel.js +126 -0
- package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
- package/dist/server/lib/pg-rate-limiter.js +86 -0
- package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
- package/dist/server/lib/prompt-sanitizer.js +177 -0
- package/dist/server/lib/provider-capabilities.d.ts +85 -0
- package/dist/server/lib/provider-capabilities.js +190 -0
- package/dist/server/lib/provider-failover.d.ts +74 -0
- package/dist/server/lib/provider-failover.js +210 -0
- package/dist/server/lib/rate-limiter.d.ts +39 -0
- package/dist/server/lib/rate-limiter.js +147 -0
- package/dist/server/lib/server-agent-loop.d.ts +107 -0
- package/dist/server/lib/server-agent-loop.js +667 -0
- package/dist/server/lib/server-subagent.d.ts +78 -0
- package/dist/server/lib/server-subagent.js +203 -0
- package/dist/server/lib/session-checkpoint.d.ts +51 -0
- package/dist/server/lib/session-checkpoint.js +145 -0
- package/dist/server/lib/ssrf-guard.d.ts +13 -0
- package/dist/server/lib/ssrf-guard.js +240 -0
- package/dist/server/lib/supabase-client.d.ts +7 -0
- package/dist/server/lib/supabase-client.js +78 -0
- package/dist/server/lib/template-resolver.d.ts +31 -0
- package/dist/server/lib/template-resolver.js +215 -0
- package/dist/server/lib/utils.d.ts +16 -0
- package/dist/server/lib/utils.js +147 -0
- package/dist/server/local-agent-gateway.d.ts +82 -0
- package/dist/server/local-agent-gateway.js +426 -0
- package/dist/server/providers/anthropic.d.ts +20 -0
- package/dist/server/providers/anthropic.js +199 -0
- package/dist/server/providers/bedrock.d.ts +20 -0
- package/dist/server/providers/bedrock.js +194 -0
- package/dist/server/providers/gemini.d.ts +24 -0
- package/dist/server/providers/gemini.js +486 -0
- package/dist/server/providers/openai.d.ts +24 -0
- package/dist/server/providers/openai.js +522 -0
- package/dist/server/providers/registry.d.ts +32 -0
- package/dist/server/providers/registry.js +58 -0
- package/dist/server/providers/shared.d.ts +32 -0
- package/dist/server/providers/shared.js +124 -0
- package/dist/server/providers/types.d.ts +92 -0
- package/dist/server/providers/types.js +12 -0
- package/dist/server/proxy-handlers.d.ts +6 -0
- package/dist/server/proxy-handlers.js +89 -0
- package/dist/server/tool-router.d.ts +149 -0
- package/dist/server/tool-router.js +803 -0
- package/dist/server/validation.d.ts +24 -0
- package/dist/server/validation.js +301 -0
- package/dist/server/worker.d.ts +19 -0
- package/dist/server/worker.js +201 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +181 -0
- package/dist/shared/agent-core.d.ts +157 -0
- package/dist/shared/agent-core.js +534 -0
- package/dist/shared/anthropic-types.d.ts +105 -0
- package/dist/shared/anthropic-types.js +7 -0
- package/dist/shared/api-client.d.ts +90 -0
- package/dist/shared/api-client.js +379 -0
- package/dist/shared/constants.d.ts +33 -0
- package/dist/shared/constants.js +80 -0
- package/dist/shared/sse-parser.d.ts +26 -0
- package/dist/shared/sse-parser.js +259 -0
- package/dist/shared/tool-dispatch.d.ts +52 -0
- package/dist/shared/tool-dispatch.js +191 -0
- package/dist/shared/types.d.ts +72 -0
- package/dist/shared/types.js +7 -0
- package/dist/updater.d.ts +25 -0
- package/dist/updater.js +140 -0
- package/dist/webchat/widget.d.ts +0 -0
- package/dist/webchat/widget.js +397 -0
- package/package.json +95 -0
- package/src/cli/services/builtin-skills/commit.md +19 -0
- package/src/cli/services/builtin-skills/review-pr.md +21 -0
- package/src/cli/services/builtin-skills/review.md +18 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch API Client — queues non-streaming LLM requests and submits them as batch jobs.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* - Anthropic Message Batches API (POST /v1/messages/batches)
|
|
6
|
+
* - OpenAI Batch API (POST /v1/batches via file upload)
|
|
7
|
+
*
|
|
8
|
+
* Batch API typically saves ~50% cost for non-latency-sensitive operations
|
|
9
|
+
* like workflow steps, bulk classification, and background processing.
|
|
10
|
+
*/
|
|
11
|
+
export interface BatchRequest {
|
|
12
|
+
id: string;
|
|
13
|
+
provider: "anthropic" | "openai";
|
|
14
|
+
model: string;
|
|
15
|
+
messages: unknown[];
|
|
16
|
+
system?: unknown;
|
|
17
|
+
tools?: unknown[];
|
|
18
|
+
max_tokens: number;
|
|
19
|
+
temperature?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface BatchResult {
|
|
22
|
+
id: string;
|
|
23
|
+
success: boolean;
|
|
24
|
+
content?: unknown;
|
|
25
|
+
text?: string;
|
|
26
|
+
error?: string;
|
|
27
|
+
usage?: {
|
|
28
|
+
input_tokens: number;
|
|
29
|
+
output_tokens: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare class BatchClient {
|
|
33
|
+
private queue;
|
|
34
|
+
/**
|
|
35
|
+
* Add a request to the queue. Call submitBatch() to send them all.
|
|
36
|
+
*/
|
|
37
|
+
queueRequest(id: string, provider: "anthropic" | "openai", model: string, messages: unknown[], config?: {
|
|
38
|
+
system?: unknown;
|
|
39
|
+
tools?: unknown[];
|
|
40
|
+
max_tokens?: number;
|
|
41
|
+
temperature?: number;
|
|
42
|
+
}): void;
|
|
43
|
+
/**
|
|
44
|
+
* Submit all queued requests as a batch job. Returns the batch ID.
|
|
45
|
+
* Clears the queue after submission.
|
|
46
|
+
*/
|
|
47
|
+
submitBatch(): Promise<{
|
|
48
|
+
batchId: string;
|
|
49
|
+
provider: "anthropic" | "openai";
|
|
50
|
+
count: number;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Poll a batch until it completes. Returns a map of custom_id → result.
|
|
54
|
+
*/
|
|
55
|
+
pollBatch(batchId: string, provider: "anthropic" | "openai"): Promise<Map<string, BatchResult>>;
|
|
56
|
+
/**
|
|
57
|
+
* Convenience: queue a single request, submit it as a batch, poll until done, return result.
|
|
58
|
+
* Best for workflow steps where you want batch pricing but only have one request.
|
|
59
|
+
*/
|
|
60
|
+
processSingle(id: string, provider: "anthropic" | "openai", model: string, messages: unknown[], config?: {
|
|
61
|
+
system?: unknown;
|
|
62
|
+
tools?: unknown[];
|
|
63
|
+
max_tokens?: number;
|
|
64
|
+
temperature?: number;
|
|
65
|
+
}): Promise<BatchResult>;
|
|
66
|
+
/** Return the current queue size (for diagnostics). */
|
|
67
|
+
get queueSize(): number;
|
|
68
|
+
private submitAnthropicBatch;
|
|
69
|
+
private pollAnthropicBatch;
|
|
70
|
+
private fetchAnthropicResults;
|
|
71
|
+
private submitOpenAIBatch;
|
|
72
|
+
private pollOpenAIBatch;
|
|
73
|
+
private fetchOpenAIResults;
|
|
74
|
+
/**
|
|
75
|
+
* Convert Anthropic-format messages to OpenAI chat format for batch requests.
|
|
76
|
+
* Simplified conversion — handles the common patterns (text, system, tool_use/tool_result).
|
|
77
|
+
*/
|
|
78
|
+
private buildOpenAIMessages;
|
|
79
|
+
}
|
|
80
|
+
export declare const batchClient: BatchClient;
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch API Client — queues non-streaming LLM requests and submits them as batch jobs.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* - Anthropic Message Batches API (POST /v1/messages/batches)
|
|
6
|
+
* - OpenAI Batch API (POST /v1/batches via file upload)
|
|
7
|
+
*
|
|
8
|
+
* Batch API typically saves ~50% cost for non-latency-sensitive operations
|
|
9
|
+
* like workflow steps, bulk classification, and background processing.
|
|
10
|
+
*/
|
|
11
|
+
import { createLogger } from "./logger.js";
|
|
12
|
+
const log = createLogger("batch-client");
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// CONSTANTS
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
17
|
+
const OPENAI_BASE_URL = "https://api.openai.com";
|
|
18
|
+
const POLL_INTERVAL_MS = 5_000;
|
|
19
|
+
const MAX_POLL_DURATION_MS = 10 * 60 * 1000; // 10 minutes
|
|
20
|
+
const ANTHROPIC_API_VERSION = "2023-06-01";
|
|
21
|
+
const ANTHROPIC_BATCH_BETA = "message-batches-2024-09-24";
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// BATCH CLIENT
|
|
24
|
+
// ============================================================================
|
|
25
|
+
export class BatchClient {
|
|
26
|
+
queue = [];
|
|
27
|
+
/**
|
|
28
|
+
* Add a request to the queue. Call submitBatch() to send them all.
|
|
29
|
+
*/
|
|
30
|
+
queueRequest(id, provider, model, messages, config = {}) {
|
|
31
|
+
this.queue.push({
|
|
32
|
+
id,
|
|
33
|
+
provider,
|
|
34
|
+
model,
|
|
35
|
+
messages,
|
|
36
|
+
system: config.system,
|
|
37
|
+
tools: config.tools,
|
|
38
|
+
max_tokens: config.max_tokens ?? 4096,
|
|
39
|
+
temperature: config.temperature,
|
|
40
|
+
});
|
|
41
|
+
log.info({ id, provider, model, queueSize: this.queue.length }, "queued batch request");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Submit all queued requests as a batch job. Returns the batch ID.
|
|
45
|
+
* Clears the queue after submission.
|
|
46
|
+
*/
|
|
47
|
+
async submitBatch() {
|
|
48
|
+
if (this.queue.length === 0) {
|
|
49
|
+
throw new Error("No requests queued for batch submission");
|
|
50
|
+
}
|
|
51
|
+
// All requests in a batch must use the same provider
|
|
52
|
+
const provider = this.queue[0].provider;
|
|
53
|
+
const mixedProvider = this.queue.find(r => r.provider !== provider);
|
|
54
|
+
if (mixedProvider) {
|
|
55
|
+
throw new Error(`Mixed providers in batch: ${provider} and ${mixedProvider.provider}. Submit separate batches per provider.`);
|
|
56
|
+
}
|
|
57
|
+
const requests = [...this.queue];
|
|
58
|
+
this.queue = [];
|
|
59
|
+
if (provider === "anthropic") {
|
|
60
|
+
return this.submitAnthropicBatch(requests);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return this.submitOpenAIBatch(requests);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Poll a batch until it completes. Returns a map of custom_id → result.
|
|
68
|
+
*/
|
|
69
|
+
async pollBatch(batchId, provider) {
|
|
70
|
+
if (provider === "anthropic") {
|
|
71
|
+
return this.pollAnthropicBatch(batchId);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
return this.pollOpenAIBatch(batchId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Convenience: queue a single request, submit it as a batch, poll until done, return result.
|
|
79
|
+
* Best for workflow steps where you want batch pricing but only have one request.
|
|
80
|
+
*/
|
|
81
|
+
async processSingle(id, provider, model, messages, config = {}) {
|
|
82
|
+
this.queueRequest(id, provider, model, messages, config);
|
|
83
|
+
const { batchId } = await this.submitBatch();
|
|
84
|
+
const results = await this.pollBatch(batchId, provider);
|
|
85
|
+
return results.get(id) || { id, success: false, error: "Result not found in batch response" };
|
|
86
|
+
}
|
|
87
|
+
/** Return the current queue size (for diagnostics). */
|
|
88
|
+
get queueSize() {
|
|
89
|
+
return this.queue.length;
|
|
90
|
+
}
|
|
91
|
+
// ==========================================================================
|
|
92
|
+
// ANTHROPIC BATCH API
|
|
93
|
+
// ==========================================================================
|
|
94
|
+
async submitAnthropicBatch(requests) {
|
|
95
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
96
|
+
if (!apiKey)
|
|
97
|
+
throw new Error("ANTHROPIC_API_KEY not set");
|
|
98
|
+
const batchRequests = requests.map(r => {
|
|
99
|
+
const params = {
|
|
100
|
+
model: r.model,
|
|
101
|
+
messages: r.messages,
|
|
102
|
+
max_tokens: r.max_tokens,
|
|
103
|
+
};
|
|
104
|
+
if (r.system)
|
|
105
|
+
params.system = r.system;
|
|
106
|
+
if (r.tools?.length) {
|
|
107
|
+
params.tools = r.tools.map((t) => ({
|
|
108
|
+
name: t.name,
|
|
109
|
+
description: typeof t.description === "string" ? t.description.slice(0, 4096) : "",
|
|
110
|
+
input_schema: t.input_schema,
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
if (r.temperature !== undefined)
|
|
114
|
+
params.temperature = r.temperature;
|
|
115
|
+
return { custom_id: r.id, params };
|
|
116
|
+
});
|
|
117
|
+
const resp = await fetch(`${ANTHROPIC_BASE_URL}/v1/messages/batches`, {
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: {
|
|
120
|
+
"Content-Type": "application/json",
|
|
121
|
+
"x-api-key": apiKey,
|
|
122
|
+
"anthropic-version": ANTHROPIC_API_VERSION,
|
|
123
|
+
"anthropic-beta": ANTHROPIC_BATCH_BETA,
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify({ requests: batchRequests }),
|
|
126
|
+
});
|
|
127
|
+
if (!resp.ok) {
|
|
128
|
+
const errText = await resp.text();
|
|
129
|
+
throw new Error(`Anthropic batch submit failed (${resp.status}): ${errText.substring(0, 500)}`);
|
|
130
|
+
}
|
|
131
|
+
const data = await resp.json();
|
|
132
|
+
log.info({ batchId: data.id, count: requests.length }, "anthropic batch submitted");
|
|
133
|
+
return { batchId: data.id, provider: "anthropic", count: requests.length };
|
|
134
|
+
}
|
|
135
|
+
async pollAnthropicBatch(batchId) {
|
|
136
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
137
|
+
if (!apiKey)
|
|
138
|
+
throw new Error("ANTHROPIC_API_KEY not set");
|
|
139
|
+
const startTime = Date.now();
|
|
140
|
+
while (Date.now() - startTime < MAX_POLL_DURATION_MS) {
|
|
141
|
+
const resp = await fetch(`${ANTHROPIC_BASE_URL}/v1/messages/batches/${batchId}`, {
|
|
142
|
+
headers: {
|
|
143
|
+
"x-api-key": apiKey,
|
|
144
|
+
"anthropic-version": ANTHROPIC_API_VERSION,
|
|
145
|
+
"anthropic-beta": ANTHROPIC_BATCH_BETA,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
if (!resp.ok) {
|
|
149
|
+
const errText = await resp.text();
|
|
150
|
+
throw new Error(`Anthropic batch poll failed (${resp.status}): ${errText.substring(0, 500)}`);
|
|
151
|
+
}
|
|
152
|
+
const batch = await resp.json();
|
|
153
|
+
log.info({
|
|
154
|
+
batchId,
|
|
155
|
+
status: batch.processing_status,
|
|
156
|
+
counts: batch.request_counts,
|
|
157
|
+
elapsed: Date.now() - startTime,
|
|
158
|
+
}, "anthropic batch poll");
|
|
159
|
+
if (batch.processing_status === "ended") {
|
|
160
|
+
return this.fetchAnthropicResults(batchId);
|
|
161
|
+
}
|
|
162
|
+
if (batch.processing_status === "canceling" || batch.processing_status === "canceled") {
|
|
163
|
+
throw new Error(`Anthropic batch ${batchId} was canceled`);
|
|
164
|
+
}
|
|
165
|
+
await sleep(POLL_INTERVAL_MS);
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`Anthropic batch ${batchId} timed out after ${MAX_POLL_DURATION_MS / 1000}s`);
|
|
168
|
+
}
|
|
169
|
+
async fetchAnthropicResults(batchId) {
|
|
170
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
171
|
+
if (!apiKey)
|
|
172
|
+
throw new Error("ANTHROPIC_API_KEY not set");
|
|
173
|
+
const resp = await fetch(`${ANTHROPIC_BASE_URL}/v1/messages/batches/${batchId}/results`, {
|
|
174
|
+
headers: {
|
|
175
|
+
"x-api-key": apiKey,
|
|
176
|
+
"anthropic-version": ANTHROPIC_API_VERSION,
|
|
177
|
+
"anthropic-beta": ANTHROPIC_BATCH_BETA,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
if (!resp.ok) {
|
|
181
|
+
const errText = await resp.text();
|
|
182
|
+
throw new Error(`Anthropic batch results fetch failed (${resp.status}): ${errText.substring(0, 500)}`);
|
|
183
|
+
}
|
|
184
|
+
// Results come as JSONL (one JSON object per line)
|
|
185
|
+
const text = await resp.text();
|
|
186
|
+
const results = new Map();
|
|
187
|
+
for (const line of text.split("\n")) {
|
|
188
|
+
if (!line.trim())
|
|
189
|
+
continue;
|
|
190
|
+
try {
|
|
191
|
+
const item = JSON.parse(line);
|
|
192
|
+
if (item.result.type === "succeeded" && item.result.message) {
|
|
193
|
+
const textBlocks = item.result.message.content
|
|
194
|
+
.filter((b) => b.type === "text" && b.text)
|
|
195
|
+
.map((b) => b.text);
|
|
196
|
+
results.set(item.custom_id, {
|
|
197
|
+
id: item.custom_id,
|
|
198
|
+
success: true,
|
|
199
|
+
content: item.result.message.content,
|
|
200
|
+
text: textBlocks.join("\n"),
|
|
201
|
+
usage: item.result.message.usage,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
results.set(item.custom_id, {
|
|
206
|
+
id: item.custom_id,
|
|
207
|
+
success: false,
|
|
208
|
+
error: item.result.error?.message || `Batch item ${item.result.type}`,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Skip malformed lines
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
log.info({ batchId, resultCount: results.size }, "anthropic batch results fetched");
|
|
217
|
+
return results;
|
|
218
|
+
}
|
|
219
|
+
// ==========================================================================
|
|
220
|
+
// OPENAI BATCH API
|
|
221
|
+
// ==========================================================================
|
|
222
|
+
async submitOpenAIBatch(requests) {
|
|
223
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
224
|
+
if (!apiKey)
|
|
225
|
+
throw new Error("OPENAI_API_KEY not set");
|
|
226
|
+
// Step 1: Build JSONL content
|
|
227
|
+
const lines = requests.map(r => {
|
|
228
|
+
const body = {
|
|
229
|
+
model: r.model,
|
|
230
|
+
messages: this.buildOpenAIMessages(r),
|
|
231
|
+
max_tokens: r.max_tokens,
|
|
232
|
+
};
|
|
233
|
+
if (r.tools?.length) {
|
|
234
|
+
body.tools = r.tools.map((t) => ({
|
|
235
|
+
type: "function",
|
|
236
|
+
function: {
|
|
237
|
+
name: t.name,
|
|
238
|
+
description: typeof t.description === "string" ? t.description.slice(0, 4096) : "",
|
|
239
|
+
parameters: t.input_schema || {},
|
|
240
|
+
},
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
if (r.temperature !== undefined)
|
|
244
|
+
body.temperature = r.temperature;
|
|
245
|
+
const item = {
|
|
246
|
+
custom_id: r.id,
|
|
247
|
+
method: "POST",
|
|
248
|
+
url: "/v1/chat/completions",
|
|
249
|
+
body,
|
|
250
|
+
};
|
|
251
|
+
return JSON.stringify(item);
|
|
252
|
+
});
|
|
253
|
+
const jsonlContent = lines.join("\n");
|
|
254
|
+
// Step 2: Upload JSONL as a file
|
|
255
|
+
const formData = new FormData();
|
|
256
|
+
const blob = new Blob([jsonlContent], { type: "application/jsonl" });
|
|
257
|
+
formData.append("file", blob, "batch_requests.jsonl");
|
|
258
|
+
formData.append("purpose", "batch");
|
|
259
|
+
const uploadResp = await fetch(`${OPENAI_BASE_URL}/v1/files`, {
|
|
260
|
+
method: "POST",
|
|
261
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
262
|
+
body: formData,
|
|
263
|
+
});
|
|
264
|
+
if (!uploadResp.ok) {
|
|
265
|
+
const errText = await uploadResp.text();
|
|
266
|
+
throw new Error(`OpenAI file upload failed (${uploadResp.status}): ${errText.substring(0, 500)}`);
|
|
267
|
+
}
|
|
268
|
+
const fileData = await uploadResp.json();
|
|
269
|
+
// Step 3: Create batch
|
|
270
|
+
const batchResp = await fetch(`${OPENAI_BASE_URL}/v1/batches`, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
headers: {
|
|
273
|
+
"Content-Type": "application/json",
|
|
274
|
+
Authorization: `Bearer ${apiKey}`,
|
|
275
|
+
},
|
|
276
|
+
body: JSON.stringify({
|
|
277
|
+
input_file_id: fileData.id,
|
|
278
|
+
endpoint: "/v1/chat/completions",
|
|
279
|
+
completion_window: "24h",
|
|
280
|
+
}),
|
|
281
|
+
});
|
|
282
|
+
if (!batchResp.ok) {
|
|
283
|
+
const errText = await batchResp.text();
|
|
284
|
+
throw new Error(`OpenAI batch create failed (${batchResp.status}): ${errText.substring(0, 500)}`);
|
|
285
|
+
}
|
|
286
|
+
const batch = await batchResp.json();
|
|
287
|
+
log.info({ batchId: batch.id, fileId: fileData.id, count: requests.length }, "openai batch submitted");
|
|
288
|
+
return { batchId: batch.id, provider: "openai", count: requests.length };
|
|
289
|
+
}
|
|
290
|
+
async pollOpenAIBatch(batchId) {
|
|
291
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
292
|
+
if (!apiKey)
|
|
293
|
+
throw new Error("OPENAI_API_KEY not set");
|
|
294
|
+
const startTime = Date.now();
|
|
295
|
+
while (Date.now() - startTime < MAX_POLL_DURATION_MS) {
|
|
296
|
+
const resp = await fetch(`${OPENAI_BASE_URL}/v1/batches/${batchId}`, {
|
|
297
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
298
|
+
});
|
|
299
|
+
if (!resp.ok) {
|
|
300
|
+
const errText = await resp.text();
|
|
301
|
+
throw new Error(`OpenAI batch poll failed (${resp.status}): ${errText.substring(0, 500)}`);
|
|
302
|
+
}
|
|
303
|
+
const batch = await resp.json();
|
|
304
|
+
log.info({
|
|
305
|
+
batchId,
|
|
306
|
+
status: batch.status,
|
|
307
|
+
counts: batch.request_counts,
|
|
308
|
+
elapsed: Date.now() - startTime,
|
|
309
|
+
}, "openai batch poll");
|
|
310
|
+
if (batch.status === "completed" && batch.output_file_id) {
|
|
311
|
+
return this.fetchOpenAIResults(batch.output_file_id);
|
|
312
|
+
}
|
|
313
|
+
if (batch.status === "failed" || batch.status === "cancelled" || batch.status === "expired") {
|
|
314
|
+
throw new Error(`OpenAI batch ${batchId} ended with status: ${batch.status}`);
|
|
315
|
+
}
|
|
316
|
+
await sleep(POLL_INTERVAL_MS);
|
|
317
|
+
}
|
|
318
|
+
throw new Error(`OpenAI batch ${batchId} timed out after ${MAX_POLL_DURATION_MS / 1000}s`);
|
|
319
|
+
}
|
|
320
|
+
async fetchOpenAIResults(outputFileId) {
|
|
321
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
322
|
+
if (!apiKey)
|
|
323
|
+
throw new Error("OPENAI_API_KEY not set");
|
|
324
|
+
const resp = await fetch(`${OPENAI_BASE_URL}/v1/files/${outputFileId}/content`, {
|
|
325
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
326
|
+
});
|
|
327
|
+
if (!resp.ok) {
|
|
328
|
+
const errText = await resp.text();
|
|
329
|
+
throw new Error(`OpenAI results fetch failed (${resp.status}): ${errText.substring(0, 500)}`);
|
|
330
|
+
}
|
|
331
|
+
const text = await resp.text();
|
|
332
|
+
const results = new Map();
|
|
333
|
+
for (const line of text.split("\n")) {
|
|
334
|
+
if (!line.trim())
|
|
335
|
+
continue;
|
|
336
|
+
try {
|
|
337
|
+
const item = JSON.parse(line);
|
|
338
|
+
if (item.response && item.response.status_code === 200) {
|
|
339
|
+
const choice = item.response.body.choices[0];
|
|
340
|
+
results.set(item.custom_id, {
|
|
341
|
+
id: item.custom_id,
|
|
342
|
+
success: true,
|
|
343
|
+
content: item.response.body.choices,
|
|
344
|
+
text: choice?.message?.content || "",
|
|
345
|
+
usage: {
|
|
346
|
+
input_tokens: item.response.body.usage.prompt_tokens,
|
|
347
|
+
output_tokens: item.response.body.usage.completion_tokens,
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
results.set(item.custom_id, {
|
|
353
|
+
id: item.custom_id,
|
|
354
|
+
success: false,
|
|
355
|
+
error: item.error?.message || `HTTP ${item.response?.status_code || "unknown"}`,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
// Skip malformed lines
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
log.info({ outputFileId, resultCount: results.size }, "openai batch results fetched");
|
|
364
|
+
return results;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Convert Anthropic-format messages to OpenAI chat format for batch requests.
|
|
368
|
+
* Simplified conversion — handles the common patterns (text, system, tool_use/tool_result).
|
|
369
|
+
*/
|
|
370
|
+
buildOpenAIMessages(r) {
|
|
371
|
+
const out = [];
|
|
372
|
+
// System prompt → system message
|
|
373
|
+
if (r.system) {
|
|
374
|
+
if (typeof r.system === "string") {
|
|
375
|
+
out.push({ role: "system", content: r.system });
|
|
376
|
+
}
|
|
377
|
+
else if (Array.isArray(r.system)) {
|
|
378
|
+
const systemText = r.system
|
|
379
|
+
.map(s => s.text || "")
|
|
380
|
+
.filter(Boolean)
|
|
381
|
+
.join("\n");
|
|
382
|
+
if (systemText)
|
|
383
|
+
out.push({ role: "system", content: systemText });
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Convert messages
|
|
387
|
+
for (const msg of r.messages) {
|
|
388
|
+
if (msg.role === "user") {
|
|
389
|
+
if (typeof msg.content === "string") {
|
|
390
|
+
out.push({ role: "user", content: msg.content });
|
|
391
|
+
}
|
|
392
|
+
else if (Array.isArray(msg.content)) {
|
|
393
|
+
const parts = [];
|
|
394
|
+
for (const block of msg.content) {
|
|
395
|
+
if (block.type === "text" && block.text) {
|
|
396
|
+
parts.push({ type: "text", text: block.text });
|
|
397
|
+
}
|
|
398
|
+
else if (block.type === "tool_result") {
|
|
399
|
+
// OpenAI tool results are separate messages
|
|
400
|
+
let output = "";
|
|
401
|
+
if (typeof block.content === "string")
|
|
402
|
+
output = block.content;
|
|
403
|
+
else if (Array.isArray(block.content)) {
|
|
404
|
+
output = block.content
|
|
405
|
+
.filter(c => c.type === "text")
|
|
406
|
+
.map(c => c.text)
|
|
407
|
+
.join("\n");
|
|
408
|
+
}
|
|
409
|
+
out.push({
|
|
410
|
+
role: "tool",
|
|
411
|
+
tool_call_id: block.tool_use_id,
|
|
412
|
+
content: output || "(no output)",
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (parts.length === 1 && parts[0].type === "text") {
|
|
417
|
+
out.push({ role: "user", content: parts[0].text });
|
|
418
|
+
}
|
|
419
|
+
else if (parts.length > 0) {
|
|
420
|
+
out.push({ role: "user", content: parts });
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
else if (msg.role === "assistant") {
|
|
425
|
+
if (typeof msg.content === "string") {
|
|
426
|
+
out.push({ role: "assistant", content: msg.content });
|
|
427
|
+
}
|
|
428
|
+
else if (Array.isArray(msg.content)) {
|
|
429
|
+
let textContent = "";
|
|
430
|
+
const toolCalls = [];
|
|
431
|
+
for (const block of msg.content) {
|
|
432
|
+
if (block.type === "text" && block.text) {
|
|
433
|
+
textContent += block.text;
|
|
434
|
+
}
|
|
435
|
+
else if (block.type === "tool_use") {
|
|
436
|
+
toolCalls.push({
|
|
437
|
+
id: block.id,
|
|
438
|
+
type: "function",
|
|
439
|
+
function: {
|
|
440
|
+
name: block.name,
|
|
441
|
+
arguments: JSON.stringify(block.input || {}),
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const assistantMsg = { role: "assistant" };
|
|
447
|
+
if (textContent)
|
|
448
|
+
assistantMsg.content = textContent;
|
|
449
|
+
if (toolCalls.length)
|
|
450
|
+
assistantMsg.tool_calls = toolCalls;
|
|
451
|
+
out.push(assistantMsg);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return out;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// ============================================================================
|
|
459
|
+
// HELPERS
|
|
460
|
+
// ============================================================================
|
|
461
|
+
function sleep(ms) {
|
|
462
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
463
|
+
}
|
|
464
|
+
// ============================================================================
|
|
465
|
+
// SINGLETON EXPORT
|
|
466
|
+
// ============================================================================
|
|
467
|
+
export const batchClient = new BatchClient();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface ExecuteRequest {
|
|
2
|
+
code: string;
|
|
3
|
+
context: {
|
|
4
|
+
steps: Record<string, unknown>;
|
|
5
|
+
trigger: Record<string, unknown>;
|
|
6
|
+
input?: unknown;
|
|
7
|
+
};
|
|
8
|
+
timeoutMs: number;
|
|
9
|
+
}
|
|
10
|
+
interface ExecuteResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
output?: unknown;
|
|
13
|
+
error?: string;
|
|
14
|
+
logs?: string[];
|
|
15
|
+
}
|
|
16
|
+
/** Initialize the worker pool. Safe to call multiple times. */
|
|
17
|
+
export declare function initWorkerPool(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Execute code using the worker pool. Falls back to direct fork if pool is unavailable.
|
|
20
|
+
*/
|
|
21
|
+
export declare function executeWithPool(req: ExecuteRequest): Promise<ExecuteResult>;
|
|
22
|
+
/** Gracefully shutdown all workers */
|
|
23
|
+
export declare function shutdownPool(): void;
|
|
24
|
+
/** Pool stats for monitoring */
|
|
25
|
+
export declare function getPoolStats(): {
|
|
26
|
+
total: number;
|
|
27
|
+
busy: number;
|
|
28
|
+
idle: number;
|
|
29
|
+
queue: number;
|
|
30
|
+
};
|
|
31
|
+
export {};
|