botinabox 2.5.2 → 2.6.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/LICENSE +21 -21
- package/README.md +190 -190
- package/bin/botinabox.mjs +1 -1
- package/dist/{chunk-UACT2WXX.js → chunk-7AGWGYZC.js} +43 -5
- package/dist/cli.js +1 -1
- package/dist/connectors/google/index.d.ts +10 -1
- package/dist/connectors/google/index.js +1 -1
- package/dist/{gmail-connector-2FVYTQJH.js → gmail-connector-VP5FF56J.js} +2 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +44 -10
- package/package.json +100 -100
- package/dist/channels/discord/adapter.d.ts +0 -32
- package/dist/channels/discord/adapter.js +0 -70
- package/dist/channels/discord/inbound.d.ts +0 -25
- package/dist/channels/discord/inbound.js +0 -24
- package/dist/channels/discord/models.d.ts +0 -8
- package/dist/channels/discord/models.js +0 -5
- package/dist/channels/discord/outbound.d.ts +0 -14
- package/dist/channels/discord/outbound.js +0 -38
- package/dist/channels/slack/adapter.d.ts +0 -33
- package/dist/channels/slack/adapter.js +0 -74
- package/dist/channels/slack/inbound.d.ts +0 -59
- package/dist/channels/slack/inbound.js +0 -96
- package/dist/channels/slack/models.d.ts +0 -9
- package/dist/channels/slack/models.js +0 -5
- package/dist/channels/slack/outbound.d.ts +0 -12
- package/dist/channels/slack/outbound.js +0 -18
- package/dist/channels/slack/transcribe.d.ts +0 -41
- package/dist/channels/slack/transcribe.js +0 -106
- package/dist/channels/webhook/adapter.d.ts +0 -23
- package/dist/channels/webhook/adapter.js +0 -86
- package/dist/channels/webhook/hmac.d.ts +0 -13
- package/dist/channels/webhook/hmac.js +0 -26
- package/dist/channels/webhook/models.d.ts +0 -9
- package/dist/channels/webhook/models.js +0 -5
- package/dist/channels/webhook/server.d.ts +0 -20
- package/dist/channels/webhook/server.js +0 -91
- package/dist/chat-pipeline-C-XlLGNl.d.ts +0 -648
- package/dist/chat-pipeline-CR1KF6eX.d.ts +0 -652
- package/dist/chat-pipeline-DisuC8SB.d.ts +0 -643
- package/dist/chunk-2LGXQPEA.js +0 -41
- package/dist/chunk-3X3YKI4T.js +0 -357
- package/dist/chunk-D47AIFOD.js +0 -351
- package/dist/chunk-DSNJKNEW.js +0 -328
- package/dist/chunk-GS2JFL6I.js +0 -144
- package/dist/chunk-J6S6QMUY.js +0 -144
- package/dist/chunk-QLA6YOFN.js +0 -22
- package/dist/cli/templates/config.yml.d.ts +0 -7
- package/dist/cli/templates/config.yml.js +0 -61
- package/dist/cli/templates/env.d.ts +0 -1
- package/dist/cli/templates/env.js +0 -30
- package/dist/cli/templates/index.ts.d.ts +0 -2
- package/dist/cli/templates/index.ts.js +0 -30
- package/dist/cli/templates/package.json.d.ts +0 -5
- package/dist/cli/templates/package.json.js +0 -28
- package/dist/connector-DDahQw-2.d.ts +0 -63
- package/dist/connectors/google/calendar-connector.d.ts +0 -40
- package/dist/connectors/google/calendar-connector.js +0 -243
- package/dist/connectors/google/gmail-connector.d.ts +0 -42
- package/dist/connectors/google/gmail-connector.js +0 -345
- package/dist/connectors/google/oauth.d.ts +0 -48
- package/dist/connectors/google/oauth.js +0 -112
- package/dist/connectors/google/types.d.ts +0 -78
- package/dist/connectors/google/types.js +0 -2
- package/dist/core/chat/auto-discovery.d.ts +0 -16
- package/dist/core/chat/auto-discovery.js +0 -54
- package/dist/core/chat/channel-registry.d.ts +0 -45
- package/dist/core/chat/channel-registry.js +0 -96
- package/dist/core/chat/chat-pipeline.d.ts +0 -113
- package/dist/core/chat/chat-pipeline.js +0 -395
- package/dist/core/chat/chat-responder.d.ts +0 -90
- package/dist/core/chat/chat-responder.js +0 -185
- package/dist/core/chat/formatter.d.ts +0 -11
- package/dist/core/chat/formatter.js +0 -60
- package/dist/core/chat/index.d.ts +0 -24
- package/dist/core/chat/index.js +0 -18
- package/dist/core/chat/message-interpreter.d.ts +0 -91
- package/dist/core/chat/message-interpreter.js +0 -166
- package/dist/core/chat/message-store.d.ts +0 -66
- package/dist/core/chat/message-store.js +0 -131
- package/dist/core/chat/notification-queue.d.ts +0 -34
- package/dist/core/chat/notification-queue.js +0 -111
- package/dist/core/chat/pipeline.d.ts +0 -38
- package/dist/core/chat/pipeline.js +0 -89
- package/dist/core/chat/policies.d.ts +0 -16
- package/dist/core/chat/policies.js +0 -25
- package/dist/core/chat/routing.d.ts +0 -17
- package/dist/core/chat/routing.js +0 -36
- package/dist/core/chat/session-key.d.ts +0 -30
- package/dist/core/chat/session-key.js +0 -65
- package/dist/core/chat/session-manager.d.ts +0 -17
- package/dist/core/chat/session-manager.js +0 -23
- package/dist/core/chat/text-chunker.d.ts +0 -9
- package/dist/core/chat/text-chunker.js +0 -48
- package/dist/core/chat/triage-router.d.ts +0 -75
- package/dist/core/chat/triage-router.js +0 -142
- package/dist/core/chat/types.d.ts +0 -5
- package/dist/core/chat/types.js +0 -5
- package/dist/core/config/defaults.d.ts +0 -2
- package/dist/core/config/defaults.js +0 -38
- package/dist/core/config/index.d.ts +0 -6
- package/dist/core/config/index.js +0 -4
- package/dist/core/config/interpolate.d.ts +0 -5
- package/dist/core/config/interpolate.js +0 -27
- package/dist/core/config/loader.d.ts +0 -24
- package/dist/core/config/loader.js +0 -59
- package/dist/core/config/schema.d.ts +0 -5
- package/dist/core/config/schema.js +0 -119
- package/dist/core/data/core-entity-contexts.d.ts +0 -14
- package/dist/core/data/core-entity-contexts.js +0 -197
- package/dist/core/data/core-migrations.d.ts +0 -5
- package/dist/core/data/core-migrations.js +0 -45
- package/dist/core/data/core-schema.d.ts +0 -6
- package/dist/core/data/core-schema.js +0 -454
- package/dist/core/data/data-store.d.ts +0 -67
- package/dist/core/data/data-store.js +0 -218
- package/dist/core/data/domain-entity-contexts.d.ts +0 -29
- package/dist/core/data/domain-entity-contexts.js +0 -321
- package/dist/core/data/domain-schema.d.ts +0 -36
- package/dist/core/data/domain-schema.js +0 -323
- package/dist/core/data/index.d.ts +0 -7
- package/dist/core/data/index.js +0 -7
- package/dist/core/data/types.d.ts +0 -111
- package/dist/core/data/types.js +0 -1
- package/dist/core/hooks/hook-bus.d.ts +0 -18
- package/dist/core/hooks/hook-bus.js +0 -120
- package/dist/core/hooks/index.d.ts +0 -2
- package/dist/core/hooks/index.js +0 -1
- package/dist/core/hooks/types.d.ts +0 -19
- package/dist/core/hooks/types.js +0 -1
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.js +0 -4
- package/dist/core/llm/auto-discovery.d.ts +0 -11
- package/dist/core/llm/auto-discovery.js +0 -49
- package/dist/core/llm/cost-tracker.d.ts +0 -6
- package/dist/core/llm/cost-tracker.js +0 -38
- package/dist/core/llm/index.d.ts +0 -4
- package/dist/core/llm/index.js +0 -3
- package/dist/core/llm/model-router.d.ts +0 -25
- package/dist/core/llm/model-router.js +0 -49
- package/dist/core/llm/provider-registry.d.ts +0 -9
- package/dist/core/llm/provider-registry.js +0 -25
- package/dist/core/llm/types.d.ts +0 -2
- package/dist/core/llm/types.js +0 -2
- package/dist/core/orchestrator/adapters/api-adapter.d.ts +0 -34
- package/dist/core/orchestrator/adapters/api-adapter.js +0 -88
- package/dist/core/orchestrator/adapters/cli-adapter.d.ts +0 -22
- package/dist/core/orchestrator/adapters/cli-adapter.js +0 -69
- package/dist/core/orchestrator/adapters/deterministic-adapter.d.ts +0 -35
- package/dist/core/orchestrator/adapters/deterministic-adapter.js +0 -75
- package/dist/core/orchestrator/adapters/env-whitelist.d.ts +0 -4
- package/dist/core/orchestrator/adapters/env-whitelist.js +0 -27
- package/dist/core/orchestrator/adapters/output-extractor.d.ts +0 -11
- package/dist/core/orchestrator/adapters/output-extractor.js +0 -59
- package/dist/core/orchestrator/adapters/process-manager.d.ts +0 -15
- package/dist/core/orchestrator/adapters/process-manager.js +0 -26
- package/dist/core/orchestrator/adapters/tool-loop.d.ts +0 -22
- package/dist/core/orchestrator/adapters/tool-loop.js +0 -66
- package/dist/core/orchestrator/agent-registry.d.ts +0 -31
- package/dist/core/orchestrator/agent-registry.js +0 -135
- package/dist/core/orchestrator/budget-controller.d.ts +0 -19
- package/dist/core/orchestrator/budget-controller.js +0 -73
- package/dist/core/orchestrator/chain-guard.d.ts +0 -14
- package/dist/core/orchestrator/chain-guard.js +0 -23
- package/dist/core/orchestrator/circuit-breaker.d.ts +0 -65
- package/dist/core/orchestrator/circuit-breaker.js +0 -159
- package/dist/core/orchestrator/claude-stream-parser.d.ts +0 -31
- package/dist/core/orchestrator/claude-stream-parser.js +0 -99
- package/dist/core/orchestrator/config-revisions.d.ts +0 -6
- package/dist/core/orchestrator/config-revisions.js +0 -17
- package/dist/core/orchestrator/dependency-resolver.d.ts +0 -20
- package/dist/core/orchestrator/dependency-resolver.js +0 -78
- package/dist/core/orchestrator/governance-gate.d.ts +0 -110
- package/dist/core/orchestrator/governance-gate.js +0 -170
- package/dist/core/orchestrator/learning-pipeline.d.ts +0 -109
- package/dist/core/orchestrator/learning-pipeline.js +0 -249
- package/dist/core/orchestrator/loop-detector.d.ts +0 -51
- package/dist/core/orchestrator/loop-detector.js +0 -133
- package/dist/core/orchestrator/ndjson-logger.d.ts +0 -6
- package/dist/core/orchestrator/ndjson-logger.js +0 -18
- package/dist/core/orchestrator/permission-relay.d.ts +0 -72
- package/dist/core/orchestrator/permission-relay.js +0 -164
- package/dist/core/orchestrator/run-manager.d.ts +0 -31
- package/dist/core/orchestrator/run-manager.js +0 -178
- package/dist/core/orchestrator/scheduler.d.ts +0 -70
- package/dist/core/orchestrator/scheduler.js +0 -198
- package/dist/core/orchestrator/secret-store.d.ts +0 -57
- package/dist/core/orchestrator/secret-store.js +0 -171
- package/dist/core/orchestrator/session-manager.d.ts +0 -13
- package/dist/core/orchestrator/session-manager.js +0 -66
- package/dist/core/orchestrator/task-queue.d.ts +0 -34
- package/dist/core/orchestrator/task-queue.js +0 -83
- package/dist/core/orchestrator/template-interpolate.d.ts +0 -5
- package/dist/core/orchestrator/template-interpolate.js +0 -18
- package/dist/core/orchestrator/user-registry.d.ts +0 -47
- package/dist/core/orchestrator/user-registry.js +0 -76
- package/dist/core/orchestrator/wakeup-queue.d.ts +0 -9
- package/dist/core/orchestrator/wakeup-queue.js +0 -45
- package/dist/core/orchestrator/workflow-engine.d.ts +0 -47
- package/dist/core/orchestrator/workflow-engine.js +0 -204
- package/dist/core/security/audit.d.ts +0 -20
- package/dist/core/security/audit.js +0 -33
- package/dist/core/security/column-validator.d.ts +0 -20
- package/dist/core/security/column-validator.js +0 -37
- package/dist/core/security/index.d.ts +0 -5
- package/dist/core/security/index.js +0 -5
- package/dist/core/security/process-env.d.ts +0 -13
- package/dist/core/security/process-env.js +0 -49
- package/dist/core/security/sanitizer.d.ts +0 -11
- package/dist/core/security/sanitizer.js +0 -39
- package/dist/core/security/types.d.ts +0 -11
- package/dist/core/security/types.js +0 -1
- package/dist/core/update/auto-update.d.ts +0 -21
- package/dist/core/update/auto-update.js +0 -102
- package/dist/core/update/backup-manager.d.ts +0 -7
- package/dist/core/update/backup-manager.js +0 -24
- package/dist/core/update/index.d.ts +0 -8
- package/dist/core/update/index.js +0 -6
- package/dist/core/update/migration-hooks.d.ts +0 -11
- package/dist/core/update/migration-hooks.js +0 -10
- package/dist/core/update/types.d.ts +0 -11
- package/dist/core/update/types.js +0 -1
- package/dist/core/update/update-checker.d.ts +0 -11
- package/dist/core/update/update-checker.js +0 -63
- package/dist/core/update/update-manager.d.ts +0 -25
- package/dist/core/update/update-manager.js +0 -101
- package/dist/core/update/version-utils.d.ts +0 -6
- package/dist/core/update/version-utils.js +0 -34
- package/dist/gmail-connector-MNUBRNFM.js +0 -6
- package/dist/gmail-connector-PS2VLGNE.js +0 -6
- package/dist/gmail-connector-ULSMN6X2.js +0 -6
- package/dist/gmail-connector-URRFX6A3.js +0 -6
- package/dist/inbound-AFBUPSPG.js +0 -10
- package/dist/inbound-AFOHYNUY.js +0 -6
- package/dist/inbound-CGIXRXGC.js +0 -8
- package/dist/inbound-MCOLRH6U.js +0 -10
- package/dist/inbound-SNEMBLGA.js +0 -6
- package/dist/inbound-ZJHAYVMF.js +0 -10
- package/dist/provider-qqJYv9nv.d.ts +0 -75
- package/dist/providers/anthropic/models.d.ts +0 -2
- package/dist/providers/anthropic/models.js +0 -29
- package/dist/providers/anthropic/provider.d.ts +0 -13
- package/dist/providers/anthropic/provider.js +0 -119
- package/dist/providers/anthropic/tool-converter.d.ts +0 -10
- package/dist/providers/anthropic/tool-converter.js +0 -7
- package/dist/providers/ollama/provider.d.ts +0 -17
- package/dist/providers/ollama/provider.js +0 -185
- package/dist/providers/openai/models.d.ts +0 -2
- package/dist/providers/openai/models.js +0 -29
- package/dist/providers/openai/provider.d.ts +0 -13
- package/dist/providers/openai/provider.js +0 -163
- package/dist/providers/openai/tool-converter.d.ts +0 -10
- package/dist/providers/openai/tool-converter.js +0 -10
- package/dist/shared/constants.d.ts +0 -50
- package/dist/shared/constants.js +0 -64
- package/dist/shared/index.d.ts +0 -14
- package/dist/shared/index.js +0 -14
- package/dist/shared/types/agent.d.ts +0 -36
- package/dist/shared/types/agent.js +0 -2
- package/dist/shared/types/channel.d.ts +0 -70
- package/dist/shared/types/channel.js +0 -2
- package/dist/shared/types/config.d.ts +0 -111
- package/dist/shared/types/config.js +0 -2
- package/dist/shared/types/connector.d.ts +0 -77
- package/dist/shared/types/connector.js +0 -2
- package/dist/shared/types/execution.d.ts +0 -29
- package/dist/shared/types/execution.js +0 -2
- package/dist/shared/types/provider.d.ts +0 -73
- package/dist/shared/types/provider.js +0 -2
- package/dist/shared/types/task.d.ts +0 -47
- package/dist/shared/types/task.js +0 -2
- package/dist/shared/types/workflow.d.ts +0 -39
- package/dist/shared/types/workflow.js +0 -2
- package/dist/shared/utils.d.ts +0 -6
- package/dist/shared/utils.js +0 -13
- package/dist/update-check.d.ts +0 -5
- package/dist/update-check.js +0 -56
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
/**
|
|
4
|
-
* Scans nodeModulesPath/@botinabox/{pkg}/package.json for each package in the scope.
|
|
5
|
-
* If pkg.botinabox?.type === 'provider', dynamically imports the package
|
|
6
|
-
* and returns the discovered LLMProvider instances.
|
|
7
|
-
*
|
|
8
|
-
* The optional importer parameter allows injection for testing.
|
|
9
|
-
*/
|
|
10
|
-
export async function discoverProviders(nodeModulesPath, importer = (name) => import(name)) {
|
|
11
|
-
const scopeDir = join(nodeModulesPath, "@botinabox");
|
|
12
|
-
let entries;
|
|
13
|
-
try {
|
|
14
|
-
entries = await readdir(scopeDir);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
// No @botinabox scope directory — gracefully return empty
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
const providers = [];
|
|
21
|
-
for (const entry of entries) {
|
|
22
|
-
const pkgPath = join(scopeDir, entry, "package.json");
|
|
23
|
-
let pkg;
|
|
24
|
-
try {
|
|
25
|
-
const raw = await readFile(pkgPath, "utf8");
|
|
26
|
-
pkg = JSON.parse(raw);
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
const botinabox = pkg.botinabox;
|
|
32
|
-
if (botinabox?.type !== "provider") {
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const packageName = pkg.name;
|
|
36
|
-
if (!packageName) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
const mod = await importer(packageName);
|
|
41
|
-
const provider = "default" in mod && mod.default ? mod.default : mod;
|
|
42
|
-
providers.push(provider);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
// Failed to import — skip silently
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return providers;
|
|
49
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { HookBus } from "../hooks/hook-bus.js";
|
|
2
|
-
import type { DataStore } from "../data/data-store.js";
|
|
3
|
-
import type { ModelInfo } from "./types.js";
|
|
4
|
-
export declare function setupCostTracker(hooks: HookBus, db: DataStore, opts?: {
|
|
5
|
-
modelCatalog?: ModelInfo[];
|
|
6
|
-
}): void;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
function calculateCostCents(usage, model) {
|
|
2
|
-
if (!model?.inputCostPerMToken)
|
|
3
|
-
return 0;
|
|
4
|
-
const inputCost = (usage.inputTokens / 1_000_000) * model.inputCostPerMToken;
|
|
5
|
-
const outputCost = (usage.outputTokens / 1_000_000) * (model.outputCostPerMToken ?? 0);
|
|
6
|
-
return Math.round((inputCost + outputCost) * 100);
|
|
7
|
-
}
|
|
8
|
-
export function setupCostTracker(hooks, db, opts) {
|
|
9
|
-
const catalog = opts?.modelCatalog ?? [];
|
|
10
|
-
hooks.register("run.completed", async (payload) => {
|
|
11
|
-
const ctx = payload;
|
|
12
|
-
if (!ctx.usage)
|
|
13
|
-
return;
|
|
14
|
-
const modelId = ctx.usage.model ?? ctx.model;
|
|
15
|
-
const providerId = ctx.usage.provider ?? ctx.provider;
|
|
16
|
-
if (!modelId || !providerId)
|
|
17
|
-
return;
|
|
18
|
-
const modelInfo = catalog.find((m) => m.id === modelId);
|
|
19
|
-
const costCents = calculateCostCents(ctx.usage, modelInfo);
|
|
20
|
-
await db.insert("cost_events", {
|
|
21
|
-
agent_id: ctx.agentId ?? null,
|
|
22
|
-
run_id: ctx.runId ?? null,
|
|
23
|
-
provider: providerId,
|
|
24
|
-
model: modelId,
|
|
25
|
-
input_tokens: ctx.usage.inputTokens,
|
|
26
|
-
output_tokens: ctx.usage.outputTokens,
|
|
27
|
-
cost_cents: costCents,
|
|
28
|
-
});
|
|
29
|
-
if (ctx.agentId) {
|
|
30
|
-
const agent = await db.get("agents", ctx.agentId);
|
|
31
|
-
if (agent) {
|
|
32
|
-
await db.update("agents", ctx.agentId, {
|
|
33
|
-
spent_monthly_cents: (agent.spent_monthly_cents ?? 0) + costCents,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}, { priority: 20 });
|
|
38
|
-
}
|
package/dist/core/llm/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { ProviderRegistry } from "./provider-registry.js";
|
|
2
|
-
export { ModelRouter } from "./model-router.js";
|
|
3
|
-
export { discoverProviders } from "./auto-discovery.js";
|
|
4
|
-
export type { LLMProvider, ModelInfo, ResolvedModel, ChatParams, ChatResult, ChatMessage, ContentBlock, TokenUsage, ToolDefinition, ToolUse, } from "./types.js";
|
package/dist/core/llm/index.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { ModelConfig } from "../../shared/index.js";
|
|
2
|
-
import type { ModelInfo, ResolvedModel } from "./types.js";
|
|
3
|
-
import type { ProviderRegistry } from "./provider-registry.js";
|
|
4
|
-
export declare class ModelRouter {
|
|
5
|
-
private readonly registry;
|
|
6
|
-
private readonly config;
|
|
7
|
-
constructor(registry: ProviderRegistry, config: ModelConfig);
|
|
8
|
-
/**
|
|
9
|
-
* Resolve a model ID or alias to a ResolvedModel.
|
|
10
|
-
* 1. Look up alias in config.aliases (or use as-is)
|
|
11
|
-
* 2. Search all registered providers for a model with that id
|
|
12
|
-
*/
|
|
13
|
-
resolve(modelIdOrAlias: string): ResolvedModel | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* Try primary model, then each in config.fallbackChain.
|
|
16
|
-
* Throws if none found.
|
|
17
|
-
*/
|
|
18
|
-
resolveWithFallback(modelIdOrAlias: string): ResolvedModel;
|
|
19
|
-
/**
|
|
20
|
-
* Use config.routing[purpose] ?? config.default, then resolveWithFallback.
|
|
21
|
-
*/
|
|
22
|
-
resolveForPurpose(purpose: string): ResolvedModel;
|
|
23
|
-
/** Returns all models from all registered providers. */
|
|
24
|
-
listAvailable(): ModelInfo[];
|
|
25
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
export class ModelRouter {
|
|
2
|
-
registry;
|
|
3
|
-
config;
|
|
4
|
-
constructor(registry, config) {
|
|
5
|
-
this.registry = registry;
|
|
6
|
-
this.config = config;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Resolve a model ID or alias to a ResolvedModel.
|
|
10
|
-
* 1. Look up alias in config.aliases (or use as-is)
|
|
11
|
-
* 2. Search all registered providers for a model with that id
|
|
12
|
-
*/
|
|
13
|
-
resolve(modelIdOrAlias) {
|
|
14
|
-
const modelId = this.config.aliases[modelIdOrAlias] ?? modelIdOrAlias;
|
|
15
|
-
for (const provider of this.registry.list()) {
|
|
16
|
-
const found = provider.models.find((m) => m.id === modelId);
|
|
17
|
-
if (found) {
|
|
18
|
-
return { provider: provider.id, model: found.id };
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Try primary model, then each in config.fallbackChain.
|
|
25
|
-
* Throws if none found.
|
|
26
|
-
*/
|
|
27
|
-
resolveWithFallback(modelIdOrAlias) {
|
|
28
|
-
const primary = this.resolve(modelIdOrAlias);
|
|
29
|
-
if (primary)
|
|
30
|
-
return primary;
|
|
31
|
-
for (const fallback of this.config.fallbackChain) {
|
|
32
|
-
const resolved = this.resolve(fallback);
|
|
33
|
-
if (resolved)
|
|
34
|
-
return resolved;
|
|
35
|
-
}
|
|
36
|
-
throw new Error(`No available model found for "${modelIdOrAlias}" and fallback chain [${this.config.fallbackChain.join(", ")}]`);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Use config.routing[purpose] ?? config.default, then resolveWithFallback.
|
|
40
|
-
*/
|
|
41
|
-
resolveForPurpose(purpose) {
|
|
42
|
-
const modelIdOrAlias = this.config.routing[purpose] ?? this.config.default;
|
|
43
|
-
return this.resolveWithFallback(modelIdOrAlias);
|
|
44
|
-
}
|
|
45
|
-
/** Returns all models from all registered providers. */
|
|
46
|
-
listAvailable() {
|
|
47
|
-
return this.registry.listModels();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { LLMProvider, ModelInfo } from "./types.js";
|
|
2
|
-
export declare class ProviderRegistry {
|
|
3
|
-
private providers;
|
|
4
|
-
register(provider: LLMProvider): void;
|
|
5
|
-
unregister(id: string): void;
|
|
6
|
-
get(id: string): LLMProvider | undefined;
|
|
7
|
-
list(): LLMProvider[];
|
|
8
|
-
listModels(): ModelInfo[];
|
|
9
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export class ProviderRegistry {
|
|
2
|
-
providers = new Map();
|
|
3
|
-
register(provider) {
|
|
4
|
-
if (this.providers.has(provider.id)) {
|
|
5
|
-
throw new Error(`Provider already registered: ${provider.id}`);
|
|
6
|
-
}
|
|
7
|
-
this.providers.set(provider.id, provider);
|
|
8
|
-
}
|
|
9
|
-
unregister(id) {
|
|
10
|
-
this.providers.delete(id);
|
|
11
|
-
}
|
|
12
|
-
get(id) {
|
|
13
|
-
return this.providers.get(id);
|
|
14
|
-
}
|
|
15
|
-
list() {
|
|
16
|
-
return Array.from(this.providers.values());
|
|
17
|
-
}
|
|
18
|
-
listModels() {
|
|
19
|
-
const models = [];
|
|
20
|
-
for (const provider of this.providers.values()) {
|
|
21
|
-
models.push(...provider.models);
|
|
22
|
-
}
|
|
23
|
-
return models;
|
|
24
|
-
}
|
|
25
|
-
}
|
package/dist/core/llm/types.d.ts
DELETED
package/dist/core/llm/types.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { ModelRouter } from '../../llm/model-router.js';
|
|
2
|
-
import type { ChatMessage, TokenUsage } from "../../../shared/index.js";
|
|
3
|
-
export declare class ApiExecutionAdapter {
|
|
4
|
-
private modelRouter;
|
|
5
|
-
readonly type = "api";
|
|
6
|
-
constructor(modelRouter: ModelRouter);
|
|
7
|
-
execute(ctx: {
|
|
8
|
-
agent: {
|
|
9
|
-
id: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
adapter_config?: string;
|
|
12
|
-
};
|
|
13
|
-
task: {
|
|
14
|
-
description?: string;
|
|
15
|
-
context?: string;
|
|
16
|
-
};
|
|
17
|
-
sessionParams?: {
|
|
18
|
-
history?: ChatMessage[];
|
|
19
|
-
};
|
|
20
|
-
contextFiles?: string[];
|
|
21
|
-
abortSignal?: AbortSignal;
|
|
22
|
-
onLog?: (stream: 'stdout' | 'stderr', chunk: string) => void;
|
|
23
|
-
}): Promise<{
|
|
24
|
-
output: string;
|
|
25
|
-
exitCode: number;
|
|
26
|
-
usage: TokenUsage & {
|
|
27
|
-
provider: string;
|
|
28
|
-
model: string;
|
|
29
|
-
};
|
|
30
|
-
sessionParams: {
|
|
31
|
-
history: ChatMessage[];
|
|
32
|
-
};
|
|
33
|
-
}>;
|
|
34
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
-
import { toolLoop } from './tool-loop.js';
|
|
3
|
-
export class ApiExecutionAdapter {
|
|
4
|
-
modelRouter;
|
|
5
|
-
type = 'api';
|
|
6
|
-
constructor(modelRouter) {
|
|
7
|
-
this.modelRouter = modelRouter;
|
|
8
|
-
}
|
|
9
|
-
async execute(ctx) {
|
|
10
|
-
const modelId = ctx.agent.model ?? 'default';
|
|
11
|
-
const resolved = this.modelRouter.resolve(modelId) ?? this.modelRouter.resolveForPurpose('default');
|
|
12
|
-
const { provider, model } = resolved;
|
|
13
|
-
// Get the LLM provider
|
|
14
|
-
const registry = this.modelRouter.registry;
|
|
15
|
-
const providerImpl = registry.list().find((p) => p.id === provider);
|
|
16
|
-
if (!providerImpl) {
|
|
17
|
-
throw new Error(`Provider not found: ${provider}`);
|
|
18
|
-
}
|
|
19
|
-
// Build system prompt
|
|
20
|
-
let systemPrompt = '';
|
|
21
|
-
// Load context files
|
|
22
|
-
if (ctx.contextFiles && ctx.contextFiles.length > 0) {
|
|
23
|
-
const fileContents = [];
|
|
24
|
-
for (const filePath of ctx.contextFiles) {
|
|
25
|
-
if (existsSync(filePath)) {
|
|
26
|
-
const content = readFileSync(filePath, 'utf8');
|
|
27
|
-
fileContents.push(`<file path="${filePath}">\n${content}\n</file>`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (fileContents.length > 0) {
|
|
31
|
-
systemPrompt = fileContents.join('\n\n');
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
// Build messages from history + task
|
|
35
|
-
const messages = [
|
|
36
|
-
...(ctx.sessionParams?.history ?? []),
|
|
37
|
-
];
|
|
38
|
-
const taskContent = [
|
|
39
|
-
ctx.task.description,
|
|
40
|
-
ctx.task.context,
|
|
41
|
-
].filter(Boolean).join('\n\n');
|
|
42
|
-
if (taskContent) {
|
|
43
|
-
messages.push({ role: 'user', content: taskContent });
|
|
44
|
-
}
|
|
45
|
-
let outputText = '';
|
|
46
|
-
let totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
47
|
-
const history = [...messages];
|
|
48
|
-
try {
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
-
const callLLM = (params) => providerImpl.chat(params);
|
|
51
|
-
for await (const event of toolLoop({
|
|
52
|
-
model,
|
|
53
|
-
messages,
|
|
54
|
-
systemPrompt: systemPrompt || undefined,
|
|
55
|
-
maxIterations: 20,
|
|
56
|
-
signal: ctx.abortSignal,
|
|
57
|
-
}, callLLM)) {
|
|
58
|
-
if (event.type === 'text') {
|
|
59
|
-
outputText += event.content;
|
|
60
|
-
ctx.onLog?.('stdout', event.content);
|
|
61
|
-
}
|
|
62
|
-
else if (event.type === 'done') {
|
|
63
|
-
totalUsage = {
|
|
64
|
-
inputTokens: (totalUsage.inputTokens ?? 0) + (event.result.usage.inputTokens ?? 0),
|
|
65
|
-
outputTokens: (totalUsage.outputTokens ?? 0) + (event.result.usage.outputTokens ?? 0),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
history.push({ role: 'assistant', content: outputText });
|
|
70
|
-
return {
|
|
71
|
-
output: outputText,
|
|
72
|
-
exitCode: 0,
|
|
73
|
-
usage: { ...totalUsage, provider, model },
|
|
74
|
-
sessionParams: { history },
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
79
|
-
ctx.onLog?.('stderr', message);
|
|
80
|
-
return {
|
|
81
|
-
output: message,
|
|
82
|
-
exitCode: 1,
|
|
83
|
-
usage: { inputTokens: 0, outputTokens: 0, provider, model },
|
|
84
|
-
sessionParams: { history },
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export declare class CliExecutionAdapter {
|
|
2
|
-
readonly type = "cli";
|
|
3
|
-
execute(ctx: {
|
|
4
|
-
agent: {
|
|
5
|
-
id: string;
|
|
6
|
-
cwd?: string;
|
|
7
|
-
adapter_config?: string;
|
|
8
|
-
skip_permissions?: boolean;
|
|
9
|
-
};
|
|
10
|
-
task: {
|
|
11
|
-
title: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
context?: string;
|
|
14
|
-
};
|
|
15
|
-
logPath?: string;
|
|
16
|
-
onLog?: (stream: string, chunk: string) => void;
|
|
17
|
-
abortSignal?: AbortSignal;
|
|
18
|
-
}): Promise<{
|
|
19
|
-
output: string;
|
|
20
|
-
exitCode: number;
|
|
21
|
-
}>;
|
|
22
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { createWriteStream } from 'node:fs';
|
|
2
|
-
import { spawnProcess, killProcessGroup } from './process-manager.js';
|
|
3
|
-
import { extractOutput } from './output-extractor.js';
|
|
4
|
-
export class CliExecutionAdapter {
|
|
5
|
-
type = 'cli';
|
|
6
|
-
async execute(ctx) {
|
|
7
|
-
const cwd = ctx.agent.cwd ?? process.cwd();
|
|
8
|
-
let config = {};
|
|
9
|
-
if (ctx.agent.adapter_config) {
|
|
10
|
-
try {
|
|
11
|
-
config = JSON.parse(ctx.agent.adapter_config);
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
14
|
-
// Ignore invalid config
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
const skipPermissions = ctx.agent.skip_permissions ?? config['skip_permissions'] ?? false;
|
|
18
|
-
const args = [];
|
|
19
|
-
if (skipPermissions) {
|
|
20
|
-
args.push('--dangerously-skip-permissions');
|
|
21
|
-
}
|
|
22
|
-
// Build prompt from task
|
|
23
|
-
const prompt = [
|
|
24
|
-
ctx.task.title,
|
|
25
|
-
ctx.task.description,
|
|
26
|
-
ctx.task.context,
|
|
27
|
-
]
|
|
28
|
-
.filter(Boolean)
|
|
29
|
-
.join('\n\n');
|
|
30
|
-
// Append prompt as final argument (--print mode)
|
|
31
|
-
args.push('--print', prompt);
|
|
32
|
-
const child = spawnProcess('claude', args, { cwd });
|
|
33
|
-
const stdoutChunks = [];
|
|
34
|
-
let logStream = null;
|
|
35
|
-
if (ctx.logPath) {
|
|
36
|
-
logStream = createWriteStream(ctx.logPath, { flags: 'a' });
|
|
37
|
-
}
|
|
38
|
-
// Set up abort handler
|
|
39
|
-
const abortHandler = () => {
|
|
40
|
-
if (child.pid != null) {
|
|
41
|
-
killProcessGroup(child.pid);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
ctx.abortSignal?.addEventListener('abort', abortHandler);
|
|
45
|
-
child.stdout?.on('data', (chunk) => {
|
|
46
|
-
stdoutChunks.push(chunk);
|
|
47
|
-
const str = chunk.toString('utf8');
|
|
48
|
-
ctx.onLog?.('stdout', str);
|
|
49
|
-
logStream?.write(chunk);
|
|
50
|
-
});
|
|
51
|
-
child.stderr?.on('data', (chunk) => {
|
|
52
|
-
const str = chunk.toString('utf8');
|
|
53
|
-
ctx.onLog?.('stderr', str);
|
|
54
|
-
});
|
|
55
|
-
const exitCode = await new Promise((resolve) => {
|
|
56
|
-
child.on('close', (code) => {
|
|
57
|
-
resolve(code ?? 1);
|
|
58
|
-
});
|
|
59
|
-
child.on('error', () => {
|
|
60
|
-
resolve(1);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
ctx.abortSignal?.removeEventListener('abort', abortHandler);
|
|
64
|
-
logStream?.end();
|
|
65
|
-
const rawOutput = Buffer.concat(stdoutChunks).toString('utf8');
|
|
66
|
-
const output = extractOutput(rawOutput);
|
|
67
|
-
return { output, exitCode };
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DeterministicAdapter — executes scripts without LLM calls.
|
|
3
|
-
* Story 6.1
|
|
4
|
-
*
|
|
5
|
-
* For tasks that don't require reasoning: routing, validation,
|
|
6
|
-
* data fetching, file transforms. Runs a user-specified command
|
|
7
|
-
* (Python, Node, bash) as a subprocess with task context on stdin.
|
|
8
|
-
*/
|
|
9
|
-
export interface DeterministicConfig {
|
|
10
|
-
command: string;
|
|
11
|
-
args?: string[];
|
|
12
|
-
env?: Record<string, string>;
|
|
13
|
-
timeoutMs?: number;
|
|
14
|
-
inputMode?: 'stdin' | 'arg';
|
|
15
|
-
}
|
|
16
|
-
export declare class DeterministicAdapter {
|
|
17
|
-
readonly type = "deterministic";
|
|
18
|
-
execute(ctx: {
|
|
19
|
-
agent: {
|
|
20
|
-
id: string;
|
|
21
|
-
cwd?: string;
|
|
22
|
-
adapter_config?: string;
|
|
23
|
-
};
|
|
24
|
-
task: {
|
|
25
|
-
title: string;
|
|
26
|
-
description?: string;
|
|
27
|
-
context?: string;
|
|
28
|
-
};
|
|
29
|
-
abortSignal?: AbortSignal;
|
|
30
|
-
onLog?: (stream: string, chunk: string) => void;
|
|
31
|
-
}): Promise<{
|
|
32
|
-
output: string;
|
|
33
|
-
exitCode: number;
|
|
34
|
-
}>;
|
|
35
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DeterministicAdapter — executes scripts without LLM calls.
|
|
3
|
-
* Story 6.1
|
|
4
|
-
*
|
|
5
|
-
* For tasks that don't require reasoning: routing, validation,
|
|
6
|
-
* data fetching, file transforms. Runs a user-specified command
|
|
7
|
-
* (Python, Node, bash) as a subprocess with task context on stdin.
|
|
8
|
-
*/
|
|
9
|
-
import { spawnProcess, killProcessGroup } from './process-manager.js';
|
|
10
|
-
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
11
|
-
export class DeterministicAdapter {
|
|
12
|
-
type = 'deterministic';
|
|
13
|
-
async execute(ctx) {
|
|
14
|
-
const cwd = ctx.agent.cwd ?? process.cwd();
|
|
15
|
-
let config = { command: 'echo' };
|
|
16
|
-
if (ctx.agent.adapter_config) {
|
|
17
|
-
try {
|
|
18
|
-
config = JSON.parse(ctx.agent.adapter_config);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
throw new Error('Invalid adapter_config for deterministic adapter');
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
if (!config.command) {
|
|
25
|
-
throw new Error('Deterministic adapter requires a command');
|
|
26
|
-
}
|
|
27
|
-
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
28
|
-
// Build task payload as JSON for the script
|
|
29
|
-
const payload = JSON.stringify({
|
|
30
|
-
taskId: ctx.task.title,
|
|
31
|
-
description: ctx.task.description ?? '',
|
|
32
|
-
context: ctx.task.context ?? '',
|
|
33
|
-
});
|
|
34
|
-
// Build args — append payload as final arg in 'arg' mode
|
|
35
|
-
const args = [...(config.args ?? [])];
|
|
36
|
-
if (config.inputMode === 'arg') {
|
|
37
|
-
args.push(payload);
|
|
38
|
-
}
|
|
39
|
-
const child = spawnProcess(config.command, args, {
|
|
40
|
-
cwd,
|
|
41
|
-
extraEnv: config.env,
|
|
42
|
-
});
|
|
43
|
-
// Write payload to stdin in default mode
|
|
44
|
-
if (config.inputMode !== 'arg' && child.stdin) {
|
|
45
|
-
child.stdin.write(payload);
|
|
46
|
-
child.stdin.end();
|
|
47
|
-
}
|
|
48
|
-
const stdoutChunks = [];
|
|
49
|
-
child.stdout?.on('data', (chunk) => {
|
|
50
|
-
stdoutChunks.push(chunk);
|
|
51
|
-
ctx.onLog?.('stdout', chunk.toString('utf8'));
|
|
52
|
-
});
|
|
53
|
-
child.stderr?.on('data', (chunk) => {
|
|
54
|
-
ctx.onLog?.('stderr', chunk.toString('utf8'));
|
|
55
|
-
});
|
|
56
|
-
// Set up abort + timeout
|
|
57
|
-
const abortHandler = () => {
|
|
58
|
-
if (child.pid != null)
|
|
59
|
-
killProcessGroup(child.pid);
|
|
60
|
-
};
|
|
61
|
-
ctx.abortSignal?.addEventListener('abort', abortHandler);
|
|
62
|
-
const timeout = setTimeout(() => {
|
|
63
|
-
if (child.pid != null)
|
|
64
|
-
killProcessGroup(child.pid);
|
|
65
|
-
}, timeoutMs);
|
|
66
|
-
const exitCode = await new Promise((resolve) => {
|
|
67
|
-
child.on('close', (code) => resolve(code ?? 1));
|
|
68
|
-
child.on('error', () => resolve(1));
|
|
69
|
-
});
|
|
70
|
-
clearTimeout(timeout);
|
|
71
|
-
ctx.abortSignal?.removeEventListener('abort', abortHandler);
|
|
72
|
-
const output = Buffer.concat(stdoutChunks).toString('utf8');
|
|
73
|
-
return { output, exitCode };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const DEFAULT_ALLOWED_ENV = [
|
|
2
|
-
'PATH',
|
|
3
|
-
'HOME',
|
|
4
|
-
'SHELL',
|
|
5
|
-
'LANG',
|
|
6
|
-
'USER',
|
|
7
|
-
'TERM',
|
|
8
|
-
'NODE_PATH',
|
|
9
|
-
'TMPDIR',
|
|
10
|
-
];
|
|
11
|
-
/**
|
|
12
|
-
* Filter the process environment to only allowed keys, then merge in extras.
|
|
13
|
-
*/
|
|
14
|
-
export function filterEnv(allowed, extra) {
|
|
15
|
-
const allowedKeys = allowed ?? DEFAULT_ALLOWED_ENV;
|
|
16
|
-
const result = {};
|
|
17
|
-
for (const key of allowedKeys) {
|
|
18
|
-
const val = process.env[key];
|
|
19
|
-
if (val !== undefined) {
|
|
20
|
-
result[key] = val;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (extra) {
|
|
24
|
-
Object.assign(result, extra);
|
|
25
|
-
}
|
|
26
|
-
return result;
|
|
27
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export declare const MAX_OUTPUT_BYTES: number;
|
|
2
|
-
/**
|
|
3
|
-
* Extract final output from NDJSON log content.
|
|
4
|
-
* Finds last line with {type:'result'} or {role:'assistant'}.
|
|
5
|
-
* Caps at 4MB.
|
|
6
|
-
*/
|
|
7
|
-
export declare function extractOutput(ndjsonContent: string): string;
|
|
8
|
-
/**
|
|
9
|
-
* Read file and extract output.
|
|
10
|
-
*/
|
|
11
|
-
export declare function extractOutputFromFile(logPath: string): string;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
export const MAX_OUTPUT_BYTES = 4 * 1024 * 1024; // 4MB
|
|
3
|
-
/**
|
|
4
|
-
* Extract final output from NDJSON log content.
|
|
5
|
-
* Finds last line with {type:'result'} or {role:'assistant'}.
|
|
6
|
-
* Caps at 4MB.
|
|
7
|
-
*/
|
|
8
|
-
export function extractOutput(ndjsonContent) {
|
|
9
|
-
const lines = ndjsonContent.split('\n').filter((l) => l.trim().length > 0);
|
|
10
|
-
let lastOutput;
|
|
11
|
-
for (const line of lines) {
|
|
12
|
-
try {
|
|
13
|
-
const parsed = JSON.parse(line);
|
|
14
|
-
if (parsed['type'] === 'result') {
|
|
15
|
-
const content = parsed['result'] ?? parsed['content'] ?? parsed['output'];
|
|
16
|
-
if (typeof content === 'string') {
|
|
17
|
-
lastOutput = content;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
else if (parsed['role'] === 'assistant') {
|
|
21
|
-
const content = parsed['content'];
|
|
22
|
-
if (typeof content === 'string') {
|
|
23
|
-
lastOutput = content;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
else if (parsed['type'] === 'assistant') {
|
|
27
|
-
const message = parsed['message'];
|
|
28
|
-
if (message && Array.isArray(message['content'])) {
|
|
29
|
-
for (const block of message['content']) {
|
|
30
|
-
if (typeof block === 'object' &&
|
|
31
|
-
block !== null &&
|
|
32
|
-
block['type'] === 'text') {
|
|
33
|
-
lastOutput = block['text'];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// Skip non-JSON lines
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (!lastOutput) {
|
|
44
|
-
// Fall back to raw content
|
|
45
|
-
lastOutput = ndjsonContent;
|
|
46
|
-
}
|
|
47
|
-
// Cap at 4MB
|
|
48
|
-
if (Buffer.byteLength(lastOutput, 'utf8') > MAX_OUTPUT_BYTES) {
|
|
49
|
-
return Buffer.from(lastOutput, 'utf8').subarray(0, MAX_OUTPUT_BYTES).toString('utf8');
|
|
50
|
-
}
|
|
51
|
-
return lastOutput;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Read file and extract output.
|
|
55
|
-
*/
|
|
56
|
-
export function extractOutputFromFile(logPath) {
|
|
57
|
-
const content = readFileSync(logPath, 'utf8');
|
|
58
|
-
return extractOutput(content);
|
|
59
|
-
}
|