@timmeck/brain-core 2.36.56 → 2.36.58
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 +6 -0
- package/command-center.html +133 -2
- package/dist/action/__tests__/action-bridge.test.d.ts +1 -0
- package/dist/action/__tests__/action-bridge.test.js +145 -0
- package/dist/action/__tests__/action-bridge.test.js.map +1 -0
- package/dist/action/__tests__/content-handler.test.d.ts +1 -0
- package/dist/action/__tests__/content-handler.test.js +100 -0
- package/dist/action/__tests__/content-handler.test.js.map +1 -0
- package/dist/action/__tests__/trade-handler.test.d.ts +1 -0
- package/dist/action/__tests__/trade-handler.test.js +165 -0
- package/dist/action/__tests__/trade-handler.test.js.map +1 -0
- package/dist/action/action-bridge.d.ts +95 -0
- package/dist/action/action-bridge.js +242 -0
- package/dist/action/action-bridge.js.map +1 -0
- package/dist/action/handlers/content-handler.d.ts +23 -0
- package/dist/action/handlers/content-handler.js +30 -0
- package/dist/action/handlers/content-handler.js.map +1 -0
- package/dist/action/handlers/index.d.ts +4 -0
- package/dist/action/handlers/index.js +3 -0
- package/dist/action/handlers/index.js.map +1 -0
- package/dist/action/handlers/trade-handler.d.ts +43 -0
- package/dist/action/handlers/trade-handler.js +43 -0
- package/dist/action/handlers/trade-handler.js.map +1 -0
- package/dist/action/index.d.ts +4 -0
- package/dist/action/index.js +3 -0
- package/dist/action/index.js.map +1 -0
- package/dist/agent-training/__tests__/agent-trainer.test.d.ts +1 -0
- package/dist/agent-training/__tests__/agent-trainer.test.js +158 -0
- package/dist/agent-training/__tests__/agent-trainer.test.js.map +1 -0
- package/dist/agent-training/__tests__/sub-agent-factory.test.d.ts +1 -0
- package/dist/agent-training/__tests__/sub-agent-factory.test.js +100 -0
- package/dist/agent-training/__tests__/sub-agent-factory.test.js.map +1 -0
- package/dist/agent-training/__tests__/sub-agent.test.d.ts +1 -0
- package/dist/agent-training/__tests__/sub-agent.test.js +102 -0
- package/dist/agent-training/__tests__/sub-agent.test.js.map +1 -0
- package/dist/agent-training/index.d.ts +4 -0
- package/dist/agent-training/index.js +2 -0
- package/dist/agent-training/index.js.map +1 -1
- package/dist/agent-training/sub-agent-factory.d.ts +36 -0
- package/dist/agent-training/sub-agent-factory.js +128 -0
- package/dist/agent-training/sub-agent-factory.js.map +1 -0
- package/dist/agent-training/sub-agent.d.ts +57 -0
- package/dist/agent-training/sub-agent.js +135 -0
- package/dist/agent-training/sub-agent.js.map +1 -0
- package/dist/chat/__tests__/chat-engine.test.d.ts +1 -0
- package/dist/chat/__tests__/chat-engine.test.js +128 -0
- package/dist/chat/__tests__/chat-engine.test.js.map +1 -0
- package/dist/chat/chat-engine.d.ts +55 -0
- package/dist/chat/chat-engine.js +186 -0
- package/dist/chat/chat-engine.js.map +1 -0
- package/dist/chat/index.d.ts +2 -0
- package/dist/chat/index.js +2 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/codegen/__tests__/code-forge.test.d.ts +1 -0
- package/dist/codegen/__tests__/code-forge.test.js +105 -0
- package/dist/codegen/__tests__/code-forge.test.js.map +1 -0
- package/dist/codegen/code-forge.d.ts +87 -0
- package/dist/codegen/code-forge.js +211 -0
- package/dist/codegen/code-forge.js.map +1 -0
- package/dist/codegen/index.d.ts +2 -0
- package/dist/codegen/index.js +1 -0
- package/dist/codegen/index.js.map +1 -1
- package/dist/content/__tests__/auto-publisher.test.d.ts +1 -0
- package/dist/content/__tests__/auto-publisher.test.js +125 -0
- package/dist/content/__tests__/auto-publisher.test.js.map +1 -0
- package/dist/content/__tests__/content-forge.test.d.ts +1 -0
- package/dist/content/__tests__/content-forge.test.js +117 -0
- package/dist/content/__tests__/content-forge.test.js.map +1 -0
- package/dist/content/auto-publisher.d.ts +51 -0
- package/dist/content/auto-publisher.js +147 -0
- package/dist/content/auto-publisher.js.map +1 -0
- package/dist/content/content-forge.d.ts +106 -0
- package/dist/content/content-forge.js +232 -0
- package/dist/content/content-forge.js.map +1 -0
- package/dist/content/index.d.ts +4 -0
- package/dist/content/index.js +3 -0
- package/dist/content/index.js.map +1 -0
- package/dist/creative/__tests__/creative-engine.test.d.ts +1 -0
- package/dist/creative/__tests__/creative-engine.test.js +151 -0
- package/dist/creative/__tests__/creative-engine.test.js.map +1 -0
- package/dist/cross-brain/__tests__/signal-router.test.d.ts +1 -0
- package/dist/cross-brain/__tests__/signal-router.test.js +159 -0
- package/dist/cross-brain/__tests__/signal-router.test.js.map +1 -0
- package/dist/cross-brain/signal-router.d.ts +57 -0
- package/dist/cross-brain/signal-router.js +148 -0
- package/dist/cross-brain/signal-router.js.map +1 -0
- package/dist/dashboard/__tests__/command-center-server.test.js +31 -0
- package/dist/dashboard/__tests__/command-center-server.test.js.map +1 -1
- package/dist/dashboard/command-center-server.d.ts +11 -0
- package/dist/dashboard/command-center-server.js +72 -0
- package/dist/dashboard/command-center-server.js.map +1 -1
- package/dist/dream/__tests__/dream-engine.test.d.ts +1 -0
- package/dist/dream/__tests__/dream-engine.test.js +184 -0
- package/dist/dream/__tests__/dream-engine.test.js.map +1 -0
- package/dist/feedback/__tests__/feedback-router.test.d.ts +1 -0
- package/dist/feedback/__tests__/feedback-router.test.js +173 -0
- package/dist/feedback/__tests__/feedback-router.test.js.map +1 -0
- package/dist/feedback/feedback-router.d.ts +53 -0
- package/dist/feedback/feedback-router.js +193 -0
- package/dist/feedback/feedback-router.js.map +1 -0
- package/dist/feedback/index.d.ts +2 -0
- package/dist/feedback/index.js +1 -0
- package/dist/feedback/index.js.map +1 -1
- package/dist/goals/__tests__/goal-engine.test.d.ts +1 -0
- package/dist/goals/__tests__/goal-engine.test.js +203 -0
- package/dist/goals/__tests__/goal-engine.test.js.map +1 -0
- package/dist/guardrails/__tests__/guardrail-engine.test.d.ts +1 -0
- package/dist/guardrails/__tests__/guardrail-engine.test.js +343 -0
- package/dist/guardrails/__tests__/guardrail-engine.test.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/metacognition/__tests__/auto-experiment-engine.test.d.ts +1 -0
- package/dist/metacognition/__tests__/auto-experiment-engine.test.js +218 -0
- package/dist/metacognition/__tests__/auto-experiment-engine.test.js.map +1 -0
- package/dist/metacognition/__tests__/evolution-engine.test.d.ts +1 -0
- package/dist/metacognition/__tests__/evolution-engine.test.js +473 -0
- package/dist/metacognition/__tests__/evolution-engine.test.js.map +1 -0
- package/dist/metacognition/__tests__/parameter-registry.test.d.ts +1 -0
- package/dist/metacognition/__tests__/parameter-registry.test.js +223 -0
- package/dist/metacognition/__tests__/parameter-registry.test.js.map +1 -0
- package/dist/prediction/__tests__/prediction-engine.test.d.ts +1 -0
- package/dist/prediction/__tests__/prediction-engine.test.js +244 -0
- package/dist/prediction/__tests__/prediction-engine.test.js.map +1 -0
- package/dist/research/research-orchestrator.d.ts +12 -0
- package/dist/research/research-orchestrator.js +109 -0
- package/dist/research/research-orchestrator.js.map +1 -1
- package/dist/sandbox/__tests__/code-sandbox.test.d.ts +1 -0
- package/dist/sandbox/__tests__/code-sandbox.test.js +182 -0
- package/dist/sandbox/__tests__/code-sandbox.test.js.map +1 -0
- package/dist/scanner/__tests__/signal-scanner.test.d.ts +1 -0
- package/dist/scanner/__tests__/signal-scanner.test.js +142 -0
- package/dist/scanner/__tests__/signal-scanner.test.js.map +1 -0
- package/dist/self-modification/__tests__/self-modification-engine.test.d.ts +1 -0
- package/dist/self-modification/__tests__/self-modification-engine.test.js +255 -0
- package/dist/self-modification/__tests__/self-modification-engine.test.js.map +1 -0
- package/dist/strategy/__tests__/strategy-forge.test.d.ts +1 -0
- package/dist/strategy/__tests__/strategy-forge.test.js +190 -0
- package/dist/strategy/__tests__/strategy-forge.test.js.map +1 -0
- package/dist/strategy/__tests__/strategy-mutator.test.d.ts +1 -0
- package/dist/strategy/__tests__/strategy-mutator.test.js +141 -0
- package/dist/strategy/__tests__/strategy-mutator.test.js.map +1 -0
- package/dist/strategy/index.d.ts +4 -0
- package/dist/strategy/index.js +3 -0
- package/dist/strategy/index.js.map +1 -0
- package/dist/strategy/strategy-forge.d.ts +114 -0
- package/dist/strategy/strategy-forge.js +296 -0
- package/dist/strategy/strategy-forge.js.map +1 -0
- package/dist/strategy/strategy-mutator.d.ts +42 -0
- package/dist/strategy/strategy-mutator.js +140 -0
- package/dist/strategy/strategy-mutator.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
4
|
+
getLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }),
|
|
5
|
+
}));
|
|
6
|
+
import { createTradeHandler } from '../handlers/trade-handler.js';
|
|
7
|
+
import { ActionBridgeEngine } from '../action-bridge.js';
|
|
8
|
+
describe('TradeHandler', () => {
|
|
9
|
+
describe('createTradeHandler', () => {
|
|
10
|
+
it('creates a handler function', () => {
|
|
11
|
+
const handler = createTradeHandler({
|
|
12
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 0, exits: 0 }),
|
|
13
|
+
});
|
|
14
|
+
expect(typeof handler).toBe('function');
|
|
15
|
+
});
|
|
16
|
+
it('calls runCycle on execution', async () => {
|
|
17
|
+
const runCycle = vi.fn().mockResolvedValue({ entries: 1, exits: 0 });
|
|
18
|
+
const handler = createTradeHandler({ runCycle });
|
|
19
|
+
const result = await handler({
|
|
20
|
+
symbol: 'BTC',
|
|
21
|
+
action: 'buy',
|
|
22
|
+
reason: 'BTC > 50000',
|
|
23
|
+
strategyId: 1,
|
|
24
|
+
confidence: 0.85,
|
|
25
|
+
});
|
|
26
|
+
expect(runCycle).toHaveBeenCalledOnce();
|
|
27
|
+
expect(result.triggered).toBe(true);
|
|
28
|
+
expect(result.action).toBe('buy');
|
|
29
|
+
expect(result.symbol).toBe('BTC');
|
|
30
|
+
expect(result.strategyId).toBe(1);
|
|
31
|
+
expect(result.cycleResult.entries).toBe(1);
|
|
32
|
+
});
|
|
33
|
+
it('returns sell action correctly', async () => {
|
|
34
|
+
const handler = createTradeHandler({
|
|
35
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 0, exits: 1 }),
|
|
36
|
+
});
|
|
37
|
+
const result = await handler({
|
|
38
|
+
symbol: 'ETH',
|
|
39
|
+
action: 'sell',
|
|
40
|
+
reason: 'ETH < 3000',
|
|
41
|
+
strategyId: 2,
|
|
42
|
+
confidence: 0.9,
|
|
43
|
+
});
|
|
44
|
+
expect(result.action).toBe('sell');
|
|
45
|
+
expect(result.symbol).toBe('ETH');
|
|
46
|
+
expect(result.cycleResult.exits).toBe(1);
|
|
47
|
+
});
|
|
48
|
+
it('includes portfolio snapshot when getPortfolio provided', async () => {
|
|
49
|
+
const handler = createTradeHandler({
|
|
50
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 1, exits: 0 }),
|
|
51
|
+
getPortfolio: () => ({
|
|
52
|
+
balance: 10000,
|
|
53
|
+
equity: 10500,
|
|
54
|
+
positions: [
|
|
55
|
+
{ symbol: 'BTC', side: 'long', pnlPct: 5 },
|
|
56
|
+
],
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
const result = await handler({ symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.8 });
|
|
60
|
+
expect(result.portfolioSnapshot).toBeDefined();
|
|
61
|
+
expect(result.portfolioSnapshot.balance).toBe(10000);
|
|
62
|
+
expect(result.portfolioSnapshot.equity).toBe(10500);
|
|
63
|
+
expect(result.portfolioSnapshot.positionCount).toBe(1);
|
|
64
|
+
});
|
|
65
|
+
it('handles missing portfolio gracefully', async () => {
|
|
66
|
+
const handler = createTradeHandler({
|
|
67
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 0, exits: 0 }),
|
|
68
|
+
});
|
|
69
|
+
const result = await handler({ symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.5 });
|
|
70
|
+
expect(result.portfolioSnapshot).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
it('handles portfolio error gracefully', async () => {
|
|
73
|
+
const handler = createTradeHandler({
|
|
74
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 0, exits: 0 }),
|
|
75
|
+
getPortfolio: () => { throw new Error('DB error'); },
|
|
76
|
+
});
|
|
77
|
+
const result = await handler({ symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.5 });
|
|
78
|
+
expect(result.portfolioSnapshot).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
it('defaults missing payload fields', async () => {
|
|
81
|
+
const handler = createTradeHandler({
|
|
82
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 0, exits: 0 }),
|
|
83
|
+
});
|
|
84
|
+
const result = await handler({});
|
|
85
|
+
expect(result.symbol).toBe('UNKNOWN');
|
|
86
|
+
expect(result.action).toBe('buy');
|
|
87
|
+
expect(result.strategyId).toBe(0);
|
|
88
|
+
});
|
|
89
|
+
it('propagates runCycle errors', async () => {
|
|
90
|
+
const handler = createTradeHandler({
|
|
91
|
+
runCycle: vi.fn().mockRejectedValue(new Error('No prices available')),
|
|
92
|
+
});
|
|
93
|
+
await expect(handler({ symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.8 }))
|
|
94
|
+
.rejects.toThrow('No prices available');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('Integration with ActionBridgeEngine', () => {
|
|
98
|
+
let db;
|
|
99
|
+
beforeEach(() => { db = new Database(':memory:'); });
|
|
100
|
+
afterEach(() => { db.close(); });
|
|
101
|
+
it('registers and executes trade handler through ActionBridge', async () => {
|
|
102
|
+
const engine = new ActionBridgeEngine(db, { brainName: 'test' });
|
|
103
|
+
const runCycle = vi.fn().mockResolvedValue({ entries: 1, exits: 0 });
|
|
104
|
+
engine.registerHandler('execute_trade', createTradeHandler({ runCycle }));
|
|
105
|
+
const id = engine.propose({
|
|
106
|
+
source: 'research',
|
|
107
|
+
type: 'execute_trade',
|
|
108
|
+
title: 'Buy BTC',
|
|
109
|
+
confidence: 0.85,
|
|
110
|
+
payload: { symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.85 },
|
|
111
|
+
});
|
|
112
|
+
const result = await engine.executeAction(id);
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
expect(runCycle).toHaveBeenCalledOnce();
|
|
115
|
+
});
|
|
116
|
+
it('auto-executes trade when confidence >= 0.8', async () => {
|
|
117
|
+
const engine = new ActionBridgeEngine(db, { brainName: 'test' });
|
|
118
|
+
const runCycle = vi.fn().mockResolvedValue({ entries: 0, exits: 1 });
|
|
119
|
+
engine.registerHandler('execute_trade', createTradeHandler({ runCycle }));
|
|
120
|
+
engine.propose({
|
|
121
|
+
source: 'research',
|
|
122
|
+
type: 'execute_trade',
|
|
123
|
+
title: 'Sell ETH',
|
|
124
|
+
confidence: 0.9,
|
|
125
|
+
payload: { symbol: 'ETH', action: 'sell', strategyId: 2, confidence: 0.9 },
|
|
126
|
+
});
|
|
127
|
+
const executed = await engine.processQueue();
|
|
128
|
+
expect(executed).toBe(1);
|
|
129
|
+
expect(runCycle).toHaveBeenCalledOnce();
|
|
130
|
+
});
|
|
131
|
+
it('does not auto-execute when confidence < 0.8', async () => {
|
|
132
|
+
const engine = new ActionBridgeEngine(db, { brainName: 'test' });
|
|
133
|
+
engine.registerHandler('execute_trade', createTradeHandler({
|
|
134
|
+
runCycle: vi.fn().mockResolvedValue({ entries: 0, exits: 0 }),
|
|
135
|
+
}));
|
|
136
|
+
engine.propose({
|
|
137
|
+
source: 'research',
|
|
138
|
+
type: 'execute_trade',
|
|
139
|
+
title: 'Low confidence trade',
|
|
140
|
+
confidence: 0.6,
|
|
141
|
+
payload: { symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.6 },
|
|
142
|
+
});
|
|
143
|
+
const executed = await engine.processQueue();
|
|
144
|
+
expect(executed).toBe(0);
|
|
145
|
+
});
|
|
146
|
+
it('records failed trade execution', async () => {
|
|
147
|
+
const engine = new ActionBridgeEngine(db, { brainName: 'test' });
|
|
148
|
+
engine.registerHandler('execute_trade', createTradeHandler({
|
|
149
|
+
runCycle: vi.fn().mockRejectedValue(new Error('Market closed')),
|
|
150
|
+
}));
|
|
151
|
+
const id = engine.propose({
|
|
152
|
+
source: 'research',
|
|
153
|
+
type: 'execute_trade',
|
|
154
|
+
title: 'Failed trade',
|
|
155
|
+
confidence: 0.9,
|
|
156
|
+
payload: { symbol: 'BTC', action: 'buy', strategyId: 1, confidence: 0.9 },
|
|
157
|
+
});
|
|
158
|
+
const result = await engine.executeAction(id);
|
|
159
|
+
expect(result.success).toBe(false);
|
|
160
|
+
const action = engine.getAction(id);
|
|
161
|
+
expect(action?.status).toBe('failed');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
//# sourceMappingURL=trade-handler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trade-handler.test.js","sourceRoot":"","sources":["../../../src/action/__tests__/trade-handler.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
export interface ProposedAction {
|
|
3
|
+
id: number;
|
|
4
|
+
source: 'proactive' | 'creative' | 'mission' | 'selfmod' | 'codegen' | 'research' | 'feedback-router';
|
|
5
|
+
type: 'publish_content' | 'apply_code' | 'execute_trade' | 'adjust_parameter' | 'create_goal' | 'start_mission' | 'creative_seed';
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
confidence: number;
|
|
9
|
+
riskLevel: 'low' | 'medium' | 'high';
|
|
10
|
+
payload: Record<string, unknown>;
|
|
11
|
+
status: 'pending' | 'approved' | 'executing' | 'completed' | 'failed' | 'rolled_back';
|
|
12
|
+
outcome?: ActionOutcome;
|
|
13
|
+
executedAt?: string;
|
|
14
|
+
createdAt?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ActionOutcome {
|
|
17
|
+
success: boolean;
|
|
18
|
+
result: unknown;
|
|
19
|
+
metrics?: Record<string, number>;
|
|
20
|
+
learnedLesson?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ActionBridgeConfig {
|
|
23
|
+
brainName: string;
|
|
24
|
+
maxPendingActions?: number;
|
|
25
|
+
autoExecuteEnabled?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ActionBridgeStatus {
|
|
28
|
+
queueSize: number;
|
|
29
|
+
executed24h: number;
|
|
30
|
+
successRate: number;
|
|
31
|
+
topSources: Array<{
|
|
32
|
+
source: string;
|
|
33
|
+
count: number;
|
|
34
|
+
}>;
|
|
35
|
+
autoExecuteEnabled: boolean;
|
|
36
|
+
}
|
|
37
|
+
type ActionType = ProposedAction['type'];
|
|
38
|
+
type ActionSource = ProposedAction['source'];
|
|
39
|
+
type RiskLevel = ProposedAction['riskLevel'];
|
|
40
|
+
export declare function runActionBridgeMigration(db: Database.Database): void;
|
|
41
|
+
export declare class ActionBridgeEngine {
|
|
42
|
+
private readonly db;
|
|
43
|
+
private readonly config;
|
|
44
|
+
private readonly log;
|
|
45
|
+
private handlers;
|
|
46
|
+
private readonly stmtInsert;
|
|
47
|
+
private readonly stmtGetById;
|
|
48
|
+
private readonly stmtUpdateStatus;
|
|
49
|
+
private readonly stmtSetOutcome;
|
|
50
|
+
private readonly stmtGetQueue;
|
|
51
|
+
private readonly stmtGetHistory;
|
|
52
|
+
private readonly stmtSuccessRate;
|
|
53
|
+
private readonly stmtSuccessRateByType;
|
|
54
|
+
private readonly stmtSuccessRateBySource;
|
|
55
|
+
private readonly stmtExecuted24h;
|
|
56
|
+
private readonly stmtTopSources;
|
|
57
|
+
constructor(db: Database.Database, config: ActionBridgeConfig);
|
|
58
|
+
/** Register an execution handler for an action type */
|
|
59
|
+
registerHandler(type: ActionType, handler: (payload: Record<string, unknown>) => Promise<unknown> | unknown): void;
|
|
60
|
+
/** Propose a new action — returns the action ID */
|
|
61
|
+
propose(action: {
|
|
62
|
+
source: ActionSource;
|
|
63
|
+
type: ActionType;
|
|
64
|
+
title: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
confidence: number;
|
|
67
|
+
payload?: Record<string, unknown>;
|
|
68
|
+
}): number;
|
|
69
|
+
/** Evaluate risk level for an action type */
|
|
70
|
+
evaluateRisk(type: ActionType, _confidence?: number): RiskLevel;
|
|
71
|
+
/** Check if an action qualifies for auto-execution */
|
|
72
|
+
canAutoExecute(action: ProposedAction): boolean;
|
|
73
|
+
/** Execute a specific action by ID */
|
|
74
|
+
executeAction(actionId: number): Promise<{
|
|
75
|
+
success: boolean;
|
|
76
|
+
result: unknown;
|
|
77
|
+
}>;
|
|
78
|
+
/** Process pending queue — auto-execute qualifying actions */
|
|
79
|
+
processQueue(): Promise<number>;
|
|
80
|
+
/** Record outcome for an already-executed action */
|
|
81
|
+
recordOutcome(actionId: number, outcome: ActionOutcome): void;
|
|
82
|
+
/** Rollback a completed action */
|
|
83
|
+
rollback(actionId: number): void;
|
|
84
|
+
/** Get success rate (optionally filtered by type or source) */
|
|
85
|
+
getSuccessRate(type?: string, source?: string): number;
|
|
86
|
+
/** Get queue items by status */
|
|
87
|
+
getQueue(status?: string): ProposedAction[];
|
|
88
|
+
/** Get action history (completed/failed/rolled_back) */
|
|
89
|
+
getHistory(limit?: number): ProposedAction[];
|
|
90
|
+
/** Get a single action by ID */
|
|
91
|
+
getAction(id: number): ProposedAction | null;
|
|
92
|
+
/** Get status overview */
|
|
93
|
+
getStatus(): ActionBridgeStatus;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// Risk thresholds: type → { risk, minConfidence }
|
|
3
|
+
const RISK_MAP = {
|
|
4
|
+
adjust_parameter: { risk: 'low', minConfidence: 0.7 },
|
|
5
|
+
create_goal: { risk: 'low', minConfidence: 0.6 },
|
|
6
|
+
start_mission: { risk: 'low', minConfidence: 0.5 },
|
|
7
|
+
publish_content: { risk: 'medium', minConfidence: 0.8 },
|
|
8
|
+
execute_trade: { risk: 'medium', minConfidence: 0.8 },
|
|
9
|
+
apply_code: { risk: 'high', minConfidence: 1.1 }, // never auto (>1.0)
|
|
10
|
+
creative_seed: { risk: 'low', minConfidence: 0.5 },
|
|
11
|
+
};
|
|
12
|
+
// ── Migration ──────────────────────────────────────────────
|
|
13
|
+
export function runActionBridgeMigration(db) {
|
|
14
|
+
db.exec(`
|
|
15
|
+
CREATE TABLE IF NOT EXISTS action_queue (
|
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
17
|
+
source TEXT NOT NULL,
|
|
18
|
+
type TEXT NOT NULL,
|
|
19
|
+
title TEXT NOT NULL,
|
|
20
|
+
description TEXT,
|
|
21
|
+
confidence REAL DEFAULT 0,
|
|
22
|
+
risk_level TEXT DEFAULT 'medium',
|
|
23
|
+
payload TEXT,
|
|
24
|
+
status TEXT DEFAULT 'pending',
|
|
25
|
+
outcome TEXT,
|
|
26
|
+
executed_at TEXT,
|
|
27
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
28
|
+
);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_action_status ON action_queue(status);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_action_source ON action_queue(source);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_action_type ON action_queue(type);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_action_created ON action_queue(created_at);
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
// ── Engine ──────────────────────────────────────────────────
|
|
36
|
+
export class ActionBridgeEngine {
|
|
37
|
+
db;
|
|
38
|
+
config;
|
|
39
|
+
log = getLogger();
|
|
40
|
+
// Execution handlers keyed by action type
|
|
41
|
+
handlers = new Map();
|
|
42
|
+
// Prepared statements
|
|
43
|
+
stmtInsert;
|
|
44
|
+
stmtGetById;
|
|
45
|
+
stmtUpdateStatus;
|
|
46
|
+
stmtSetOutcome;
|
|
47
|
+
stmtGetQueue;
|
|
48
|
+
stmtGetHistory;
|
|
49
|
+
stmtSuccessRate;
|
|
50
|
+
stmtSuccessRateByType;
|
|
51
|
+
stmtSuccessRateBySource;
|
|
52
|
+
stmtExecuted24h;
|
|
53
|
+
stmtTopSources;
|
|
54
|
+
constructor(db, config) {
|
|
55
|
+
this.db = db;
|
|
56
|
+
this.config = {
|
|
57
|
+
brainName: config.brainName,
|
|
58
|
+
maxPendingActions: config.maxPendingActions ?? 100,
|
|
59
|
+
autoExecuteEnabled: config.autoExecuteEnabled ?? true,
|
|
60
|
+
};
|
|
61
|
+
runActionBridgeMigration(db);
|
|
62
|
+
this.stmtInsert = db.prepare(`
|
|
63
|
+
INSERT INTO action_queue (source, type, title, description, confidence, risk_level, payload, status)
|
|
64
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')
|
|
65
|
+
`);
|
|
66
|
+
this.stmtGetById = db.prepare(`SELECT * FROM action_queue WHERE id = ?`);
|
|
67
|
+
this.stmtUpdateStatus = db.prepare(`UPDATE action_queue SET status = ? WHERE id = ?`);
|
|
68
|
+
this.stmtSetOutcome = db.prepare(`UPDATE action_queue SET status = ?, outcome = ?, executed_at = datetime('now') WHERE id = ?`);
|
|
69
|
+
this.stmtGetQueue = db.prepare(`SELECT * FROM action_queue WHERE status = ? ORDER BY confidence DESC, created_at ASC LIMIT ?`);
|
|
70
|
+
this.stmtGetHistory = db.prepare(`SELECT * FROM action_queue WHERE status IN ('completed', 'failed', 'rolled_back') ORDER BY executed_at DESC LIMIT ?`);
|
|
71
|
+
this.stmtSuccessRate = db.prepare(`SELECT COUNT(*) as total, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successes FROM action_queue WHERE status IN ('completed', 'failed')`);
|
|
72
|
+
this.stmtSuccessRateByType = db.prepare(`SELECT COUNT(*) as total, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successes FROM action_queue WHERE status IN ('completed', 'failed') AND type = ?`);
|
|
73
|
+
this.stmtSuccessRateBySource = db.prepare(`SELECT COUNT(*) as total, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successes FROM action_queue WHERE status IN ('completed', 'failed') AND source = ?`);
|
|
74
|
+
this.stmtExecuted24h = db.prepare(`SELECT COUNT(*) as count FROM action_queue WHERE executed_at > datetime('now', '-1 day')`);
|
|
75
|
+
this.stmtTopSources = db.prepare(`SELECT source, COUNT(*) as count FROM action_queue GROUP BY source ORDER BY count DESC LIMIT 5`);
|
|
76
|
+
}
|
|
77
|
+
/** Register an execution handler for an action type */
|
|
78
|
+
registerHandler(type, handler) {
|
|
79
|
+
this.handlers.set(type, handler);
|
|
80
|
+
}
|
|
81
|
+
/** Propose a new action — returns the action ID */
|
|
82
|
+
propose(action) {
|
|
83
|
+
const risk = this.evaluateRisk(action.type, action.confidence);
|
|
84
|
+
// Check queue limit
|
|
85
|
+
const pending = this.getQueue('pending');
|
|
86
|
+
if (pending.length >= this.config.maxPendingActions) {
|
|
87
|
+
this.log.warn(`[action-bridge] Queue full (${pending.length}/${this.config.maxPendingActions}), rejecting: ${action.title}`);
|
|
88
|
+
return -1;
|
|
89
|
+
}
|
|
90
|
+
const result = this.stmtInsert.run(action.source, action.type, action.title, action.description ?? '', action.confidence, risk, JSON.stringify(action.payload ?? {}));
|
|
91
|
+
const id = Number(result.lastInsertRowid);
|
|
92
|
+
this.log.info(`[action-bridge] Proposed #${id}: ${action.title} (${action.source}/${action.type}, risk=${risk}, conf=${action.confidence.toFixed(2)})`);
|
|
93
|
+
return id;
|
|
94
|
+
}
|
|
95
|
+
/** Evaluate risk level for an action type */
|
|
96
|
+
evaluateRisk(type, _confidence) {
|
|
97
|
+
return RISK_MAP[type]?.risk ?? 'high';
|
|
98
|
+
}
|
|
99
|
+
/** Check if an action qualifies for auto-execution */
|
|
100
|
+
canAutoExecute(action) {
|
|
101
|
+
if (!this.config.autoExecuteEnabled)
|
|
102
|
+
return false;
|
|
103
|
+
const rule = RISK_MAP[action.type];
|
|
104
|
+
if (!rule)
|
|
105
|
+
return false;
|
|
106
|
+
return action.confidence >= rule.minConfidence;
|
|
107
|
+
}
|
|
108
|
+
/** Execute a specific action by ID */
|
|
109
|
+
async executeAction(actionId) {
|
|
110
|
+
const row = this.stmtGetById.get(actionId);
|
|
111
|
+
if (!row)
|
|
112
|
+
throw new Error(`Action #${actionId} not found`);
|
|
113
|
+
const action = deserializeAction(row);
|
|
114
|
+
if (action.status !== 'pending' && action.status !== 'approved') {
|
|
115
|
+
throw new Error(`Action #${actionId} cannot be executed (status=${action.status})`);
|
|
116
|
+
}
|
|
117
|
+
const handler = this.handlers.get(action.type);
|
|
118
|
+
if (!handler) {
|
|
119
|
+
this.log.warn(`[action-bridge] No handler for type: ${action.type}`);
|
|
120
|
+
this.stmtSetOutcome.run('failed', JSON.stringify({ success: false, result: 'No handler registered' }), actionId);
|
|
121
|
+
return { success: false, result: 'No handler registered' };
|
|
122
|
+
}
|
|
123
|
+
this.stmtUpdateStatus.run('executing', actionId);
|
|
124
|
+
try {
|
|
125
|
+
const result = await handler(action.payload);
|
|
126
|
+
const outcome = { success: true, result };
|
|
127
|
+
this.stmtSetOutcome.run('completed', JSON.stringify(outcome), actionId);
|
|
128
|
+
this.log.info(`[action-bridge] Executed #${actionId}: ${action.title} → success`);
|
|
129
|
+
return { success: true, result };
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
const outcome = { success: false, result: err.message };
|
|
133
|
+
this.stmtSetOutcome.run('failed', JSON.stringify(outcome), actionId);
|
|
134
|
+
this.log.warn(`[action-bridge] Executed #${actionId}: ${action.title} → failed: ${err.message}`);
|
|
135
|
+
return { success: false, result: err.message };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Process pending queue — auto-execute qualifying actions */
|
|
139
|
+
async processQueue() {
|
|
140
|
+
if (!this.config.autoExecuteEnabled)
|
|
141
|
+
return 0;
|
|
142
|
+
const pending = this.getQueue('pending');
|
|
143
|
+
let executed = 0;
|
|
144
|
+
for (const action of pending) {
|
|
145
|
+
if (this.canAutoExecute(action)) {
|
|
146
|
+
try {
|
|
147
|
+
await this.executeAction(action.id);
|
|
148
|
+
executed++;
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
this.log.warn(`[action-bridge] Auto-execute error for #${action.id}: ${err.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (executed > 0) {
|
|
156
|
+
this.log.info(`[action-bridge] Auto-executed ${executed} action(s)`);
|
|
157
|
+
}
|
|
158
|
+
return executed;
|
|
159
|
+
}
|
|
160
|
+
/** Record outcome for an already-executed action */
|
|
161
|
+
recordOutcome(actionId, outcome) {
|
|
162
|
+
const row = this.stmtGetById.get(actionId);
|
|
163
|
+
if (!row)
|
|
164
|
+
throw new Error(`Action #${actionId} not found`);
|
|
165
|
+
const status = outcome.success ? 'completed' : 'failed';
|
|
166
|
+
this.stmtSetOutcome.run(status, JSON.stringify(outcome), actionId);
|
|
167
|
+
this.log.info(`[action-bridge] Outcome recorded for #${actionId}: ${status}`);
|
|
168
|
+
}
|
|
169
|
+
/** Rollback a completed action */
|
|
170
|
+
rollback(actionId) {
|
|
171
|
+
const row = this.stmtGetById.get(actionId);
|
|
172
|
+
if (!row)
|
|
173
|
+
throw new Error(`Action #${actionId} not found`);
|
|
174
|
+
if (row.status !== 'completed' && row.status !== 'failed') {
|
|
175
|
+
throw new Error(`Action #${actionId} cannot be rolled back (status=${row.status})`);
|
|
176
|
+
}
|
|
177
|
+
this.stmtUpdateStatus.run('rolled_back', actionId);
|
|
178
|
+
this.log.info(`[action-bridge] Rolled back #${actionId}`);
|
|
179
|
+
}
|
|
180
|
+
/** Get success rate (optionally filtered by type or source) */
|
|
181
|
+
getSuccessRate(type, source) {
|
|
182
|
+
let row;
|
|
183
|
+
if (type) {
|
|
184
|
+
row = this.stmtSuccessRateByType.get(type);
|
|
185
|
+
}
|
|
186
|
+
else if (source) {
|
|
187
|
+
row = this.stmtSuccessRateBySource.get(source);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
row = this.stmtSuccessRate.get();
|
|
191
|
+
}
|
|
192
|
+
if (!row || row.total === 0)
|
|
193
|
+
return 0;
|
|
194
|
+
return row.successes / row.total;
|
|
195
|
+
}
|
|
196
|
+
/** Get queue items by status */
|
|
197
|
+
getQueue(status) {
|
|
198
|
+
const rows = this.stmtGetQueue.all(status ?? 'pending', 100);
|
|
199
|
+
return rows.map(deserializeAction);
|
|
200
|
+
}
|
|
201
|
+
/** Get action history (completed/failed/rolled_back) */
|
|
202
|
+
getHistory(limit) {
|
|
203
|
+
const rows = this.stmtGetHistory.all(limit ?? 50);
|
|
204
|
+
return rows.map(deserializeAction);
|
|
205
|
+
}
|
|
206
|
+
/** Get a single action by ID */
|
|
207
|
+
getAction(id) {
|
|
208
|
+
const row = this.stmtGetById.get(id);
|
|
209
|
+
return row ? deserializeAction(row) : null;
|
|
210
|
+
}
|
|
211
|
+
/** Get status overview */
|
|
212
|
+
getStatus() {
|
|
213
|
+
const queueSize = (this.getQueue('pending')).length;
|
|
214
|
+
const executed24h = this.stmtExecuted24h.get().count;
|
|
215
|
+
const successRate = this.getSuccessRate();
|
|
216
|
+
const topSources = this.stmtTopSources.all();
|
|
217
|
+
return {
|
|
218
|
+
queueSize,
|
|
219
|
+
executed24h,
|
|
220
|
+
successRate,
|
|
221
|
+
topSources,
|
|
222
|
+
autoExecuteEnabled: this.config.autoExecuteEnabled,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function deserializeAction(row) {
|
|
227
|
+
return {
|
|
228
|
+
id: row.id,
|
|
229
|
+
source: row.source,
|
|
230
|
+
type: row.type,
|
|
231
|
+
title: row.title,
|
|
232
|
+
description: row.description,
|
|
233
|
+
confidence: row.confidence,
|
|
234
|
+
riskLevel: row.risk_level,
|
|
235
|
+
payload: JSON.parse(row.payload || '{}'),
|
|
236
|
+
status: row.status,
|
|
237
|
+
outcome: row.outcome ? JSON.parse(row.outcome) : undefined,
|
|
238
|
+
executedAt: row.executed_at ?? undefined,
|
|
239
|
+
createdAt: row.created_at,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=action-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-bridge.js","sourceRoot":"","sources":["../../src/action/action-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ContentHandlerDeps {
|
|
2
|
+
publishNow: (pieceId: number) => Promise<{
|
|
3
|
+
success: boolean;
|
|
4
|
+
postId?: string;
|
|
5
|
+
}>;
|
|
6
|
+
getPiece: (id: number) => {
|
|
7
|
+
id: number;
|
|
8
|
+
title: string;
|
|
9
|
+
platform: string;
|
|
10
|
+
status: string;
|
|
11
|
+
} | null;
|
|
12
|
+
}
|
|
13
|
+
export interface ContentHandlerResult {
|
|
14
|
+
published: boolean;
|
|
15
|
+
pieceId: number;
|
|
16
|
+
postId?: string;
|
|
17
|
+
platform?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates an ActionBridge handler for `publish_content` actions.
|
|
21
|
+
* Translates publish proposals into ContentForge.publishNow() calls.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createContentHandler(deps: ContentHandlerDeps): (payload: Record<string, unknown>) => Promise<ContentHandlerResult>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getLogger } from '../../utils/logger.js';
|
|
2
|
+
// ── Handler Factory ──────────────────────────────────────────
|
|
3
|
+
const log = getLogger();
|
|
4
|
+
/**
|
|
5
|
+
* Creates an ActionBridge handler for `publish_content` actions.
|
|
6
|
+
* Translates publish proposals into ContentForge.publishNow() calls.
|
|
7
|
+
*/
|
|
8
|
+
export function createContentHandler(deps) {
|
|
9
|
+
return async (payload) => {
|
|
10
|
+
const pieceId = payload.pieceId ?? 0;
|
|
11
|
+
const piece = deps.getPiece(pieceId);
|
|
12
|
+
if (!piece) {
|
|
13
|
+
log.warn(`[content-handler] Content piece #${pieceId} not found`);
|
|
14
|
+
throw new Error(`Content piece #${pieceId} not found`);
|
|
15
|
+
}
|
|
16
|
+
if (piece.status === 'published') {
|
|
17
|
+
log.info(`[content-handler] Content #${pieceId} already published`);
|
|
18
|
+
return { published: false, pieceId, platform: piece.platform };
|
|
19
|
+
}
|
|
20
|
+
log.info(`[content-handler] Publishing content #${pieceId}: ${piece.title} on ${piece.platform}`);
|
|
21
|
+
const result = await deps.publishNow(pieceId);
|
|
22
|
+
return {
|
|
23
|
+
published: result.success,
|
|
24
|
+
pieceId,
|
|
25
|
+
postId: result.postId,
|
|
26
|
+
platform: piece.platform,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=content-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-handler.js","sourceRoot":"","sources":["../../../src/action/handlers/content-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAgBlD,gEAAgE;AAEhE,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAwB;IAC3D,OAAO,KAAK,EAAE,OAAgC,EAAiC,EAAE;QAC/E,MAAM,OAAO,GAAI,OAAO,CAAC,OAAkB,IAAI,CAAC,CAAC;QAEjD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,oCAAoC,OAAO,YAAY,CAAC,CAAC;YAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,YAAY,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,8BAA8B,OAAO,oBAAoB,CAAC,CAAC;YACpE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjE,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,yCAAyC,OAAO,KAAK,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAElG,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAE9C,OAAO;YACL,SAAS,EAAE,MAAM,CAAC,OAAO;YACzB,OAAO;YACP,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createTradeHandler } from './trade-handler.js';
|
|
2
|
+
export type { TradeActionPayload, TradeHandlerDeps, TradeHandlerResult } from './trade-handler.js';
|
|
3
|
+
export { createContentHandler } from './content-handler.js';
|
|
4
|
+
export type { ContentHandlerDeps, ContentHandlerResult } from './content-handler.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/action/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface TradeActionPayload {
|
|
2
|
+
symbol: string;
|
|
3
|
+
action: 'buy' | 'sell';
|
|
4
|
+
reason: string;
|
|
5
|
+
strategyId: number;
|
|
6
|
+
ruleCondition: string;
|
|
7
|
+
confidence: number;
|
|
8
|
+
}
|
|
9
|
+
export interface TradeHandlerDeps {
|
|
10
|
+
runCycle: () => Promise<{
|
|
11
|
+
entries: number;
|
|
12
|
+
exits: number;
|
|
13
|
+
}>;
|
|
14
|
+
getPortfolio?: () => {
|
|
15
|
+
balance: number;
|
|
16
|
+
equity: number;
|
|
17
|
+
positions: Array<{
|
|
18
|
+
symbol: string;
|
|
19
|
+
side: string;
|
|
20
|
+
pnlPct: number;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface TradeHandlerResult {
|
|
25
|
+
triggered: boolean;
|
|
26
|
+
action: 'buy' | 'sell';
|
|
27
|
+
symbol: string;
|
|
28
|
+
strategyId: number;
|
|
29
|
+
cycleResult: {
|
|
30
|
+
entries: number;
|
|
31
|
+
exits: number;
|
|
32
|
+
};
|
|
33
|
+
portfolioSnapshot?: {
|
|
34
|
+
balance: number;
|
|
35
|
+
equity: number;
|
|
36
|
+
positionCount: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates an ActionBridge handler for `execute_trade` actions.
|
|
41
|
+
* Translates trade proposals from StrategyForge into PaperEngine cycles.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createTradeHandler(deps: TradeHandlerDeps): (payload: Record<string, unknown>) => Promise<TradeHandlerResult>;
|