@springbrand/agent-runtime 0.2.0-alpha.43 → 0.2.0-alpha.45
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 +1 -1
- package/src/adapter/cloudflare/subagent/definition.ts +0 -3
- package/src/adapter/cloudflare/subagent/runner.ts +19 -6
- package/src/db/schema.ts +6 -1
- package/src/db/submission.repo.ts +13 -1
- package/src/index.ts +0 -1
- package/src/kernel/submission-lifecycle.ts +25 -8
- package/src/pi/assembly/context.ts +23 -10
- package/src/pi/assembly/snapshot.ts +14 -8
- package/src/pi/message/projection.ts +47 -21
- package/src/pi/runtime-adapter/assembly.ts +2 -30
- package/src/pi/runtime-adapter/execution.ts +56 -46
- package/src/pi/runtime-adapter/index.ts +2 -8
- package/src/pi/runtime-adapter/models.ts +63 -26
- package/src/pi/runtime-adapter/transcript.ts +6 -3
- package/src/pi/tool/base.ts +10 -15
- package/src/pi/tool/compiler.ts +1 -1
- package/src/pi/tool/core.ts +2 -0
- package/src/pi/tool/schedule.ts +15 -11
- package/src/pi/tool/skill.ts +3 -0
- package/src/pi/tool/subagent.ts +2 -0
- package/src/pi/tool/time.ts +1 -0
- package/src/pi/tool/web-search/api.ts +8 -0
- package/src/pi/tool/web-search/web-search.ts +1 -0
- package/src/pi/tool/workspace-sandbox.ts +3 -0
- package/src/runtime-agent.ts +9 -0
- package/src/runtime-assembler.ts +17 -11
- package/src/runtime.ts +103 -20
package/src/runtime.ts
CHANGED
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
} from "./telemetry";
|
|
67
67
|
import { connectConfiguredMcpServers } from "./lib/mcp";
|
|
68
68
|
import {
|
|
69
|
+
ContextOverflowError,
|
|
69
70
|
PiRuntimeAdapter,
|
|
70
71
|
MODEL_STREAM_STALL_TIMEOUT_MS,
|
|
71
72
|
readModelStreamStallDetails,
|
|
@@ -109,6 +110,7 @@ import {
|
|
|
109
110
|
isTerminalSubmissionStatus,
|
|
110
111
|
RuntimeDatabase,
|
|
111
112
|
type StoredSubmissionAdmission,
|
|
113
|
+
type SubmissionRecoveryReason,
|
|
112
114
|
type SubmissionStatus,
|
|
113
115
|
} from "./db/index";
|
|
114
116
|
import {
|
|
@@ -150,6 +152,8 @@ export const CHAT_RECOVERY_MAX_ATTEMPTS = 5;
|
|
|
150
152
|
export const CHAT_STALL_MAX_ATTEMPTS = 3;
|
|
151
153
|
const CHAT_RECOVERY_TERMINAL_MESSAGE =
|
|
152
154
|
"Recovery failed after multiple attempts. This generation has stopped and your progress has been saved. Send a new message to continue.";
|
|
155
|
+
const CONTEXT_OVERFLOW_TERMINAL_MESSAGE =
|
|
156
|
+
"The model context is still too large after forced compaction. Start a new conversation or reduce the attached context.";
|
|
153
157
|
|
|
154
158
|
type RuntimeEventOutboxPayload =
|
|
155
159
|
| { readonly type: "model-usage"; readonly event: RuntimeModelUsageEvent }
|
|
@@ -172,7 +176,10 @@ interface StoredSubmission extends SubmissionReceipt {
|
|
|
172
176
|
userMessageId?: string | null;
|
|
173
177
|
regenerateMessageId?: string | null;
|
|
174
178
|
recoveryErrorCount: number;
|
|
175
|
-
recoveryReason?:
|
|
179
|
+
recoveryReason?:
|
|
180
|
+
| "no_meaningful_model_progress"
|
|
181
|
+
| "transient_model_error"
|
|
182
|
+
| "context_overflow";
|
|
176
183
|
runId: string | null;
|
|
177
184
|
accountId: string | null;
|
|
178
185
|
rateVersion: number | null;
|
|
@@ -532,6 +539,8 @@ export abstract class AgentRuntimeKernel<
|
|
|
532
539
|
this.db.submissions.findRunning() as StoredSubmission | null,
|
|
533
540
|
findNextPending: () =>
|
|
534
541
|
this.db.submissions.findNextPending() as StoredSubmission | null,
|
|
542
|
+
listPending: () =>
|
|
543
|
+
this.db.submissions.listPending() as StoredSubmission[],
|
|
535
544
|
updateAbortReason: (submissionId, reason) =>
|
|
536
545
|
this.db.submissions.updateAbortReason(submissionId, reason),
|
|
537
546
|
};
|
|
@@ -999,6 +1008,26 @@ export abstract class AgentRuntimeKernel<
|
|
|
999
1008
|
});
|
|
1000
1009
|
this.projectNestedToolSettlement(submission.submissionId, event);
|
|
1001
1010
|
},
|
|
1011
|
+
onUnknownToolStarted: (event) => {
|
|
1012
|
+
this.telemetry.capture("toolStarted", {
|
|
1013
|
+
submissionId: submission.submissionId,
|
|
1014
|
+
toolCallId: event.toolCallId,
|
|
1015
|
+
toolName: event.toolName,
|
|
1016
|
+
input: event.input,
|
|
1017
|
+
occurredAt: event.occurredAt,
|
|
1018
|
+
});
|
|
1019
|
+
},
|
|
1020
|
+
onUnknownToolFinished: (event) => {
|
|
1021
|
+
this.telemetry.capture("toolFinished", {
|
|
1022
|
+
submissionId: submission.submissionId,
|
|
1023
|
+
toolCallId: event.toolCallId,
|
|
1024
|
+
toolName: event.toolName,
|
|
1025
|
+
outcome: event.outcome,
|
|
1026
|
+
output: event.output,
|
|
1027
|
+
outputBytes: json(event.output).length,
|
|
1028
|
+
occurredAt: event.occurredAt,
|
|
1029
|
+
});
|
|
1030
|
+
},
|
|
1002
1031
|
...(toolExecutors && Object.keys(toolExecutors).length > 0
|
|
1003
1032
|
? { toolExecutors }
|
|
1004
1033
|
: {}),
|
|
@@ -1662,7 +1691,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
1662
1691
|
|
|
1663
1692
|
// 作用:按当前模型输入预算压缩 Pi 上下文。
|
|
1664
1693
|
// 调用:Pi Turn 适配器在发模型请求前通过 `transformContext` 回调。
|
|
1665
|
-
// 原因:模型窗口必须预留最大输出,压缩也必须使用本 Snapshot
|
|
1694
|
+
// 原因:模型窗口必须预留最大输出,压缩也必须使用本 Snapshot 的模型。
|
|
1666
1695
|
private async transformPiContext(
|
|
1667
1696
|
submissionId: string,
|
|
1668
1697
|
messages: Parameters<PiRuntimeTranscript["compactContext"]>[0],
|
|
@@ -1671,13 +1700,12 @@ export abstract class AgentRuntimeKernel<
|
|
|
1671
1700
|
const snapshot = this.assembly();
|
|
1672
1701
|
const inputBudget = snapshot.pi.model.contextWindow -
|
|
1673
1702
|
snapshot.pi.model.maxTokens;
|
|
1703
|
+
const force = this.readSubmission(submissionId)?.recoveryReason ===
|
|
1704
|
+
"context_overflow";
|
|
1674
1705
|
const compacted = await this.transcript.compactContext(messages, {
|
|
1675
1706
|
compactAfterTokens: inputBudget * 0.85,
|
|
1707
|
+
force,
|
|
1676
1708
|
model: snapshot.pi.model,
|
|
1677
|
-
apiKey: this.pi.resolveApiKey(
|
|
1678
|
-
snapshot.bindings.provider,
|
|
1679
|
-
snapshot.pi.model.id,
|
|
1680
|
-
),
|
|
1681
1709
|
signal,
|
|
1682
1710
|
submissionId,
|
|
1683
1711
|
onCompactionPersisted: (event) => {
|
|
@@ -1710,6 +1738,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
1710
1738
|
});
|
|
1711
1739
|
},
|
|
1712
1740
|
});
|
|
1741
|
+
if (force) this.db.submissions.clearRecoveryReason(submissionId);
|
|
1713
1742
|
await this.drainRuntimeEvents();
|
|
1714
1743
|
return compacted;
|
|
1715
1744
|
}
|
|
@@ -2840,7 +2869,9 @@ export abstract class AgentRuntimeKernel<
|
|
|
2840
2869
|
reason: submission.recoveryReason ?? "runtime_restart",
|
|
2841
2870
|
attempt: Math.max(1, submission.recoveryErrorCount),
|
|
2842
2871
|
});
|
|
2843
|
-
|
|
2872
|
+
if (submission.recoveryReason !== "context_overflow") {
|
|
2873
|
+
this.db.submissions.clearRecoveryReason(submissionId);
|
|
2874
|
+
}
|
|
2844
2875
|
await this.broadcastApprovals();
|
|
2845
2876
|
}
|
|
2846
2877
|
if (mode !== "fresh") await this.ensureRuntimeReady();
|
|
@@ -3135,15 +3166,25 @@ export abstract class AgentRuntimeKernel<
|
|
|
3135
3166
|
return this.readSubmission(submissionId)!;
|
|
3136
3167
|
}
|
|
3137
3168
|
const stalled = error instanceof ChatStreamStalledError;
|
|
3169
|
+
const contextOverflow = error instanceof ContextOverflowError;
|
|
3138
3170
|
const abortReason = this.readSubmission(submissionId)?.abortReason;
|
|
3139
3171
|
if (!abortReason && (stalled || error instanceof RetryableModelError)) {
|
|
3140
|
-
const
|
|
3141
|
-
|
|
3172
|
+
const recoveryReason: SubmissionRecoveryReason = stalled
|
|
3173
|
+
? "no_meaningful_model_progress"
|
|
3174
|
+
: contextOverflow
|
|
3175
|
+
? "context_overflow"
|
|
3176
|
+
: "transient_model_error";
|
|
3177
|
+
let contextOverflowRecoveryClaimed = false;
|
|
3178
|
+
const recoveryErrorCount = this.db.transaction(() => {
|
|
3179
|
+
if (contextOverflow) {
|
|
3180
|
+
contextOverflowRecoveryClaimed = this.db.submissions
|
|
3181
|
+
.claimContextOverflowRecovery(submissionId);
|
|
3182
|
+
}
|
|
3183
|
+
return this.db.submissions.incrementRecoveryErrorCount(
|
|
3142
3184
|
submissionId,
|
|
3143
|
-
|
|
3144
|
-
? "no_meaningful_model_progress"
|
|
3145
|
-
: "transient_model_error",
|
|
3185
|
+
recoveryReason,
|
|
3146
3186
|
);
|
|
3187
|
+
});
|
|
3147
3188
|
if (stalled) {
|
|
3148
3189
|
const stallDetails = readModelStreamStallDetails(errorText(error)) ?? {
|
|
3149
3190
|
lastMeaningfulActivityAt:
|
|
@@ -3163,10 +3204,14 @@ export abstract class AgentRuntimeKernel<
|
|
|
3163
3204
|
await this.broadcastApprovals();
|
|
3164
3205
|
const stoppedDuringRecovery = this.readSubmission(submissionId)
|
|
3165
3206
|
?.abortReason;
|
|
3207
|
+
const retryAllowed = contextOverflow
|
|
3208
|
+
? contextOverflowRecoveryClaimed &&
|
|
3209
|
+
recoveryErrorCount < CHAT_RECOVERY_MAX_ATTEMPTS
|
|
3210
|
+
: recoveryErrorCount <
|
|
3211
|
+
(stalled ? CHAT_STALL_MAX_ATTEMPTS : CHAT_RECOVERY_MAX_ATTEMPTS);
|
|
3166
3212
|
if (
|
|
3167
3213
|
!stoppedDuringRecovery &&
|
|
3168
|
-
|
|
3169
|
-
(stalled ? CHAT_STALL_MAX_ATTEMPTS : CHAT_RECOVERY_MAX_ATTEMPTS)
|
|
3214
|
+
retryAllowed
|
|
3170
3215
|
) {
|
|
3171
3216
|
const recoveryOutcome = await this.scheduleChatRecoveryRetry(
|
|
3172
3217
|
{
|
|
@@ -3207,7 +3252,9 @@ export abstract class AgentRuntimeKernel<
|
|
|
3207
3252
|
} else if (!stoppedDuringRecovery) {
|
|
3208
3253
|
terminalIntent = {
|
|
3209
3254
|
outcome: "failed",
|
|
3210
|
-
message:
|
|
3255
|
+
message: contextOverflow
|
|
3256
|
+
? CONTEXT_OVERFLOW_TERMINAL_MESSAGE
|
|
3257
|
+
: CHAT_RECOVERY_TERMINAL_MESSAGE,
|
|
3211
3258
|
};
|
|
3212
3259
|
}
|
|
3213
3260
|
}
|
|
@@ -4105,6 +4152,35 @@ export abstract class AgentRuntimeKernel<
|
|
|
4105
4152
|
return result;
|
|
4106
4153
|
}
|
|
4107
4154
|
|
|
4155
|
+
/** Stops every running, queued, or steered user request in this Session. */
|
|
4156
|
+
async stopAllSubmissions(reason?: string): Promise<{ ok: boolean }> {
|
|
4157
|
+
const current = this.db.submissions.findRunning() ??
|
|
4158
|
+
this.db.submissions.findNextPending();
|
|
4159
|
+
if (current) {
|
|
4160
|
+
this.db.transaction(() => {
|
|
4161
|
+
for (const steer of this.db.steers.listForSubmission(
|
|
4162
|
+
current.submissionId,
|
|
4163
|
+
)) {
|
|
4164
|
+
const message = JSON.parse(
|
|
4165
|
+
steer.canonicalJson,
|
|
4166
|
+
) as PiCanonicalUserInput;
|
|
4167
|
+
const userMessage = steer.uiMessageJson
|
|
4168
|
+
? JSON.parse(steer.uiMessageJson) as UIMessage & { role: "user" }
|
|
4169
|
+
: undefined;
|
|
4170
|
+
this.transcript.append(steer.messageId, message, {
|
|
4171
|
+
submissionId: current.submissionId,
|
|
4172
|
+
createdAt: steer.createdAt,
|
|
4173
|
+
...(userMessage ? { userMessage } : {}),
|
|
4174
|
+
});
|
|
4175
|
+
this.db.steers.deleteByMessageId(steer.messageId);
|
|
4176
|
+
}
|
|
4177
|
+
});
|
|
4178
|
+
}
|
|
4179
|
+
const result = await this.submissions.stopAll(reason ?? "Stopped");
|
|
4180
|
+
await this.broadcastApprovals();
|
|
4181
|
+
return result;
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4108
4184
|
/** 返回当前已装配 User Agent 的执行档位,不提供 Session 覆盖。 */
|
|
4109
4185
|
executionLevel(): ExecutionLevel {
|
|
4110
4186
|
return this.assembly().profile.executionLevel;
|
|
@@ -4553,13 +4629,20 @@ export abstract class AgentRuntimeKernel<
|
|
|
4553
4629
|
...(current.recoveryErrorCount === undefined
|
|
4554
4630
|
? {}
|
|
4555
4631
|
: {
|
|
4556
|
-
recoveryAttempt:
|
|
4632
|
+
recoveryAttempt:
|
|
4633
|
+
current.recoveryReason === "context_overflow"
|
|
4634
|
+
? 1
|
|
4635
|
+
: current.recoveryErrorCount,
|
|
4557
4636
|
// 上限按当前恢复原因取,否则 stall 会显示 "2/5" 却在第 3 次就终止。
|
|
4558
4637
|
recoveryMax:
|
|
4559
|
-
current.recoveryReason === "
|
|
4560
|
-
?
|
|
4561
|
-
:
|
|
4562
|
-
|
|
4638
|
+
current.recoveryReason === "context_overflow"
|
|
4639
|
+
? 1
|
|
4640
|
+
: current.recoveryReason ===
|
|
4641
|
+
"no_meaningful_model_progress"
|
|
4642
|
+
? CHAT_STALL_MAX_ATTEMPTS
|
|
4643
|
+
: CHAT_RECOVERY_MAX_ATTEMPTS,
|
|
4644
|
+
...(current.recoveryReason &&
|
|
4645
|
+
current.recoveryReason !== "context_overflow"
|
|
4563
4646
|
? { recoveryReason: current.recoveryReason }
|
|
4564
4647
|
: {}),
|
|
4565
4648
|
}),
|