@bolloon/bolloon-agent 0.4.5 → 0.4.6
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 +135 -135
- package/bin/bolloon-cli.cjs +183 -183
- package/bin/bolloon.cjs +0 -0
- package/bin/bolloon.js +157 -0
- package/dist/agents/constraint-layer.js +19 -19
- package/dist/agents/judgment-protocol.js +14 -14
- package/dist/agents/pi-sdk-tools.js +62 -45
- package/dist/agents/pi-sdk-types.js +12 -12
- package/dist/agents/pi-sdk.js +103 -90
- package/dist/agents/skill-organizer.js +19 -19
- package/dist/agents/skill-writer.js +15 -3
- package/dist/agents/workflow-pivot-loop.js +13 -3
- package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
- package/dist/bollharness-integration/context-router-judgment.js +4 -4
- package/dist/bollharness-integration/context-router.js +292 -292
- package/dist/bollharness-integration/gate-state-machine.js +13 -13
- package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
- package/dist/bollharness-integration/skill-adapter.js +21 -21
- package/dist/bootstrap/chat-archiver.js +14 -14
- package/dist/bootstrap/context-os.js +24 -24
- package/dist/bootstrap/memory-compressor.js +14 -14
- package/dist/cli/ink-app.js +18 -0
- package/dist/cli-entry.js +36 -36
- package/dist/context-compaction/auto-compact.js +7 -7
- package/dist/electron/first-run.js +54 -54
- package/dist/electron-build/electron/first-run.js +54 -54
- package/dist/electron-preload.js.map +1 -1
- package/dist/electron.js.map +1 -1
- package/dist/index.js +222 -138
- package/dist/llm/llm-judgment-client.js +102 -102
- package/dist/llm/pi-ai.js +48 -48
- package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
- package/dist/llm/system-prompt/layers/channel/local.md +14 -14
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
- package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
- package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
- package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
- package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
- package/dist/llm/system-prompt/layers/core/identity.md +48 -48
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
- package/dist/llm/system-prompt/layers/core/tone.md +31 -31
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
- package/dist/llm/system-prompt/layers/role/architect.md +20 -20
- package/dist/llm/system-prompt/layers/role/expert.md +19 -19
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
- package/dist/llm/system-prompt/layers/role/security.md +15 -15
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
- package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
- package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
- package/dist/llm/tool-manifest/ask_user_input.js +1 -1
- package/dist/llm/tool-manifest/bash.js +3 -3
- package/dist/llm/tool-manifest/create_file.js +4 -4
- package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
- package/dist/llm/tool-manifest/image_search.js +2 -2
- package/dist/llm/tool-manifest/index.js +0 -59
- package/dist/llm/tool-manifest/mcp.js +2 -2
- package/dist/llm/tool-manifest/message_compose.js +3 -3
- package/dist/llm/tool-manifest/places.js +2 -2
- package/dist/llm/tool-manifest/present_files.js +1 -1
- package/dist/llm/tool-manifest/recipe.js +2 -2
- package/dist/llm/tool-manifest/str_replace.js +5 -5
- package/dist/llm/tool-manifest/view.js +3 -3
- package/dist/llm/tool-manifest/weather.js +4 -4
- package/dist/llm/tool-manifest/web.js +4 -4
- package/dist/orbitdb/agent-tools.js +139 -0
- package/dist/orbitdb/kanban-store.js +259 -0
- package/dist/orbitdb/task-store.js +112 -0
- package/dist/pi-ecosystem-colony/index.js +365 -0
- package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
- package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
- package/dist/pi-ecosystem-judgment/distillation.js +14 -14
- package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
- package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
- package/dist/security/context-router-tool.js +15 -15
- package/dist/security/tool-gate.js +2 -0
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
- package/dist/social/ant-colony/PheromoneEngine.js +227 -0
- package/dist/social/ant-colony/index.js +6 -0
- package/dist/social/ant-colony/types.js +24 -0
- package/dist/storage/trajectory.js +101 -0
- package/dist/test/ai-judgment-test.js +80 -0
- package/dist/test/bollharness-integration.test.js +318 -0
- package/dist/test/channel-agent-multi-dialogue.js +205 -0
- package/dist/test/channel-heartbeat-agent-test.js +201 -0
- package/dist/test/constraint-layer.test.js +164 -0
- package/dist/test/diap-identity-test.js +172 -0
- package/dist/test/diap-quick-test.js +62 -0
- package/dist/test/global-shared-context.test.js +315 -0
- package/dist/test/harness-judgment-injection.test.js +246 -0
- package/dist/test/harness-workflow-integrator-test.js +228 -0
- package/dist/test/human-value-store.test.js +243 -0
- package/dist/test/hybrid-integration-test.js +118 -0
- package/dist/test/hybrid-messenger-verify.js +55 -0
- package/dist/test/iroh-bistream-debug.js +38 -0
- package/dist/test/iroh-communication.test.js +66 -0
- package/dist/test/iroh-debug-test.js +57 -0
- package/dist/test/iroh-diap-test.js +71 -0
- package/dist/test/iroh-direct-connect.js +55 -0
- package/dist/test/iroh-e2e-fixed.js +89 -0
- package/dist/test/iroh-e2e-same-process.js +63 -0
- package/dist/test/iroh-e2e.js +66 -0
- package/dist/test/iroh-final-e2e.js +72 -0
- package/dist/test/iroh-relay-test.js +37 -0
- package/dist/test/iroh-simple-test.js +41 -0
- package/dist/test/iroh-transport-verify.js +54 -0
- package/dist/test/iroh-transport.test.js +37 -0
- package/dist/test/iroh-two-nodes.js +70 -0
- package/dist/test/iroh-verify.js +44 -0
- package/dist/test/judgment-decision.test.js +219 -0
- package/dist/test/llm-judgment-integration.test.js +220 -0
- package/dist/test/p2p-agent-complex-dialogue.js +385 -0
- package/dist/test/p2p-agent-dialogue.js +341 -0
- package/dist/test/p2p-agent-full-bidirectional.js +510 -0
- package/dist/test/p2p-agent-harness-flow.js +437 -0
- package/dist/test/p2p-agent-harness-single.js +143 -0
- package/dist/test/p2p-ai-dialogue-test.js +318 -0
- package/dist/test/p2p-cid-connect-test.js +195 -0
- package/dist/test/p2p-connect-receiver.js +69 -0
- package/dist/test/p2p-doc-transfer.js +110 -0
- package/dist/test/p2p-identity-page-test.js +77 -0
- package/dist/test/p2p-iroh-test.js +171 -0
- package/dist/test/p2p-minimal-test.js +241 -0
- package/dist/test/p2p-node-1.js +148 -0
- package/dist/test/p2p-node-2.js +148 -0
- package/dist/test/p2p-server.js +281 -0
- package/dist/test/p2p-two-nodes-test.js +438 -0
- package/dist/test/pi-sdk.test.js +44 -0
- package/dist/test/set-persona.js +40 -0
- package/dist/test/simple.test.js +9 -0
- package/dist/test/storage-integration.test.js +150 -0
- package/dist/test/subagent-manager.test.js +276 -0
- package/dist/test/test-gate-flow.test.js +81 -0
- package/dist/test/workflow-engine.test.js +87 -0
- package/dist/test/workflow-pivot-loop.test.js +246 -0
- package/dist/web/api-config.html +779 -779
- package/dist/web/client-hearth.js +10 -10
- package/dist/web/components/wallet-viem.mjs +118 -118
- package/dist/web/index.html +472 -472
- package/dist/web/manifest.json +20 -20
- package/dist/web/server-storage.js +29 -0
- package/dist/web/server.js +30 -14
- package/dist/web/style.css +4946 -4946
- package/package.json +195 -195
- package/scripts/build-cli.js +215 -215
- package/scripts/build-web.ts +130 -130
- package/scripts/postinstall.js +152 -152
- package/bin/bolloon-daemon.sh +0 -207
- package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +0 -63
- package/dist/constraint-runtime/reference_data/commands_snapshot.json +0 -1037
- package/dist/constraint-runtime/reference_data/subsystems/assistant.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/bridge.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/buddy.json +0 -13
- package/dist/constraint-runtime/reference_data/subsystems/cli.json +0 -26
- package/dist/constraint-runtime/reference_data/subsystems/components.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/constants.json +0 -28
- package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +0 -15
- package/dist/constraint-runtime/reference_data/subsystems/hooks.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +0 -21
- package/dist/constraint-runtime/reference_data/subsystems/memdir.json +0 -15
- package/dist/constraint-runtime/reference_data/subsystems/migrations.json +0 -18
- package/dist/constraint-runtime/reference_data/subsystems/moreright.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +0 -11
- package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/plugins.json +0 -9
- package/dist/constraint-runtime/reference_data/subsystems/remote.json +0 -11
- package/dist/constraint-runtime/reference_data/subsystems/schemas.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/screens.json +0 -10
- package/dist/constraint-runtime/reference_data/subsystems/server.json +0 -10
- package/dist/constraint-runtime/reference_data/subsystems/services.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/skills.json +0 -27
- package/dist/constraint-runtime/reference_data/subsystems/state.json +0 -13
- package/dist/constraint-runtime/reference_data/subsystems/types.json +0 -18
- package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +0 -9
- package/dist/constraint-runtime/reference_data/subsystems/utils.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/vim.json +0 -12
- package/dist/constraint-runtime/reference_data/subsystems/voice.json +0 -8
- package/dist/constraint-runtime/reference_data/tools_snapshot.json +0 -922
- package/dist/electron/config.js.map +0 -1
- package/dist/electron/dialogs.js.map +0 -1
- package/dist/electron/first-run.js.map +0 -1
- package/dist/electron/ipc.js.map +0 -1
- package/dist/electron/logger.js.map +0 -1
- package/dist/electron/main.js.map +0 -1
- package/dist/electron/menu.js.map +0 -1
- package/dist/electron/paths.js.map +0 -1
- package/dist/electron/server.js.map +0 -1
- package/dist/electron/tray.js.map +0 -1
- package/dist/electron/window.js.map +0 -1
- package/dist/utils/auto-update.js.map +0 -1
- package/dist/web/client.js.map +0 -7
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* task-store.ts — Task 队列的 OrbitDB 主存储 (2026-08-12, Task6)
|
|
3
|
+
*
|
|
4
|
+
* 把 hermes kanban 用 OrbitDB 实现: 任务队列以 OrbitDB keyvalue store 为主存储,
|
|
5
|
+
* 支持跨设备/去中心化同步 (与 did-catalog-replication 同模式, 共享同一 helia 节点).
|
|
6
|
+
*
|
|
7
|
+
* 设计:
|
|
8
|
+
* - store 名: `bolloon-tasks-<did短名>` (确定性, 跨设备同名 → 同一复制流)
|
|
9
|
+
* - 存整个任务数组到单键 `tasks` (兼容 server-storage 现有 loadTaskQueue/saveTaskQueue)
|
|
10
|
+
* - 懒初始化 + 幂等: 首次 warm 时打开 store; 失败静默 → 回退本地文件 (增强层, 不阻塞)
|
|
11
|
+
* - 生产由 server 启动时 warmTaskOrbitStore() 预热; 测试环境 (临时 HOME) 不预热 → 走本地
|
|
12
|
+
*
|
|
13
|
+
* 失败静默: OrbitDB 不可用 (离线/首次/测试) 时任务照常走本地文件, 不阻塞主路径.
|
|
14
|
+
*/
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import * as os from 'os';
|
|
17
|
+
import { getCIDDatabase } from './cid-database.js';
|
|
18
|
+
const homeRoot = () => process.env.HOME || os.homedir() || '/tmp';
|
|
19
|
+
export const TASK_ORBIT_STORE_KEY = 'tasks';
|
|
20
|
+
/** store 名: 按 did 短名确定性命名 */
|
|
21
|
+
export function taskStoreName(did) {
|
|
22
|
+
const short = String(did || 'local').replace(/[^a-zA-Z0-9-]/g, '_').slice(0, 40) || 'local';
|
|
23
|
+
return `bolloon-tasks-${short}`;
|
|
24
|
+
}
|
|
25
|
+
/** 真实实现 (OrbitDB). 单例: 同一进程共享 CID 数据库单例. */
|
|
26
|
+
export class OrbitDBTaskStore {
|
|
27
|
+
did;
|
|
28
|
+
db;
|
|
29
|
+
_store = null;
|
|
30
|
+
ready = false;
|
|
31
|
+
storeName;
|
|
32
|
+
storeAddress = '';
|
|
33
|
+
constructor(did, db = getCIDDatabase()) {
|
|
34
|
+
this.did = did;
|
|
35
|
+
this.db = db;
|
|
36
|
+
this.storeName = taskStoreName(did);
|
|
37
|
+
}
|
|
38
|
+
async warm() {
|
|
39
|
+
if (this.ready && this._store)
|
|
40
|
+
return true;
|
|
41
|
+
try {
|
|
42
|
+
this._store = await this.db.openStore(this.storeName, 'keyvalue');
|
|
43
|
+
this.storeAddress = this._store.address;
|
|
44
|
+
this.ready = true;
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
// OrbitDB 不可用 (离线/首次/测试环境) → 静默回退本地
|
|
49
|
+
try {
|
|
50
|
+
console.warn(`[task-store] OrbitDB 任务存储不可用, 回退本地: ${err?.message?.slice(0, 120)}`);
|
|
51
|
+
}
|
|
52
|
+
catch { /* 忽略 */ }
|
|
53
|
+
this.ready = false;
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async loadTasks() {
|
|
58
|
+
if (!this.ready || !this._store)
|
|
59
|
+
return null;
|
|
60
|
+
try {
|
|
61
|
+
const v = await this._store.get(TASK_ORBIT_STORE_KEY);
|
|
62
|
+
if (v == null)
|
|
63
|
+
return null;
|
|
64
|
+
if (Array.isArray(v))
|
|
65
|
+
return v;
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async saveTasks(tasks) {
|
|
73
|
+
if (!this.ready || !this._store)
|
|
74
|
+
return false;
|
|
75
|
+
try {
|
|
76
|
+
await this._store.put(TASK_ORBIT_STORE_KEY, tasks);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async close() {
|
|
84
|
+
this._store = null;
|
|
85
|
+
this.ready = false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
let _instance = null;
|
|
89
|
+
let _warmPromise = null;
|
|
90
|
+
/** 获取任务 OrbitDB 存储单例 (首次调用时 warm). did 为 '' 时用 'local'. */
|
|
91
|
+
export function getTaskOrbitStore(did = '') {
|
|
92
|
+
if (!_instance)
|
|
93
|
+
_instance = new OrbitDBTaskStore(did || 'local');
|
|
94
|
+
return _instance;
|
|
95
|
+
}
|
|
96
|
+
/** 预热任务 OrbitDB 存储 (server 启动时调用, 幂等). 返回是否就绪. */
|
|
97
|
+
export function warmTaskOrbitStore(did = '') {
|
|
98
|
+
if (!_warmPromise) {
|
|
99
|
+
const store = getTaskOrbitStore(did);
|
|
100
|
+
_warmPromise = store.warm().then((ok) => ok).catch(() => false);
|
|
101
|
+
}
|
|
102
|
+
return _warmPromise;
|
|
103
|
+
}
|
|
104
|
+
/** 重置单例 (测试用) */
|
|
105
|
+
export function resetTaskOrbitStore() {
|
|
106
|
+
_instance = null;
|
|
107
|
+
_warmPromise = null;
|
|
108
|
+
}
|
|
109
|
+
/** 用 did 短名构造 task store 名 (供 server 组装 store name 展示) */
|
|
110
|
+
export function taskStorePath(did, home = homeRoot()) {
|
|
111
|
+
return path.join(home, '.bolloon', 'orbitdb', 'stores', taskStoreName(did));
|
|
112
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi Ant Colony Integration for Bolloon
|
|
3
|
+
*
|
|
4
|
+
* Multi-agent collaboration system with white-box signal protocol.
|
|
5
|
+
* Based on oh-pi's ant colony system: COLONY_SIGNAL protocol for agent coordination.
|
|
6
|
+
*
|
|
7
|
+
* Signal Protocol:
|
|
8
|
+
* COLONY_SIGNAL:LAUNCHED → SCOUTING → WORKING → REVIEWING → COMPLETE
|
|
9
|
+
*
|
|
10
|
+
* Key features:
|
|
11
|
+
* - Fully visible signal protocol (no black boxes)
|
|
12
|
+
* - Per-ant turn limits, cost tracking, concurrent scheduling
|
|
13
|
+
* - White-box design: no "what is it doing in the background" anxiety
|
|
14
|
+
*/
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import * as fs from 'fs/promises';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
// Colony state
|
|
19
|
+
const ants = new Map();
|
|
20
|
+
const tasks = new Map();
|
|
21
|
+
const signalHistory = [];
|
|
22
|
+
const STATE_DIR = path.join(process.env.HOME || '/tmp', '.bolloon', 'colony');
|
|
23
|
+
// Event emitter
|
|
24
|
+
class ColonyEventEmitter extends EventEmitter {
|
|
25
|
+
}
|
|
26
|
+
const colonyEvents = new ColonyEventEmitter();
|
|
27
|
+
/**
|
|
28
|
+
* Generate a unique ant ID
|
|
29
|
+
*/
|
|
30
|
+
function generateAntId() {
|
|
31
|
+
return `ant-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Register a new ant in the colony
|
|
35
|
+
*/
|
|
36
|
+
export function registerAnt(name, role, maxTurns = 10, tokenBudget = 50000) {
|
|
37
|
+
const id = generateAntId();
|
|
38
|
+
const ant = {
|
|
39
|
+
id,
|
|
40
|
+
name,
|
|
41
|
+
role,
|
|
42
|
+
signal: 'LAUNCHED',
|
|
43
|
+
turnCount: 0,
|
|
44
|
+
maxTurns,
|
|
45
|
+
tokenBudget,
|
|
46
|
+
tokensUsed: 0,
|
|
47
|
+
createdAt: new Date().toISOString(),
|
|
48
|
+
updatedAt: new Date().toISOString(),
|
|
49
|
+
};
|
|
50
|
+
ants.set(id, ant);
|
|
51
|
+
emitSignal(id, 'LAUNCHED');
|
|
52
|
+
console.log(`[Colony] Registered ant: ${name} (${role})`);
|
|
53
|
+
return ant;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Emit a signal transition
|
|
57
|
+
*/
|
|
58
|
+
function emitSignal(antId, newSignal, details) {
|
|
59
|
+
const ant = ants.get(antId);
|
|
60
|
+
if (!ant)
|
|
61
|
+
return;
|
|
62
|
+
const event = {
|
|
63
|
+
antId,
|
|
64
|
+
antName: ant.name,
|
|
65
|
+
fromSignal: ant.signal,
|
|
66
|
+
toSignal: newSignal,
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
details,
|
|
69
|
+
};
|
|
70
|
+
signalHistory.push(event);
|
|
71
|
+
if (signalHistory.length > 100) {
|
|
72
|
+
signalHistory.shift();
|
|
73
|
+
}
|
|
74
|
+
ant.signal = newSignal;
|
|
75
|
+
ant.updatedAt = new Date().toISOString();
|
|
76
|
+
ants.set(antId, ant);
|
|
77
|
+
colonyEvents.emit('signal', event);
|
|
78
|
+
console.log(`[Colony] ${ant.name}: ${event.fromSignal} → ${event.toSignal}${details ? ` (${details})` : ''}`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Transition ant to SCOUTING
|
|
82
|
+
*/
|
|
83
|
+
export function antScouting(antId, task) {
|
|
84
|
+
const ant = ants.get(antId);
|
|
85
|
+
if (!ant)
|
|
86
|
+
return;
|
|
87
|
+
ant.task = task;
|
|
88
|
+
ants.set(antId, ant);
|
|
89
|
+
emitSignal(antId, 'SCOUTING', `Task: ${task.substring(0, 50)}...`);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Transition ant to WORKING
|
|
93
|
+
*/
|
|
94
|
+
export function antWorking(antId) {
|
|
95
|
+
const ant = ants.get(antId);
|
|
96
|
+
if (!ant)
|
|
97
|
+
return;
|
|
98
|
+
emitSignal(antId, 'WORKING');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Transition ant to REVIEWING
|
|
102
|
+
*/
|
|
103
|
+
export function antReviewing(antId) {
|
|
104
|
+
emitSignal(antId, 'REVIEWING');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Complete ant work
|
|
108
|
+
*/
|
|
109
|
+
export function antComplete(antId, result) {
|
|
110
|
+
const ant = ants.get(antId);
|
|
111
|
+
if (!ant)
|
|
112
|
+
return;
|
|
113
|
+
ant.result = result;
|
|
114
|
+
ants.set(antId, ant);
|
|
115
|
+
emitSignal(antId, 'COMPLETE', `Result: ${result.substring(0, 50)}...`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Fail ant work
|
|
119
|
+
*/
|
|
120
|
+
export function antFail(antId, error) {
|
|
121
|
+
const ant = ants.get(antId);
|
|
122
|
+
if (!ant)
|
|
123
|
+
return;
|
|
124
|
+
ant.result = error;
|
|
125
|
+
ants.set(antId, ant);
|
|
126
|
+
emitSignal(antId, 'FAILED', error);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Abort ant work
|
|
130
|
+
*/
|
|
131
|
+
export function antAbort(antId, reason) {
|
|
132
|
+
emitSignal(antId, 'ABORTED', reason);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Increment turn count
|
|
136
|
+
*/
|
|
137
|
+
export function antTick(antId, tokensUsed = 0) {
|
|
138
|
+
const ant = ants.get(antId);
|
|
139
|
+
if (!ant)
|
|
140
|
+
return;
|
|
141
|
+
ant.turnCount++;
|
|
142
|
+
ant.tokensUsed += tokensUsed;
|
|
143
|
+
ant.updatedAt = new Date().toISOString();
|
|
144
|
+
ants.set(antId, ant);
|
|
145
|
+
// Check if exceeded limits
|
|
146
|
+
if (ant.turnCount >= ant.maxTurns) {
|
|
147
|
+
antAbort(antId, 'Max turns exceeded');
|
|
148
|
+
}
|
|
149
|
+
else if (ant.tokensUsed >= ant.tokenBudget) {
|
|
150
|
+
antAbort(antId, 'Token budget exceeded');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create a colony task
|
|
155
|
+
*/
|
|
156
|
+
export function createTask(description) {
|
|
157
|
+
const id = `task-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
|
158
|
+
const task = {
|
|
159
|
+
id,
|
|
160
|
+
description,
|
|
161
|
+
status: 'pending',
|
|
162
|
+
assignedAnts: [],
|
|
163
|
+
results: new Map(),
|
|
164
|
+
createdAt: new Date().toISOString(),
|
|
165
|
+
};
|
|
166
|
+
tasks.set(id, task);
|
|
167
|
+
console.log(`[Colony] Created task: ${id} - ${description.substring(0, 50)}...`);
|
|
168
|
+
return task;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Dispatch task to ants
|
|
172
|
+
*/
|
|
173
|
+
export function dispatchTask(taskId, antIds) {
|
|
174
|
+
const task = tasks.get(taskId);
|
|
175
|
+
if (!task)
|
|
176
|
+
return;
|
|
177
|
+
task.status = 'dispatched';
|
|
178
|
+
task.assignedAnts = antIds;
|
|
179
|
+
tasks.set(taskId, task);
|
|
180
|
+
for (const antId of antIds) {
|
|
181
|
+
const ant = ants.get(antId);
|
|
182
|
+
if (ant) {
|
|
183
|
+
antScouting(antId, task.description);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
console.log(`[Colony] Dispatched task ${taskId} to ${antIds.length} ants`);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Record ant result for a task
|
|
190
|
+
*/
|
|
191
|
+
export function recordResult(taskId, antId, result) {
|
|
192
|
+
const task = tasks.get(taskId);
|
|
193
|
+
if (!task)
|
|
194
|
+
return;
|
|
195
|
+
task.results.set(antId, result);
|
|
196
|
+
// Check if all ants completed
|
|
197
|
+
if (task.results.size === task.assignedAnts.length) {
|
|
198
|
+
task.status = 'completed';
|
|
199
|
+
task.completedAt = new Date().toISOString();
|
|
200
|
+
for (const id of task.assignedAnts) {
|
|
201
|
+
antReviewing(id);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
tasks.set(taskId, task);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get ant by ID
|
|
208
|
+
*/
|
|
209
|
+
export function getAnt(antId) {
|
|
210
|
+
return ants.get(antId);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* List all ants
|
|
214
|
+
*/
|
|
215
|
+
export function listAnts() {
|
|
216
|
+
return Array.from(ants.values());
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* List ants by role
|
|
220
|
+
*/
|
|
221
|
+
export function listAntsByRole(role) {
|
|
222
|
+
return Array.from(ants.values()).filter((a) => a.role === role);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get ants by signal state
|
|
226
|
+
*/
|
|
227
|
+
export function listAntsBySignal(signal) {
|
|
228
|
+
return Array.from(ants.values()).filter((a) => a.signal === signal);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get active ants (not complete/failed/aborted)
|
|
232
|
+
*/
|
|
233
|
+
export function getActiveAnts() {
|
|
234
|
+
return Array.from(ants.values()).filter((a) => !['COMPLETE', 'FAILED', 'ABORTED'].includes(a.signal));
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get task by ID
|
|
238
|
+
*/
|
|
239
|
+
export function getTask(taskId) {
|
|
240
|
+
return tasks.get(taskId);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* List all tasks
|
|
244
|
+
*/
|
|
245
|
+
export function listTasks() {
|
|
246
|
+
return Array.from(tasks.values());
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get signal history
|
|
250
|
+
*/
|
|
251
|
+
export function getSignalHistory() {
|
|
252
|
+
return [...signalHistory];
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get colony status
|
|
256
|
+
*/
|
|
257
|
+
export function getColonyStatus() {
|
|
258
|
+
const antList = Array.from(ants.values());
|
|
259
|
+
const taskList = Array.from(tasks.values());
|
|
260
|
+
const signalDistribution = {
|
|
261
|
+
LAUNCHED: 0,
|
|
262
|
+
SCOUTING: 0,
|
|
263
|
+
WORKING: 0,
|
|
264
|
+
REVIEWING: 0,
|
|
265
|
+
COMPLETE: 0,
|
|
266
|
+
FAILED: 0,
|
|
267
|
+
ABORTED: 0,
|
|
268
|
+
};
|
|
269
|
+
for (const ant of antList) {
|
|
270
|
+
signalDistribution[ant.signal]++;
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
antCount: antList.length,
|
|
274
|
+
activeAnts: antList.filter((a) => !['COMPLETE', 'FAILED', 'ABORTED'].includes(a.signal)).length,
|
|
275
|
+
taskCount: taskList.length,
|
|
276
|
+
activeTasks: taskList.filter((t) => t.status === 'in_progress' || t.status === 'dispatched').length,
|
|
277
|
+
signalDistribution,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Subscribe to colony events
|
|
282
|
+
*/
|
|
283
|
+
export function onColonyEvent(event, callback) {
|
|
284
|
+
colonyEvents.on(event, callback);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Unsubscribe from colony events
|
|
288
|
+
*/
|
|
289
|
+
export function offColonyEvent(event, callback) {
|
|
290
|
+
colonyEvents.off(event, callback);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get formatted colony dump for debugging
|
|
294
|
+
*/
|
|
295
|
+
export function getColonyDump() {
|
|
296
|
+
const status = getColonyStatus();
|
|
297
|
+
const active = getActiveAnts();
|
|
298
|
+
let dump = '# Colony Status\n\n';
|
|
299
|
+
dump += `Ants: ${status.antCount} total, ${status.activeAnts} active\n`;
|
|
300
|
+
dump += `Tasks: ${status.taskCount} total, ${status.activeTasks} active\n\n`;
|
|
301
|
+
dump += '## Signal Distribution\n';
|
|
302
|
+
for (const [signal, count] of Object.entries(status.signalDistribution)) {
|
|
303
|
+
if (count > 0) {
|
|
304
|
+
dump += `- ${signal}: ${count}\n`;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
dump += '\n## Active Ants\n';
|
|
308
|
+
for (const ant of active) {
|
|
309
|
+
dump += `- ${ant.name} (${ant.role}): ${ant.signal} [${ant.turnCount}/${ant.maxTurns} turns, ${ant.tokensUsed}/${ant.tokenBudget} tokens]\n`;
|
|
310
|
+
if (ant.task) {
|
|
311
|
+
dump += ` Task: ${ant.task.substring(0, 60)}...\n`;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
dump += '\n## Recent Signals\n';
|
|
315
|
+
const recent = signalHistory.slice(-10);
|
|
316
|
+
for (const event of recent.reverse()) {
|
|
317
|
+
dump += `- ${event.timestamp}: ${event.antName}: ${event.fromSignal} → ${event.toSignal}\n`;
|
|
318
|
+
}
|
|
319
|
+
return dump;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Persist colony state
|
|
323
|
+
*/
|
|
324
|
+
export async function persistColony() {
|
|
325
|
+
try {
|
|
326
|
+
await fs.mkdir(STATE_DIR, { recursive: true });
|
|
327
|
+
const state = {
|
|
328
|
+
ants: Array.from(ants.values()),
|
|
329
|
+
tasks: Array.from(tasks.entries()).map(([id, t]) => ({
|
|
330
|
+
...t,
|
|
331
|
+
results: Array.from(t.results.entries()),
|
|
332
|
+
})),
|
|
333
|
+
signalHistory: signalHistory.slice(-50),
|
|
334
|
+
persistedAt: new Date().toISOString(),
|
|
335
|
+
};
|
|
336
|
+
await fs.writeFile(path.join(STATE_DIR, 'colony.json'), JSON.stringify(state, null, 2));
|
|
337
|
+
console.log('[Colony] Persisted state');
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
console.warn('[Colony] Failed to persist:', e);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Load colony state
|
|
345
|
+
*/
|
|
346
|
+
export async function loadColony() {
|
|
347
|
+
try {
|
|
348
|
+
const data = await fs.readFile(path.join(STATE_DIR, 'colony.json'), 'utf-8');
|
|
349
|
+
const state = JSON.parse(data);
|
|
350
|
+
ants.clear();
|
|
351
|
+
for (const a of state.ants) {
|
|
352
|
+
ants.set(a.id, a);
|
|
353
|
+
}
|
|
354
|
+
tasks.clear();
|
|
355
|
+
for (const t of state.tasks) {
|
|
356
|
+
tasks.set(t.id, { ...t, results: new Map(t.results) });
|
|
357
|
+
}
|
|
358
|
+
signalHistory.length = 0;
|
|
359
|
+
signalHistory.push(...state.signalHistory);
|
|
360
|
+
console.log(`[Colony] Loaded ${ants.size} ants, ${tasks.size} tasks`);
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
// No persisted state
|
|
364
|
+
}
|
|
365
|
+
}
|
|
@@ -81,21 +81,21 @@ function getLLM() {
|
|
|
81
81
|
}
|
|
82
82
|
return cachedModel;
|
|
83
83
|
}
|
|
84
|
-
const CORRELATION_PROMPT = `你是"判断力关联分析器"。给定两条 judgment:
|
|
85
|
-
A: {a}
|
|
86
|
-
B: {b}
|
|
87
|
-
|
|
88
|
-
它们经常在同一对话里被同时注入 (共现 {co} 次).
|
|
89
|
-
判断 A 与 B 的因果关系:
|
|
90
|
-
- "A→B": A 引发 B (A 概念在 B 之前)
|
|
91
|
-
- "B→A": B 引发 A
|
|
92
|
-
- "common_cause": 共同原因 (e.g. 都是某场景触发)
|
|
93
|
-
- "unclear": 关系不明确
|
|
94
|
-
|
|
95
|
-
输出严格 JSON:
|
|
96
|
-
{
|
|
97
|
-
"direction": "A→B" | "B→A" | "common_cause" | "unclear",
|
|
98
|
-
"explanation": "≤100 字解释, 含 1 个具体例"
|
|
84
|
+
const CORRELATION_PROMPT = `你是"判断力关联分析器"。给定两条 judgment:
|
|
85
|
+
A: {a}
|
|
86
|
+
B: {b}
|
|
87
|
+
|
|
88
|
+
它们经常在同一对话里被同时注入 (共现 {co} 次).
|
|
89
|
+
判断 A 与 B 的因果关系:
|
|
90
|
+
- "A→B": A 引发 B (A 概念在 B 之前)
|
|
91
|
+
- "B→A": B 引发 A
|
|
92
|
+
- "common_cause": 共同原因 (e.g. 都是某场景触发)
|
|
93
|
+
- "unclear": 关系不明确
|
|
94
|
+
|
|
95
|
+
输出严格 JSON:
|
|
96
|
+
{
|
|
97
|
+
"direction": "A→B" | "B→A" | "common_cause" | "unclear",
|
|
98
|
+
"explanation": "≤100 字解释, 含 1 个具体例"
|
|
99
99
|
}`;
|
|
100
100
|
async function explainPair(judgmentA, judgmentB, coOccurrence) {
|
|
101
101
|
const fallback = { direction: 'unclear', explanation: '(LLM 不可用, 仅显示统计)' };
|
|
@@ -213,21 +213,21 @@ export async function runCorrelationAnalysis(opts = {}) {
|
|
|
213
213
|
}
|
|
214
214
|
return out;
|
|
215
215
|
}
|
|
216
|
-
const INTERVENTION_PROMPT = `你是"判断力干预分析器"。判断力库有一条 judgment, 用户想评估它的边际贡献.
|
|
217
|
-
给定:
|
|
218
|
-
- judgment: {judgment}
|
|
219
|
-
- 上次用过的场景 (user 输入 + AI 回复): {scenario}
|
|
220
|
-
- 同时存在的相邻 judgment (供参考): {peers}
|
|
221
|
-
|
|
222
|
-
模拟反事实推理: 如果库**没有**这条 judgment, AI 在同一场景下回答会怎么变?
|
|
223
|
-
|
|
224
|
-
输出严格 JSON:
|
|
225
|
-
{
|
|
226
|
-
"causalEffect": 0.0-1.0, // 0 = 无影响, 1 = 行为完全变
|
|
227
|
-
"reasoning": "2-3 步推理, 含 1 个具体例",
|
|
228
|
-
"confidence": 0.0-1.0
|
|
229
|
-
}
|
|
230
|
-
|
|
216
|
+
const INTERVENTION_PROMPT = `你是"判断力干预分析器"。判断力库有一条 judgment, 用户想评估它的边际贡献.
|
|
217
|
+
给定:
|
|
218
|
+
- judgment: {judgment}
|
|
219
|
+
- 上次用过的场景 (user 输入 + AI 回复): {scenario}
|
|
220
|
+
- 同时存在的相邻 judgment (供参考): {peers}
|
|
221
|
+
|
|
222
|
+
模拟反事实推理: 如果库**没有**这条 judgment, AI 在同一场景下回答会怎么变?
|
|
223
|
+
|
|
224
|
+
输出严格 JSON:
|
|
225
|
+
{
|
|
226
|
+
"causalEffect": 0.0-1.0, // 0 = 无影响, 1 = 行为完全变
|
|
227
|
+
"reasoning": "2-3 步推理, 含 1 个具体例",
|
|
228
|
+
"confidence": 0.0-1.0
|
|
229
|
+
}
|
|
230
|
+
|
|
231
231
|
注意: causalEffect < 0 也合法 (如"没有这条 AI 反而更好" — 库污染)`;
|
|
232
232
|
export async function runIntervention(judgmentId, opts = {}) {
|
|
233
233
|
const fallback = {
|
|
@@ -273,27 +273,27 @@ export async function runIntervention(judgmentId, opts = {}) {
|
|
|
273
273
|
return fallback;
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
|
-
const COUNTERFACTUAL_PROMPT = `你是"判断力反事实审计员"。某次 AI 回复违反了注入的 judgment. 判断是库设计问题还是 LLM 偶然违规.
|
|
277
|
-
|
|
278
|
-
事件:
|
|
279
|
-
- 用户: {userInput}
|
|
280
|
-
- AI 回复: {aiReply}
|
|
281
|
-
- 违反原则: {principles}
|
|
282
|
-
|
|
283
|
-
构造 3 个反事实 scenario:
|
|
284
|
-
1. 删去最相关那条 judgment
|
|
285
|
-
2. 把那条 judgment 改成反向 (例如"必须"→"避免")
|
|
286
|
-
3. 删去整个 channel 的 judgment 库 (空库)
|
|
287
|
-
|
|
288
|
-
每个 scenario 模拟 AI 在该库下的回答, 判断还会不会违规.
|
|
289
|
-
|
|
290
|
-
输出严格 JSON:
|
|
291
|
-
{
|
|
292
|
-
"scenarios": [
|
|
293
|
-
{ "modification": "...", "outcomeCompliant": true/false, "explanation": "≤100 字" }
|
|
294
|
-
],
|
|
295
|
-
"verdict": "库设计合理" | "建议调库" | "需更多数据",
|
|
296
|
-
"recomendaciones": "≤200 字, ≤3 条建议"
|
|
276
|
+
const COUNTERFACTUAL_PROMPT = `你是"判断力反事实审计员"。某次 AI 回复违反了注入的 judgment. 判断是库设计问题还是 LLM 偶然违规.
|
|
277
|
+
|
|
278
|
+
事件:
|
|
279
|
+
- 用户: {userInput}
|
|
280
|
+
- AI 回复: {aiReply}
|
|
281
|
+
- 违反原则: {principles}
|
|
282
|
+
|
|
283
|
+
构造 3 个反事实 scenario:
|
|
284
|
+
1. 删去最相关那条 judgment
|
|
285
|
+
2. 把那条 judgment 改成反向 (例如"必须"→"避免")
|
|
286
|
+
3. 删去整个 channel 的 judgment 库 (空库)
|
|
287
|
+
|
|
288
|
+
每个 scenario 模拟 AI 在该库下的回答, 判断还会不会违规.
|
|
289
|
+
|
|
290
|
+
输出严格 JSON:
|
|
291
|
+
{
|
|
292
|
+
"scenarios": [
|
|
293
|
+
{ "modification": "...", "outcomeCompliant": true/false, "explanation": "≤100 字" }
|
|
294
|
+
],
|
|
295
|
+
"verdict": "库设计合理" | "建议调库" | "需更多数据",
|
|
296
|
+
"recomendaciones": "≤200 字, ≤3 条建议"
|
|
297
297
|
}`;
|
|
298
298
|
export async function runCounterfactualAudit(opts) {
|
|
299
299
|
const fallback = {
|