@springbrand/agent-runtime 0.3.0-alpha.2 → 0.3.0-alpha.20
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 +11 -9
- package/src/adapter/cloudflare/agent.ts +177 -122
- package/src/adapter/cloudflare/define-agent.ts +47 -26
- package/src/adapter/cloudflare/index.ts +18 -0
- package/src/adapter/cloudflare/scheduling/schedule-rule.ts +322 -0
- package/src/adapter/cloudflare/scheduling/zoned-cron.ts +11 -6
- package/src/adapter/cloudflare/schema.ts +15 -0
- package/src/adapter/cloudflare/subagent/definition.ts +25 -13
- package/src/adapter/cloudflare/subagent/runner.ts +43 -50
- package/src/adapter/cloudflare/subagent/tools.ts +4 -4
- package/src/adapter/cloudflare/universal-agent/preparation.ts +3 -3
- package/src/adapter/cloudflare/universal-agent/tools.ts +4 -6
- package/src/adapter/cloudflare/workspace/version-control.ts +1 -1
- package/src/config/agent-context.ts +1 -1
- package/src/config/assembler.ts +48 -31
- package/src/config/assembly-snapshot.ts +1 -1
- package/src/config/definition.ts +1 -1
- package/src/config/harness-runtime.ts +51 -13
- package/src/config/model-guidance.ts +20 -0
- package/src/config/pinning.ts +39 -5
- package/src/config/ports.ts +57 -7
- package/src/config/public-contracts.ts +2 -2
- package/src/context/assembly.ts +1 -1
- package/src/context/extension/assembly.ts +2 -2
- package/src/context/memory/budget/gate.ts +19 -3
- package/src/conversation/harness-resume.ts +89 -238
- package/src/conversation/harness-stream.ts +87 -71
- package/src/conversation/history.ts +154 -152
- package/src/conversation/message/contract.ts +12 -0
- package/src/conversation/message/conversion.ts +3 -3
- package/src/conversation/message/projection.ts +61 -21
- package/src/conversation/session-entry.ts +29 -0
- package/src/conversation/state.ts +23 -2
- package/src/harness/governance.ts +206 -0
- package/src/harness/index.ts +3 -0
- package/src/harness/session-harness.ts +255 -446
- package/src/harness/submission-operation.ts +15 -40
- package/src/index.ts +18 -8
- package/src/lib/artifacts.ts +18 -0
- package/src/lib/execution-level.ts +13 -0
- package/src/lib/prompt.ts +9 -10
- package/src/lib/token-estimate.ts +8 -0
- package/src/model-protocol/openrouter.ts +41 -0
- package/src/models/index.ts +200 -35
- package/src/models/openrouter/messages.ts +13 -8
- package/src/models/openrouter/openai.ts +200 -0
- package/src/models/openrouter/protocol-response.ts +85 -0
- package/src/models/provider-streams.ts +45 -0
- package/src/session/cloudflare/migration.ts +382 -864
- package/src/session/cloudflare/storage.ts +13 -536
- package/src/session/index.ts +22 -35
- package/src/skills/springbrand-worker-website/index.ts +1 -1
- package/src/submission/admission.ts +12 -1
- package/src/submission/contracts.ts +42 -2
- package/src/submission/delivery.ts +1 -1
- package/src/submission/finalization.ts +36 -15
- package/src/submission/repository.ts +64 -25
- package/src/submission/steer-delivery.ts +32 -76
- package/src/submission/unattended.ts +40 -0
- package/src/telemetry/coordinator.ts +1 -1
- package/src/telemetry/subagent-lifecycle.ts +1 -1
- package/src/telemetry/turn-events.ts +35 -25
- package/src/tools/README.md +44 -0
- package/src/tools/{ai-adapter.ts → adapters/ai-to-pi.ts} +6 -9
- package/src/tools/{declared.ts → adapters/declared.ts} +6 -2
- package/src/tools/{nested-tools.ts → adapters/pi-to-ai.ts} +4 -4
- package/src/tools/assistant/ask-user.ts +317 -0
- package/src/tools/assistant/candidate.ts +15 -0
- package/src/tools/assistant/followups.ts +34 -0
- package/src/tools/assistant/index.ts +19 -0
- package/src/tools/assistant/memory.ts +73 -0
- package/src/tools/assistant/plan.ts +98 -0
- package/src/tools/{time.ts → assistant/time.ts} +1 -1
- package/src/tools/{core-host.ts → codemode/adapter.ts} +50 -53
- package/src/tools/{core.ts → codemode/index.ts} +36 -92
- package/src/tools/codemode/workspace-connector.ts +198 -0
- package/src/tools/extension/index.ts +42 -0
- package/src/tools/index.ts +29 -26
- package/src/tools/{gateway.ts → mcp/gateway.ts} +19 -19
- package/src/tools/{mcp.ts → mcp/index.ts} +5 -5
- package/src/tools/runtime/activation.ts +40 -0
- package/src/tools/{approval → runtime/approval}/repository.ts +13 -12
- package/src/tools/runtime/compiler.ts +246 -0
- package/src/tools/runtime/contracts.ts +140 -0
- package/src/tools/{decision-gate.ts → runtime/decision-gate.ts} +149 -39
- package/src/tools/{human-decisions.ts → runtime/human-decisions.ts} +4 -4
- package/src/tools/{interaction → runtime/interaction}/repository.ts +1 -7
- package/src/tools/runtime/result.ts +22 -0
- package/src/tools/runtime/unattended-error.ts +4 -0
- package/src/tools/sandbox/index.ts +228 -0
- package/src/tools/schedule/index.ts +301 -0
- package/src/tools/skill/contracts.ts +20 -0
- package/src/tools/skill/index.ts +99 -0
- package/src/tools/skill/resources.ts +322 -0
- package/src/tools/skill/scripts.ts +168 -0
- package/src/tools/{subagent-authority.ts → subagent/authority.ts} +31 -31
- package/src/tools/{subagent.ts → subagent/index.ts} +34 -37
- package/src/tools/{subagent-run-repository.ts → subagent/repository.ts} +1 -1
- package/src/tools/{subagent-runtime.ts → subagent/runtime.ts} +1 -1
- package/src/tools/{temporary-agent → subagent/temporary}/approvals.ts +4 -7
- package/src/tools/{temporary-agent → subagent/temporary}/core.ts +2 -3
- package/src/tools/{temporary-agent → subagent/temporary}/runner.ts +1 -1
- package/src/tools/{temporary-agent → subagent/temporary}/workspace.ts +1 -4
- package/src/tools/{web-fetch.ts → web/fetch.ts} +4 -13
- package/src/tools/web/index.ts +2 -0
- package/src/tools/web/search/api.ts +1322 -0
- package/src/tools/web/search/index.ts +2 -0
- package/src/tools/{web-search/web-search.ts → web/search/search.ts} +5 -7
- package/src/tools/{workspace-sandbox.ts → workspace/index.ts} +12 -272
- package/src/tools/{workspace-revision.ts → workspace/revision.ts} +3 -3
- package/src/tools/base.ts +0 -534
- package/src/tools/compiler.ts +0 -327
- package/src/tools/schedule.ts +0 -261
- package/src/tools/skill.ts +0 -565
- package/src/tools/web-search/api.ts +0 -1318
- package/src/tools/web-search/index.ts +0 -2
- package/src/tools/workspace-state-connector.ts +0 -146
- package/src/tools/{approval → runtime/approval}/index.ts +0 -0
- package/src/tools/{interaction → runtime/interaction}/index.ts +0 -0
- package/src/tools/{temporary-agent → subagent/temporary}/coordinator.ts +0 -0
- package/src/tools/{subagent-types → subagent/types}/contract.ts +0 -0
- package/src/tools/{subagent-types → subagent/types}/extract/index.ts +0 -0
- package/src/tools/{subagent-types → subagent/types}/fanout/index.ts +0 -0
- package/src/tools/{subagent-types → subagent/types}/registry.ts +1 -1
- /package/src/tools/{workspace-versioning.ts → workspace/versioning.ts} +0 -0
package/src/config/pinning.ts
CHANGED
|
@@ -157,6 +157,11 @@ export interface PreparedPiRuntime {
|
|
|
157
157
|
export interface PinPiRuntimeOptions {
|
|
158
158
|
readonly prepared: PreparedPiRuntime;
|
|
159
159
|
readonly baseRevision: string;
|
|
160
|
+
/**
|
|
161
|
+
* Whether this Submission may inherit automatic hot and cold Memory context.
|
|
162
|
+
* Scheduled task input is intentionally isolated from those sources.
|
|
163
|
+
*/
|
|
164
|
+
readonly includeMemory?: boolean;
|
|
160
165
|
/**
|
|
161
166
|
* 读取一个扩展要写入固定系统提示词的上下文。
|
|
162
167
|
*
|
|
@@ -249,9 +254,20 @@ function describeTools(candidates: readonly PiToolCandidate[]) {
|
|
|
249
254
|
description: candidate.tool.description ?? candidate.tool.label,
|
|
250
255
|
parameters: candidate.tool.parameters,
|
|
251
256
|
requiredExecutionLevel: candidate.requiredExecutionLevel,
|
|
257
|
+
...(candidate.confirmation ? { confirmation: true } : {}),
|
|
252
258
|
...(candidate.alwaysRequiresApproval
|
|
253
259
|
? { alwaysRequiresApproval: true }
|
|
254
260
|
: {}),
|
|
261
|
+
...(candidate.unattendedExecution
|
|
262
|
+
? {
|
|
263
|
+
unattendedExecution: {
|
|
264
|
+
capability: candidate.unattendedExecution.capability,
|
|
265
|
+
operation: candidate.unattendedExecution.operation,
|
|
266
|
+
objectConstrained:
|
|
267
|
+
candidate.unattendedExecution.objectForInput !== undefined,
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
: {}),
|
|
255
271
|
...(candidate.deferLoading ? { deferLoading: true } : {}),
|
|
256
272
|
...(candidate.source ? { source: candidate.source } : {}),
|
|
257
273
|
retry: piToolRetryPolicy(candidate),
|
|
@@ -267,10 +283,25 @@ function describeRuntime(
|
|
|
267
283
|
candidates: readonly PiToolCandidate[],
|
|
268
284
|
loadedExtensions: readonly PiLoadedExtension[],
|
|
269
285
|
): string {
|
|
286
|
+
const model = snapshot.pi.model;
|
|
287
|
+
const openRouterRouting = model.compat && "openRouterRouting" in model.compat
|
|
288
|
+
? model.compat.openRouterRouting
|
|
289
|
+
: undefined;
|
|
270
290
|
return JSON.stringify({
|
|
271
291
|
version: 1,
|
|
272
|
-
model:
|
|
273
|
-
provider:
|
|
292
|
+
model: model.id,
|
|
293
|
+
provider: model.provider,
|
|
294
|
+
modelConfig: {
|
|
295
|
+
api: model.api,
|
|
296
|
+
name: model.name,
|
|
297
|
+
reasoning: model.reasoning,
|
|
298
|
+
input: model.input,
|
|
299
|
+
contextWindow: model.contextWindow,
|
|
300
|
+
maxTokens: model.maxTokens,
|
|
301
|
+
cost: model.cost,
|
|
302
|
+
...(model.thinkingLevelMap ? { thinkingLevelMap: model.thinkingLevelMap } : {}),
|
|
303
|
+
...(openRouterRouting ? { openRouterRouting } : {}),
|
|
304
|
+
},
|
|
274
305
|
thinking: snapshot.pi.thinkingLevel,
|
|
275
306
|
systemPrompt: snapshot.pi.systemPrompt,
|
|
276
307
|
executionLevel: snapshot.profile.executionLevel,
|
|
@@ -481,11 +512,14 @@ export async function pinPiRuntime(
|
|
|
481
512
|
): Promise<PinnedPiRuntime> {
|
|
482
513
|
const state = readPreparedPiRuntime(options.prepared, owner);
|
|
483
514
|
const { snapshot, assembly } = state;
|
|
515
|
+
const includeMemory = options.includeMemory !== false;
|
|
484
516
|
const context = await assemblePiSystemContext({
|
|
485
517
|
baseSystemPrompt: snapshot.pi.systemPrompt,
|
|
486
|
-
memory:
|
|
487
|
-
|
|
488
|
-
|
|
518
|
+
memory: includeMemory
|
|
519
|
+
? snapshot.profile.memory
|
|
520
|
+
: { ...snapshot.profile.memory, enabled: false },
|
|
521
|
+
memoryPort: includeMemory ? snapshot.bindings.memory : undefined,
|
|
522
|
+
workspace: includeMemory ? snapshot.bindings.workspace : undefined,
|
|
489
523
|
skills: snapshot.bindings.skills.sources,
|
|
490
524
|
extensionContexts: assembly.context,
|
|
491
525
|
readExtensionContext: options.readExtensionContext,
|
package/src/config/ports.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
export type { RuntimeSchedulePreparation } from "../submission/contracts";
|
|
1
2
|
import type { RuntimeModelInputModality } from "./profile";
|
|
2
3
|
import type { SkillSource } from "agents/skills";
|
|
3
|
-
import type { ScheduleSpec } from "../submission/contracts";
|
|
4
|
+
import type { ScheduleSpec, RuntimeSchedulePreparation } from "../submission/contracts";
|
|
4
5
|
import type { RuntimeActivityProjection } from "../conversation/state";
|
|
5
6
|
import type { ExecutionLevel } from "../lib/execution-level";
|
|
6
7
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
7
|
-
import type { PiToolCandidate } from "../tools/
|
|
8
|
+
import type { PiToolCandidate } from "../tools/runtime/contracts";
|
|
8
9
|
import type {
|
|
9
10
|
RuntimeEventConfirmation,
|
|
10
11
|
RuntimeLifecycleFact,
|
|
11
12
|
RuntimeSubagentUsageEvent,
|
|
12
13
|
RuntimeSubagentUsageMetrics,
|
|
13
|
-
} from "../tools/subagent
|
|
14
|
+
} from "../tools/subagent/authority";
|
|
14
15
|
export type { RuntimeModelInputModality } from "./profile";
|
|
15
16
|
export type {
|
|
16
17
|
RuntimeEventConfirmation,
|
|
@@ -21,7 +22,7 @@ export type {
|
|
|
21
22
|
RuntimeSubmissionAdmissionHook,
|
|
22
23
|
RuntimeSubmissionAdmissionInput,
|
|
23
24
|
RuntimeSubmissionAdmissionResult,
|
|
24
|
-
} from "../tools/subagent
|
|
25
|
+
} from "../tools/subagent/authority";
|
|
25
26
|
|
|
26
27
|
// #region Workspace 端口
|
|
27
28
|
|
|
@@ -669,16 +670,25 @@ export interface RuntimeScheduleAgentSummary {
|
|
|
669
670
|
* 让 Runtime 通过 Host 管理当前用户的定时任务。
|
|
670
671
|
*
|
|
671
672
|
* @remarks
|
|
672
|
-
*
|
|
673
|
+
* Host 提供准备与提交操作;Runtime 在现有持久化审批中固定候选并等待用户确认。
|
|
673
674
|
*
|
|
674
|
-
*
|
|
675
|
+
* 任务事实、候选版本、授权检查和保存幂等由 Host 持有,不存放凭据。
|
|
675
676
|
*/
|
|
677
|
+
export interface RuntimeScheduleConfirmationPort {
|
|
678
|
+
/** Read-only preparation; bind the full candidate and authorization to this stable intent. */
|
|
679
|
+
prepare(request: RuntimeScheduleUpdate & { intentId: string; id?: string }): Promise<RuntimeSchedulePreparation>;
|
|
680
|
+
/** Atomically check candidate/version, live authorization and quotas. Replay must return the same task. */
|
|
681
|
+
commit(prepared: RuntimeSchedulePreparation, context: { intentId: string; signal: AbortSignal }): Promise<{ id: string }>;
|
|
682
|
+
}
|
|
683
|
+
|
|
676
684
|
export interface RuntimeSchedulePort {
|
|
685
|
+
/** Required for chat creation/editing. Legacy management callers retain their CRUD contract. */
|
|
686
|
+
confirmation?: RuntimeScheduleConfirmationPort;
|
|
677
687
|
/**
|
|
678
688
|
* 创建一条定时任务并返回它的 ID。
|
|
679
689
|
*
|
|
680
690
|
* @remarks
|
|
681
|
-
* `schedule`
|
|
691
|
+
* 保留给既有宿主管理调用者;聊天 `schedule` 只经 confirmation.commit 保存。
|
|
682
692
|
*
|
|
683
693
|
* Host 在该边界内绑定用户与会话,Runtime 不携带业务归属 ID。
|
|
684
694
|
*/
|
|
@@ -940,6 +950,8 @@ export interface RuntimeBrowserPort {
|
|
|
940
950
|
export type RuntimeModelProtocol =
|
|
941
951
|
| "openai-chat"
|
|
942
952
|
| "openrouter-messages"
|
|
953
|
+
| "openrouter-chat"
|
|
954
|
+
| "openrouter-responses"
|
|
943
955
|
| "anthropic-messages"
|
|
944
956
|
| "google-generative-ai"
|
|
945
957
|
| "openai-codex-responses";
|
|
@@ -953,6 +965,31 @@ export type RuntimeModelProtocol =
|
|
|
953
965
|
*
|
|
954
966
|
* 凭据只留在 Port 对象,不进入 `RuntimeProfile` 或持久状态;术语见 `../index.ts`。
|
|
955
967
|
*/
|
|
968
|
+
export type RuntimeModelThinkingLevel =
|
|
969
|
+
| "off"
|
|
970
|
+
| "minimal"
|
|
971
|
+
| "low"
|
|
972
|
+
| "medium"
|
|
973
|
+
| "high"
|
|
974
|
+
| "xhigh"
|
|
975
|
+
| "max";
|
|
976
|
+
|
|
977
|
+
export interface RuntimeModelMetadata {
|
|
978
|
+
readonly name: string;
|
|
979
|
+
readonly reasoning: boolean;
|
|
980
|
+
readonly contextWindow: number;
|
|
981
|
+
readonly maxTokens: number;
|
|
982
|
+
readonly cost: Readonly<{
|
|
983
|
+
input: number;
|
|
984
|
+
output: number;
|
|
985
|
+
cacheRead: number;
|
|
986
|
+
cacheWrite: number;
|
|
987
|
+
}>;
|
|
988
|
+
readonly thinkingLevelMap?: Readonly<
|
|
989
|
+
Partial<Record<RuntimeModelThinkingLevel, string | null>>
|
|
990
|
+
>;
|
|
991
|
+
}
|
|
992
|
+
|
|
956
993
|
export interface RuntimeModelEndpoint {
|
|
957
994
|
protocol: RuntimeModelProtocol;
|
|
958
995
|
/** Resolved credential; never enters RuntimeProfile or persisted state. */
|
|
@@ -967,6 +1004,9 @@ export interface RuntimeModelEndpoint {
|
|
|
967
1004
|
>;
|
|
968
1005
|
/** OpenRouter upstream provider pins keyed by model ID; pinned requests never fall back. */
|
|
969
1006
|
openRouterProviderPins?: Readonly<Record<string, string>>;
|
|
1007
|
+
/** OpenRouter provider ordering; omitted keeps OpenRouter's default routing. */
|
|
1008
|
+
openRouterProviderSort?: "price" | "throughput" | "latency";
|
|
1009
|
+
modelMetadata?: Readonly<Record<string, RuntimeModelMetadata>>;
|
|
970
1010
|
}
|
|
971
1011
|
|
|
972
1012
|
/**
|
|
@@ -1020,6 +1060,16 @@ export interface RuntimePlatformPort {
|
|
|
1020
1060
|
requiredExecutionLevel: ExecutionLevel;
|
|
1021
1061
|
signal: AbortSignal;
|
|
1022
1062
|
}): Promise<void>;
|
|
1063
|
+
/**
|
|
1064
|
+
* Match a pinned scheduled-task grant against the concrete Tool operation
|
|
1065
|
+
* and recheck the Host-owned live account authorization.
|
|
1066
|
+
*
|
|
1067
|
+
* This callback must fail closed by throwing a user-safe, specific reason.
|
|
1068
|
+
* It is called before dispatch and again at the effect boundary so a grant
|
|
1069
|
+
* revocation cannot be hidden by an earlier decision.
|
|
1070
|
+
*/
|
|
1071
|
+
/** @deprecated Scheduled execution is authorized locally by execution level. */
|
|
1072
|
+
authorizeUnattendedExecution?(request: unknown): Promise<void>;
|
|
1023
1073
|
}
|
|
1024
1074
|
|
|
1025
1075
|
/**
|
|
@@ -17,7 +17,7 @@ export * from "../conversation/message";
|
|
|
17
17
|
export * from "../submission/contracts";
|
|
18
18
|
export * from "../conversation/state";
|
|
19
19
|
export * from "../lib/execution-level";
|
|
20
|
-
export type { WorkspaceRevision, WorkspaceRevisionManifest } from "../tools/workspace
|
|
20
|
+
export type { WorkspaceRevision, WorkspaceRevisionManifest } from "../tools/workspace/versioning";
|
|
21
21
|
export type {
|
|
22
22
|
RuntimeEventConfirmation,
|
|
23
23
|
RuntimeLifecycleFact,
|
|
@@ -27,4 +27,4 @@ export type {
|
|
|
27
27
|
RuntimeSubmissionAdmissionHook,
|
|
28
28
|
RuntimeSubmissionAdmissionInput,
|
|
29
29
|
RuntimeSubmissionAdmissionResult,
|
|
30
|
-
} from "../tools/subagent
|
|
30
|
+
} from "../tools/subagent/authority";
|
package/src/context/assembly.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { estimateStringTokens } from "
|
|
1
|
+
import { estimateStringTokens } from "../lib/token-estimate";
|
|
2
2
|
import type { RuntimeMemoryPort } from "../config/ports";
|
|
3
3
|
import type { RuntimeDegradation } from "../config/degradation";
|
|
4
4
|
import type { RuntimeMemoryProfile } from "../config/profile";
|
|
@@ -12,8 +12,8 @@ import type {
|
|
|
12
12
|
import type { RuntimeDegradation } from "../../config/degradation";
|
|
13
13
|
import { withRuntimeLoadTimeout } from "../../config/runtime-load";
|
|
14
14
|
import { sanitizeExtensionName } from "../../lib/extension-name";
|
|
15
|
-
import type { PiToolCandidate } from "../../tools/
|
|
16
|
-
import { createPiDeclaredToolCandidate } from "../../tools/declared";
|
|
15
|
+
import type { PiToolCandidate } from "../../tools/runtime/contracts";
|
|
16
|
+
import { createPiDeclaredToolCandidate } from "../../tools/adapters/declared";
|
|
17
17
|
|
|
18
18
|
export interface PiExtensionContextContribution {
|
|
19
19
|
readonly extensionName: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
artifactId,
|
|
2
3
|
type ArtifactRef,
|
|
3
4
|
serializeOutput,
|
|
4
5
|
sha256Hex,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
/**
|
|
30
31
|
* 持久化单个字符串叶子的上限。
|
|
31
32
|
*
|
|
32
|
-
* MUST ≥ 单页 read 的上限(见 `workspace
|
|
33
|
+
* MUST ≥ 单页 read 的上限(见 `tools/workspace/index.ts` 的 `READ_PAGE_MAX_CHARS`),
|
|
33
34
|
* 否则持久记录会比模型当轮看到的内容还少,会话恢复后出现凭空缺页。
|
|
34
35
|
*/
|
|
35
36
|
export const STORAGE_LEAF_MAX_CHARS = 64 * 1024;
|
|
@@ -161,11 +162,26 @@ export async function spillDurableToolOutput(
|
|
|
161
162
|
text,
|
|
162
163
|
ext === "json" ? "application/json" : "text/plain",
|
|
163
164
|
);
|
|
165
|
+
if (!options.workspace.stat || !options.workspace.readFileBytes) {
|
|
166
|
+
throw new Error("Workspace artifact verification is unavailable");
|
|
167
|
+
}
|
|
168
|
+
const stat = await options.workspace.stat(path);
|
|
169
|
+
const expectedBytes = new TextEncoder().encode(text).byteLength;
|
|
170
|
+
if (!stat || stat.type !== "file" || stat.size !== expectedBytes) {
|
|
171
|
+
throw new Error("Workspace artifact failed size verification");
|
|
172
|
+
}
|
|
173
|
+
const stored = await options.workspace.readFileBytes(path);
|
|
174
|
+
if (!stored || new TextDecoder().decode(stored) !== text) {
|
|
175
|
+
throw new Error("Workspace artifact failed content verification");
|
|
176
|
+
}
|
|
164
177
|
return {
|
|
165
178
|
kind: "artifact_ref",
|
|
179
|
+
artifactId: artifactId(hash),
|
|
166
180
|
path,
|
|
167
|
-
bytes:
|
|
168
|
-
hash
|
|
181
|
+
bytes: expectedBytes,
|
|
182
|
+
hash,
|
|
183
|
+
workspaceRevision: stat.contentVersion ?? `${stat.updatedAt}:${stat.size}`,
|
|
184
|
+
availability: "available",
|
|
169
185
|
preview: text.slice(0, PREVIEW_CHARS),
|
|
170
186
|
// 出口指令必须是可执行的:只说“去 read 这个路径”会诱导模型整读,而整读一个
|
|
171
187
|
// 刚刚因为过大被外置的文件毫无意义。这里明确要求分页,并告知 read 会返回
|