botinabox 2.4.3 → 2.5.1
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/cli.js +0 -0
- package/dist/connectors/google/index.d.ts +67 -1
- package/dist/connectors/google/index.js +240 -0
- package/dist/index.js +19 -5
- package/package.json +100 -99
- 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/chunk-UACT2WXX.js +0 -381
- 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-2FVYTQJH.js +0 -6
- 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,15 +0,0 @@
|
|
|
1
|
-
import type { ChildProcess } from 'node:child_process';
|
|
2
|
-
export interface SpawnOpts {
|
|
3
|
-
cwd: string;
|
|
4
|
-
allowedEnvVars?: string[];
|
|
5
|
-
extraEnv?: Record<string, string>;
|
|
6
|
-
timeoutMs?: number;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Spawn a process with its own PGID (detached=true) and piped stdio.
|
|
10
|
-
*/
|
|
11
|
-
export declare function spawnProcess(command: string, args: string[], opts: SpawnOpts): ChildProcess;
|
|
12
|
-
/**
|
|
13
|
-
* Kill an entire process group by negative PID.
|
|
14
|
-
*/
|
|
15
|
-
export declare function killProcessGroup(pid: number, signal?: NodeJS.Signals): void;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { filterEnv } from './env-whitelist.js';
|
|
3
|
-
/**
|
|
4
|
-
* Spawn a process with its own PGID (detached=true) and piped stdio.
|
|
5
|
-
*/
|
|
6
|
-
export function spawnProcess(command, args, opts) {
|
|
7
|
-
const env = filterEnv(opts.allowedEnvVars, opts.extraEnv);
|
|
8
|
-
const child = spawn(command, args, {
|
|
9
|
-
cwd: opts.cwd,
|
|
10
|
-
env,
|
|
11
|
-
detached: true,
|
|
12
|
-
stdio: 'pipe',
|
|
13
|
-
});
|
|
14
|
-
return child;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Kill an entire process group by negative PID.
|
|
18
|
-
*/
|
|
19
|
-
export function killProcessGroup(pid, signal = 'SIGTERM') {
|
|
20
|
-
try {
|
|
21
|
-
process.kill(-pid, signal);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// Process may already be gone
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { ChatMessage, ChatParams, ChatResult, ToolDefinition } from "../../../shared/index.js";
|
|
2
|
-
export interface ToolExecutor {
|
|
3
|
-
(toolName: string, toolInput: unknown): Promise<string>;
|
|
4
|
-
}
|
|
5
|
-
export declare function toolLoop(params: {
|
|
6
|
-
model: string;
|
|
7
|
-
messages: ChatMessage[];
|
|
8
|
-
systemPrompt?: string;
|
|
9
|
-
tools?: ToolDefinition[];
|
|
10
|
-
maxIterations?: number;
|
|
11
|
-
signal?: AbortSignal;
|
|
12
|
-
}, callLLM: (params: ChatParams) => Promise<ChatResult>, executeTool?: ToolExecutor): AsyncGenerator<{
|
|
13
|
-
type: 'text';
|
|
14
|
-
content: string;
|
|
15
|
-
} | {
|
|
16
|
-
type: 'tool_use';
|
|
17
|
-
name: string;
|
|
18
|
-
input: unknown;
|
|
19
|
-
} | {
|
|
20
|
-
type: 'done';
|
|
21
|
-
result: ChatResult;
|
|
22
|
-
}>;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
export async function* toolLoop(params, callLLM, executeTool) {
|
|
2
|
-
const maxIterations = params.maxIterations ?? 20;
|
|
3
|
-
const messages = [...params.messages];
|
|
4
|
-
let iterations = 0;
|
|
5
|
-
while (iterations < maxIterations) {
|
|
6
|
-
if (params.signal?.aborted) {
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
|
-
iterations++;
|
|
10
|
-
const chatParams = {
|
|
11
|
-
model: params.model,
|
|
12
|
-
messages,
|
|
13
|
-
system: params.systemPrompt,
|
|
14
|
-
tools: params.tools,
|
|
15
|
-
};
|
|
16
|
-
const result = await callLLM(chatParams);
|
|
17
|
-
if (result.content) {
|
|
18
|
-
yield { type: 'text', content: result.content };
|
|
19
|
-
}
|
|
20
|
-
if (result.stopReason === 'end_turn' || result.stopReason === 'stop_sequence' || result.stopReason === 'max_tokens') {
|
|
21
|
-
yield { type: 'done', result };
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (result.stopReason === 'tool_use' && result.toolUses && result.toolUses.length > 0) {
|
|
25
|
-
const toolResults = [];
|
|
26
|
-
for (const toolUse of result.toolUses) {
|
|
27
|
-
yield { type: 'tool_use', name: toolUse.name, input: toolUse.input };
|
|
28
|
-
if (executeTool) {
|
|
29
|
-
const toolResult = await executeTool(toolUse.name, toolUse.input);
|
|
30
|
-
toolResults.push(toolResult);
|
|
31
|
-
// Add assistant message with tool use
|
|
32
|
-
messages.push({
|
|
33
|
-
role: 'assistant',
|
|
34
|
-
content: [
|
|
35
|
-
...(result.content ? [{ type: 'text', text: result.content }] : []),
|
|
36
|
-
{ type: 'tool_use', id: toolUse.id, name: toolUse.name, input: toolUse.input },
|
|
37
|
-
],
|
|
38
|
-
});
|
|
39
|
-
// Add tool result message
|
|
40
|
-
messages.push({
|
|
41
|
-
role: 'user',
|
|
42
|
-
content: [
|
|
43
|
-
{ type: 'tool_result', tool_use_id: toolUse.id, content: toolResult },
|
|
44
|
-
],
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (!executeTool) {
|
|
49
|
-
yield { type: 'done', result };
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
yield { type: 'done', result };
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// Max iterations reached — yield final done with last known state
|
|
59
|
-
const finalResult = await callLLM({
|
|
60
|
-
model: params.model,
|
|
61
|
-
messages,
|
|
62
|
-
system: params.systemPrompt,
|
|
63
|
-
tools: params.tools,
|
|
64
|
-
});
|
|
65
|
-
yield { type: 'done', result: finalResult };
|
|
66
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { DataStore } from '../data/data-store.js';
|
|
2
|
-
import type { HookBus } from '../hooks/hook-bus.js';
|
|
3
|
-
export declare class AgentRegistry {
|
|
4
|
-
private db;
|
|
5
|
-
private hooks;
|
|
6
|
-
constructor(db: DataStore, hooks: HookBus);
|
|
7
|
-
register(agent: {
|
|
8
|
-
slug: string;
|
|
9
|
-
name: string;
|
|
10
|
-
adapter: string;
|
|
11
|
-
role?: string;
|
|
12
|
-
[key: string]: unknown;
|
|
13
|
-
}, opts?: {
|
|
14
|
-
actorAgentId?: string;
|
|
15
|
-
}): Promise<string>;
|
|
16
|
-
getById(id: string): Promise<Record<string, unknown> | undefined>;
|
|
17
|
-
getBySlug(slug: string): Promise<Record<string, unknown> | undefined>;
|
|
18
|
-
list(filter?: {
|
|
19
|
-
status?: string;
|
|
20
|
-
role?: string;
|
|
21
|
-
}): Promise<Record<string, unknown>[]>;
|
|
22
|
-
update(id: string, changes: Record<string, unknown>): Promise<void>;
|
|
23
|
-
setStatus(id: string, newStatus: string): Promise<void>;
|
|
24
|
-
terminate(id: string): Promise<void>;
|
|
25
|
-
seedFromConfig(agentConfigs: Array<{
|
|
26
|
-
slug: string;
|
|
27
|
-
name: string;
|
|
28
|
-
adapter: string;
|
|
29
|
-
[key: string]: unknown;
|
|
30
|
-
}>): Promise<void>;
|
|
31
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { createConfigRevision } from './config-revisions.js';
|
|
2
|
-
const VALID_TRANSITIONS = {
|
|
3
|
-
idle: ['running', 'paused'],
|
|
4
|
-
running: ['idle', 'paused', 'terminated'],
|
|
5
|
-
paused: ['idle', 'terminated'],
|
|
6
|
-
terminated: [],
|
|
7
|
-
};
|
|
8
|
-
const WRITE_ACTIVITY_LOG_STATUSES = new Set(['paused', 'terminated']);
|
|
9
|
-
export class AgentRegistry {
|
|
10
|
-
db;
|
|
11
|
-
hooks;
|
|
12
|
-
constructor(db, hooks) {
|
|
13
|
-
this.db = db;
|
|
14
|
-
this.hooks = hooks;
|
|
15
|
-
}
|
|
16
|
-
async register(agent, opts) {
|
|
17
|
-
if (!agent.slug || !agent.name || !agent.adapter) {
|
|
18
|
-
throw new Error('Agent must have slug, name, and adapter');
|
|
19
|
-
}
|
|
20
|
-
// Permission check: if actorAgentId is set, verify the actor can create agents
|
|
21
|
-
if (opts?.actorAgentId) {
|
|
22
|
-
const actor = await this.db.get('agents', { id: opts.actorAgentId });
|
|
23
|
-
if (!actor)
|
|
24
|
-
throw new Error(`Actor agent not found: ${opts.actorAgentId}`);
|
|
25
|
-
// Check canCreateAgents in adapter_config JSON
|
|
26
|
-
let canCreate = false;
|
|
27
|
-
try {
|
|
28
|
-
const cfg = JSON.parse(actor['adapter_config'] ?? '{}');
|
|
29
|
-
canCreate = cfg['canCreateAgents'] === true;
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
canCreate = false;
|
|
33
|
-
}
|
|
34
|
-
if (!canCreate) {
|
|
35
|
-
throw new Error(`Agent ${opts.actorAgentId} does not have permission to create agents`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const row = await this.db.insert('agents', {
|
|
39
|
-
slug: agent.slug,
|
|
40
|
-
name: agent.name,
|
|
41
|
-
adapter: agent.adapter,
|
|
42
|
-
role: agent.role ?? 'general',
|
|
43
|
-
...Object.fromEntries(Object.entries(agent).filter(([k]) => !['slug', 'name', 'adapter', 'role'].includes(k))),
|
|
44
|
-
});
|
|
45
|
-
const newAgentId = row['id'];
|
|
46
|
-
if (opts?.actorAgentId) {
|
|
47
|
-
await this.db.insert('activity_log', {
|
|
48
|
-
agent_id: opts.actorAgentId,
|
|
49
|
-
event_type: 'agent_created_by_agent',
|
|
50
|
-
payload: JSON.stringify({
|
|
51
|
-
actorAgentId: opts.actorAgentId,
|
|
52
|
-
newAgentId,
|
|
53
|
-
slug: agent.slug,
|
|
54
|
-
}),
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
await this.hooks.emit('agent.created', { agentId: newAgentId, slug: agent.slug });
|
|
58
|
-
return newAgentId;
|
|
59
|
-
}
|
|
60
|
-
async getById(id) {
|
|
61
|
-
return (await this.db.get('agents', { id })) ?? undefined;
|
|
62
|
-
}
|
|
63
|
-
async getBySlug(slug) {
|
|
64
|
-
const rows = await this.db.query('agents', { where: { slug } });
|
|
65
|
-
return rows[0] ?? undefined;
|
|
66
|
-
}
|
|
67
|
-
async list(filter) {
|
|
68
|
-
const where = {};
|
|
69
|
-
if (filter?.status)
|
|
70
|
-
where['status'] = filter.status;
|
|
71
|
-
if (filter?.role)
|
|
72
|
-
where['role'] = filter.role;
|
|
73
|
-
return await this.db.query('agents', Object.keys(where).length ? { where } : undefined);
|
|
74
|
-
}
|
|
75
|
-
async update(id, changes) {
|
|
76
|
-
const existing = await this.db.get('agents', { id });
|
|
77
|
-
if (!existing)
|
|
78
|
-
throw new Error(`Agent not found: ${id}`);
|
|
79
|
-
const before = { ...existing };
|
|
80
|
-
await createConfigRevision(this.db, id, before, { ...before, ...changes });
|
|
81
|
-
await this.db.update('agents', { id }, {
|
|
82
|
-
...changes,
|
|
83
|
-
updated_at: new Date().toISOString(),
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
async setStatus(id, newStatus) {
|
|
87
|
-
const agent = await this.db.get('agents', { id });
|
|
88
|
-
if (!agent)
|
|
89
|
-
throw new Error(`Agent not found: ${id}`);
|
|
90
|
-
const currentStatus = agent['status'];
|
|
91
|
-
const allowed = VALID_TRANSITIONS[currentStatus] ?? [];
|
|
92
|
-
if (!allowed.includes(newStatus)) {
|
|
93
|
-
throw new Error(`Invalid status transition: ${currentStatus} → ${newStatus}`);
|
|
94
|
-
}
|
|
95
|
-
await this.db.update('agents', { id }, {
|
|
96
|
-
status: newStatus,
|
|
97
|
-
updated_at: new Date().toISOString(),
|
|
98
|
-
});
|
|
99
|
-
if (WRITE_ACTIVITY_LOG_STATUSES.has(newStatus)) {
|
|
100
|
-
await this.db.insert('activity_log', {
|
|
101
|
-
agent_id: id,
|
|
102
|
-
event_type: `agent.${newStatus}`,
|
|
103
|
-
payload: JSON.stringify({ agentId: id, status: newStatus }),
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async terminate(id) {
|
|
108
|
-
const agent = await this.db.get('agents', { id });
|
|
109
|
-
if (!agent)
|
|
110
|
-
throw new Error(`Agent not found: ${id}`);
|
|
111
|
-
const currentStatus = agent['status'];
|
|
112
|
-
if (currentStatus === 'terminated') {
|
|
113
|
-
// Already terminated — no-op
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
await this.db.update('agents', { id }, {
|
|
117
|
-
status: 'terminated',
|
|
118
|
-
deleted_at: new Date().toISOString(),
|
|
119
|
-
updated_at: new Date().toISOString(),
|
|
120
|
-
});
|
|
121
|
-
await this.db.insert('activity_log', {
|
|
122
|
-
agent_id: id,
|
|
123
|
-
event_type: 'agent.terminated',
|
|
124
|
-
payload: JSON.stringify({ agentId: id }),
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
async seedFromConfig(agentConfigs) {
|
|
128
|
-
for (const config of agentConfigs) {
|
|
129
|
-
const existing = await this.getBySlug(config.slug);
|
|
130
|
-
if (existing)
|
|
131
|
-
continue; // Skip — DB values take precedence
|
|
132
|
-
await this.register(config);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { DataStore } from '../data/data-store.js';
|
|
2
|
-
import type { HookBus } from '../hooks/hook-bus.js';
|
|
3
|
-
export declare class BudgetController {
|
|
4
|
-
private db;
|
|
5
|
-
private hooks;
|
|
6
|
-
constructor(db: DataStore, hooks: HookBus);
|
|
7
|
-
checkBudget(agentId: string): Promise<{
|
|
8
|
-
allowed: boolean;
|
|
9
|
-
reason?: string;
|
|
10
|
-
currentSpendCents: number;
|
|
11
|
-
limitCents: number;
|
|
12
|
-
}>;
|
|
13
|
-
resetMonthlySpend(agentId: string): Promise<void>;
|
|
14
|
-
globalCheck(): Promise<{
|
|
15
|
-
allowed: boolean;
|
|
16
|
-
totalSpentCents: number;
|
|
17
|
-
limitCents: number;
|
|
18
|
-
}>;
|
|
19
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
export class BudgetController {
|
|
2
|
-
db;
|
|
3
|
-
hooks;
|
|
4
|
-
constructor(db, hooks) {
|
|
5
|
-
this.db = db;
|
|
6
|
-
this.hooks = hooks;
|
|
7
|
-
}
|
|
8
|
-
async checkBudget(agentId) {
|
|
9
|
-
const agent = await this.db.get('agents', { id: agentId });
|
|
10
|
-
if (!agent) {
|
|
11
|
-
throw new Error(`Agent not found: ${agentId}`);
|
|
12
|
-
}
|
|
13
|
-
const limitCents = agent['budget_monthly_cents'] ?? 0;
|
|
14
|
-
const currentSpendCents = agent['spent_monthly_cents'] ?? 0;
|
|
15
|
-
// No budget set = always allowed
|
|
16
|
-
if (limitCents <= 0) {
|
|
17
|
-
return { allowed: true, currentSpendCents, limitCents };
|
|
18
|
-
}
|
|
19
|
-
if (currentSpendCents >= limitCents) {
|
|
20
|
-
return {
|
|
21
|
-
allowed: false,
|
|
22
|
-
reason: 'Monthly budget exceeded',
|
|
23
|
-
currentSpendCents,
|
|
24
|
-
limitCents,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
// Check warn threshold — look up agent-specific policy first, then global
|
|
28
|
-
let warnPercent = 80;
|
|
29
|
-
const agentPolicies = await this.db.query('budget_policies', {
|
|
30
|
-
where: { agent_id: agentId },
|
|
31
|
-
});
|
|
32
|
-
if (agentPolicies.length > 0) {
|
|
33
|
-
warnPercent = agentPolicies[0]['warn_percent'] ?? 80;
|
|
34
|
-
}
|
|
35
|
-
const warnThreshold = limitCents * (warnPercent / 100);
|
|
36
|
-
if (currentSpendCents >= warnThreshold) {
|
|
37
|
-
await this.hooks.emit('budget.exceeded', {
|
|
38
|
-
agentId,
|
|
39
|
-
currentSpendCents,
|
|
40
|
-
limitCents,
|
|
41
|
-
warnPercent,
|
|
42
|
-
message: `Budget warning: ${currentSpendCents} of ${limitCents} cents used (${warnPercent}% threshold)`,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return { allowed: true, currentSpendCents, limitCents };
|
|
46
|
-
}
|
|
47
|
-
async resetMonthlySpend(agentId) {
|
|
48
|
-
await this.db.update('agents', { id: agentId }, {
|
|
49
|
-
spent_monthly_cents: 0,
|
|
50
|
-
updated_at: new Date().toISOString(),
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
async globalCheck() {
|
|
54
|
-
const agents = await this.db.query('agents');
|
|
55
|
-
const totalSpentCents = agents.reduce((sum, a) => sum + (a['spent_monthly_cents'] ?? 0), 0);
|
|
56
|
-
// Find global budget policy
|
|
57
|
-
const globalPolicies = await this.db.query('budget_policies', {
|
|
58
|
-
where: { scope: 'global' },
|
|
59
|
-
});
|
|
60
|
-
if (globalPolicies.length === 0) {
|
|
61
|
-
return { allowed: true, totalSpentCents, limitCents: 0 };
|
|
62
|
-
}
|
|
63
|
-
const limitCents = globalPolicies[0]['monthly_limit_cents'] ?? 0;
|
|
64
|
-
if (limitCents <= 0) {
|
|
65
|
-
return { allowed: true, totalSpentCents, limitCents };
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
allowed: totalSpentCents < limitCents,
|
|
69
|
-
totalSpentCents,
|
|
70
|
-
limitCents,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export declare const MAX_CHAIN_DEPTH = 5;
|
|
2
|
-
/**
|
|
3
|
-
* Throws if depth exceeds the maximum allowed chain depth.
|
|
4
|
-
*/
|
|
5
|
-
export declare function checkChainDepth(depth: number, max?: number): void;
|
|
6
|
-
/**
|
|
7
|
-
* Build chain origin metadata for a new child task.
|
|
8
|
-
* If parentTaskId is provided, sets chain_origin_id and increments depth.
|
|
9
|
-
* Otherwise returns depth=0 with no origin.
|
|
10
|
-
*/
|
|
11
|
-
export declare function buildChainOrigin(parentTaskId?: string, parentOriginId?: string, parentDepth?: number): {
|
|
12
|
-
chain_origin_id?: string;
|
|
13
|
-
chain_depth: number;
|
|
14
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export const MAX_CHAIN_DEPTH = 5;
|
|
2
|
-
/**
|
|
3
|
-
* Throws if depth exceeds the maximum allowed chain depth.
|
|
4
|
-
*/
|
|
5
|
-
export function checkChainDepth(depth, max = MAX_CHAIN_DEPTH) {
|
|
6
|
-
if (depth > max) {
|
|
7
|
-
throw new Error(`Chain depth limit exceeded (max ${max})`);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Build chain origin metadata for a new child task.
|
|
12
|
-
* If parentTaskId is provided, sets chain_origin_id and increments depth.
|
|
13
|
-
* Otherwise returns depth=0 with no origin.
|
|
14
|
-
*/
|
|
15
|
-
export function buildChainOrigin(parentTaskId, parentOriginId, parentDepth) {
|
|
16
|
-
if (!parentTaskId) {
|
|
17
|
-
return { chain_depth: 0 };
|
|
18
|
-
}
|
|
19
|
-
return {
|
|
20
|
-
chain_origin_id: parentOriginId ?? parentTaskId,
|
|
21
|
-
chain_depth: (parentDepth ?? 0) + 1,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CircuitBreaker — prevents runaway agent failures with automatic escalation.
|
|
3
|
-
* Story 6.2
|
|
4
|
-
*
|
|
5
|
-
* States:
|
|
6
|
-
* CLOSED → normal operation, failures counted
|
|
7
|
-
* OPEN → tripped, all executions blocked, escalated to human
|
|
8
|
-
* HALF_OPEN → probe mode, one execution allowed to test recovery
|
|
9
|
-
*
|
|
10
|
-
* Integrates with LoopDetector and RunManager via HookBus events.
|
|
11
|
-
*/
|
|
12
|
-
import type { DataStore } from '../data/data-store.js';
|
|
13
|
-
import type { HookBus } from '../hooks/hook-bus.js';
|
|
14
|
-
export declare enum BreakerState {
|
|
15
|
-
CLOSED = "closed",
|
|
16
|
-
OPEN = "open",
|
|
17
|
-
HALF_OPEN = "half_open"
|
|
18
|
-
}
|
|
19
|
-
export interface CircuitBreakerConfig {
|
|
20
|
-
/** Failures before tripping. Default: 3 */
|
|
21
|
-
failureThreshold?: number;
|
|
22
|
-
/** Milliseconds to wait before half-open probe. Default: 300_000 (5 min) */
|
|
23
|
-
resetTimeoutMs?: number;
|
|
24
|
-
/** Log events to the database. Default: true */
|
|
25
|
-
persist?: boolean;
|
|
26
|
-
}
|
|
27
|
-
export declare class CircuitBreaker {
|
|
28
|
-
private db;
|
|
29
|
-
private hooks;
|
|
30
|
-
private readonly breakers;
|
|
31
|
-
private readonly failureThreshold;
|
|
32
|
-
private readonly resetTimeoutMs;
|
|
33
|
-
private readonly persist;
|
|
34
|
-
constructor(db: DataStore, hooks: HookBus, config?: CircuitBreakerConfig);
|
|
35
|
-
/**
|
|
36
|
-
* Check if an agent is allowed to execute.
|
|
37
|
-
* Returns true if execution is allowed, false if circuit is open.
|
|
38
|
-
*/
|
|
39
|
-
canExecute(agentId: string): boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Record a successful execution. Resets the breaker to CLOSED.
|
|
42
|
-
*/
|
|
43
|
-
recordSuccess(agentId: string): Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Record a failed execution. Increments failure count and may trip breaker.
|
|
46
|
-
*/
|
|
47
|
-
recordFailure(agentId: string, reason?: string): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* Trip the breaker to OPEN state and escalate to human.
|
|
50
|
-
*/
|
|
51
|
-
trip(agentId: string, reason: string): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Manually reset a breaker (e.g. after human review).
|
|
54
|
-
*/
|
|
55
|
-
reset(agentId: string): Promise<void>;
|
|
56
|
-
/**
|
|
57
|
-
* Get the current state of a breaker.
|
|
58
|
-
*/
|
|
59
|
-
getState(agentId: string): BreakerState;
|
|
60
|
-
/**
|
|
61
|
-
* Get failure count for an agent.
|
|
62
|
-
*/
|
|
63
|
-
getFailureCount(agentId: string): number;
|
|
64
|
-
private logEvent;
|
|
65
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CircuitBreaker — prevents runaway agent failures with automatic escalation.
|
|
3
|
-
* Story 6.2
|
|
4
|
-
*
|
|
5
|
-
* States:
|
|
6
|
-
* CLOSED → normal operation, failures counted
|
|
7
|
-
* OPEN → tripped, all executions blocked, escalated to human
|
|
8
|
-
* HALF_OPEN → probe mode, one execution allowed to test recovery
|
|
9
|
-
*
|
|
10
|
-
* Integrates with LoopDetector and RunManager via HookBus events.
|
|
11
|
-
*/
|
|
12
|
-
export var BreakerState;
|
|
13
|
-
(function (BreakerState) {
|
|
14
|
-
BreakerState["CLOSED"] = "closed";
|
|
15
|
-
BreakerState["OPEN"] = "open";
|
|
16
|
-
BreakerState["HALF_OPEN"] = "half_open";
|
|
17
|
-
})(BreakerState || (BreakerState = {}));
|
|
18
|
-
const DEFAULT_FAILURE_THRESHOLD = 3;
|
|
19
|
-
const DEFAULT_RESET_TIMEOUT_MS = 5 * 60 * 1000;
|
|
20
|
-
export class CircuitBreaker {
|
|
21
|
-
db;
|
|
22
|
-
hooks;
|
|
23
|
-
breakers = new Map();
|
|
24
|
-
failureThreshold;
|
|
25
|
-
resetTimeoutMs;
|
|
26
|
-
persist;
|
|
27
|
-
constructor(db, hooks, config) {
|
|
28
|
-
this.db = db;
|
|
29
|
-
this.hooks = hooks;
|
|
30
|
-
this.failureThreshold = config?.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD;
|
|
31
|
-
this.resetTimeoutMs = config?.resetTimeoutMs ?? DEFAULT_RESET_TIMEOUT_MS;
|
|
32
|
-
this.persist = config?.persist ?? true;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Check if an agent is allowed to execute.
|
|
36
|
-
* Returns true if execution is allowed, false if circuit is open.
|
|
37
|
-
*/
|
|
38
|
-
canExecute(agentId) {
|
|
39
|
-
const breaker = this.breakers.get(agentId);
|
|
40
|
-
if (!breaker)
|
|
41
|
-
return true;
|
|
42
|
-
switch (breaker.state) {
|
|
43
|
-
case BreakerState.CLOSED:
|
|
44
|
-
return true;
|
|
45
|
-
case BreakerState.OPEN: {
|
|
46
|
-
// Check if enough time has passed for a probe
|
|
47
|
-
const elapsed = Date.now() - (breaker.trippedAt ?? 0);
|
|
48
|
-
if (elapsed >= this.resetTimeoutMs) {
|
|
49
|
-
breaker.state = BreakerState.HALF_OPEN;
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
case BreakerState.HALF_OPEN:
|
|
55
|
-
// Allow one probe execution
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Record a successful execution. Resets the breaker to CLOSED.
|
|
61
|
-
*/
|
|
62
|
-
async recordSuccess(agentId) {
|
|
63
|
-
const breaker = this.breakers.get(agentId);
|
|
64
|
-
if (!breaker)
|
|
65
|
-
return;
|
|
66
|
-
const previousState = breaker.state;
|
|
67
|
-
breaker.state = BreakerState.CLOSED;
|
|
68
|
-
breaker.failureCount = 0;
|
|
69
|
-
if (previousState === BreakerState.HALF_OPEN) {
|
|
70
|
-
await this.logEvent(agentId, 'circuit_recovered', {
|
|
71
|
-
previousState,
|
|
72
|
-
});
|
|
73
|
-
await this.hooks.emit('circuit_breaker.recovered', {
|
|
74
|
-
agentId,
|
|
75
|
-
previousState,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Record a failed execution. Increments failure count and may trip breaker.
|
|
81
|
-
*/
|
|
82
|
-
async recordFailure(agentId, reason) {
|
|
83
|
-
let breaker = this.breakers.get(agentId);
|
|
84
|
-
if (!breaker) {
|
|
85
|
-
breaker = {
|
|
86
|
-
state: BreakerState.CLOSED,
|
|
87
|
-
failureCount: 0,
|
|
88
|
-
lastFailureAt: Date.now(),
|
|
89
|
-
};
|
|
90
|
-
this.breakers.set(agentId, breaker);
|
|
91
|
-
}
|
|
92
|
-
breaker.failureCount++;
|
|
93
|
-
breaker.lastFailureAt = Date.now();
|
|
94
|
-
if (breaker.state === BreakerState.HALF_OPEN) {
|
|
95
|
-
// Probe failed — reopen
|
|
96
|
-
await this.trip(agentId, reason ?? 'Probe execution failed during half-open state');
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (breaker.failureCount >= this.failureThreshold) {
|
|
100
|
-
await this.trip(agentId, reason ?? `Failure threshold reached (${this.failureThreshold})`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Trip the breaker to OPEN state and escalate to human.
|
|
105
|
-
*/
|
|
106
|
-
async trip(agentId, reason) {
|
|
107
|
-
let breaker = this.breakers.get(agentId);
|
|
108
|
-
if (!breaker) {
|
|
109
|
-
breaker = {
|
|
110
|
-
state: BreakerState.CLOSED,
|
|
111
|
-
failureCount: 0,
|
|
112
|
-
lastFailureAt: Date.now(),
|
|
113
|
-
};
|
|
114
|
-
this.breakers.set(agentId, breaker);
|
|
115
|
-
}
|
|
116
|
-
breaker.state = BreakerState.OPEN;
|
|
117
|
-
breaker.trippedAt = Date.now();
|
|
118
|
-
await this.logEvent(agentId, 'circuit_tripped', {
|
|
119
|
-
reason,
|
|
120
|
-
failureCount: breaker.failureCount,
|
|
121
|
-
});
|
|
122
|
-
// Emit escalation hook for human notification
|
|
123
|
-
await this.hooks.emit('circuit_breaker.tripped', {
|
|
124
|
-
agentId,
|
|
125
|
-
reason,
|
|
126
|
-
failureCount: breaker.failureCount,
|
|
127
|
-
action: 'escalate_to_human',
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Manually reset a breaker (e.g. after human review).
|
|
132
|
-
*/
|
|
133
|
-
async reset(agentId) {
|
|
134
|
-
this.breakers.delete(agentId);
|
|
135
|
-
await this.logEvent(agentId, 'circuit_reset', {});
|
|
136
|
-
await this.hooks.emit('circuit_breaker.reset', { agentId });
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Get the current state of a breaker.
|
|
140
|
-
*/
|
|
141
|
-
getState(agentId) {
|
|
142
|
-
return this.breakers.get(agentId)?.state ?? BreakerState.CLOSED;
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Get failure count for an agent.
|
|
146
|
-
*/
|
|
147
|
-
getFailureCount(agentId) {
|
|
148
|
-
return this.breakers.get(agentId)?.failureCount ?? 0;
|
|
149
|
-
}
|
|
150
|
-
async logEvent(agentId, eventType, payload) {
|
|
151
|
-
if (!this.persist)
|
|
152
|
-
return;
|
|
153
|
-
await this.db.insert('activity_log', {
|
|
154
|
-
agent_id: agentId,
|
|
155
|
-
event_type: eventType,
|
|
156
|
-
payload: JSON.stringify(payload),
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|