@bolloon/bolloon-agent 0.1.11 → 0.1.13
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/agents/p2p-chat-tools.js +321 -0
- package/dist/agents/p2p-document-tools.js +121 -1
- package/dist/agents/workflow-pivot-loop.js +4 -4
- package/dist/cli-entry.js +1 -1
- package/dist/documents/reader.js +5 -0
- package/dist/documents/store.js +1 -1
- package/dist/llm/pi-ai.js +6 -5
- package/dist/network/iroh-discovery.js +2 -1
- package/dist/network/iroh-transport.js +15 -2
- package/dist/network/p2p.js +9 -8
- package/dist/network/storage/adapters/json-adapter.js +16 -1
- package/dist/network/storage/index.js +2 -1
- package/dist/pi-ecosystem-judgment/index.js +43 -115
- package/dist/social/channels/channel-heartbeat-agent.js +1 -1
- package/dist/utils/auto-update.js +15 -1
- package/dist/web/components/p2p/index.js +226 -264
- package/dist/web/index.html +12 -0
- package/package.json +3 -1
- package/scripts/build-web.ts +1 -1
- package/scripts/postinstall.js +1 -1
- package/src/agents/p2p-chat-tools.ts +383 -0
- package/src/agents/p2p-document-tools.ts +151 -1
- package/src/agents/workflow-pivot-loop.ts +13 -12
- package/src/bollharness-integration/channel-judgment-engine.ts +1 -1
- package/src/cli-entry.ts +1 -1
- package/src/documents/reader.ts +5 -0
- package/src/documents/store.ts +1 -1
- package/src/llm/pi-ai.ts +6 -5
- package/src/network/iroh-discovery.ts +2 -1
- package/src/network/iroh-transport.ts +15 -2
- package/src/network/p2p.ts +9 -8
- package/src/network/storage/adapters/json-adapter.ts +17 -2
- package/src/network/storage/index.ts +19 -3
- package/src/social/channels/channel-heartbeat-agent.ts +1 -1
- package/src/utils/auto-update.ts +17 -1
- package/src/web/server.ts +149 -0
- package/tsconfig.electron.json +1 -1
- package/tsconfig.json +1 -1
- package/dist/web/components/p2p/P2PModal.js +0 -188
- package/dist/web/components/p2p/p2p-modal.js +0 -657
- package/dist/web/components/p2p/p2p-tools.js +0 -248
- package/dist/web/server.js +0 -1890
|
@@ -43,7 +43,7 @@ export class JsonMessageStore {
|
|
|
43
43
|
const stored = { ...msg, id };
|
|
44
44
|
const filePath = this.getMessageFilePath(new Date(msg.timestamp));
|
|
45
45
|
await this.withLock(filePath, async () => {
|
|
46
|
-
|
|
46
|
+
let messages = await this.readJsonFile(filePath) || [];
|
|
47
47
|
messages.push(stored);
|
|
48
48
|
// 如果文件过大,拆分
|
|
49
49
|
if (messages.length > this.config.maxMessagesPerFile) {
|
|
@@ -189,6 +189,21 @@ export class JsonMessageStore {
|
|
|
189
189
|
}
|
|
190
190
|
return count;
|
|
191
191
|
}
|
|
192
|
+
async getAllOfflineTargets() {
|
|
193
|
+
// 重新从磁盘加载最新状态(避免内存 vs 磁盘不一致)
|
|
194
|
+
const baseDir = path.join(this.config.baseDir, 'offline');
|
|
195
|
+
let files = [];
|
|
196
|
+
try {
|
|
197
|
+
files = await fs.readdir(baseDir);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return Array.from(this.offlineMessages.keys());
|
|
201
|
+
}
|
|
202
|
+
return files
|
|
203
|
+
.filter((f) => f.endsWith('.json'))
|
|
204
|
+
.map((f) => f.replace(/\.json$/, ''))
|
|
205
|
+
.filter((id) => id.length > 0);
|
|
206
|
+
}
|
|
192
207
|
// ============================================================================
|
|
193
208
|
// 待响应请求
|
|
194
209
|
// ============================================================================
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Storage Layer Entry Point
|
|
3
3
|
* 导出消息存储工厂函数和类型
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import { DEFAULT_STORAGE_CONFIG } from './types.js';
|
|
6
|
+
export { DEFAULT_STORAGE_CONFIG };
|
|
6
7
|
import { JsonMessageStore } from './adapters/json-adapter.js';
|
|
7
8
|
import * as path from 'path';
|
|
8
9
|
// 默认存储配置
|
|
@@ -16,12 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import * as fs from 'fs/promises';
|
|
18
18
|
import * as path from 'path';
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
20
|
+
const yaml = require('js-yaml');
|
|
19
21
|
const JUDGMENTS_DIR = path.join(process.env.HOME || '/tmp', '.bolloon', 'judgments');
|
|
20
22
|
const JUDGMENT_FILES = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
rule: path.join(JUDGMENTS_DIR, 'rules.yaml'),
|
|
24
|
+
preference: path.join(JUDGMENTS_DIR, 'preferences.yaml'),
|
|
25
|
+
trajectory: path.join(JUDGMENTS_DIR, 'trajectories.yaml'),
|
|
26
|
+
reward: path.join(JUDGMENTS_DIR, 'rewards.yaml'),
|
|
25
27
|
};
|
|
26
28
|
let judgmentCache = new Map();
|
|
27
29
|
let valueFunctionCache = null;
|
|
@@ -99,8 +101,9 @@ async function saveJudgments(type, judgments) {
|
|
|
99
101
|
const filePath = JUDGMENT_FILES[type];
|
|
100
102
|
if (!filePath)
|
|
101
103
|
return;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
+
const body = yaml.dump({ judgments });
|
|
105
|
+
const header = '# Auto-generated by Pi Judgment System\n# Do not edit manually\n\n';
|
|
106
|
+
await fs.writeFile(filePath, header + body, 'utf-8');
|
|
104
107
|
cacheDirty = true;
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
@@ -323,122 +326,37 @@ function parseYaml(content) {
|
|
|
323
326
|
try {
|
|
324
327
|
if (!content.trim())
|
|
325
328
|
return [];
|
|
326
|
-
|
|
327
|
-
const lines = content.split('\n');
|
|
328
|
-
const arrayItems = [];
|
|
329
|
-
let inArray = false;
|
|
330
|
-
let currentItem = null;
|
|
331
|
-
let currentItemIndent = 0;
|
|
332
|
-
for (const line of lines) {
|
|
333
|
-
const trimmed = line.trim();
|
|
334
|
-
const indent = line.search(/\S/);
|
|
335
|
-
const isArrayItem = trimmed.startsWith('-');
|
|
336
|
-
const isComment = trimmed.startsWith('#');
|
|
337
|
-
if (isComment)
|
|
338
|
-
continue;
|
|
339
|
-
if (trimmed.startsWith('judgments:')) {
|
|
340
|
-
inArray = true;
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
if (!inArray)
|
|
344
|
-
continue;
|
|
345
|
-
if (isArrayItem) {
|
|
346
|
-
if (currentItem) {
|
|
347
|
-
arrayItems.push(currentItem);
|
|
348
|
-
}
|
|
349
|
-
currentItem = {};
|
|
350
|
-
currentItemIndent = indent + 1;
|
|
351
|
-
const itemContent = trimmed.substring(1).trim();
|
|
352
|
-
const kvMatch = itemContent.match(/^(\w+):\s*(.*)/);
|
|
353
|
-
if (kvMatch) {
|
|
354
|
-
currentItem[kvMatch[1]] = parseValue(kvMatch[2]);
|
|
355
|
-
}
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
if (currentItem && indent > currentItemIndent) {
|
|
359
|
-
const kvMatch = trimmed.match(/^(\w+):\s*(.*)/);
|
|
360
|
-
if (kvMatch) {
|
|
361
|
-
currentItem[kvMatch[1]] = parseValue(kvMatch[2]);
|
|
362
|
-
}
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
if (trimmed.includes(':')) {
|
|
366
|
-
const kvMatch = trimmed.match(/^(\w+):\s*(.*)/);
|
|
367
|
-
if (kvMatch && !isArrayItem) {
|
|
368
|
-
data[kvMatch[1]] = parseValue(kvMatch[2]);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (currentItem) {
|
|
373
|
-
arrayItems.push(currentItem);
|
|
374
|
-
}
|
|
375
|
-
if (arrayItems.length > 0) {
|
|
376
|
-
data['judgments'] = arrayItems;
|
|
377
|
-
}
|
|
378
|
-
return data;
|
|
329
|
+
return yaml.load(content) ?? [];
|
|
379
330
|
}
|
|
380
331
|
catch {
|
|
381
332
|
return [];
|
|
382
333
|
}
|
|
383
334
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
335
|
+
/**
|
|
336
|
+
* (YAML serialization now delegated to js-yaml)
|
|
337
|
+
*/
|
|
338
|
+
/**
|
|
339
|
+
* Best-effort coercion for a scalar frontmatter value.
|
|
340
|
+
* Returns booleans, numbers, or the raw string.
|
|
341
|
+
*/
|
|
342
|
+
function parseFrontmatterValue(raw) {
|
|
343
|
+
const value = raw.trim();
|
|
344
|
+
if (value === '')
|
|
345
|
+
return '';
|
|
346
|
+
if (value === 'true')
|
|
387
347
|
return true;
|
|
388
|
-
if (
|
|
348
|
+
if (value === 'false')
|
|
389
349
|
return false;
|
|
390
|
-
if (
|
|
350
|
+
if (value === 'null' || value === '~')
|
|
391
351
|
return null;
|
|
392
|
-
if (
|
|
393
|
-
return Number(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
*/
|
|
399
|
-
function serializeYaml(data) {
|
|
400
|
-
const lines = ['# Auto-generated by Pi Judgment System', '# Do not edit manually', ''];
|
|
401
|
-
if (typeof data === 'object' && data !== null) {
|
|
402
|
-
lines.push('judgments:');
|
|
403
|
-
const d = data;
|
|
404
|
-
const arr = d.judgments;
|
|
405
|
-
if (Array.isArray(arr)) {
|
|
406
|
-
for (const item of arr) {
|
|
407
|
-
lines.push(' - ' + serializeObject(item, 4));
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
return lines.join('\n');
|
|
412
|
-
}
|
|
413
|
-
function serializeObject(obj, indent) {
|
|
414
|
-
if (typeof obj !== 'object' || obj === null) {
|
|
415
|
-
return String(obj);
|
|
416
|
-
}
|
|
417
|
-
const spaces = ' '.repeat(indent);
|
|
418
|
-
const innerSpace = ' '.repeat(indent + 2);
|
|
419
|
-
const parts = [];
|
|
420
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
421
|
-
if (value === undefined || value === null)
|
|
422
|
-
continue;
|
|
423
|
-
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
424
|
-
parts.push(`${key}:`);
|
|
425
|
-
parts.push(serializeObject(value, indent + 2));
|
|
426
|
-
}
|
|
427
|
-
else if (Array.isArray(value)) {
|
|
428
|
-
parts.push(`${key}:`);
|
|
429
|
-
for (const item of value) {
|
|
430
|
-
parts.push(`${innerSpace}- ${serializeObject(item, indent + 4)}`);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
else {
|
|
434
|
-
const strValue = typeof value === 'string' ? `"${value}"` : String(value);
|
|
435
|
-
parts.push(`${key}: ${strValue}`);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (parts.length === 1 && !parts[0].includes(':')) {
|
|
439
|
-
return parts[0];
|
|
352
|
+
if (/^-?\d+(\.\d+)?$/.test(value))
|
|
353
|
+
return Number(value);
|
|
354
|
+
// Strip surrounding quotes if present
|
|
355
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
356
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
357
|
+
return value.slice(1, -1);
|
|
440
358
|
}
|
|
441
|
-
return
|
|
359
|
+
return value;
|
|
442
360
|
}
|
|
443
361
|
/**
|
|
444
362
|
* Extract YAML frontmatter from markdown
|
|
@@ -447,6 +365,16 @@ function extractFrontmatter(content) {
|
|
|
447
365
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
448
366
|
if (!match)
|
|
449
367
|
return {};
|
|
368
|
+
// Try js-yaml first; fall back to simple line parser if it fails or types missing.
|
|
369
|
+
try {
|
|
370
|
+
const parsed = yaml.load(match[1]);
|
|
371
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
372
|
+
return parsed;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// fall through to manual parsing
|
|
377
|
+
}
|
|
450
378
|
const frontmatter = {};
|
|
451
379
|
const lines = match[1].split('\n');
|
|
452
380
|
let currentKey = '';
|
|
@@ -465,10 +393,10 @@ function extractFrontmatter(content) {
|
|
|
465
393
|
const [key, ...valueParts] = trimmed.split(':');
|
|
466
394
|
const value = valueParts.join(':').trim();
|
|
467
395
|
if (currentKey === 'judgment' && indent > 0) {
|
|
468
|
-
frontmatter[currentKey][key] =
|
|
396
|
+
frontmatter[currentKey][key] = parseFrontmatterValue(value);
|
|
469
397
|
}
|
|
470
398
|
else {
|
|
471
|
-
frontmatter[key.trim()] =
|
|
399
|
+
frontmatter[key.trim()] = parseFrontmatterValue(value);
|
|
472
400
|
currentKey = key.trim();
|
|
473
401
|
}
|
|
474
402
|
}
|
|
@@ -306,7 +306,7 @@ export class ChannelHeartbeatAgent {
|
|
|
306
306
|
currentMessage: message,
|
|
307
307
|
senderName: peer.name
|
|
308
308
|
};
|
|
309
|
-
const decision = this.judgmentEngine.decide(context);
|
|
309
|
+
const decision = await this.judgmentEngine.decide(context);
|
|
310
310
|
if (decision.shouldCall) {
|
|
311
311
|
console.log(`[HeartbeatAgent] Auto-triggering Harness: Gate ${decision.gate} for ${peer.name}`);
|
|
312
312
|
// 这里可以发送消息触发对方响应
|
|
@@ -56,14 +56,19 @@ function getGlobalBolloonDir() {
|
|
|
56
56
|
* 优先使用全局安装的版本(更准确反映实际运行的版本)
|
|
57
57
|
*/
|
|
58
58
|
function getInstalledVersion(packageName) {
|
|
59
|
+
// 调试:打印 cwd
|
|
60
|
+
console.error(`[DEBUG] getInstalledVersion called, cwd=${process.cwd()}, package=${packageName}`);
|
|
59
61
|
// 对于 @bolloon/bolloon-agent,始终优先从全局安装位置读取版本
|
|
60
62
|
// 这样可以准确检测实际安装的版本,而不受 cwd 影响
|
|
61
63
|
if (packageName === '@bolloon/bolloon-agent') {
|
|
62
64
|
const globalDir = getGlobalBolloonDir();
|
|
65
|
+
console.error(`[DEBUG] globalDir=${globalDir}`);
|
|
63
66
|
if (globalDir) {
|
|
64
67
|
const pkgPath = path.join(globalDir, 'package.json');
|
|
68
|
+
console.error(`[DEBUG] pkgPath=${pkgPath}, exists=${fs.existsSync(pkgPath)}`);
|
|
65
69
|
try {
|
|
66
70
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
71
|
+
console.error(`[DEBUG] pkg.version=${pkg.version}`);
|
|
67
72
|
return pkg.version || null;
|
|
68
73
|
}
|
|
69
74
|
catch (e) {
|
|
@@ -72,9 +77,11 @@ function getInstalledVersion(packageName) {
|
|
|
72
77
|
}
|
|
73
78
|
// 回退到本地 package.json
|
|
74
79
|
const localPkgPath = path.join(process.cwd(), 'package.json');
|
|
80
|
+
console.error(`[DEBUG] localPkgPath=${localPkgPath}, exists=${fs.existsSync(localPkgPath)}`);
|
|
75
81
|
if (fs.existsSync(localPkgPath)) {
|
|
76
82
|
try {
|
|
77
83
|
const pkg = JSON.parse(fs.readFileSync(localPkgPath, 'utf-8'));
|
|
84
|
+
console.error(`[DEBUG] local pkg.version=${pkg.version}`);
|
|
78
85
|
return pkg.version || null;
|
|
79
86
|
}
|
|
80
87
|
catch (e) {
|
|
@@ -84,9 +91,11 @@ function getInstalledVersion(packageName) {
|
|
|
84
91
|
}
|
|
85
92
|
// 检查本地 node_modules
|
|
86
93
|
const packageJsonPath = findPackageJson(packageName);
|
|
94
|
+
console.error(`[DEBUG] findPackageJson=${packageJsonPath}`);
|
|
87
95
|
if (packageJsonPath) {
|
|
88
96
|
try {
|
|
89
97
|
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
98
|
+
console.error(`[DEBUG] node_modules pkg.version=${pkg.version}`);
|
|
90
99
|
return pkg.version || null;
|
|
91
100
|
}
|
|
92
101
|
catch (e) {
|
|
@@ -155,10 +164,15 @@ async function checkBolloonUpdates() {
|
|
|
155
164
|
let latestVersion = '';
|
|
156
165
|
for (const pkg of packagesToCheck) {
|
|
157
166
|
const installed = getInstalledVersion(pkg);
|
|
167
|
+
console.error(`[DEBUG] getInstalledVersion(${pkg}) = ${installed}`);
|
|
158
168
|
if (!installed)
|
|
159
169
|
continue;
|
|
160
|
-
|
|
170
|
+
// 只记录 @bolloon/bolloon-agent 的版本作为当前版本
|
|
171
|
+
if (pkg === '@bolloon/bolloon-agent') {
|
|
172
|
+
currentVersion = installed;
|
|
173
|
+
}
|
|
161
174
|
const latest = await getLatestVersion(pkg);
|
|
175
|
+
console.error(`[DEBUG] getLatestVersion(${pkg}) = ${latest}`);
|
|
162
176
|
if (latest && compareVersions(installed, latest) < 0) {
|
|
163
177
|
hasUpdate = true;
|
|
164
178
|
latestVersion = latest;
|