@bolloon/bolloon-agent 0.1.32 → 0.1.34
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 +7 -2
- package/dist/agents/pi-sdk.js +10 -1
- package/dist/bollharness-integration/index.js +8 -1
- package/dist/heartbeat/Watchdog.js +9 -1
- package/dist/llm/audio-config-store.js +199 -0
- package/dist/llm/config-store.js +20 -10
- package/dist/llm/pi-ai.js +2 -2
- package/dist/llm/video-config-store.js +31 -1
- package/dist/network/p2p-direct.js +59 -2
- package/dist/pi-ecosystem/index.js +10 -7
- package/dist/pi-ecosystem-judgment/decision.js +5 -2
- package/dist/social/heartbeat.js +19 -2
- package/dist/web/api-config.html +16 -4
- package/dist/web/client.js +1017 -137
- package/dist/web/index.html +10 -27
- package/dist/web/server.js +865 -52
- package/dist/web/style.css +370 -0
- package/package.json +2 -1
- package/src/agents/pi-sdk.ts +9 -1
- package/src/bollharness-integration/index.ts +8 -32
- package/src/heartbeat/Watchdog.ts +9 -1
- package/src/llm/audio-config-store.ts +6 -1
- package/src/llm/config-store.ts +21 -11
- package/src/llm/pi-ai.ts +2 -2
- package/src/llm/video-config-store.ts +7 -1
- package/src/network/p2p-direct.ts +59 -3
- package/src/social/ant-colony/index.js +19 -0
- package/src/social/heartbeat.ts +18 -2
- package/src/web/api-config.html +16 -4
- package/src/web/client.js +1017 -137
- package/src/web/index.html +10 -27
- package/src/web/server.ts +810 -47
- package/src/web/style.css +370 -0
- package/src/social/ant-colony/AdaptiveHeartbeat.ts +0 -131
- package/src/social/ant-colony/PheromoneEngine.ts +0 -302
- package/src/social/ant-colony/index.ts +0 -18
- package/src/social/ant-colony/types.ts +0 -94
package/dist/web/style.css
CHANGED
|
@@ -4083,3 +4083,373 @@ body:has(> .api-config-page) {
|
|
|
4083
4083
|
cursor: pointer;
|
|
4084
4084
|
accent-color: var(--accent);
|
|
4085
4085
|
}
|
|
4086
|
+
|
|
4087
|
+
/* ============================================================
|
|
4088
|
+
* 2026-06-10: 远程聊天 modal — 完全对齐本地聊天风格
|
|
4089
|
+
* 用 CSS 变量, 字体继承全局 JetBrains Mono, 支持深/浅色主题切换
|
|
4090
|
+
* ============================================================ */
|
|
4091
|
+
.remote-chat-overlay {
|
|
4092
|
+
position: fixed;
|
|
4093
|
+
inset: 0;
|
|
4094
|
+
background: rgba(0, 0, 0, 0.55);
|
|
4095
|
+
z-index: 10002;
|
|
4096
|
+
display: flex;
|
|
4097
|
+
align-items: center;
|
|
4098
|
+
justify-content: center;
|
|
4099
|
+
}
|
|
4100
|
+
.remote-chat-shell {
|
|
4101
|
+
background: var(--bg-main);
|
|
4102
|
+
color: var(--text);
|
|
4103
|
+
border: 1px solid var(--border);
|
|
4104
|
+
border-radius: 8px;
|
|
4105
|
+
width: 720px;
|
|
4106
|
+
max-width: 92vw;
|
|
4107
|
+
height: 80vh;
|
|
4108
|
+
max-height: 80vh;
|
|
4109
|
+
display: flex;
|
|
4110
|
+
flex-direction: column;
|
|
4111
|
+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
|
|
4112
|
+
font-family: inherit;
|
|
4113
|
+
}
|
|
4114
|
+
.remote-chat-header {
|
|
4115
|
+
padding: 12px 16px;
|
|
4116
|
+
border-bottom: 1px solid var(--border);
|
|
4117
|
+
display: flex;
|
|
4118
|
+
align-items: center;
|
|
4119
|
+
justify-content: space-between;
|
|
4120
|
+
gap: 8px;
|
|
4121
|
+
background: var(--bg-sidebar);
|
|
4122
|
+
border-radius: 8px 8px 0 0;
|
|
4123
|
+
}
|
|
4124
|
+
.remote-chat-title {
|
|
4125
|
+
font-size: 15px;
|
|
4126
|
+
font-weight: 600;
|
|
4127
|
+
color: var(--text);
|
|
4128
|
+
}
|
|
4129
|
+
.remote-chat-meta {
|
|
4130
|
+
font-size: 11px;
|
|
4131
|
+
color: var(--text-muted);
|
|
4132
|
+
margin-top: 2px;
|
|
4133
|
+
overflow: hidden;
|
|
4134
|
+
text-overflow: ellipsis;
|
|
4135
|
+
white-space: nowrap;
|
|
4136
|
+
}
|
|
4137
|
+
.remote-chat-btn-secondary {
|
|
4138
|
+
background: var(--bg-hover);
|
|
4139
|
+
border: 1px solid var(--border);
|
|
4140
|
+
color: var(--text-secondary);
|
|
4141
|
+
cursor: pointer;
|
|
4142
|
+
padding: 4px 10px;
|
|
4143
|
+
border-radius: 4px;
|
|
4144
|
+
font-size: 11px;
|
|
4145
|
+
font-family: inherit;
|
|
4146
|
+
}
|
|
4147
|
+
.remote-chat-btn-secondary:hover {
|
|
4148
|
+
background: var(--bg-active);
|
|
4149
|
+
color: var(--text);
|
|
4150
|
+
}
|
|
4151
|
+
.remote-chat-btn-close {
|
|
4152
|
+
background: none;
|
|
4153
|
+
border: none;
|
|
4154
|
+
font-size: 20px;
|
|
4155
|
+
color: var(--text-muted);
|
|
4156
|
+
cursor: pointer;
|
|
4157
|
+
padding: 0 8px;
|
|
4158
|
+
line-height: 1;
|
|
4159
|
+
}
|
|
4160
|
+
.remote-chat-btn-close:hover {
|
|
4161
|
+
color: var(--text);
|
|
4162
|
+
}
|
|
4163
|
+
.remote-chat-thinking {
|
|
4164
|
+
padding: 8px 16px;
|
|
4165
|
+
background: var(--bg-hover);
|
|
4166
|
+
color: var(--text-secondary);
|
|
4167
|
+
font-size: 12px;
|
|
4168
|
+
border-bottom: 1px solid var(--border);
|
|
4169
|
+
}
|
|
4170
|
+
.remote-chat-log {
|
|
4171
|
+
flex: 1;
|
|
4172
|
+
overflow-y: auto;
|
|
4173
|
+
padding: 12px 16px;
|
|
4174
|
+
background: var(--bg-main);
|
|
4175
|
+
}
|
|
4176
|
+
.remote-chat-input-row {
|
|
4177
|
+
padding: 10px 12px;
|
|
4178
|
+
border-top: 1px solid var(--border);
|
|
4179
|
+
display: flex;
|
|
4180
|
+
gap: 6px;
|
|
4181
|
+
background: var(--bg-sidebar);
|
|
4182
|
+
border-radius: 0 0 8px 8px;
|
|
4183
|
+
}
|
|
4184
|
+
.remote-chat-input {
|
|
4185
|
+
flex: 1;
|
|
4186
|
+
padding: 8px 10px;
|
|
4187
|
+
border: 1px solid var(--border);
|
|
4188
|
+
border-radius: 4px;
|
|
4189
|
+
font-size: 13px;
|
|
4190
|
+
background: var(--bg-main);
|
|
4191
|
+
color: var(--text);
|
|
4192
|
+
font-family: inherit;
|
|
4193
|
+
}
|
|
4194
|
+
.remote-chat-input:focus {
|
|
4195
|
+
outline: none;
|
|
4196
|
+
border-color: var(--accent, #a4b630);
|
|
4197
|
+
}
|
|
4198
|
+
.remote-chat-btn-send {
|
|
4199
|
+
padding: 8px 14px;
|
|
4200
|
+
background: var(--user-bg);
|
|
4201
|
+
color: var(--user-text);
|
|
4202
|
+
border: none;
|
|
4203
|
+
border-radius: 4px;
|
|
4204
|
+
cursor: pointer;
|
|
4205
|
+
font-size: 13px;
|
|
4206
|
+
font-weight: 600;
|
|
4207
|
+
font-family: inherit;
|
|
4208
|
+
}
|
|
4209
|
+
.remote-chat-btn-send:hover:not(:disabled) {
|
|
4210
|
+
filter: brightness(1.1);
|
|
4211
|
+
}
|
|
4212
|
+
.remote-chat-btn-send:disabled {
|
|
4213
|
+
opacity: 0.5;
|
|
4214
|
+
cursor: wait;
|
|
4215
|
+
}
|
|
4216
|
+
.remote-chat-sysmsg {
|
|
4217
|
+
margin: 6px 0;
|
|
4218
|
+
padding: 6px 10px;
|
|
4219
|
+
border-radius: 4px;
|
|
4220
|
+
font-size: 11px;
|
|
4221
|
+
text-align: center;
|
|
4222
|
+
border: 1px solid var(--border);
|
|
4223
|
+
}
|
|
4224
|
+
.remote-chat-sysmsg-info {
|
|
4225
|
+
background: var(--bg-hover);
|
|
4226
|
+
color: var(--text-secondary);
|
|
4227
|
+
}
|
|
4228
|
+
.remote-chat-sysmsg-warn {
|
|
4229
|
+
background: var(--bg-hover);
|
|
4230
|
+
color: var(--text);
|
|
4231
|
+
border-color: var(--border-light);
|
|
4232
|
+
}
|
|
4233
|
+
.remote-chat-sysmsg-error {
|
|
4234
|
+
background: rgba(220, 38, 38, 0.12);
|
|
4235
|
+
color: #fca5a5;
|
|
4236
|
+
border-color: rgba(220, 38, 38, 0.3);
|
|
4237
|
+
}
|
|
4238
|
+
.remote-chat-judgments {
|
|
4239
|
+
margin: 0 0 8px;
|
|
4240
|
+
padding: 8px 10px;
|
|
4241
|
+
background: var(--bg-hover);
|
|
4242
|
+
border-left: 3px solid var(--accent, #a4b630);
|
|
4243
|
+
border-radius: 4px;
|
|
4244
|
+
font-size: 12px;
|
|
4245
|
+
}
|
|
4246
|
+
.remote-chat-judgments-title {
|
|
4247
|
+
font-weight: 600;
|
|
4248
|
+
color: var(--text);
|
|
4249
|
+
margin-bottom: 4px;
|
|
4250
|
+
}
|
|
4251
|
+
.remote-chat-judgment-item {
|
|
4252
|
+
margin: 3px 0;
|
|
4253
|
+
padding-left: 8px;
|
|
4254
|
+
color: var(--text);
|
|
4255
|
+
}
|
|
4256
|
+
.remote-chat-judgment-tag {
|
|
4257
|
+
color: var(--text-muted);
|
|
4258
|
+
font-size: 10px;
|
|
4259
|
+
}
|
|
4260
|
+
.remote-chat-judgment-reason {
|
|
4261
|
+
color: var(--text-secondary);
|
|
4262
|
+
font-size: 11px;
|
|
4263
|
+
}
|
|
4264
|
+
.remote-chat-judgments-foot {
|
|
4265
|
+
margin-top: 6px;
|
|
4266
|
+
color: var(--text-muted);
|
|
4267
|
+
font-size: 11px;
|
|
4268
|
+
}
|
|
4269
|
+
|
|
4270
|
+
/* ============================================================
|
|
4271
|
+
* 2026-06-10: 好友申请 modal — 对齐本地风格 + CSS 变量
|
|
4272
|
+
* ============================================================ */
|
|
4273
|
+
.friend-req-overlay {
|
|
4274
|
+
position: fixed;
|
|
4275
|
+
inset: 0;
|
|
4276
|
+
background: rgba(0, 0, 0, 0.55);
|
|
4277
|
+
z-index: 10004;
|
|
4278
|
+
display: flex;
|
|
4279
|
+
align-items: center;
|
|
4280
|
+
justify-content: center;
|
|
4281
|
+
}
|
|
4282
|
+
.friend-req-shell {
|
|
4283
|
+
background: var(--bg-main);
|
|
4284
|
+
color: var(--text);
|
|
4285
|
+
border: 1px solid var(--border);
|
|
4286
|
+
border-radius: 8px;
|
|
4287
|
+
width: 460px;
|
|
4288
|
+
max-width: 92vw;
|
|
4289
|
+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
|
|
4290
|
+
font-family: inherit;
|
|
4291
|
+
}
|
|
4292
|
+
.friend-req-header {
|
|
4293
|
+
padding: 14px 18px;
|
|
4294
|
+
border-bottom: 1px solid var(--border);
|
|
4295
|
+
background: var(--bg-sidebar);
|
|
4296
|
+
display: flex;
|
|
4297
|
+
align-items: center;
|
|
4298
|
+
gap: 10px;
|
|
4299
|
+
border-radius: 8px 8px 0 0;
|
|
4300
|
+
}
|
|
4301
|
+
.friend-req-title {
|
|
4302
|
+
font-size: 15px;
|
|
4303
|
+
font-weight: 600;
|
|
4304
|
+
color: var(--text);
|
|
4305
|
+
}
|
|
4306
|
+
.friend-req-meta {
|
|
4307
|
+
font-size: 11px;
|
|
4308
|
+
color: var(--text-muted);
|
|
4309
|
+
margin-top: 2px;
|
|
4310
|
+
overflow: hidden;
|
|
4311
|
+
text-overflow: ellipsis;
|
|
4312
|
+
white-space: nowrap;
|
|
4313
|
+
}
|
|
4314
|
+
.friend-req-body {
|
|
4315
|
+
padding: 14px 18px;
|
|
4316
|
+
font-size: 13px;
|
|
4317
|
+
color: var(--text);
|
|
4318
|
+
line-height: 1.5;
|
|
4319
|
+
}
|
|
4320
|
+
.friend-req-actions {
|
|
4321
|
+
padding: 10px 18px;
|
|
4322
|
+
border-top: 1px solid var(--border);
|
|
4323
|
+
display: flex;
|
|
4324
|
+
gap: 8px;
|
|
4325
|
+
justify-content: flex-end;
|
|
4326
|
+
background: var(--bg-sidebar);
|
|
4327
|
+
border-radius: 0 0 8px 8px;
|
|
4328
|
+
}
|
|
4329
|
+
.friend-req-btn-deny {
|
|
4330
|
+
padding: 6px 14px;
|
|
4331
|
+
background: var(--bg-hover);
|
|
4332
|
+
color: var(--text-secondary);
|
|
4333
|
+
border: 1px solid var(--border);
|
|
4334
|
+
border-radius: 4px;
|
|
4335
|
+
cursor: pointer;
|
|
4336
|
+
font-size: 13px;
|
|
4337
|
+
font-family: inherit;
|
|
4338
|
+
}
|
|
4339
|
+
.friend-req-btn-deny:hover {
|
|
4340
|
+
background: var(--bg-active);
|
|
4341
|
+
color: var(--text);
|
|
4342
|
+
}
|
|
4343
|
+
.friend-req-btn-accept {
|
|
4344
|
+
padding: 6px 14px;
|
|
4345
|
+
background: var(--user-bg);
|
|
4346
|
+
color: var(--user-text);
|
|
4347
|
+
border: none;
|
|
4348
|
+
border-radius: 4px;
|
|
4349
|
+
cursor: pointer;
|
|
4350
|
+
font-size: 13px;
|
|
4351
|
+
font-weight: 600;
|
|
4352
|
+
font-family: inherit;
|
|
4353
|
+
}
|
|
4354
|
+
.friend-req-btn-accept:hover {
|
|
4355
|
+
filter: brightness(1.1);
|
|
4356
|
+
}
|
|
4357
|
+
|
|
4358
|
+
/* ============================================================
|
|
4359
|
+
* 2026-06-10: Toast 入场动画 (simple-toast 用)
|
|
4360
|
+
* ============================================================ */
|
|
4361
|
+
@keyframes toast-in {
|
|
4362
|
+
from {
|
|
4363
|
+
opacity: 0;
|
|
4364
|
+
transform: translateX(20px);
|
|
4365
|
+
}
|
|
4366
|
+
to {
|
|
4367
|
+
opacity: 1;
|
|
4368
|
+
transform: translateX(0);
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
/* ============================================================
|
|
4373
|
+
* 2026-06-10: P2P peer-group 可折叠 — 复用 #remote-agents-section.collapsed 模式
|
|
4374
|
+
* peer header 加 .peer-caret, 点击切 .remote-peer-group.collapsed
|
|
4375
|
+
* 折叠后隐藏 .remote-peer-channels, caret 旋转 -90deg
|
|
4376
|
+
* ============================================================ */
|
|
4377
|
+
.remote-peer-group .peer-caret {
|
|
4378
|
+
display: inline-block;
|
|
4379
|
+
font-size: 10px;
|
|
4380
|
+
color: var(--text-muted);
|
|
4381
|
+
transition: transform 0.15s ease;
|
|
4382
|
+
user-select: none;
|
|
4383
|
+
width: 12px;
|
|
4384
|
+
text-align: center;
|
|
4385
|
+
}
|
|
4386
|
+
.remote-peer-group.collapsed .peer-caret {
|
|
4387
|
+
transform: rotate(-90deg);
|
|
4388
|
+
}
|
|
4389
|
+
.remote-peer-group.collapsed > .remote-peer-channels {
|
|
4390
|
+
display: none;
|
|
4391
|
+
}
|
|
4392
|
+
.remote-peer-group .remote-peer-header {
|
|
4393
|
+
/* 让 caret 单独成可点区域时不撑破 header */
|
|
4394
|
+
user-select: none;
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
/* ============================================================
|
|
4398
|
+
* 2026-06-11: 分享 channel modal (P2P peer 分享) — 用 friend-req-shell 风格
|
|
4399
|
+
* ============================================================ */
|
|
4400
|
+
.share-modal-shell {
|
|
4401
|
+
width: 520px;
|
|
4402
|
+
max-height: 80vh;
|
|
4403
|
+
}
|
|
4404
|
+
.share-modal-hint {
|
|
4405
|
+
padding: 8px 18px;
|
|
4406
|
+
font-size: 12px;
|
|
4407
|
+
color: var(--text-muted);
|
|
4408
|
+
background: var(--bg-sidebar);
|
|
4409
|
+
border-bottom: 1px solid var(--border);
|
|
4410
|
+
}
|
|
4411
|
+
.share-modal-list {
|
|
4412
|
+
flex: 1;
|
|
4413
|
+
overflow-y: auto;
|
|
4414
|
+
padding: 4px 18px;
|
|
4415
|
+
max-height: 50vh;
|
|
4416
|
+
}
|
|
4417
|
+
.share-modal-empty {
|
|
4418
|
+
color: var(--text-muted);
|
|
4419
|
+
padding: 20px;
|
|
4420
|
+
text-align: center;
|
|
4421
|
+
}
|
|
4422
|
+
.share-modal-row {
|
|
4423
|
+
display: flex;
|
|
4424
|
+
align-items: flex-start;
|
|
4425
|
+
gap: 10px;
|
|
4426
|
+
padding: 8px 4px;
|
|
4427
|
+
cursor: pointer;
|
|
4428
|
+
border-bottom: 1px solid var(--border);
|
|
4429
|
+
font-family: inherit;
|
|
4430
|
+
}
|
|
4431
|
+
.share-modal-row:hover {
|
|
4432
|
+
background: var(--bg-hover);
|
|
4433
|
+
}
|
|
4434
|
+
.share-modal-cb {
|
|
4435
|
+
margin-top: 4px;
|
|
4436
|
+
cursor: pointer;
|
|
4437
|
+
width: 16px;
|
|
4438
|
+
height: 16px;
|
|
4439
|
+
accent-color: var(--accent);
|
|
4440
|
+
}
|
|
4441
|
+
.share-modal-row-info {
|
|
4442
|
+
flex: 1;
|
|
4443
|
+
min-width: 0;
|
|
4444
|
+
}
|
|
4445
|
+
.share-modal-row-name {
|
|
4446
|
+
font-size: 13px;
|
|
4447
|
+
font-weight: 500;
|
|
4448
|
+
color: var(--text);
|
|
4449
|
+
}
|
|
4450
|
+
.share-modal-row-meta {
|
|
4451
|
+
font-size: 10px;
|
|
4452
|
+
color: var(--text-muted);
|
|
4453
|
+
margin-top: 2px;
|
|
4454
|
+
font-family: 'JetBrains Mono', monospace;
|
|
4455
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bolloon/bolloon-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "P2P AI Document Agent - 全局安装后执行 `bolloon` 启动产品",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"viem": "^2.52.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
+
"@playwright/test": "^1.60.0",
|
|
63
64
|
"@types/express": "^5.0.6",
|
|
64
65
|
"@types/node": "^25.9.1",
|
|
65
66
|
"@types/pdf-parse": "^1.1.5",
|
package/src/agents/pi-sdk.ts
CHANGED
|
@@ -1178,6 +1178,7 @@ ${toolDefs}
|
|
|
1178
1178
|
const reply = response.reply.trim();
|
|
1179
1179
|
|
|
1180
1180
|
console.log(`[PiAgent] LLM 回复长度: ${reply.length}, 内容预览: "${reply.substring(0, 80)}..."`);
|
|
1181
|
+
console.log(`[PiAgent] LLM 完整回复:\n${reply}`);
|
|
1181
1182
|
|
|
1182
1183
|
// 通知前端:收到 LLM 回复
|
|
1183
1184
|
if (onStream) {
|
|
@@ -1450,7 +1451,14 @@ Workspace root folder: ${this.cwd}
|
|
|
1450
1451
|
const marker = '<final gen>';
|
|
1451
1452
|
const markerIndex = content.indexOf(marker);
|
|
1452
1453
|
if (markerIndex !== -1) {
|
|
1453
|
-
|
|
1454
|
+
const after = content.substring(markerIndex + marker.length).trim();
|
|
1455
|
+
// v3 修复: 如果 <final gen> 之后是空, fallback 用 marker 之前的内容 (去掉 marker)
|
|
1456
|
+
// 否则 LLM 写了 <final gen> 在末尾时, 用户看到空回复 + error
|
|
1457
|
+
if (after) {
|
|
1458
|
+
content = after;
|
|
1459
|
+
} else {
|
|
1460
|
+
content = content.substring(0, markerIndex).trim();
|
|
1461
|
+
}
|
|
1454
1462
|
}
|
|
1455
1463
|
// 移除任何 tool call 标记
|
|
1456
1464
|
let cleaned = content
|
|
@@ -96,38 +96,14 @@ export {
|
|
|
96
96
|
type SubagentResult,
|
|
97
97
|
} from '../pi-ecosystem-subagents/index.js';
|
|
98
98
|
|
|
99
|
-
export
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
antTick,
|
|
108
|
-
createTask,
|
|
109
|
-
dispatchTask,
|
|
110
|
-
recordResult,
|
|
111
|
-
getAnt,
|
|
112
|
-
listAnts,
|
|
113
|
-
listAntsByRole,
|
|
114
|
-
listAntsBySignal,
|
|
115
|
-
getActiveAnts,
|
|
116
|
-
getTask,
|
|
117
|
-
listTasks,
|
|
118
|
-
getSignalHistory,
|
|
119
|
-
getColonyStatus,
|
|
120
|
-
getColonyDump,
|
|
121
|
-
persistColony,
|
|
122
|
-
loadColony,
|
|
123
|
-
onColonyEvent,
|
|
124
|
-
offColonyEvent,
|
|
125
|
-
type Ant,
|
|
126
|
-
type ColonyTask,
|
|
127
|
-
type ColonySignalEvent,
|
|
128
|
-
type ColonySignal,
|
|
129
|
-
type AntRole,
|
|
130
|
-
} from '../pi-ecosystem-colony/index.js';
|
|
99
|
+
// 2026-06-11: 蚁群模块 (pi-ecosystem-colony) 已被用户删除, 移除对应 re-export 防止启动失败
|
|
100
|
+
// export {
|
|
101
|
+
// registerAnt, antScouting, antWorking, antReviewing, antComplete, antFail, antAbort, antTick,
|
|
102
|
+
// createTask, dispatchTask, recordResult, getAnt, listAnts, listAntsByRole, listAntsBySignal,
|
|
103
|
+
// getActiveAnts, getTask, listTasks, getSignalHistory, getColonyStatus, getColonyDump,
|
|
104
|
+
// persistColony, loadColony, onColonyEvent, offColonyEvent,
|
|
105
|
+
// type Ant, type ColonyTask, type ColonySignalEvent, type ColonySignal, type AntRole,
|
|
106
|
+
// } from '../pi-ecosystem-colony/index.js';
|
|
131
107
|
|
|
132
108
|
// Judgment exports
|
|
133
109
|
export {
|
|
@@ -42,11 +42,19 @@ export class Watchdog {
|
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* 记录活动(调用后更新 lastActivityTime)
|
|
45
|
+
* 2026-06-10: 加 5s 去抖, 防 broadcast / SSE 高频路径炸 log + CPU
|
|
46
|
+
* - lastActivityTime 始终更新 (cheap)
|
|
47
|
+
* - 但 onLog 回调只在距上次 ≥5s 时触发, 避免每秒几十次 console.log
|
|
45
48
|
*/
|
|
49
|
+
private _lastLogAt = 0;
|
|
46
50
|
recordActivity(component?: string): void {
|
|
47
51
|
this.state.lastActivityTime = Date.now();
|
|
48
52
|
if (component) {
|
|
49
|
-
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
if (now - this._lastLogAt >= 5000) {
|
|
55
|
+
this._lastLogAt = now;
|
|
56
|
+
this.callbacks.onLog?.(`[Watchdog] Activity from ${component}`);
|
|
57
|
+
}
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
|
|
@@ -222,9 +222,14 @@ class AudioConfigStore {
|
|
|
222
222
|
return { success: true, latency };
|
|
223
223
|
} else {
|
|
224
224
|
const errorText = await response.text().catch(() => 'Unknown error');
|
|
225
|
+
const hint = response.status === 401
|
|
226
|
+
? '(请确认是 MiniMax 的 API Key)'
|
|
227
|
+
: response.status === 404
|
|
228
|
+
? '(端点不存在 — 请检查 baseUrl)'
|
|
229
|
+
: '';
|
|
225
230
|
return {
|
|
226
231
|
success: false,
|
|
227
|
-
error: `HTTP ${response.status}: ${errorText.substring(0,
|
|
232
|
+
error: `HTTP ${response.status}: ${errorText.substring(0, 500)}${hint ? ' ' + hint : ''}`,
|
|
228
233
|
latency
|
|
229
234
|
};
|
|
230
235
|
}
|
package/src/llm/config-store.ts
CHANGED
|
@@ -77,7 +77,7 @@ export const DEFAULT_PROVIDER_CONFIGS: Record<ModelProvider, ProviderConfig> = {
|
|
|
77
77
|
enabled: false,
|
|
78
78
|
apiKey: '',
|
|
79
79
|
baseUrl: 'https://api.minimaxi.com/v1',
|
|
80
|
-
model: 'MiniMax-
|
|
80
|
+
model: 'MiniMax-M3',
|
|
81
81
|
temperature: 0.7,
|
|
82
82
|
maxTokens: 4096,
|
|
83
83
|
requiresApiKey: true
|
|
@@ -129,17 +129,22 @@ export const DEFAULT_PROVIDER_CONFIGS: Record<ModelProvider, ProviderConfig> = {
|
|
|
129
129
|
}
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
-
export const PROVIDER_INFO: Record<ModelProvider, { name: string; description: string; requiresApiKey: boolean }> = {
|
|
133
|
-
openai: { name: 'OpenAI', description: 'GPT-4, GPT-3.5 等模型', requiresApiKey: true },
|
|
134
|
-
anthropic: { name: 'Anthropic', description: 'Claude 3.5 系列模型', requiresApiKey: true },
|
|
132
|
+
export const PROVIDER_INFO: Record<ModelProvider, { name: string; description: string; requiresApiKey: boolean; models?: string[] }> = {
|
|
133
|
+
openai: { name: 'OpenAI', description: 'GPT-4, GPT-3.5 等模型', requiresApiKey: true, models: ['gpt-4', 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-3.5-turbo'] },
|
|
134
|
+
anthropic: { name: 'Anthropic', description: 'Claude 3.5 系列模型', requiresApiKey: true, models: ['claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229'] },
|
|
135
135
|
openrouter: { name: 'OpenRouter', description: '聚合多个 AI 供应商', requiresApiKey: true },
|
|
136
|
-
gemini: { name: 'Google Gemini', description: 'Gemini 系列模型', requiresApiKey: true },
|
|
136
|
+
gemini: { name: 'Google Gemini', description: 'Gemini 系列模型', requiresApiKey: true, models: ['gemini-2.0-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'] },
|
|
137
137
|
ollama: { name: 'Ollama', description: '本地 LLM 运行框架', requiresApiKey: false },
|
|
138
|
-
minimax: {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
minimax: {
|
|
139
|
+
name: 'MiniMax',
|
|
140
|
+
description: '国产大模型服务',
|
|
141
|
+
requiresApiKey: true,
|
|
142
|
+
models: ['MiniMax-M3', 'MiniMax-M2.7', 'MiniMax-M2', 'MiniMax-M2.1-highspeed', 'MiniMax-M2.7-highspeed']
|
|
143
|
+
},
|
|
144
|
+
deepseek: { name: 'DeepSeek', description: '深度求索大模型', requiresApiKey: true, models: ['deepseek-chat', 'deepseek-reasoner'] },
|
|
145
|
+
kimi: { name: 'Kimi (月之暗面)', description: 'Moonshot 长上下文模型', requiresApiKey: true, models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'] },
|
|
146
|
+
glm: { name: 'GLM (智谱)', description: '智谱 ChatGLM 系列模型', requiresApiKey: true, models: ['glm-4-flash', 'glm-4', 'glm-4-plus', 'glm-4-air', 'glm-4-airx'] },
|
|
147
|
+
qwen: { name: 'Qwen (通义千问)', description: '阿里云通义千问系列', requiresApiKey: true, models: ['qwen-plus', 'qwen-max', 'qwen-turbo', 'qwen-long'] },
|
|
143
148
|
local: { name: '本地模型', description: '本地部署的模型服务', requiresApiKey: false }
|
|
144
149
|
};
|
|
145
150
|
|
|
@@ -323,7 +328,12 @@ class LLMConfigStore {
|
|
|
323
328
|
return { success: true, latency };
|
|
324
329
|
} else {
|
|
325
330
|
const errorText = await response.text().catch(() => 'Unknown error');
|
|
326
|
-
|
|
331
|
+
const hint = response.status === 401
|
|
332
|
+
? '(API Key 无效或不匹配该供应商 — 请检查是否复制完整、有无多余空格)'
|
|
333
|
+
: response.status === 404
|
|
334
|
+
? '(端点不存在 — 请检查 baseUrl)'
|
|
335
|
+
: '';
|
|
336
|
+
return { success: false, error: `HTTP ${response.status}: ${errorText.substring(0, 500)}${hint ? ' ' + hint : ''}`, latency };
|
|
327
337
|
}
|
|
328
338
|
} catch (error: any) {
|
|
329
339
|
return { success: false, error: error.message || 'Connection failed', latency: Date.now() - startTime };
|
package/src/llm/pi-ai.ts
CHANGED
|
@@ -176,7 +176,7 @@ export class PiAIModel {
|
|
|
176
176
|
ollama: this.config.model || 'llama3.2',
|
|
177
177
|
openrouter: this.config.model || 'anthropic/claude-3.5-sonnet',
|
|
178
178
|
gemini: this.config.model || 'gemini-2.0-flash',
|
|
179
|
-
minimax: this.config.model || process.env.MINIMAX_MODEL || 'MiniMax-
|
|
179
|
+
minimax: this.config.model || process.env.MINIMAX_MODEL || 'MiniMax-M3',
|
|
180
180
|
deepseek: this.config.model || process.env.DEEPSEEK_MODEL || 'deepseek-chat',
|
|
181
181
|
kimi: this.config.model || process.env.KIMI_MODEL || process.env.MOONSHOT_MODEL || 'moonshot-v1-8k',
|
|
182
182
|
glm: this.config.model || process.env.GLM_MODEL || process.env.ZHIPU_MODEL || 'glm-4-flash',
|
|
@@ -482,7 +482,7 @@ function detectModel(provider: ModelProvider): string {
|
|
|
482
482
|
ollama: 'llama3.2',
|
|
483
483
|
openrouter: 'anthropic/claude-3.5-sonnet',
|
|
484
484
|
gemini: 'gemini-2.0-flash',
|
|
485
|
-
minimax: 'MiniMax-
|
|
485
|
+
minimax: 'MiniMax-M3',
|
|
486
486
|
deepseek: 'deepseek-chat',
|
|
487
487
|
kimi: 'moonshot-v1-8k',
|
|
488
488
|
glm: 'glm-4-flash',
|
|
@@ -232,9 +232,15 @@ class VideoConfigStore {
|
|
|
232
232
|
return { success: true, latency };
|
|
233
233
|
} else {
|
|
234
234
|
const errorText = await response.text().catch(() => 'Unknown error');
|
|
235
|
+
// 401 通常是 key 错误,给出针对性提示
|
|
236
|
+
const hint = response.status === 401
|
|
237
|
+
? '(请确认是火山方舟 ARK 的 API Key,不是 MiniMax / 其他平台)'
|
|
238
|
+
: response.status === 404
|
|
239
|
+
? '(端点不存在 — 火山方舟可能没有 /models,请检查 baseUrl)'
|
|
240
|
+
: '';
|
|
235
241
|
return {
|
|
236
242
|
success: false,
|
|
237
|
-
error: `HTTP ${response.status}: ${errorText.substring(0,
|
|
243
|
+
error: `HTTP ${response.status}: ${errorText.substring(0, 500)}${hint ? ' ' + hint : ''}`,
|
|
238
244
|
latency
|
|
239
245
|
};
|
|
240
246
|
}
|
|
@@ -88,10 +88,9 @@ export class P2PDirect extends EventEmitter {
|
|
|
88
88
|
// 双向记录 (inbound + outbound 都能拿到)
|
|
89
89
|
this.conns.set(remotePubKeyHex, conn);
|
|
90
90
|
|
|
91
|
-
// v3: 触发 'connection' 事件, 上层 (web server) 可以主动给新连接发消息
|
|
92
|
-
this.emit('connection', { remotePublicKey: remotePubKeyHex, conn });
|
|
93
|
-
|
|
94
91
|
// 收到数据时 → 触发 'data' 事件
|
|
92
|
+
// 注意: data 监听器必须在 emit('connection') 之前注册,
|
|
93
|
+
// 否则 server 的 connection handler 发送消息后, 对端回复可能在 data 监听器就绪前到达
|
|
95
94
|
conn.on('data', (chunk: Buffer | Uint8Array) => {
|
|
96
95
|
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
97
96
|
console.log(`[P2PDirect:${this.name}] 收到数据 from ${remotePubKeyHex.substring(0,12)}... (${buf.length} bytes)`);
|
|
@@ -108,6 +107,10 @@ export class P2PDirect extends EventEmitter {
|
|
|
108
107
|
conn.on('close', () => {
|
|
109
108
|
this.conns.delete(remotePubKeyHex);
|
|
110
109
|
});
|
|
110
|
+
|
|
111
|
+
// v3: 触发 'connection' 事件, 上层 (web server) 可以主动给新连接发消息
|
|
112
|
+
// 注意: 放在 data/error/close 监听器之后, 确保 server 的 connection handler 不会先于 data 就绪
|
|
113
|
+
this.emit('connection', { remotePublicKey: remotePubKeyHex, conn });
|
|
111
114
|
});
|
|
112
115
|
|
|
113
116
|
await this.swarm.listen(); // server 模式
|
|
@@ -159,6 +162,59 @@ export class P2PDirect extends EventEmitter {
|
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
|
|
165
|
+
/**
|
|
166
|
+
* 2026-06-10: 真"主动发, 等握手完成"版本 — 修复好友申请 fire-and-forget bug.
|
|
167
|
+
*
|
|
168
|
+
* 之前的问题: server.ts:2914 `await swarm.joinPeer(...)` 只触发握手, conn 还没 push 进 this.conns,
|
|
169
|
+
* 立即调 sendTo 找不到 conn → 静默返回 false → 消息扔进虚空.
|
|
170
|
+
*
|
|
171
|
+
* 现在: sendToWithWait 监听 'connection' 事件, 等到 targetPublicKey 真正出现在 this.conns,
|
|
172
|
+
* 才 write; 超时返回 NO_CONN; 写失败返回 WRITE_FAIL; 成功返回 SENT.
|
|
173
|
+
*
|
|
174
|
+
* 上层调用: const r = await p2p.sendToWithWait(pk, rpc, 5000);
|
|
175
|
+
* if (r !== 'SENT') return 502 给前端.
|
|
176
|
+
*/
|
|
177
|
+
async sendToWithWait(
|
|
178
|
+
publicKeyHex: string,
|
|
179
|
+
data: Buffer | string,
|
|
180
|
+
timeoutMs: number = 5000
|
|
181
|
+
): Promise<'SENT' | 'NO_CONN' | 'WRITE_FAIL'> {
|
|
182
|
+
// 2026-06-11: 先主动触发 joinPeer, 否则 DHT 上对面可能没 push conn
|
|
183
|
+
if (this.swarm) {
|
|
184
|
+
try { await this.swarm.joinPeer(Buffer.from(publicKeyHex, 'hex')); } catch {}
|
|
185
|
+
}
|
|
186
|
+
// 1) 已有 conn → 立即试
|
|
187
|
+
let conn = this.conns.get(publicKeyHex);
|
|
188
|
+
if (!conn || conn.destroyed) {
|
|
189
|
+
// 2) 等 'connection' 事件 (this.emit('connection', { remotePublicKey, conn }))
|
|
190
|
+
const waitResult = await new Promise<'READY' | 'TIMEOUT'>((resolve) => {
|
|
191
|
+
const timer = setTimeout(() => {
|
|
192
|
+
this.off('connection', onConn);
|
|
193
|
+
resolve('TIMEOUT');
|
|
194
|
+
}, timeoutMs);
|
|
195
|
+
const onConn = (evt: { remotePublicKey: string; conn: any }) => {
|
|
196
|
+
if (evt.remotePublicKey === publicKeyHex) {
|
|
197
|
+
clearTimeout(timer);
|
|
198
|
+
this.off('connection', onConn);
|
|
199
|
+
resolve('READY');
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
this.on('connection', onConn);
|
|
203
|
+
});
|
|
204
|
+
if (waitResult === 'TIMEOUT') return 'NO_CONN';
|
|
205
|
+
conn = this.conns.get(publicKeyHex);
|
|
206
|
+
if (!conn || conn.destroyed) return 'NO_CONN'; // 双保险
|
|
207
|
+
}
|
|
208
|
+
const buf = typeof data === 'string' ? Buffer.from(data) : data;
|
|
209
|
+
try {
|
|
210
|
+
conn.write(buf);
|
|
211
|
+
return 'SENT';
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.error(`[P2PDirect:${this.name}] sendToWithWait 写失败 (${publicKeyHex.substring(0,12)}...):`, (err as Error).message);
|
|
214
|
+
return 'WRITE_FAIL';
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
162
218
|
getPublicKey(): string {
|
|
163
219
|
if (!this.swarm) return '';
|
|
164
220
|
return b4a.toString(this.swarm.keyPair.publicKey, 'hex');
|