Skip to content

Commit 22d4bf9

Browse files
author
jovanSAPFIONEER
committed
fix: serialization crash in parallel waves + add openai devDep
- validateValue: handle undefined (JSON.stringify(undefined) returns undefined not a string, causing .length to throw as 'circular reference') - executeSingleTask: propagate adapter failure instead of returning success with undefined result - executeParallel: wrap cache write in try-catch so cache failures don't abort the entire wave - package.json: add openai as devDependency (used in examples/04-live-swarm) - .gitignore: exclude examples/04-live-swarm.ts (contains API key) - swarm-blackboard.md: updated with live demo run state
1 parent 36dd680 commit 22d4bf9

File tree

5 files changed

+265
-48
lines changed

5 files changed

+265
-48
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Thumbs.db
1818
# Python
1919
__pycache__/
2020
*.pyc
21+
22+
# Live demo (contains API key - never commit)
23+
examples/04-live-swarm.ts
2124
*.pyo
2225
.env
2326
.venv/

index.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,15 @@ class SharedBlackboard {
407407
* Prevents DoS via oversized writes and circular data.
408408
*/
409409
private validateValue(value: unknown): { valid: boolean; reason?: string } {
410+
if (value === undefined) {
411+
return { valid: false, reason: 'Value is undefined and cannot be stored' };
412+
}
410413
try {
411414
const serialized = JSON.stringify(value);
415+
if (serialized === undefined) {
416+
// JSON.stringify returns undefined for unsupported root types (functions, symbols, etc.)
417+
return { valid: false, reason: 'Value cannot be serialized (unsupported type)' };
418+
}
412419
if (serialized.length > CONFIG.maxBlackboardValueSize) {
413420
return { valid: false, reason: `Value exceeds max size (${serialized.length} > ${CONFIG.maxBlackboardValueSize} bytes)` };
414421
}
@@ -1201,10 +1208,14 @@ class TaskDecomposer {
12011208

12021209
individualResults.push(result);
12031210

1204-
// Cache successful results
1205-
if (result.success) {
1206-
const cacheKey = `task:${task.agentType}:${this.hashPayload(task.taskPayload)}`;
1207-
this.blackboard.write(cacheKey, result.result, context.agentId, 3600, 'system-orchestrator-token'); // 1 hour TTL
1211+
// Cache successful results (non-fatal if caching fails)
1212+
if (result.success && result.result !== undefined) {
1213+
try {
1214+
const cacheKey = `task:${task.agentType}:${this.hashPayload(task.taskPayload)}`;
1215+
this.blackboard.write(cacheKey, result.result, context.agentId, 3600, 'system-orchestrator-token'); // 1 hour TTL
1216+
} catch {
1217+
// Caching failure should not abort the entire wave
1218+
}
12081219
}
12091220
}
12101221
}
@@ -1282,6 +1293,19 @@ class TaskDecomposer {
12821293

12831294
const result = await this.adapterRegistry.executeAgent(task.agentType, agentPayload, agentContext);
12841295

1296+
// If the adapter returned a failure, propagate it
1297+
if (!result.success) {
1298+
return {
1299+
agentType: task.agentType,
1300+
success: false,
1301+
result: {
1302+
error: result.error?.message ?? 'Agent execution failed',
1303+
recoverable: result.error?.recoverable ?? true,
1304+
},
1305+
executionTime: Date.now() - taskStart,
1306+
};
1307+
}
1308+
12851309
// Sanitize adapter output before returning/caching
12861310
let sanitizedData = result.data;
12871311
try {

package-lock.json

Lines changed: 27 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
},
7171
"devDependencies": {
7272
"@types/node": "^25.2.3",
73+
"openai": "^6.22.0",
7374
"ts-node": "^10.9.2",
7475
"typescript": "^5.9.3"
7576
},

0 commit comments

Comments
 (0)