@springbrand/agent-runtime 0.2.0-alpha.51 → 0.2.0-alpha.53
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/package.json +2 -2
- package/src/kernel/state.ts +1 -0
- package/src/lib/prompt.ts +3 -3
- package/src/pi/tool/base.ts +1 -1
- package/src/runtime.ts +34 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@springbrand/agent-runtime",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.53",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@cloudflare/codemode": "0.5.1",
|
|
21
21
|
"@cloudflare/sandbox": "0.12.4",
|
|
22
22
|
"@cloudflare/shell": "0.4.3",
|
|
23
|
-
"@cloudflare/think": "0.
|
|
23
|
+
"@cloudflare/think": "0.17.0",
|
|
24
24
|
"@earendil-works/pi-agent-core": "0.83.0",
|
|
25
25
|
"@earendil-works/pi-ai": "0.83.0",
|
|
26
26
|
"@types/lodash-es": "^4.17.12",
|
package/src/kernel/state.ts
CHANGED
|
@@ -59,6 +59,7 @@ export interface RuntimeQueuedSubmission {
|
|
|
59
59
|
export interface RuntimeTurnState {
|
|
60
60
|
activeSubmissionId?: string;
|
|
61
61
|
activeRequestId?: string;
|
|
62
|
+
activeMessageId?: string;
|
|
62
63
|
recoveryAttempt?: number;
|
|
63
64
|
recoveryMax?: number;
|
|
64
65
|
recoveryReason?: "no_meaningful_model_progress" | "transient_model_error";
|
package/src/lib/prompt.ts
CHANGED
|
@@ -113,9 +113,9 @@ export const INTERACTION =
|
|
|
113
113
|
"a bounded choice; for required free text, omit the options field entirely — never pass an empty or single-item options array; " +
|
|
114
114
|
"continue the same turn when its result arrives. " +
|
|
115
115
|
"Don't use it when a sensible default lets you proceed. " +
|
|
116
|
-
"After completing a substantive task (report, analysis, multi-step job)
|
|
117
|
-
"
|
|
118
|
-
"write
|
|
116
|
+
"After completing a substantive task (report, analysis, multi-step job), finish all work and other Tool calls, " +
|
|
117
|
+
"then call suggest_followups (2-4 directions) as the last Tool call before your final answer. " +
|
|
118
|
+
"After it returns, write your complete final answer and make no further Tool calls. Never for small talk or while a " +
|
|
119
119
|
"task is still in progress; it is non-blocking, unlike ask_user.";
|
|
120
120
|
|
|
121
121
|
// Separates short always-on memory from indexed long-tail workspace files.
|
package/src/pi/tool/base.ts
CHANGED
|
@@ -300,7 +300,7 @@ export function basePiToolCandidates(
|
|
|
300
300
|
name: "suggest_followups",
|
|
301
301
|
label: "Suggest follow-ups",
|
|
302
302
|
description:
|
|
303
|
-
"Offer the user 2-4 optional follow-up directions after completing a substantive task (a report, an analysis, a multi-step job). Call this at most once,
|
|
303
|
+
"Offer the user 2-4 optional follow-up directions after completing a substantive task (a report, an analysis, a multi-step job). Call this at most once, after all work and other Tool calls are complete. It MUST be the last Tool call before the final answer. After it returns, write the complete final answer and make no further Tool calls. Do NOT call it for small talk, quick answers, or while a task is still in progress.",
|
|
304
304
|
parameters: suggestFollowupsParameters,
|
|
305
305
|
async execute(_toolCallId, input) {
|
|
306
306
|
return result({ noted: true, count: input.items.length });
|
package/src/runtime.ts
CHANGED
|
@@ -442,6 +442,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
442
442
|
private readonly approvals: ApprovalLifecycle<StoredSubmission>;
|
|
443
443
|
private readonly interactions: InteractionLifecycle<StoredSubmission>;
|
|
444
444
|
private runtimeLoadTracker?: RuntimeLoadTracker;
|
|
445
|
+
private runtimeEventDrainTail?: Promise<void>;
|
|
445
446
|
private readonly streamBySubmission = new Map<string, string>();
|
|
446
447
|
private migratedSubmissionIds?: Set<string>;
|
|
447
448
|
private db!: RuntimeDatabase;
|
|
@@ -1153,7 +1154,19 @@ export abstract class AgentRuntimeKernel<
|
|
|
1153
1154
|
);
|
|
1154
1155
|
}
|
|
1155
1156
|
|
|
1156
|
-
private
|
|
1157
|
+
private drainRuntimeEvents(idempotentRetry = true): Promise<void> {
|
|
1158
|
+
const drain = (this.runtimeEventDrainTail ?? Promise.resolve())
|
|
1159
|
+
.catch(() => undefined)
|
|
1160
|
+
.then(() => this.deliverRuntimeEvents(idempotentRetry));
|
|
1161
|
+
this.runtimeEventDrainTail = drain;
|
|
1162
|
+
return drain.finally(() => {
|
|
1163
|
+
if (this.runtimeEventDrainTail === drain) {
|
|
1164
|
+
this.runtimeEventDrainTail = undefined;
|
|
1165
|
+
}
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
private async deliverRuntimeEvents(idempotentRetry: boolean): Promise<void> {
|
|
1157
1170
|
const turnEvents = this.turnEventsPort();
|
|
1158
1171
|
if (!turnEvents) return;
|
|
1159
1172
|
|
|
@@ -3411,15 +3424,15 @@ export abstract class AgentRuntimeKernel<
|
|
|
3411
3424
|
* @remarks
|
|
3412
3425
|
* Cloudflare Agents SDK 为每条新 WebSocket 连接调用。
|
|
3413
3426
|
*
|
|
3414
|
-
*
|
|
3415
|
-
*
|
|
3427
|
+
* 先发送已完成 transcript,再让恢复基类独自重建 active assistant,
|
|
3428
|
+
* 使持久化历史和 resumable stream 只有一个生产者。
|
|
3416
3429
|
*/
|
|
3417
3430
|
async onConnect(connection: Connection): Promise<void> {
|
|
3418
3431
|
sendIfOpen(
|
|
3419
3432
|
connection,
|
|
3420
3433
|
json({
|
|
3421
3434
|
type: MessageType.CF_AGENT_CHAT_MESSAGES,
|
|
3422
|
-
messages: await this.
|
|
3435
|
+
messages: await this.hydrationMessages(),
|
|
3423
3436
|
}),
|
|
3424
3437
|
);
|
|
3425
3438
|
await super.onConnect(connection);
|
|
@@ -3435,8 +3448,13 @@ export abstract class AgentRuntimeKernel<
|
|
|
3435
3448
|
* 避免在这里复制 Agents SDK 的默认协议行为。
|
|
3436
3449
|
*/
|
|
3437
3450
|
async onRequest(request: Request): Promise<Response> {
|
|
3438
|
-
|
|
3439
|
-
|
|
3451
|
+
const url = new URL(request.url);
|
|
3452
|
+
if (url.pathname.endsWith("/get-messages")) {
|
|
3453
|
+
return Response.json(
|
|
3454
|
+
url.searchParams.get("view") === "hydration"
|
|
3455
|
+
? await this.hydrationMessages()
|
|
3456
|
+
: await this.getMessages(),
|
|
3457
|
+
);
|
|
3440
3458
|
}
|
|
3441
3459
|
return super.onRequest(request);
|
|
3442
3460
|
}
|
|
@@ -3577,12 +3595,20 @@ export abstract class AgentRuntimeKernel<
|
|
|
3577
3595
|
* @remarks
|
|
3578
3596
|
* 新连接、HTTP 读取、Turn 完成投影和 RPC 调用方需要消息快照时调用。
|
|
3579
3597
|
*
|
|
3580
|
-
* 统一从 transcript
|
|
3598
|
+
* 统一从 transcript 生成完整视图;HTTP fallback、fork 和 RPC 读取保留 active assistant。
|
|
3581
3599
|
*/
|
|
3582
3600
|
async getMessages(): Promise<UIMessage[]> {
|
|
3583
3601
|
return this.transcript.browserMessages();
|
|
3584
3602
|
}
|
|
3585
3603
|
|
|
3604
|
+
private async hydrationMessages(): Promise<UIMessage[]> {
|
|
3605
|
+
const messages = await this.getMessages();
|
|
3606
|
+
const running = this.db.submissions.findRunning();
|
|
3607
|
+
return running?.assistantMessageId
|
|
3608
|
+
? messages.filter(({ id }) => id !== running.assistantMessageId)
|
|
3609
|
+
: messages;
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3586
3612
|
/** 读取当前 canonical transcript 中最后一条助手文本。 */
|
|
3587
3613
|
protected async latestAssistantText(): Promise<string | undefined> {
|
|
3588
3614
|
const message = [...await this.transcript.canonicalMessages()]
|
|
@@ -4620,6 +4646,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
4620
4646
|
...(current
|
|
4621
4647
|
? {
|
|
4622
4648
|
activeSubmissionId: current.submissionId,
|
|
4649
|
+
activeMessageId: current.assistantMessageId,
|
|
4623
4650
|
...(current.requestId
|
|
4624
4651
|
? { activeRequestId: current.requestId }
|
|
4625
4652
|
: {}),
|