@trim21/personal-pi-extensions 0.0.198 → 0.0.199
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 +1 -1
- package/package.json +1 -1
- package/src/talk/core.ts +29 -12
- package/src/talk/registry.ts +5 -1
package/README.md
CHANGED
|
@@ -246,7 +246,7 @@ index.ts —— pi adapter:把 core 接到 pi 的 sendMessage / 生命周
|
|
|
246
246
|
|
|
247
247
|
### 关键设计
|
|
248
248
|
|
|
249
|
-
- **心跳即活跃**:每个 session 每 15s 写一次 `lastSeenAt`;`talk-list-sessions` 默认只显示最近 15 分钟内有心跳的 session,已结束/挂起的 session 自动从默认列表消失(`includeOffline: true` 可见全部)。`status` 用 45s 心跳阈值区分 live / not responding / offline
|
|
249
|
+
- **心跳即活跃**:每个 session 每 15s 写一次 `lastSeenAt`;`talk-list-sessions` 默认只显示最近 15 分钟内有心跳的 session,已结束/挂起的 session 自动从默认列表消失(`includeOffline: true` 可见全部)。`status` 用 45s 心跳阈值区分 live / not responding / offline,并显示 `working` / `waiting-talk-message`(`talk-wait` / `talk-ask` 阻塞等待中)/ `idle`。
|
|
250
250
|
- **定期清理**:心跳停止超过 24h 且无未投递 mail 的记录会被定期 sweep(30 分钟一次)回收;有 mail 的保留 30 天。resume 后 session 会自动重新注册,无 mail 即无损失。
|
|
251
251
|
- **投递成功才消费**:信件只在成功交给 `sendMessage` 后才从 inbox 删除,投递失败留在 inbox 下次重试——不会因 `sendMessage` 吞异常而静默丢信。
|
|
252
252
|
- **双向 ask 仲裁**:`talk-ask` 发起前先检查收件箱(有对方消息就先读/先回);阻塞等待期间若收到对方的 ask(而非 reply),按两个 ask 的 `ts` 字段仲裁——先 ask 者主导继续等,后 ask 者让位并先回复对方。`ts` 是信件内固定字段,双方读到同一对值,结论天然对称;同毫秒碰撞用 `session dir + session id` 字符串比较兜底。
|
package/package.json
CHANGED
package/src/talk/core.ts
CHANGED
|
@@ -205,6 +205,11 @@ export class TalkCore {
|
|
|
205
205
|
void this.writeSelf({ status: "working" });
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/** Blocked on talk-wait / talk-ask — visible as "waiting-talk-message". */
|
|
209
|
+
setWaiting(): void {
|
|
210
|
+
void this.writeSelf({ status: "waiting-talk-message" });
|
|
211
|
+
}
|
|
212
|
+
|
|
208
213
|
setIdle(): void {
|
|
209
214
|
void this.writeSelf({ status: "idle" });
|
|
210
215
|
}
|
|
@@ -473,13 +478,19 @@ export class TalkCore {
|
|
|
473
478
|
async wait(timeoutMs: number, signal?: AbortSignal): Promise<string> {
|
|
474
479
|
const self = this.requireSelf();
|
|
475
480
|
const deadline = this.now() + timeoutMs;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
481
|
+
this.setWaiting();
|
|
482
|
+
try {
|
|
483
|
+
for (;;) {
|
|
484
|
+
const inbox = await listInbox(this.storage, self.addr);
|
|
485
|
+
const fresh = await this.consumeFresh(inbox);
|
|
486
|
+
if (fresh.length > 0) return fresh.map((l) => formatDelivery(l)).join("\n\n");
|
|
487
|
+
if (signal?.aborted) return "aborted";
|
|
488
|
+
if (this.now() >= deadline) return `No message within ${Math.round(timeoutMs / 1000)}s.`;
|
|
489
|
+
await sleep(WAIT_POLL_MS);
|
|
490
|
+
}
|
|
491
|
+
} finally {
|
|
492
|
+
// The tool call is still part of a running agent turn.
|
|
493
|
+
this.setWorking();
|
|
483
494
|
}
|
|
484
495
|
}
|
|
485
496
|
|
|
@@ -608,11 +619,17 @@ export class TalkCore {
|
|
|
608
619
|
body,
|
|
609
620
|
ts: sent.letter.ts,
|
|
610
621
|
});
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
622
|
+
this.setWaiting();
|
|
623
|
+
try {
|
|
624
|
+
const outcome = await this.waitForReply(sent.letter.id, Math.max(1000, timeoutMs), signal);
|
|
625
|
+
await clearAsk(this.storage, self.addr, sent.letter.id);
|
|
626
|
+
if (!outcome.replied)
|
|
627
|
+
return `Ask ${sent.letter.id.slice(0, 8)} to "${record.name}": ${outcome.reason}.`;
|
|
628
|
+
return `"${record.name}" replied:\n\n${outcome.body}`;
|
|
629
|
+
} finally {
|
|
630
|
+
// The ask tool call is still part of a running agent turn.
|
|
631
|
+
this.setWorking();
|
|
632
|
+
}
|
|
616
633
|
}
|
|
617
634
|
|
|
618
635
|
async reply(replyTo: string, body: string): Promise<string> {
|
package/src/talk/registry.ts
CHANGED
|
@@ -30,7 +30,11 @@ export const SessionRecordSchema = Type.Object({
|
|
|
30
30
|
pid: Type.Number(),
|
|
31
31
|
startedAt: Type.Number(),
|
|
32
32
|
lastSeenAt: Type.Number(),
|
|
33
|
-
status: Type.Union([
|
|
33
|
+
status: Type.Union([
|
|
34
|
+
Type.Literal("idle"),
|
|
35
|
+
Type.Literal("working"),
|
|
36
|
+
Type.Literal("waiting-talk-message"),
|
|
37
|
+
]),
|
|
34
38
|
offline: Type.Optional(Type.Boolean()),
|
|
35
39
|
});
|
|
36
40
|
export type SessionRecord = Static<typeof SessionRecordSchema>;
|