@wopr-network/defcon 1.6.0 → 1.6.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/dist/src/engine/engine.d.ts +4 -0
- package/dist/src/engine/engine.js +30 -6
- package/dist/src/execution/cli.js +2 -0
- package/dist/src/main.d.ts +6 -0
- package/dist/src/main.js +20 -0
- package/package.json +1 -1
|
@@ -38,6 +38,8 @@ export interface EngineDeps {
|
|
|
38
38
|
adapters: Map<string, unknown>;
|
|
39
39
|
eventEmitter: IEventBusAdapter;
|
|
40
40
|
logger?: Logger;
|
|
41
|
+
/** Optional transaction wrapper from the database layer. When provided, processSignal runs inside a single transaction and events are flushed only after successful commit. */
|
|
42
|
+
withTransaction?: <T>(fn: () => T | Promise<T>) => Promise<T>;
|
|
41
43
|
}
|
|
42
44
|
export declare class Engine {
|
|
43
45
|
private entityRepo;
|
|
@@ -48,6 +50,7 @@ export declare class Engine {
|
|
|
48
50
|
readonly adapters: Map<string, unknown>;
|
|
49
51
|
private eventEmitter;
|
|
50
52
|
private readonly logger;
|
|
53
|
+
private readonly withTransactionFn;
|
|
51
54
|
private drainingWorkers;
|
|
52
55
|
constructor(deps: EngineDeps);
|
|
53
56
|
drainWorker(workerId: string): void;
|
|
@@ -56,6 +59,7 @@ export declare class Engine {
|
|
|
56
59
|
listDrainingWorkers(): string[];
|
|
57
60
|
emit(event: import("./event-types.js").EngineEvent): Promise<void>;
|
|
58
61
|
processSignal(entityId: string, signal: string, artifacts?: Artifacts, triggeringInvocationId?: string): Promise<ProcessSignalResult>;
|
|
62
|
+
private _processSignalInner;
|
|
59
63
|
/**
|
|
60
64
|
* Evaluate a gate and return a routing decision:
|
|
61
65
|
* - `proceed` — gate passed, continue to transition.toState
|
|
@@ -17,6 +17,7 @@ export class Engine {
|
|
|
17
17
|
adapters;
|
|
18
18
|
eventEmitter;
|
|
19
19
|
logger;
|
|
20
|
+
withTransactionFn;
|
|
20
21
|
drainingWorkers = new Set();
|
|
21
22
|
constructor(deps) {
|
|
22
23
|
this.entityRepo = deps.entityRepo;
|
|
@@ -27,6 +28,7 @@ export class Engine {
|
|
|
27
28
|
this.adapters = deps.adapters;
|
|
28
29
|
this.eventEmitter = deps.eventEmitter;
|
|
29
30
|
this.logger = deps.logger ?? consoleLogger;
|
|
31
|
+
this.withTransactionFn = deps.withTransaction ?? null;
|
|
30
32
|
}
|
|
31
33
|
drainWorker(workerId) {
|
|
32
34
|
this.drainingWorkers.add(workerId);
|
|
@@ -44,6 +46,28 @@ export class Engine {
|
|
|
44
46
|
await this.eventEmitter.emit(event);
|
|
45
47
|
}
|
|
46
48
|
async processSignal(entityId, signal, artifacts, triggeringInvocationId) {
|
|
49
|
+
const pendingEvents = [];
|
|
50
|
+
const bufferingEmitter = {
|
|
51
|
+
emit: async (event) => {
|
|
52
|
+
pendingEvents.push(event);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
if (this.withTransactionFn) {
|
|
56
|
+
// Run DB writes inside a transaction; events are buffered and only
|
|
57
|
+
// flushed to real subscribers after successful COMMIT.
|
|
58
|
+
const result = await this.withTransactionFn(() => this._processSignalInner(entityId, signal, artifacts, triggeringInvocationId, bufferingEmitter));
|
|
59
|
+
for (const event of pendingEvents) {
|
|
60
|
+
await this.eventEmitter.emit(event);
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
const result = await this._processSignalInner(entityId, signal, artifacts, triggeringInvocationId, bufferingEmitter);
|
|
65
|
+
for (const event of pendingEvents) {
|
|
66
|
+
await this.eventEmitter.emit(event);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
async _processSignalInner(entityId, signal, artifacts, triggeringInvocationId, emitter = this.eventEmitter) {
|
|
47
71
|
// 1. Load entity
|
|
48
72
|
const entity = await this.entityRepo.get(entityId);
|
|
49
73
|
if (!entity)
|
|
@@ -98,7 +122,7 @@ export class Engine {
|
|
|
98
122
|
// Keep the in-memory entity in sync so buildInvocation sees the cleared failures
|
|
99
123
|
updated = { ...updated, artifacts: { ...updated.artifacts, gate_failures: [] } };
|
|
100
124
|
// 6. Emit transition event
|
|
101
|
-
await
|
|
125
|
+
await emitter.emit({
|
|
102
126
|
type: "entity.transitioned",
|
|
103
127
|
entityId,
|
|
104
128
|
flowId: flow.id,
|
|
@@ -118,7 +142,7 @@ export class Engine {
|
|
|
118
142
|
if (newStateDef?.onEnter) {
|
|
119
143
|
const onEnterResult = await executeOnEnter(newStateDef.onEnter, updated, this.entityRepo);
|
|
120
144
|
if (onEnterResult.skipped) {
|
|
121
|
-
await
|
|
145
|
+
await emitter.emit({
|
|
122
146
|
type: "onEnter.skipped",
|
|
123
147
|
entityId,
|
|
124
148
|
state: toState,
|
|
@@ -126,7 +150,7 @@ export class Engine {
|
|
|
126
150
|
});
|
|
127
151
|
}
|
|
128
152
|
else if (onEnterResult.error) {
|
|
129
|
-
await
|
|
153
|
+
await emitter.emit({
|
|
130
154
|
type: "onEnter.failed",
|
|
131
155
|
entityId,
|
|
132
156
|
state: toState,
|
|
@@ -151,7 +175,7 @@ export class Engine {
|
|
|
151
175
|
};
|
|
152
176
|
}
|
|
153
177
|
else {
|
|
154
|
-
await
|
|
178
|
+
await emitter.emit({
|
|
155
179
|
type: "onEnter.completed",
|
|
156
180
|
entityId,
|
|
157
181
|
state: toState,
|
|
@@ -179,7 +203,7 @@ export class Engine {
|
|
|
179
203
|
? { systemPrompt: build.systemPrompt, userContent: build.userContent }
|
|
180
204
|
: undefined, newStateDef.agentRole ?? null);
|
|
181
205
|
result.invocationId = invocation.id;
|
|
182
|
-
await
|
|
206
|
+
await emitter.emit({
|
|
183
207
|
type: "invocation.created",
|
|
184
208
|
entityId,
|
|
185
209
|
invocationId: invocation.id,
|
|
@@ -202,7 +226,7 @@ export class Engine {
|
|
|
202
226
|
const spawned = await executeSpawn({ spawnFlow }, updated, this.flowRepo, this.entityRepo, this.logger);
|
|
203
227
|
if (spawned) {
|
|
204
228
|
result.spawned = [spawned.id];
|
|
205
|
-
await
|
|
229
|
+
await emitter.emit({
|
|
206
230
|
type: "flow.spawned",
|
|
207
231
|
entityId,
|
|
208
232
|
flowId: flow.id,
|
|
@@ -14,6 +14,7 @@ import { loadSeed } from "../config/seed-loader.js";
|
|
|
14
14
|
import { resolveCorsOrigin } from "../cors.js";
|
|
15
15
|
import { Engine } from "../engine/engine.js";
|
|
16
16
|
import { EventEmitter } from "../engine/event-emitter.js";
|
|
17
|
+
import { withTransaction } from "../main.js";
|
|
17
18
|
import { DrizzleEntityRepository } from "../repositories/drizzle/entity.repo.js";
|
|
18
19
|
import { DrizzleEventRepository } from "../repositories/drizzle/event.repo.js";
|
|
19
20
|
import { DrizzleFlowRepository } from "../repositories/drizzle/flow.repo.js";
|
|
@@ -173,6 +174,7 @@ program
|
|
|
173
174
|
transitionLogRepo,
|
|
174
175
|
adapters: new Map(),
|
|
175
176
|
eventEmitter,
|
|
177
|
+
withTransaction: (fn) => withTransaction(sqlite, fn),
|
|
176
178
|
});
|
|
177
179
|
const deps = {
|
|
178
180
|
entities: entityRepo,
|
package/dist/src/main.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ export declare function createDatabase(dbPath?: string): {
|
|
|
5
5
|
db: ReturnType<typeof drizzle<typeof schema>>;
|
|
6
6
|
sqlite: Database.Database;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* Wraps `fn` in a BEGIN/COMMIT/ROLLBACK transaction on `sqlite`.
|
|
10
|
+
* If already inside a transaction, runs `fn` directly (allows nested calls).
|
|
11
|
+
* Supports both synchronous and Promise-returning `fn`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function withTransaction<T>(sqlite: Database.Database, fn: () => T | Promise<T>): Promise<T>;
|
|
8
14
|
export declare function runMigrations(db: ReturnType<typeof drizzle>, migrationsFolder?: string): void;
|
|
9
15
|
export declare function bootstrap(dbPath?: string): {
|
|
10
16
|
db: ReturnType<typeof drizzle>;
|
package/dist/src/main.js
CHANGED
|
@@ -10,6 +10,26 @@ export function createDatabase(dbPath = DB_PATH) {
|
|
|
10
10
|
const db = drizzle(sqlite, { schema });
|
|
11
11
|
return { db, sqlite };
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Wraps `fn` in a BEGIN/COMMIT/ROLLBACK transaction on `sqlite`.
|
|
15
|
+
* If already inside a transaction, runs `fn` directly (allows nested calls).
|
|
16
|
+
* Supports both synchronous and Promise-returning `fn`.
|
|
17
|
+
*/
|
|
18
|
+
export async function withTransaction(sqlite, fn) {
|
|
19
|
+
if (sqlite.inTransaction) {
|
|
20
|
+
return fn();
|
|
21
|
+
}
|
|
22
|
+
sqlite.exec("BEGIN");
|
|
23
|
+
try {
|
|
24
|
+
const result = await fn();
|
|
25
|
+
sqlite.exec("COMMIT");
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
sqlite.exec("ROLLBACK");
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
13
33
|
export function runMigrations(db, migrationsFolder = "./drizzle") {
|
|
14
34
|
migrate(db, { migrationsFolder });
|
|
15
35
|
}
|