@epoch-agent/core 2.8.0 → 3.0.0
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 +108 -5
- package/dist/index.d.ts +909 -163
- package/dist/index.js +1630 -625
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ToolProvider, EpochTool, EpochPlugin, ToolExposure, EpochSkill, HookType, EpochHook, PluginContext, QuestionRequest, QuestionAnswer, ComplianceCategory, ComplianceAction, ToolArtifactInput, ToolArtifact, TrustLevel, TrustManager as TrustManager$1, TokenUsage, EpochConfig, BudgetBreach, NoticeCode, ProviderType, EpochMessage, JsonSchema, ModelSelection, BackgroundTaskInfo, EpochToolCall, Telemetry, HookManager as HookManager$1, Lang, PermissionManager as PermissionManager$1, ApprovalRequest, ApprovalReply, AgentRoleScope, AgentRoleSource, EpochUserContent, EpochContentPart, AgentRole, PermissionLevel, PlanProposal, ScheduleRunnerSpec, ScheduleBackendKind, ScheduleTrigger, OperationType, ScheduleAllowlist, ScheduleDefinition, ScheduleRunStatus, ScheduleRun, SchedulePendingApproval, DiagnosticSink, CustomCommandDef, ModelRef, ExpandedCommand, CustomCommandSource, ContextBreakdown, WireMcpConnector,
|
|
2
|
-
export { API_KEY_ENV_VARS, AgentEvent, AgentEventOf, AgentEventType, ApprovalAnswer, ApprovalOutcome, ApprovalReply, ApprovalRequest, ApprovalScope, BudgetBreach, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, ComplianceAction, ComplianceCategory, DecidedTrustLevel, EpochConfig, EpochHook, EpochPlugin, EpochSkill, EpochTool, FinishReason, HookContext, HookEvent, HookHandler, HookRegistration, HookType, HookManager as IHookManager, PermissionManager as IPermissionManager, TrustManager as ITrustManager, JsonSchema, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, Operation, OperationType, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, PermissionDecision, PermissionLevel, PlanApprovalOutcome, PlanProposal, PluginContext, ProviderInfo, ProviderType, TokenUsage, ToolContext, ToolDefinition, ToolExposure, ToolResult, TrustExecGrant, TrustGrant, TrustLevel, TrustRecord, TrustScope, TrustTier, VerifyResult, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
|
|
3
|
-
import { IsolationBackend, SqliteDatabase, ParseIssue, ShellFlavor } from '@epoch-agent/infra';
|
|
1
|
+
import { ToolProvider, EpochTool, EpochPlugin, ToolExposure, EpochSkill, HookType, EpochHook, PluginContext, QuestionRequest, QuestionAnswer, ComplianceCategory, ComplianceAction, ToolArtifactInput, ToolArtifact, TrustLevel, TrustManager as TrustManager$1, TokenUsage, EpochConfig, BudgetBreach, NoticeCode, ProviderType, EpochMessage, JsonSchema, ModelSelection, BackgroundTaskInfo, EpochToolCall, Telemetry, HookManager as HookManager$1, Lang, PermissionManager as PermissionManager$1, ApprovalRequest, ApprovalReply, AgentRoleScope, AgentRoleSource, EpochUserContent, EpochContentPart, AgentEvent, AgentRole, PermissionLevel, PlanProposal, ScheduleRunnerSpec, ScheduleBackendKind, ScheduleTrigger, OperationType, ScheduleAllowlist, ScheduleDefinition, ScheduleRunStatus, ScheduleRun, SchedulePendingApproval, DiagnosticSink, CustomCommandDef, ModelRef, ExpandedCommand, CustomCommandSource, ContextBreakdown, WireMcpConnector, SelectionContext, SetSelectionResult, ModelEntry, ReasoningState, ReasoningChoice, PermissionRuleLists, MoneyDigits, CurrencyDisplay, KeybindingTable, Diagnostic, KeybindingReport, FileOmitReason, SessionOmitReason, EpochToolResult, EpochUserCommand, EpochTurnFacts, LocalizedDetail, ApprovalScope, RuleValue, Operation, ApprovalOutcome, PermissionDecision, ScheduleDraft, ScheduleWideningKind, WireAgentEvent, WireAgentEnvelope, HookEvent, LogFn, HookRegistration, HookHandler, HookContext, VerifyResult, EpochFilePart, EpochSessionPart, MentionSet, EpochImagePart, TrustExecGrant, DecidedTrustLevel, TrustScope, TrustGrant, TrustRecord } from '@epoch-agent/protocol';
|
|
2
|
+
export { API_KEY_ENV_VARS, AgentEvent, AgentEventOf, AgentEventType, ApprovalAnswer, ApprovalOutcome, ApprovalReply, ApprovalRequest, ApprovalScope, BudgetBreach, COMPLIANCE_ACTIONS, COMPLIANCE_CATEGORIES, ComplianceAction, ComplianceCategory, DecidedTrustLevel, EpochConfig, EpochHook, EpochPlugin, EpochSkill, EpochTool, FinishReason, HookContext, HookEvent, HookHandler, HookRegistration, HookType, HookManager as IHookManager, PermissionManager as IPermissionManager, TrustManager as ITrustManager, JsonSchema, LEGACY_LEVEL_ALIASES, MAX_ATTACH_BYTES, MAX_ATTACH_FILES, MAX_ATTACH_TOTAL_BYTES, MAX_SESSION_ATTACH_BYTES, MAX_SESSION_REFS, OPERATION_TYPES, Operation, OperationType, PERMISSION_LEVELS, PLAN_OUTCOMES, PROVIDER_INFOS, PROVIDER_TYPES, PermissionDecision, PermissionLevel, PlanApprovalOutcome, PlanProposal, PluginContext, ProviderInfo, ProviderType, TokenUsage, ToolContext, ToolDefinition, ToolExposure, ToolResult, TrustExecGrant, TrustGrant, TrustLevel, TrustRecord, TrustScope, TrustTier, VerifyResult, apiKeyEnvVar, approvalPolicyForLevel, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval, resolvePermissionLevel } from '@epoch-agent/protocol';
|
|
3
|
+
import { IsolationBackend, SqliteDatabase, ParseIssue, ShellFlavor, SandboxMode, FailureVerdict } from '@epoch-agent/infra';
|
|
4
4
|
export { BubblewrapOptions, DangerMatch, IS_WINDOWS, IsolationBackend, IsolationOptions, LogLevel, SeatbeltOptions, WINDOWS_HIDE_FLAGS, buildBwrapArgs, buildProfile, checkDangerousCommand, checkObfuscation, createLogger, detectBackend, getDefaultShell, getPythonCommand, isInWorkspace, isReadOnlyCommand, isolate, maskApiKey, probeBubblewrap, probeSeatbelt, complianceDir as resolveComplianceDir, policiesDir as resolvePoliciesDir, setLogLevel } from '@epoch-agent/infra';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
@@ -182,12 +182,47 @@ declare class ToolRegistry {
|
|
|
182
182
|
/** 批量注册独立工具 */
|
|
183
183
|
registerTools(tools: EpochTool[], source?: string): void;
|
|
184
184
|
private addTool;
|
|
185
|
+
/**
|
|
186
|
+
* 把**某一个来源**的工具表整个换成新的一份,**保住已有工具的位置**。
|
|
187
|
+
*
|
|
188
|
+
* ## 为什么不能「撤干净再注册一遍」(2026-10-26)
|
|
189
|
+
*
|
|
190
|
+
* 撤回再注册在功能上等价,但**顺序会变**:`this.tools` 是 `Map`,删掉再插
|
|
191
|
+
* 等于让这个来源的工具全部挪到表尾。而工具表的顺序是**请求前缀的一部分** ——
|
|
192
|
+
* OpenAI / DeepSeek 的前缀缓存要求「两次请求从第 0 个 token 起完全相同」,
|
|
193
|
+
* 顺序一动,整段历史按全价重新预填。装了几台 MCP 的会话里,任意一台
|
|
194
|
+
* `list_changed` 或重连都会触发这件事,而用户看到的是账单,不是报错。
|
|
195
|
+
*
|
|
196
|
+
* 所以这里逐个 `set`:`Map` 对**已存在的键**不改插入顺序,于是已发出去的那些
|
|
197
|
+
* 工具逐字节不动,只有真正新增的才 append 到表尾。hermes 那边把同一条判据写成
|
|
198
|
+
* `preserve_prefix=True`,docstring 逐字是「existing tools keep their slot and
|
|
199
|
+
* the schema bytes already sent, new tools append at the tail」。
|
|
200
|
+
*
|
|
201
|
+
* ## 和 {@link unregisterBySource} 的分工
|
|
202
|
+
*
|
|
203
|
+
* 那个是「**全部**撤掉」(删除一个来源、整表销毁),这个是「**换成这一批**」。
|
|
204
|
+
* MCP 那条全量刷新的路走这个 —— 它一次 `tools/list` 拿到的是那台 server 的
|
|
205
|
+
* 完整现状,包括「哪些没了」。
|
|
206
|
+
*
|
|
207
|
+
* ## 三条语义
|
|
208
|
+
*
|
|
209
|
+
* 1. **新一批里没有的** → 真删(那是 server 撤掉的工具);
|
|
210
|
+
* 2. **两边都有** → 就地覆盖(位置不变,description / schema 可以变);
|
|
211
|
+
* 3. **只有新一批有** → append 到表尾。
|
|
212
|
+
*
|
|
213
|
+
* 跨来源撞名仍然是「先注册的赢」(同 `addTool`),**同批内重名则是先到的赢**
|
|
214
|
+
* —— 与逐条 `addTool` 的行为一致,只是不再记一条 `keptFrom === droppedFrom`
|
|
215
|
+
* 那样的自我冲突(那条记录在启动诊断里读起来像 bug)。
|
|
216
|
+
*
|
|
217
|
+
* @returns 真被删掉(新一批不再提供)的条数
|
|
218
|
+
*/
|
|
219
|
+
replaceBySource(tools: readonly EpochTool[], source?: string): number;
|
|
185
220
|
/**
|
|
186
221
|
* 撤掉某个来源的全部工具。
|
|
187
222
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
223
|
+
* 给「整个来源消失」用(删掉一台 server、销毁注册表)。**热更新不要用它** ——
|
|
224
|
+
* 撤干净再注册会让这个来源的工具全部挪到表尾,把请求前缀缓存整个废掉,
|
|
225
|
+
* 判据见 {@link replaceBySource}。
|
|
191
226
|
*
|
|
192
227
|
* 连带清掉与这个来源相关的冲突记录:不清的话每刷新一次就多攒一条,
|
|
193
228
|
* 启动诊断里会出现同一个撞名重复十遍。
|
|
@@ -690,8 +725,10 @@ declare class CodeSandbox {
|
|
|
690
725
|
* 模型压根拿不到这个能力。
|
|
691
726
|
*
|
|
692
727
|
* 工具输出会**如实附上本次的隔离级别**。这不是啰嗦:
|
|
693
|
-
* macOS 上是 OS 强制的(写不出沙箱、默认断网),
|
|
694
|
-
*
|
|
728
|
+
* macOS 上是 OS 强制的(写不出沙箱、默认断网),Windows 上没有 OS 级后端 ——
|
|
729
|
+
* 但 **JavaScript 那档从 2026-10-27 起挂着 Node 自己的权限模型**
|
|
730
|
+
* (`sandbox/node-permission.ts`,Node ≥ 22.5 才挂),Python 那档仍然只有进程隔离。
|
|
731
|
+
* 几档的风险差一个量级,不能让人以为都一样安全。
|
|
695
732
|
*
|
|
696
733
|
* ## ⚠️ 2026-08-16 起 `terminal` 也走隔离层了,但**边界不一样**
|
|
697
734
|
*
|
|
@@ -1709,6 +1746,44 @@ interface CompressConfig {
|
|
|
1709
1746
|
* 不给(或空串)时摘要提示词**逐字**保持原样,理由同 `instruction` / `plan`。
|
|
1710
1747
|
*/
|
|
1711
1748
|
goal?: string;
|
|
1749
|
+
/**
|
|
1750
|
+
* **撞墙之后**那一次压缩:不按尾部 token 预算留,只保最小的那几条
|
|
1751
|
+
* (2026-10-28)。
|
|
1752
|
+
*
|
|
1753
|
+
* ## 它修的是哪一种救不回来
|
|
1754
|
+
*
|
|
1755
|
+
* `determineBoundaries` 的尾部预算 = `threshold × contextLength × targetRatio`
|
|
1756
|
+
* ([compressor.ts](./compressor.ts) 的 Phase 2)。窗口设得越大,这一份预算越宽
|
|
1757
|
+
* ——**宽到能把整段历史都吃进去**,于是中段为空、`compress()` 在 Phase 2
|
|
1758
|
+
* 之后直接返回、`shrank()` 判为没变小,最后原样抛。
|
|
1759
|
+
*
|
|
1760
|
+
* 而这不是假想的边角:撞墙**恰恰常常发生在 token 侧还宽松的时候**。
|
|
1761
|
+
* 图片的 token 按宽高估(一张 2 MB 截图只记一千出头),字节却是几 MB ——
|
|
1762
|
+
* 于是「窗口 200K、历史才 10K token」这种看起来毫无压力的会话,请求体已经
|
|
1763
|
+
* 撞穿了网关。那时正常那一套边界计算一条都不愿松手,而我们要的正是
|
|
1764
|
+
* 「能拿多少拿多少」。
|
|
1765
|
+
*
|
|
1766
|
+
* ## 落到哪一档(判据是一次明确的选择,不是顺手)
|
|
1767
|
+
*
|
|
1768
|
+
* `true` 时尾部预算按 **0** 算,于是尾部循环只受那两条下限约束:
|
|
1769
|
+
* `protectLastN` 条、`minTailUserMessages` 条 user 消息。
|
|
1770
|
+
*
|
|
1771
|
+
* - **头部的 `protectFirstN` 不动。** 保住的那一条是会话开头的第一条用户消息,
|
|
1772
|
+
* 摘要模板的 `## Goal` 正是对着它写的 —— 连它一起压掉,摘要就失去了
|
|
1773
|
+
* 「这一摊到底要干什么」的锚点,压出来的是一段不知道自己为了什么而写的转述。
|
|
1774
|
+
* - **那两条下限也不动。** 它们守的是「刚才在干什么」,压掉之后模型会拿一份
|
|
1775
|
+
* 摘要接着干一件它已经做到一半的事,而它不知道做到哪儿了。
|
|
1776
|
+
*
|
|
1777
|
+
* 也就是说:`force` 松的是**按 token 摊开的那份预算**,不是任何一条保护。
|
|
1778
|
+
*
|
|
1779
|
+
* ## 谁给、谁不给
|
|
1780
|
+
*
|
|
1781
|
+
* **只有 `AgentLoop` 撞墙后的那一次给**(`compressNow` 的 `force`)。
|
|
1782
|
+
* 自动压缩的两条线(轮初硬线、轮末软线)和手动 `/compact` 都不给 ——
|
|
1783
|
+
* 那几处上一发是**正常结束**的,没有「这一发根本发不出去」这个前提,
|
|
1784
|
+
* 按正常预算留够近期内容才是对的。
|
|
1785
|
+
*/
|
|
1786
|
+
force?: boolean;
|
|
1712
1787
|
}
|
|
1713
1788
|
/**
|
|
1714
1789
|
* 压缩用的消息形状。
|
|
@@ -1725,6 +1800,27 @@ interface CompressMessage {
|
|
|
1725
1800
|
toolCallIds?: string[];
|
|
1726
1801
|
/** tool 消息回应的 tool call id */
|
|
1727
1802
|
toolCallId?: string;
|
|
1803
|
+
/**
|
|
1804
|
+
* 这一步模型的思考原文(2026-10-28)。
|
|
1805
|
+
*
|
|
1806
|
+
* ## 它为什么必须**穿过**压缩器,而不是在这里被丢掉
|
|
1807
|
+
*
|
|
1808
|
+
* 两件事,缺一件就是 bug:
|
|
1809
|
+
*
|
|
1810
|
+
* 1. **head / tail 原样保留那一段,思考不能掉。** 压缩的形状是
|
|
1811
|
+
* `head + 摘要 + tail`,两头是逐字带过去的。而 DeepSeek 思考模式 + `tools`
|
|
1812
|
+
* 时要求**每一条**历史 assistant 都带 `reasoning_content`(判据在
|
|
1813
|
+
* `EpochMessage.reasoning` 上)。这里不带上,压一次就把两头的思考洗掉了 ——
|
|
1814
|
+
* 不是因为「模型变笨」,是下一次请求直接 400。
|
|
1815
|
+
* 2. **中间段进摘要时,思考是素材的一部分。** 摘要是唯一活下来的那一段,
|
|
1816
|
+
* 而「为什么这么做」几乎全在思考里(正文常常只有一句「我查一下」)。
|
|
1817
|
+
* 只喂 `content` 等于让摘要模型对着一堆动作猜动机。
|
|
1818
|
+
*
|
|
1819
|
+
* ⚠️ **它是 `content` 之外的一格,不是并进 `content`**:并进去的话
|
|
1820
|
+
* `unflattenMessage` 还原时分不出哪半是正文、哪半是思考,回灌给模型的
|
|
1821
|
+
* `reasoning_content` 会连正文一起塞进去 —— 而模型会读到「自己说过两遍」。
|
|
1822
|
+
*/
|
|
1823
|
+
reasoning?: string;
|
|
1728
1824
|
}
|
|
1729
1825
|
/**
|
|
1730
1826
|
* 摘要调用的产出。
|
|
@@ -2834,6 +2930,28 @@ interface AgentConfig {
|
|
|
2834
2930
|
* 而它们同名的那半个词已经让人查错过一次方向。
|
|
2835
2931
|
*/
|
|
2836
2932
|
maxOutputTokens?: number;
|
|
2933
|
+
/**
|
|
2934
|
+
* 单次请求里**所有图片 base64 的合计**上限(字节,2026-10-28)。
|
|
2935
|
+
*
|
|
2936
|
+
* **缺省 = `DEFAULT_MAX_REQUEST_IMAGE_BYTES`(8 MiB,猜的)**,判据全文
|
|
2937
|
+
* (含「为什么这个数没有权威出处」)在 `provider/body-limit-cache.ts` 的文件头。
|
|
2938
|
+
*
|
|
2939
|
+
* ⚠️ 它是**字节**这条线,和 `contextLength`(token)是两个量纲 ——
|
|
2940
|
+
* 一张 2 MB 的截图在 token 账上只记一千出头,在字节账上是 2.7 MB。
|
|
2941
|
+
* 两条线都要有,因为只有文本那一半时 token 会先抓住,而只有图片时
|
|
2942
|
+
* token 那条线**永远抓不住**。
|
|
2943
|
+
*
|
|
2944
|
+
* 撞上一次之后,学到的值会在比它更小时顶替它(`effectiveImageBudget`)。
|
|
2945
|
+
*/
|
|
2946
|
+
maxRequestImageBytes?: number;
|
|
2947
|
+
/**
|
|
2948
|
+
* 数据目录(`~/.epoch` 那一层),学到的字节上限存进它的 `cache/` 下。
|
|
2949
|
+
*
|
|
2950
|
+
* 不给就**不学、也不读**历史学习值 —— 退回只用配置值/缺省值。理由同
|
|
2951
|
+
* `MultimodalPolicy.homeDir`:这一层够不着「这台机器的数据目录在哪」,
|
|
2952
|
+
* 自己猜一个 `homedir()` 在测试和多 profile 场景下会写错地方。
|
|
2953
|
+
*/
|
|
2954
|
+
homeDir?: string;
|
|
2837
2955
|
/**
|
|
2838
2956
|
* 预先算好的项目上下文(含工作区信任判定和已加载的指令文件)。
|
|
2839
2957
|
*
|
|
@@ -3225,6 +3343,15 @@ interface HistoryEntry {
|
|
|
3225
3343
|
role: 'user' | 'assistant';
|
|
3226
3344
|
content: string;
|
|
3227
3345
|
parts?: EpochContentPart[];
|
|
3346
|
+
/**
|
|
3347
|
+
* 这一轮的思考原文(2026-10-28)。
|
|
3348
|
+
*
|
|
3349
|
+
* ⚠️ **必须能跟着历史穿过来。** 原来它只落在会话库的 `messages.reasoning` 列上
|
|
3350
|
+
* 给人看,`loadHistory()` 一个字都不带 —— 于是刷新页面 / `--resume` 之后下一条
|
|
3351
|
+
* 消息发出去,DeepSeek 看不见上一轮的 reasoning_content,当场 400。
|
|
3352
|
+
* 判据在 registry 的 `CARRIES_REASONING_BACK` 上。
|
|
3353
|
+
*/
|
|
3354
|
+
reasoning?: string;
|
|
3228
3355
|
}
|
|
3229
3356
|
interface RunInput {
|
|
3230
3357
|
/** 纯文本或多模态部件数组。两种形态 AI SDK 都原生接受,不需要在这里分支 */
|
|
@@ -3272,6 +3399,26 @@ interface RunInput {
|
|
|
3272
3399
|
* 不给就是今天的行为:这一轮跑完才轮到下一条消息。
|
|
3273
3400
|
*/
|
|
3274
3401
|
steer?: SteerSource;
|
|
3402
|
+
/**
|
|
3403
|
+
* 这一轮每产出一个事件就旁路回调一次(2026-10-27)。
|
|
3404
|
+
*
|
|
3405
|
+
* ## 为什么是在 `run()` 上开个口,而不是改成让调用方用 `stream()`
|
|
3406
|
+
*
|
|
3407
|
+
* `run()` 和 `stream()` 走的是同一个 `runTurns()`,但 `stream()` 不回
|
|
3408
|
+
* `RunResult`(它的 `turns` 是内部数组,调用方拿不到)。子 agent 那一路
|
|
3409
|
+
* 既需要完整结果(它的汇总要交给父 agent),又需要知道「跑到哪一步了」
|
|
3410
|
+
* (后台作业的 `task_output` 一直只写着「还没跑完」)。改 `stream()` 的返回
|
|
3411
|
+
* 等于把两个生成器合并,而那是另一笔账。
|
|
3412
|
+
*
|
|
3413
|
+
* ## 默认什么都不做
|
|
3414
|
+
*
|
|
3415
|
+
* 不给这一格 = 改造前的行为,引擎一处都不多花。
|
|
3416
|
+
*
|
|
3417
|
+
* ## ⚠️ 回调里不要抛
|
|
3418
|
+
*
|
|
3419
|
+
* 它住在引擎的事件循环里,抛出来会把整轮掀翻。要防护自己在回调里做完。
|
|
3420
|
+
*/
|
|
3421
|
+
onEvent?: (ev: AgentEvent) => void;
|
|
3275
3422
|
}
|
|
3276
3423
|
/**
|
|
3277
3424
|
* 「正在跑的这一轮里,用户又说话了吗」——**由宿主实现,引擎只来拉**。
|
|
@@ -3347,37 +3494,39 @@ interface AbortLike {
|
|
|
3347
3494
|
*
|
|
3348
3495
|
* LLM 调用 delegate_task 工具,派发子任务给独立 Agent 并行执行。
|
|
3349
3496
|
*
|
|
3350
|
-
* ##
|
|
3497
|
+
* ## 两种派法:同步等(默认)和后台作业(`background: true`)
|
|
3351
3498
|
*
|
|
3352
|
-
*
|
|
3353
|
-
*
|
|
3354
|
-
*
|
|
3355
|
-
* 而 §3.3 的判据是「现在统一,不等它」:等到真做后台子 agent 时再统一,
|
|
3356
|
-
* 代价是那时要同时改三处已经发出去的工具。
|
|
3499
|
+
* 默认仍然是**同步等**:`delegate()` 一路 `await` 到所有子任务结束才返回,
|
|
3500
|
+
* 这一条一个字没改 —— 大多数委托十几次工具调用就回来了,模型拿到结论直接接着
|
|
3501
|
+
* 往下干,是它要的形状。
|
|
3357
3502
|
*
|
|
3358
|
-
*
|
|
3359
|
-
|
|
3503
|
+
* `background: true` 是 2026-10-26 接上的第三类作业(`JobKind = 'agent'`):
|
|
3504
|
+
|
|
3505
|
+
* - 派完**立刻返回作业 id**(`a1`),父回合接着干别的
|
|
3506
|
+
* - 作业登记在**派活的那个会话**名下(`task_*` 那道按会话分区的墙靠它)
|
|
3507
|
+
* - 子任务结束 / 失败 / 被杀时,`task_output` 读得到汇总,下一轮开头
|
|
3508
|
+
* `TaskNoticeTracker` 会挂一条「a1 已结束」的 `user` note
|
|
3509
|
+
* - **父回合的终止不再打到它身上**:用户按停只停父回合,后台子任务继续跑
|
|
3510
|
+
* (四家竞品一致:Claude Code 在后台 agent 的 abort controller 上专门留了
|
|
3511
|
+
* 一句注释说明它不挂父链)。要收掉它只有两条路 —— `task_stop a1`,或者
|
|
3512
|
+
* 进程退出
|
|
3360
3513
|
*
|
|
3361
|
-
*
|
|
3362
|
-
*
|
|
3363
|
-
*
|
|
3364
|
-
*
|
|
3365
|
-
*
|
|
3366
|
-
*
|
|
3367
|
-
*
|
|
3368
|
-
*
|
|
3369
|
-
*
|
|
3370
|
-
* });
|
|
3371
|
-
* ```
|
|
3514
|
+
* ### 为什么不学另外三家「一律后台」
|
|
3515
|
+
*
|
|
3516
|
+
* 那三家(codex / hermes-agent / deepseek-harness)没有这个开关,它们的
|
|
3517
|
+
* 委托入口本来就**只有后台一种**。我们保留默认同步,判据是我们的宿主没有
|
|
3518
|
+
* 它们那套推送:`epoch -p` 一轮结束就是结束,TUI 空转时也不会自己开口。
|
|
3519
|
+
* 一轮里「派出去然后等结论」仍然是最常见的形态,把它也改成异步,模型得
|
|
3520
|
+
* 每派一次就 `task_wait` 一次,等于白多一轮往返。
|
|
3521
|
+
*
|
|
3522
|
+
* ### 作业的 `stop` 收的是控制器,不是进程
|
|
3372
3523
|
*
|
|
3373
|
-
*
|
|
3374
|
-
*
|
|
3375
|
-
*
|
|
3376
|
-
* 那是一张 `Record<JobKind, string>`,漏了会在编译期报缺键。
|
|
3524
|
+
* `JobSpec.stop` 收的是一个 `AbortController.abort()` —— 子 agent 不是子进程,
|
|
3525
|
+
* 退出时那张按 pid 记的表摸不到它。所以「进程退出时收干净」这件事在这一族上
|
|
3526
|
+
* 是靠**进程一起没了**实现的,不是靠 `release()`。
|
|
3377
3527
|
*
|
|
3378
|
-
* ⚠️
|
|
3379
|
-
*
|
|
3380
|
-
* `delegate_task` 那一档 `command`)还没判过。真做那一轮要答的就是这个问题。
|
|
3528
|
+
* ⚠️ **`detail` 里只放 controller**:`task_*` 那四个工具不读它,`jobSandbox()`
|
|
3529
|
+
* 读的那一格(`sandbox`)在这一族上不存在,于是它照旧返回 `undefined`。
|
|
3381
3530
|
*/
|
|
3382
3531
|
|
|
3383
3532
|
/** 子任务定义 */
|
|
@@ -3399,6 +3548,11 @@ interface DelegateArgs {
|
|
|
3399
3548
|
max_concurrent?: number;
|
|
3400
3549
|
/** `goal` 简写形式的角色名 */
|
|
3401
3550
|
role?: string;
|
|
3551
|
+
/**
|
|
3552
|
+
* `true` = 派到后台立刻返回(作业 id 形如 `a1`)。缺省 `false` = 同步等,
|
|
3553
|
+
* 与改造前逐字节相同。判据与取舍见文件头「两种派法」那一节。
|
|
3554
|
+
*/
|
|
3555
|
+
background?: boolean;
|
|
3402
3556
|
}
|
|
3403
3557
|
/** 委托结果 */
|
|
3404
3558
|
interface DelegateTaskResult {
|
|
@@ -3413,6 +3567,16 @@ interface DelegateTaskResult {
|
|
|
3413
3567
|
}>;
|
|
3414
3568
|
total_duration: number;
|
|
3415
3569
|
}
|
|
3570
|
+
/** `delegate()` 的返回值。后台那一档多两个字段,同步那一档不受影响 */
|
|
3571
|
+
interface DelegateOutcome {
|
|
3572
|
+
success: boolean;
|
|
3573
|
+
output: string;
|
|
3574
|
+
duration: number;
|
|
3575
|
+
/** 只有后台派活才有 —— 模型拿它去 `task_output` / `task_wait` / `task_stop` */
|
|
3576
|
+
jobId?: string;
|
|
3577
|
+
/** 父回合是不是被放走了(后台那一档)。**不是**「有没有作业」 */
|
|
3578
|
+
background?: boolean;
|
|
3579
|
+
}
|
|
3416
3580
|
/**
|
|
3417
3581
|
* 子 Agent 被禁止的工具 [Hermes]。
|
|
3418
3582
|
*
|
|
@@ -3426,6 +3590,12 @@ declare const BLOCKED_TOOLS: readonly string[];
|
|
|
3426
3590
|
interface DelegateConfig {
|
|
3427
3591
|
max_concurrent_children: number;
|
|
3428
3592
|
max_spawn_depth: number;
|
|
3593
|
+
/**
|
|
3594
|
+
* 一个子任务最多跑多久(毫秒)。**`0` = 不限时**。
|
|
3595
|
+
*
|
|
3596
|
+
* 真源是 `config.delegate.taskTimeoutSec`(秒),在 `build.ts` 里折成毫秒;
|
|
3597
|
+
* 构造函数里那个 `900_000` 只给不经过配置的调用方(用例、嵌入宿主)。
|
|
3598
|
+
*/
|
|
3429
3599
|
task_timeout: number;
|
|
3430
3600
|
}
|
|
3431
3601
|
declare class DelegateManager {
|
|
@@ -3438,29 +3608,43 @@ declare class DelegateManager {
|
|
|
3438
3608
|
*
|
|
3439
3609
|
* @param parentSessionId 派活的那个会话(`ToolContext.sessionId`)。一路带到
|
|
3440
3610
|
* `runner` 上,让子任务的花费和文件快照记到**它**头上而不是装配时那个会话
|
|
3611
|
+
* @param signal 父回合的终止信号。**只有同步那一档会挂到子任务上** ——
|
|
3612
|
+
* 后台派活的判据见文件头「两种派法」
|
|
3441
3613
|
*/
|
|
3442
|
-
delegate(args: DelegateArgs, parentSessionId: string, signal?: AbortLike): Promise<
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3614
|
+
delegate(args: DelegateArgs, parentSessionId: string, signal?: AbortLike): Promise<DelegateOutcome>;
|
|
3615
|
+
/**
|
|
3616
|
+
* 把这一批登记成一格 `agent` 作业。
|
|
3617
|
+
*
|
|
3618
|
+
* 归**派活的那个会话**(不是子任务自己那个 `delegate-xxxx`):`task_*` 那道
|
|
3619
|
+
* 按会话分区的墙靠这一格 —— 记到子任务名下的话,父会话一结束就谁都看不见、
|
|
3620
|
+
* 也停不掉了。
|
|
3621
|
+
*/
|
|
3622
|
+
private registerJob;
|
|
3447
3623
|
private normalizeTasks;
|
|
3624
|
+
/**
|
|
3625
|
+
* 分批跑,每批最多 `maxConcurrent` 个。
|
|
3626
|
+
*
|
|
3627
|
+
* @param signal **整批**那个控制器的信号(不是父回合的)—— 每一格再各自
|
|
3628
|
+
* 派生一个,判据在 {@link runSingleTask} 上
|
|
3629
|
+
* @param onDone 每收一格回调一次。后台那一档用它往作业缓冲里写进度;
|
|
3630
|
+
* 同步那一档不传(写进去也没有人读 —— 那一档没有作业)
|
|
3631
|
+
*/
|
|
3448
3632
|
private runWithConcurrency;
|
|
3449
3633
|
/**
|
|
3450
3634
|
* 跑一个子任务。
|
|
3451
3635
|
*
|
|
3452
3636
|
* ## 每个子任务一个自己的 controller(2026-09-24)
|
|
3453
3637
|
*
|
|
3454
|
-
*
|
|
3455
|
-
*
|
|
3456
|
-
*
|
|
3457
|
-
* `Promise.race` 抢答 —— 父回合往下走了,子 agent 在后台接着跑、接着花钱,
|
|
3458
|
-
* 屏幕上一个字都看不见。
|
|
3638
|
+
* 进来的 `signal` 是**整批**那个控制器的(`delegate()` 建的),每格再链一个
|
|
3639
|
+
* 自己的:这一格的超时只掐它自己,而 `task_stop` / 父回合终止打的是整批那一个,
|
|
3640
|
+
* 于是两件事都成立 —— 超时不会误伤兄弟,收批也不会漏掉哪一格。
|
|
3459
3641
|
*
|
|
3460
|
-
*
|
|
3461
|
-
*
|
|
3642
|
+
* 父回合的终止是不是真的会打下来,取决于派法:同步那一档 `delegate()` 把
|
|
3643
|
+
* 父 signal 链到整批控制器上,后台那一档**不链**(判据在文件头)。
|
|
3462
3644
|
*/
|
|
3463
3645
|
private runSingleTask;
|
|
3646
|
+
/** 进度那一行里的「谁、干了什么、多久」—— 和汇总标题同一套写法 */
|
|
3647
|
+
private describeResult;
|
|
3464
3648
|
private buildSummary;
|
|
3465
3649
|
}
|
|
3466
3650
|
|
|
@@ -3496,7 +3680,18 @@ interface SubAgentRunner {
|
|
|
3496
3680
|
* 实现方要把它交给子 agent 的 `run()` —— 不交的话按了终止它照跑,判据在
|
|
3497
3681
|
* `DelegateManager.runSingleTask` 上。可选只是为了不拆已有的调用方
|
|
3498
3682
|
*/
|
|
3499
|
-
signal?: AbortSignal
|
|
3683
|
+
signal?: AbortSignal,
|
|
3684
|
+
/**
|
|
3685
|
+
* 子任务跑的过程中每完成一步回调一次(2026-10-27)。
|
|
3686
|
+
*
|
|
3687
|
+
* 收的是一行已经拼好的人话(`读文件 `src/a.ts``),不是事件对象 ——
|
|
3688
|
+
* 两个调用方(作业缓冲 / 未来的其他通道)要的是同一句话,而把事件形状
|
|
3689
|
+
* 漏上去等于让每个调用方重写一遍折行逻辑。
|
|
3690
|
+
*
|
|
3691
|
+
* **同步那一档目前不给**:父回合正卡在这个工具调用上,没有地方显示它。
|
|
3692
|
+
* 后台那一档接了 —— 那里的 `task_output` 在此之前只能看到「还没跑完」。
|
|
3693
|
+
*/
|
|
3694
|
+
onProgress?: (line: string) => void): Promise<{
|
|
3500
3695
|
text: string;
|
|
3501
3696
|
error?: string;
|
|
3502
3697
|
}>;
|
|
@@ -4019,13 +4214,20 @@ declare function createMemoryTool(memory: MemoryManager$1): EpochTool;
|
|
|
4019
4214
|
*
|
|
4020
4215
|
* ⚠️ **这一段 2026-08-28 之前写的是「`run_code` 的边界在权限管线,不在进程隔离」,
|
|
4021
4216
|
* 那句话被 PR-3 判为假**(程序里 `import('node:fs')` 直通,权限管线整个被绕过)。
|
|
4022
|
-
*
|
|
4217
|
+
* 那时改成了「一次 `run_code` = 一次任意本机代码执行,边界是审批那一下」,
|
|
4023
4218
|
* 全文在 [PR-3 记录 §二](../../../../docs/verify/VERIFY_RECORD-51-code-mode-pr3.md)。
|
|
4024
4219
|
*
|
|
4025
|
-
*
|
|
4026
|
-
*
|
|
4027
|
-
*
|
|
4028
|
-
*
|
|
4220
|
+
* **2026-10-27 又收窄了一层**:`runner.ts` 给 worker 挂了 `--permission` +
|
|
4221
|
+
* 清空的 env(判据在 [policy.ts](./policy.ts) 的文件头)。所以今天的口径是
|
|
4222
|
+
* 「审批是边界,权限策略把程序限制在工作目录内、起不了子进程、看不见 env」。
|
|
4223
|
+
* ⚠️ **但下面的表仍然成立,它守的东西也没变** —— 这个文件管的是「别把宿主拖死」,
|
|
4224
|
+
* 不是「别越权」。权限模型不管死循环、不管吃内存、更不管
|
|
4225
|
+
* 「一个写错的 `for` 调一万次工具」,而这四格里没有一格能被 `--permission` 代替。
|
|
4226
|
+
*
|
|
4227
|
+
* 它跑在我们自己的进程里的一个 worker 线程上,所以这四道上限守的是
|
|
4228
|
+
* **「别把宿主拖死」**(死循环、吃内存、一个写错的 `for` 调一万次工具),
|
|
4229
|
+
* 不是「别越权」。越权那一半今天由审批 + 权限策略两层兜着 ——
|
|
4230
|
+
* 而下面这张表列的是**权限策略一格都盖不到**的那部分:
|
|
4029
4231
|
*
|
|
4030
4232
|
* | 多出来的能力 | 这里的哪一格 |
|
|
4031
4233
|
* | --------------------------------- | ----------------------------------------- |
|
|
@@ -4114,14 +4316,14 @@ declare const CODE_MODE_LIMITS: CodeModeLimits;
|
|
|
4114
4316
|
* | ------------ | ---------------------------------------------- | ---------------------------------------- |
|
|
4115
4317
|
* | 干什么 | 算东西、处理数据 | **编排工具调用** |
|
|
4116
4318
|
* | 能不能碰宿主 | **不能** —— 写不出沙箱、默认断网、读不到 `$HOME` | **必须能** —— 它的全部意义就是回调工具 |
|
|
4117
|
-
* | 隔离级别 | macOS 上 OS 强制(Seatbelt) |
|
|
4118
|
-
* | 安全模型 | 沙箱是边界 |
|
|
4319
|
+
* | 隔离级别 | macOS 上 OS 强制(Seatbelt) | worker 线程 + Node 权限模型(`code-mode/policy.ts`) |
|
|
4320
|
+
* | 安全模型 | 沙箱是边界 | **审批是边界**;权限策略只收窄「程序能碰什么」 |
|
|
4119
4321
|
*
|
|
4120
4322
|
* 所以 `sandbox/sandbox.ts` 的那整套设计(沙箱目录在 tmpdir、`~/.epoch` 在读黑名单
|
|
4121
4323
|
* 里)对这个工具**一条都不适用** —— 一个连 `~/.epoch` 都读不到的程序怎么调
|
|
4122
4324
|
* `file_read`。**别把两个工具的措辞「统一」**,它们说的是两条不同的路。
|
|
4123
4325
|
*
|
|
4124
|
-
* ## ⚠️
|
|
4326
|
+
* ## ⚠️ 边界是**审批**;权限策略只是让那次审批的语义变准
|
|
4125
4327
|
*
|
|
4126
4328
|
* 这一段 2026-08-28 之前写的是「一个 `run_code` 程序能做的事**逐字等于**模型
|
|
4127
4329
|
* 一个个调那些工具能做的事」。**那句话是假的**,而且是被实测推翻的:程序跑在
|
|
@@ -4132,16 +4334,36 @@ declare const CODE_MODE_LIMITS: CodeModeLimits;
|
|
|
4132
4334
|
* [PR-4 记录](../../../../../docs/verify/VERIFY_RECORD-51-code-mode-pr4.md) §三 第 3 / 4 条,
|
|
4133
4335
|
* 那不是理论上的洞,是模型自己找到并用上的路。
|
|
4134
4336
|
*
|
|
4135
|
-
* PR-3
|
|
4337
|
+
* PR-3 那轮**判定不做**引擎隔离(三个选项和判据在
|
|
4136
4338
|
* [PR-3 记录](../../../../../docs/verify/VERIFY_RECORD-51-code-mode-pr3.md) §二),
|
|
4137
4339
|
* 改成把边界说准:
|
|
4138
4340
|
*
|
|
4139
4341
|
* > **一次 `run_code` = 一次任意本机代码执行,和 `terminal` 同一档。
|
|
4140
4342
|
* > 边界是审批那一下 —— 用户看到程序全文,批的是「这段程序可以跑」。**
|
|
4141
4343
|
*
|
|
4142
|
-
*
|
|
4143
|
-
*
|
|
4144
|
-
*
|
|
4344
|
+
* ## 2026-10-27:那句话里「一点隔离都没有」的一半补上了
|
|
4345
|
+
*
|
|
4346
|
+
* PR-3 当时只有两个选项:preload 拦 `node:fs`(实测无效,`Module._load` 只盖 CJS),
|
|
4347
|
+
* 或者上 OS 隔离(要改成子进程,动整个进程模型)。两个都不成立,所以「不做」
|
|
4348
|
+
* 在那时是对的。
|
|
4349
|
+
*
|
|
4350
|
+
* 第三条路是 worker 自己的 `execArgv` 挂 `--permission`:进程模型一个字不动,
|
|
4351
|
+
* 策略只作用在那一个线程上。实测数据和它**没**拦住什么(网络、env)全部在
|
|
4352
|
+
* [policy.ts](../../code-mode/policy.ts) 的文件头。
|
|
4353
|
+
*
|
|
4354
|
+
* 于是口径变成两句:
|
|
4355
|
+
*
|
|
4356
|
+
* > **审批仍然是边界**;权限策略把「一次任意本机代码执行」收窄成
|
|
4357
|
+
* > 「工作目录内读写、起不了子进程、看不见环境变量」。
|
|
4358
|
+
*
|
|
4359
|
+
* 剩下那个没被收窄的是**网络**,而这里不假装它变了:权限模型不管网络,
|
|
4360
|
+
* 所以一段恶意程序照样能把读到的内容发出去。想在 `bypass` 档 / headless
|
|
4361
|
+
* 预授权下开着它,判断照旧同 `docs/TOOLS.md` 那句 —— 「那一眼是唯一的边界」。
|
|
4362
|
+
*
|
|
4363
|
+
* `operation: 'command'` 和 `describeTarget` = 程序全文仍然是承重墙,
|
|
4364
|
+
* 各有一条会红的用例钉着(`tool-executor.test.ts` 的「run_code 的审批对象是程序全文」、
|
|
4365
|
+
* tui 的「多行 / 超宽 target」)。加权限策略**不改**这一格:策略算错时
|
|
4366
|
+
* 程序起不来,而审批框里看到的仍然是全文。
|
|
4145
4367
|
* 落进 git 的 `permissions.allow` 里也一条 `run_code` 规则都不许有
|
|
4146
4368
|
* (`permission/rule-validate.ts` 的 `NEVER_ALLOW_TOOL_NAMES`)。
|
|
4147
4369
|
*
|
|
@@ -4184,6 +4406,9 @@ declare const CODE_MODE_LIMITS: CodeModeLimits;
|
|
|
4184
4406
|
* 断网要么靠子进程 + 沙箱(PR-3 记录 §二 选项 C,重开条件在 §五末尾),要么不做。
|
|
4185
4407
|
* 原来的理由是「它想联网就调 `web_fetch`,那条路有 SSRF 三层防护」——
|
|
4186
4408
|
* 那句话仍然成立,只是它**描述不了今天的现状**。
|
|
4409
|
+
* ⚠️ **2026-10-27 加权限策略之后再确认一遍:它管不了网络。** 实测带着
|
|
4410
|
+
* `--permission` 跑,`fetch` 照样通 —— 权限模型只管文件系统、子进程、worker、
|
|
4411
|
+
* 原生插件这四类。别把「加了策略」读成「断网了」。
|
|
4187
4412
|
*
|
|
4188
4413
|
* ## ⚠️ 三条边界,别在读这个文件时以为方案已经全落了
|
|
4189
4414
|
*
|
|
@@ -4761,8 +4986,6 @@ type ScheduleIssueCode =
|
|
|
4761
4986
|
| 'permission-unknown'
|
|
4762
4987
|
/** 工作目录不存在 */
|
|
4763
4988
|
| 'work-dir-missing'
|
|
4764
|
-
/** `maxBudgetUsd` 必填且必须为正。**这是刻意的摩擦**,见协议上那段 */
|
|
4765
|
-
| 'budget-missing'
|
|
4766
4989
|
/** `maxTurns` 必须是正整数 */
|
|
4767
4990
|
| 'max-turns-invalid'
|
|
4768
4991
|
/** 墙钟超时必须是正数 */
|
|
@@ -4793,18 +5016,18 @@ type ScheduleIssueCode =
|
|
|
4793
5016
|
/** 清单里有一条规则写错了(`detail` 是 `rule-validate` 给的位置与原因) */
|
|
4794
5017
|
| 'rule-invalid'
|
|
4795
5018
|
/**
|
|
4796
|
-
*
|
|
5019
|
+
* 「完全访问」+ 空工作区。
|
|
4797
5020
|
*
|
|
4798
5021
|
* ⚠️ **2026-09-18 起没有产出点了** —— 空着落到的是 `~/.epoch/automation/<id>/`,
|
|
4799
5022
|
* 一个确定、专属、隔离的目录,不是「不确定的 cwd」。判据全文在
|
|
4800
5023
|
* `validate.ts` 的 `bypassIssues()` 第 1 条上。保留这条 code 是为了不破坏协议。
|
|
4801
5024
|
*/
|
|
4802
5025
|
| 'bypass-needs-workdir'
|
|
4803
|
-
/**
|
|
5026
|
+
/** 「完全访问」的工作区指到了家目录本身 —— 那和不绑定没有区别 */
|
|
4804
5027
|
| 'bypass-workdir-too-broad'
|
|
4805
|
-
/**
|
|
5028
|
+
/** 「完全访问」缺尺子 —— 今天只剩超时那一把 */
|
|
4806
5029
|
| 'bypass-needs-limits'
|
|
4807
|
-
/**
|
|
5030
|
+
/** 「完全访问」没有拿到那次二次确认 */
|
|
4808
5031
|
| 'bypass-not-confirmed';
|
|
4809
5032
|
/** 全集。CLI 侧靠它穷举文案,少一条编译不过 */
|
|
4810
5033
|
declare const SCHEDULE_ISSUE_CODES: readonly ScheduleIssueCode[];
|
|
@@ -4843,7 +5066,6 @@ interface ScheduleImportInput {
|
|
|
4843
5066
|
allowOperations: readonly OperationType[];
|
|
4844
5067
|
allowRules: readonly string[];
|
|
4845
5068
|
maxTurns: number;
|
|
4846
|
-
maxBudgetUsd: number;
|
|
4847
5069
|
timeoutMs: number;
|
|
4848
5070
|
showInSessionList?: boolean;
|
|
4849
5071
|
trigger: ScheduleTrigger;
|
|
@@ -4874,8 +5096,6 @@ interface CreateScheduleInput {
|
|
|
4874
5096
|
allowOperations?: readonly OperationType[];
|
|
4875
5097
|
allowRules?: readonly string[];
|
|
4876
5098
|
maxTurns?: number;
|
|
4877
|
-
/** **必填**,没有默认值 */
|
|
4878
|
-
maxBudgetUsd: number;
|
|
4879
5099
|
timeoutMs?: number;
|
|
4880
5100
|
/**
|
|
4881
5101
|
* 跑完的会话直接进会话列表吗。缺省 `false` = 收起来(归档),
|
|
@@ -4922,8 +5142,7 @@ interface CreateScheduleInput {
|
|
|
4922
5142
|
* `ScheduleControl.update` 解析掉;**`ScheduleStore.update` 的入参不收它**
|
|
4923
5143
|
* (同 `create(input & { workDir: string })` 那条契约,收窄在编译期)。
|
|
4924
5144
|
*/
|
|
4925
|
-
type UpdateScheduleInput = Partial<Omit<CreateScheduleInput, '
|
|
4926
|
-
maxBudgetUsd?: number;
|
|
5145
|
+
type UpdateScheduleInput = Partial<Omit<CreateScheduleInput, 'workDir' | 'model' | 'role' | 'startDate' | 'endDate'>> & {
|
|
4927
5146
|
/** `null` = 不绑工作区了 → 落回 `~/.epoch/automation/<id>/`,**不是**删掉这一格 */
|
|
4928
5147
|
workDir?: string | null;
|
|
4929
5148
|
model?: string | null;
|
|
@@ -4933,74 +5152,57 @@ type UpdateScheduleInput = Partial<Omit<CreateScheduleInput, 'maxBudgetUsd' | 'w
|
|
|
4933
5152
|
endDate?: string | null;
|
|
4934
5153
|
};
|
|
4935
5154
|
/**
|
|
4936
|
-
*
|
|
5155
|
+
* 两把尺子的缺省值 —— **「调 API / CLI 没给这一格时引擎用什么」**。
|
|
4937
5156
|
*
|
|
4938
|
-
* ## ⚠️
|
|
5157
|
+
* ## ⚠️ 2026-10-29:只剩轮次和超时(预算那一把整个撤了)
|
|
4939
5158
|
*
|
|
4940
|
-
*
|
|
5159
|
+
* 这里原来还挂着一段「预算不在这份缺省里,因为一个假默认会让『一觉醒来 40
|
|
5160
|
+
* 美元』变成我们的错」。那次撤掉的不只是那一段注释,而是**那一格本身**:
|
|
5161
|
+
* `maxBudgetUsd` 已经从契约、库、网线、CLI、表单上全部退场,判据在
|
|
5162
|
+
* `validate.ts` 的 `bypassIssues()` 上。
|
|
4941
5163
|
*
|
|
4942
|
-
*
|
|
4943
|
-
*
|
|
4944
|
-
* 一份说「表单打开时格子里印什么」,一份说「没给值时引擎用什么」。
|
|
4945
|
-
* 把 200 抄进这一份的表现是**网线那一道闸整个消失** —— 任何一个不经表单的调用方
|
|
4946
|
-
* 从此都能建出一条没人想过预算的任务,而那正是这一格的缺席拦着的事。
|
|
5164
|
+
* 于是这一份和界面预填那一份(protocol 的 `WireScheduleDefaults`)**不再有
|
|
5165
|
+
* 任何区别** —— 两份都只是「轮次 + 超时」。
|
|
4947
5166
|
*/
|
|
4948
5167
|
declare const SCHEDULE_DEFAULTS: {
|
|
4949
5168
|
/**
|
|
4950
|
-
*
|
|
5169
|
+
* 轮次上限。**`0` = 不限**(`UNLIMITED_TURNS`)。
|
|
5170
|
+
*
|
|
5171
|
+
* ## 为什么缺省是「不限」,而不是一个保守的数
|
|
4951
5172
|
*
|
|
4952
|
-
*
|
|
4953
|
-
* 它当初拦的是「跑飞了没人按 Esc
|
|
4954
|
-
*
|
|
4955
|
-
*
|
|
4956
|
-
* 就要 60 轮」—— 而那种失败要等到第二天 9 点才看得见(同下面
|
|
5173
|
+
* 这一格原来是自己的一个 `20`,理由写的是「无人看着的一轮不该比有人看着的
|
|
5174
|
+
* 更长」。它不成立了 —— 它当初拦的是「跑飞了没人按 Esc」,而用轮次替它把
|
|
5175
|
+
* 无人值守的活压到 20,拦掉的绝大多数不是跑飞,是「这个任务本来就要 60 轮」
|
|
5176
|
+
* —— 而那种失败要等到第二天 9 点才看得见(同下面
|
|
4957
5177
|
* `SCHEDULE_DEFAULT_ALLOWLIST` 那节的判据)。
|
|
4958
5178
|
*
|
|
4959
5179
|
* ⚠️ 这一份是**没有配置在手时的兜底**。真正拿着用户那格 `maxTurns` 的地方是
|
|
4960
5180
|
* `server/src/schedule/handlers.ts` 的 `defaultsOf()` —— 表单预填走它,
|
|
4961
5181
|
* 所以用户把设置里那个数改成 500,新建任务那一格就预填 500。
|
|
4962
5182
|
*
|
|
4963
|
-
* ⚠️ **2026-09-06 起这个缺省是「不设上限」**(`UNLIMITED_TURNS
|
|
4964
|
-
*
|
|
4965
|
-
*
|
|
4966
|
-
* (必填,所以它不在这份缺省里)和 `timeoutMs`。要一道轮次闸门的人在新建任务
|
|
5183
|
+
* ⚠️ **2026-09-06 起这个缺省是「不设上限」**(`UNLIMITED_TURNS`),判据同上。
|
|
5184
|
+
* 🔴 **2026-10-29 起这条路真正兜得住「跑飞」的只剩下面那一个 `timeoutMs`**
|
|
5185
|
+
* —— 预算那把尺子没了,而这一格缺省是 0。要一道轮次闸门的人在新建任务
|
|
4967
5186
|
* 那一格自己填一个数。
|
|
4968
5187
|
*/
|
|
4969
5188
|
readonly maxTurns: 0;
|
|
4970
5189
|
/**
|
|
4971
|
-
*
|
|
4972
|
-
*
|
|
5190
|
+
* 墙钟超时。**无人值守路上唯一兜得住「跑飞」的那把尺子**(2026-10-29 起)。
|
|
5191
|
+
*
|
|
5192
|
+
* 它要拦两种前一把拦不住的东西:一条 `terminal` 命令挂住了(那种情况下轮次
|
|
5193
|
+
* 不增长),以及一个每轮都很便宜、但一轮接一轮跑下去的循环。
|
|
4973
5194
|
*
|
|
4974
5195
|
* ⚠️ **2026-09-18 从 15 分钟抬到 60 分钟**(用户定的)。15 分钟那条线当初是
|
|
4975
5196
|
* 照着「一次巡检」估的,而它砍掉的不是跑飞,是**本来就要跑久的那种任务**:
|
|
4976
5197
|
* 一条被这把尺子掐断的运行和跑飞长得一模一样(都是 `timeout`),
|
|
4977
5198
|
* 而定时任务的反馈回路按天算 —— 第二天早上看到的只有「超时了」三个字。
|
|
4978
5199
|
*
|
|
4979
|
-
* 兜住真正跑飞的是必填的 `maxBudgetUsd`(钱是比时间准的尺子),
|
|
4980
|
-
* 判据同上面 `maxTurns` 那一段。
|
|
4981
|
-
*
|
|
4982
5200
|
* ⚠️ 这个数**两条路共用**(CLI 不给 `--timeout`、表单预填,都读它)——
|
|
4983
5201
|
* 在服务端那侧另写一份的表现,`runtime/schedule/control.ts` 那段注释记着:
|
|
4984
5202
|
* 「表单预填 200、直接调这个 API 却得到 20」。
|
|
4985
5203
|
*/
|
|
4986
5204
|
readonly timeoutMs: number;
|
|
4987
5205
|
};
|
|
4988
|
-
/**
|
|
4989
|
-
* 新建**表单**里预算那一格印什么(2026-09-18,用户定的 200 美元)。
|
|
4990
|
-
*
|
|
4991
|
-
* ## ⚠️ 它**刻意不在** {@link SCHEDULE_DEFAULTS} 里,这一条是承重的
|
|
4992
|
-
*
|
|
4993
|
-
* 那一份答的是「调 API / CLI 没给这一格时引擎用什么」,而这一格**没有**那种兜底:
|
|
4994
|
-
* 网线上没给预算就是 400(`budget-required`),CLI 上 `--budget` 照旧必给。
|
|
4995
|
-
*
|
|
4996
|
-
* 这一份答的是另一个问题:「表单打开时那个格子里印着什么」。两者混成一份的表现是
|
|
4997
|
-
* 网线那道闸整个消失 —— 任何一个不经表单的调用方从此都能建出一条没人想过预算的
|
|
4998
|
-
* 任务,而定时任务是没人看着的(一觉醒来那笔账已经花完了)。
|
|
4999
|
-
*
|
|
5000
|
-
* 判据全文、以及这个数撤掉了方案 45 §3.5 的哪一半,写在 protocol 的
|
|
5001
|
-
* `WireScheduleDefaults` 上。
|
|
5002
|
-
*/
|
|
5003
|
-
declare const SCHEDULE_FORM_BUDGET_USD = 200;
|
|
5004
5206
|
/**
|
|
5005
5207
|
* 新建任务时预填的最小清单(方案 45 §3.2 的落点)。
|
|
5006
5208
|
*
|
|
@@ -5326,8 +5528,10 @@ declare class ScheduleRegistrar {
|
|
|
5326
5528
|
*
|
|
5327
5529
|
* 1. `validateSchedule()` 照旧跑,红了就**一个字都不写**(半条任务比没有更糟);
|
|
5328
5530
|
* 2. 「无人值守下跑不出结果」的那两族措辞照旧**拒收**(`unattendedIssues`);
|
|
5329
|
-
* 3. `bypass`
|
|
5330
|
-
*
|
|
5531
|
+
* 3. `bypass` 档照旧要**正的超时**(`bypassIssues` 的 `bypass-needs-limits`),
|
|
5532
|
+
* 而工作目录不许宽到等于没绑。
|
|
5533
|
+
* ⚠️ **2026-10-29 起这条尺子只剩超时**:那一刻那条第 2 条里的「三把尺子」
|
|
5534
|
+
* 改成了「超时 + 轮次(而轮次缺省不限)」—— 判据在 `validate.ts` 上。
|
|
5331
5535
|
*
|
|
5332
5536
|
* ## ⚠️ 有一档仍然降级成提案:`plan`(只读调研模式)
|
|
5333
5537
|
*
|
|
@@ -5563,12 +5767,24 @@ declare function resolveSessionVisibility(input: SessionVisibilityInput): Sessio
|
|
|
5563
5767
|
* ## 为什么这值得一个工具
|
|
5564
5768
|
*
|
|
5565
5769
|
* `delegate_task` 派出去的子 agent 有**独立的 sessionId**,`fork()` 出来的会话
|
|
5566
|
-
* 也有 `parent_id`。于是「刚才那个子 agent
|
|
5567
|
-
*
|
|
5568
|
-
*
|
|
5770
|
+
* 也有 `parent_id`。于是「刚才那个子 agent 到底干了什么」可查:它的结论回来了
|
|
5771
|
+
* (一段 summary),而它中间读了哪些文件、试过哪些路、在哪一步拐弯,
|
|
5772
|
+
* 全在另一段会话里。
|
|
5569
5773
|
*
|
|
5570
5774
|
* 这一份给的就是那些 id:拿到之后接 `session_messages_search` 就能进去看。
|
|
5571
5775
|
*
|
|
5776
|
+
* ## ⚠️ 2026-10-27 之前这段说明是假话
|
|
5777
|
+
*
|
|
5778
|
+
* 那时子 agent 的过程**从来没落过盘**:`delegate-xxxxxxxx` 只是个临时字符串,
|
|
5779
|
+
* `sessions` 表里根本没有它那一行。于是上面那句话(以及 `docs/TOOLS.md` 里
|
|
5780
|
+
* 同一句)描述的是一个不存在的能力 —— 模型照着描述去查,查回来是空的,
|
|
5781
|
+
* 而它没有办法分辨「真没有」和「没存下来」。
|
|
5782
|
+
*
|
|
5783
|
+
* 修法不是改文案:`subRunner` 跑完之后把这一轮按步折下来落进库,并写上
|
|
5784
|
+
* `parent_id`(判据在 `runtime/src/session-factory.ts` 的 `persistDelegateTurn` 上)。
|
|
5785
|
+
* 那段会话的 `source` 是 `delegate`,所以它不会出现在「接着哪一段聊」的列表里
|
|
5786
|
+
* —— 列表那一边有 `includeDelegate` 这个开关,判据在 `DELEGATE_SESSION_SOURCE` 上。
|
|
5787
|
+
*
|
|
5572
5788
|
* ## 为什么不长在 [authorization.ts](./authorization.js) 里
|
|
5573
5789
|
*
|
|
5574
5790
|
* 那边的 `lineageOf()` 也走 `parent_id`,但它要的是**一串 id**(拼进 WHERE),
|
|
@@ -6840,6 +7056,22 @@ declare class TrackerDB {
|
|
|
6840
7056
|
countOpen(sessionId: string): number;
|
|
6841
7057
|
/** 全量替换会话的 TODO 列表(事务:DELETE + INSERT 批量) */
|
|
6842
7058
|
replaceAll(sessionId: string, todos: TodoItem[]): void;
|
|
7059
|
+
/**
|
|
7060
|
+
* 删掉一段会话的全部 TODO(2026-10-27)。返回删了几条。
|
|
7061
|
+
*
|
|
7062
|
+
* ## 什么时候需要它
|
|
7063
|
+
*
|
|
7064
|
+
* `delegate_task` 派出去的子任务用**自己那个** `sessionId` 写 TODO
|
|
7065
|
+
* (判据在 `AgentConfig.pendingTodos` 上:闸门要读的是「它自己那几件活」)。
|
|
7066
|
+
* 而那个 id 对应的 sessions 行是**跑完之后才补建的** —— 建行失败或压根没落盘时,
|
|
7067
|
+
* 这几行 TODO 就成了谁也删不掉的孤儿:`epoch sessions` 列不到它,
|
|
7068
|
+
* 会话保留期清理也扫不到它(那一支按 `sessions` 表扫)。
|
|
7069
|
+
*
|
|
7070
|
+
* 所以那一条失败路径上要主动收一下。正常路径**不在这儿删**:子会话已经有
|
|
7071
|
+
* 自己的 sessions 行了,`SessionDB.deleteSession` 会连带清掉
|
|
7072
|
+
* (判据在 db.ts 的 `DELETE FROM todos WHERE session_id = ?` 那一行)。
|
|
7073
|
+
*/
|
|
7074
|
+
deleteBySession(sessionId: string): number;
|
|
6843
7075
|
/** 释放连接(引用计数归零才真正关闭) */
|
|
6844
7076
|
close(): void;
|
|
6845
7077
|
}
|
|
@@ -10430,6 +10662,15 @@ interface BreakdownInput {
|
|
|
10430
10662
|
tool: EpochTool;
|
|
10431
10663
|
source: string;
|
|
10432
10664
|
}>;
|
|
10665
|
+
/**
|
|
10666
|
+
* 上一次请求的用量(2026-10-26)。**只用来算缓存那一格**,不给就整个缺席 ——
|
|
10667
|
+
* 「没跑过任何一轮」和「跑了一轮但一次没命中」是两件事,前者不该显示成 0%。
|
|
10668
|
+
*
|
|
10669
|
+
* 口径是**最近一次**而不是累计:累计值会随着高命中的历史越来越好看,
|
|
10670
|
+
* 从而掩盖「刚改的这一处根本没生效」—— 而这正是 {@link ContextBreakdown.cache}
|
|
10671
|
+
* 存在的理由。
|
|
10672
|
+
*/
|
|
10673
|
+
lastUsage?: TokenUsage;
|
|
10433
10674
|
}
|
|
10434
10675
|
declare function buildContextBreakdown(input: BreakdownInput): ContextBreakdown;
|
|
10435
10676
|
|
|
@@ -11155,6 +11396,34 @@ declare class AgentLoop {
|
|
|
11155
11396
|
private learnedSkills;
|
|
11156
11397
|
constructor(config: AgentConfig);
|
|
11157
11398
|
abort(): void;
|
|
11399
|
+
/**
|
|
11400
|
+
* 撞上「请求体太大」之后的第一段救援:**摘掉最老的几张图**,返回摘过的那份。
|
|
11401
|
+
*
|
|
11402
|
+
* ## 为什么它排在压缩之前(这是全套改动的判据所在)
|
|
11403
|
+
*
|
|
11404
|
+
* 1. **代价差一个量级**:摘图是纯本地操作(把 base64 换成一行占位),压缩是
|
|
11405
|
+
* 一发真实的摘要请求(花钱、要等几秒)。而这一档的现场绝大多数是图撑的
|
|
11406
|
+
* (`request-bytes.ts` 文件头那张量纲表),先试便宜的那个。
|
|
11407
|
+
* 2. **压缩的代价高得多,而且它动的是整段历史**:`compress()` 收到的是文本投影
|
|
11408
|
+
* (`message-codec.ts` 的 `flattenMessage` 明确把 `parts` 丢掉),所以图片
|
|
11409
|
+
* 它确实能拿掉。但拿掉图只是它的副作用 —— 它真正干的是把中段**整段换成一段
|
|
11410
|
+
* 摘要**,而那是不可逆的。仅仅为了几张老图就这么干,不值当。
|
|
11411
|
+
*
|
|
11412
|
+
* ## ⚠️ 目标**不能用 {@link imageBudget}**(实测踩到过)
|
|
11413
|
+
*
|
|
11414
|
+
* 走到这儿说明那一次**真的超了**,而 `imageBudget()` 正是撞墙前用的那个数。
|
|
11415
|
+
* 拿它当「摘到多少为止」,在「配置值给得太宽松」和「没有 `homeDir`、学不到
|
|
11416
|
+
* 值」这两档上都会得出「一张都不用摘」(图总量本来就小于那个宽松预算),
|
|
11417
|
+
* 于是救援原地空转、重发同一份东西。
|
|
11418
|
+
*
|
|
11419
|
+
* 撞墙这个事实本身就说明「必须比刚才小」,所以目标是**实发量打八折**
|
|
11420
|
+
* (同 `LEARN_SHRINK` 的口径:留两成余量)。学到的那个值只是让**下一次**
|
|
11421
|
+
* 不必先撞一次。
|
|
11422
|
+
*
|
|
11423
|
+
* @returns 摘动了就回新的 messages + 摘了几张;**一张都摘不掉时回 `null`**
|
|
11424
|
+
* —— 调用方据此知道「这一招不管用」,别拿一模一样的东西再撞一次墙
|
|
11425
|
+
*/
|
|
11426
|
+
private tryOffloadForBodyLimit;
|
|
11158
11427
|
/**
|
|
11159
11428
|
* 多模态策略的**现读出口**:尺寸上限来自 config,`supportsImages` 来自
|
|
11160
11429
|
* provider 自己(见 {@link AgentProvider.capabilities})。
|
|
@@ -11173,6 +11442,47 @@ declare class AgentLoop {
|
|
|
11173
11442
|
* 磁盘缓存)。相对一次模型调用,这个量级不值得为它留一个会说谎的快照。
|
|
11174
11443
|
*/
|
|
11175
11444
|
private multimodal;
|
|
11445
|
+
/**
|
|
11446
|
+
* 这一发该按多大的图片预算走 —— **配置/缺省值和学习值取小的那个**。
|
|
11447
|
+
*
|
|
11448
|
+
* ## 为什么每轮现算,不构造时算一次
|
|
11449
|
+
*
|
|
11450
|
+
* 判据逐字同 {@link multimodal}:**学习值会在一次 run 中途变化** ——
|
|
11451
|
+
* 撞上 1051 的那一刻 {@link learnBodyLimit} 刚把它写下去,而同一轮接下来的
|
|
11452
|
+
* 重发就该按新值(更紧的那个)走。构造时算一次的话,那一次重发用的还是撞墙
|
|
11453
|
+
* 前那个宽松的预算,于是再摘不掉、再撞一次。
|
|
11454
|
+
*
|
|
11455
|
+
* ## 没有 `homeDir` 时
|
|
11456
|
+
*
|
|
11457
|
+
* 不读历史学习值(盘上那份在哪都不知道),只用配置值/缺省值 —— 于是「学」
|
|
11458
|
+
* 这件事在这种宿主上不发生。这是一个**明确的降级**,不是 bug:没给数据目录的
|
|
11459
|
+
* 嵌入宿主不该被我们写文件。
|
|
11460
|
+
*/
|
|
11461
|
+
private imageBudget;
|
|
11462
|
+
/**
|
|
11463
|
+
* 记一笔「这个端点收不下这么大的图片」。best-effort:写不进去只是下次再撞一遍。
|
|
11464
|
+
*
|
|
11465
|
+
* ⚠️ 传进来的是**这一次真的发出去的字节数**(不是预算值)。两者的区别就是这条线
|
|
11466
|
+
* 的全部意义:预算可能比它小(那我们不该撞),撞上了说明预算偏大,而偏大多少
|
|
11467
|
+
* 只看这一次的实发量。
|
|
11468
|
+
*/
|
|
11469
|
+
private learnBodyLimit;
|
|
11470
|
+
/**
|
|
11471
|
+
* 学习缓存的三元组 `[homeDir, provider, model]` —— 没有 `homeDir` 时回
|
|
11472
|
+
* `undefined`,于是「学」和「读」两条路一起关掉。
|
|
11473
|
+
*
|
|
11474
|
+
* ⚠️ **`provider` 那一格只能退而求其次。** `body-limit-cache.ts` 的文件头要求
|
|
11475
|
+
* 缓存键带 provider(同一个裸名在两家下面可以是两个模型、端点更是各家自己的),
|
|
11476
|
+
* 但 `AgentLoop` 手上**没有** provider 类型:`AgentProvider` 只给 `modelId`
|
|
11477
|
+
* (一个裸名,`agent/types.ts`),provider 身份在 router 里,core 这一层够不着。
|
|
11478
|
+
*
|
|
11479
|
+
* 所以这里 provider 给空串,也就是**本机所有 provider 共享同一条学习值**。
|
|
11480
|
+
* 这是已知的精度损失,方向是**安全的那一侧**:两个端点里更保守的那个值被两边
|
|
11481
|
+
* 共用,代价是最慢那家让我们摘得比别家早一点(可逆、不花钱),而不是在宽松
|
|
11482
|
+
* 那家上撞墙。要修成真带 provider,得让装配层把它递进 `AgentConfig` ——
|
|
11483
|
+
* 那是一次跨包改契约,不在这一笔的范围里。
|
|
11484
|
+
*/
|
|
11485
|
+
private imageLimitKey;
|
|
11176
11486
|
/**
|
|
11177
11487
|
* 「这一轮会用哪个模型、它认不认图」——**给 system prompt 用的那一份**
|
|
11178
11488
|
* (2026-09-02)。判据全文在 `AgentProvider.modelId` 上。
|
|
@@ -11253,6 +11563,12 @@ declare class AgentLoop {
|
|
|
11253
11563
|
contextBreakdown(opts: {
|
|
11254
11564
|
historyText: string;
|
|
11255
11565
|
toolSource?: (name: string) => string | undefined;
|
|
11566
|
+
/**
|
|
11567
|
+
* 上一次请求的用量(2026-10-26)。只用来算缓存那一格 —— `/context` 要回答
|
|
11568
|
+
* 「我说了缓存到底有没有生效」,而这句话只能由 provider 报的真数回答。
|
|
11569
|
+
* 不给就是「这个宿主量不到」,那一格整个缺席(不是 0%)。
|
|
11570
|
+
*/
|
|
11571
|
+
lastUsage?: TokenUsage;
|
|
11256
11572
|
}): ContextBreakdown;
|
|
11257
11573
|
/** 执行一次对话,收敛成最终结果 */
|
|
11258
11574
|
run(input: RunInput): Promise<RunResult>;
|
|
@@ -12167,7 +12483,7 @@ declare function describeJsonError(err: unknown, text: string): string;
|
|
|
12167
12483
|
* | -------------------------------- | ------------------------------------------ |
|
|
12168
12484
|
* | `allowManagedPermissionRulesOnly` | 其余各层的 allow / ask / deny 全部忽略 |
|
|
12169
12485
|
* | `allowManagedHooksOnly` | 用户级 hook 一律不加载 |
|
|
12170
|
-
* | `disableBypassPermissionsMode` | `
|
|
12486
|
+
* | `disableBypassPermissionsMode` | 审批轴 = `never` 的那一档拒绝启动(今天就是 `auto`) |
|
|
12171
12487
|
*
|
|
12172
12488
|
* ## 这一层**不过信任闸门**,而且不该过
|
|
12173
12489
|
*
|
|
@@ -12246,12 +12562,17 @@ declare class ManagedPolicyError extends Error {
|
|
|
12246
12562
|
*
|
|
12247
12563
|
* ## 为什么是**拒绝启动**而不是静默降级到 default
|
|
12248
12564
|
*
|
|
12249
|
-
*
|
|
12565
|
+
* 降级是「更安全」的那一侧,但它会让用户以为自己在那一档里 —— 然后每一次
|
|
12250
12566
|
* 审批弹窗都成了怪现象,而真正的原因(IT 禁掉了这个级别)一个字都看不见。
|
|
12251
|
-
* 权限级别是用户**显式**要的东西(`--permission
|
|
12567
|
+
* 权限级别是用户**显式**要的东西(`--permission auto` 或 config.yaml 里那一行),
|
|
12252
12568
|
* 显式请求被策略挡下必须当面说,这跟「配了个不认识的级别回退到 default」
|
|
12253
12569
|
* 那种笔误不是一回事。
|
|
12254
12570
|
*
|
|
12571
|
+
* ⚠️ **2026-10-27 起它挡的是「审批轴 = `never`」这个组合,不再是一个档位名。**
|
|
12572
|
+
* 合并 `auto` + `bypass` 之后,「不问」这件事不再由某个档位名独有 ——
|
|
12573
|
+
* 用一个 `level === 'auto'` 判断也能对得上今天的代码,但那是第二份知识,
|
|
12574
|
+
* 下一次加一档 `never` 的档位时它会静默漏掉。
|
|
12575
|
+
*
|
|
12255
12576
|
* 挡的是级别本身,不区分它从哪一层来 —— `--permission`、`EPOCH_PERMISSION`、
|
|
12256
12577
|
* `~/.epoch/config.yaml` 最后都汇进同一个 `config.permission`,
|
|
12257
12578
|
* 在这里分叉等于把「哪个来源算数」这个问题又答一遍。
|
|
@@ -13600,13 +13921,7 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
13600
13921
|
maxOutputTokens: z.ZodOptional<z.ZodInt>;
|
|
13601
13922
|
homeDir: z.ZodDefault<z.ZodString>;
|
|
13602
13923
|
dbPath: z.ZodDefault<z.ZodString>;
|
|
13603
|
-
permission: z.ZodDefault<z.
|
|
13604
|
-
default: "default";
|
|
13605
|
-
acceptEdits: "acceptEdits";
|
|
13606
|
-
plan: "plan";
|
|
13607
|
-
auto: "auto";
|
|
13608
|
-
bypass: "bypass";
|
|
13609
|
-
}>>;
|
|
13924
|
+
permission: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<"default" | "acceptEdits" | "plan" | "auto", string>>;
|
|
13610
13925
|
permissions: z.ZodOptional<z.ZodObject<{
|
|
13611
13926
|
allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13612
13927
|
ask: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -13634,6 +13949,9 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
13634
13949
|
sandbox: z.ZodPrefault<z.ZodObject<{
|
|
13635
13950
|
terminal: z.ZodDefault<z.ZodBoolean>;
|
|
13636
13951
|
}, z.core.$strip>>;
|
|
13952
|
+
delegate: z.ZodPrefault<z.ZodObject<{
|
|
13953
|
+
taskTimeoutSec: z.ZodDefault<z.ZodInt>;
|
|
13954
|
+
}, z.core.$strip>>;
|
|
13637
13955
|
tools: z.ZodPrefault<z.ZodObject<{
|
|
13638
13956
|
deferMcp: z.ZodDefault<z.ZodBoolean>;
|
|
13639
13957
|
mode: z.ZodDefault<z.ZodEnum<{
|
|
@@ -13649,6 +13967,9 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
13649
13967
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
13650
13968
|
threshold: z.ZodDefault<z.ZodNumber>;
|
|
13651
13969
|
}, z.core.$strip>>;
|
|
13970
|
+
limits: z.ZodPrefault<z.ZodObject<{
|
|
13971
|
+
maxRequestImageBytes: z.ZodOptional<z.ZodInt>;
|
|
13972
|
+
}, z.core.$strip>>;
|
|
13652
13973
|
memory: z.ZodPrefault<z.ZodObject<{
|
|
13653
13974
|
memoryCharLimit: z.ZodDefault<z.ZodInt>;
|
|
13654
13975
|
userCharLimit: z.ZodDefault<z.ZodInt>;
|
|
@@ -13796,6 +14117,10 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
13796
14117
|
}> & z.core.$partial, z.ZodString>>;
|
|
13797
14118
|
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
13798
14119
|
}, z.core.$strip>>;
|
|
14120
|
+
scheduleRemoveConfirm: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
|
|
14121
|
+
zh: "zh";
|
|
14122
|
+
en: "en";
|
|
14123
|
+
}> & z.core.$partial, z.ZodString>>;
|
|
13799
14124
|
user: z.ZodOptional<z.ZodObject<{
|
|
13800
14125
|
label: z.ZodString;
|
|
13801
14126
|
icon: z.ZodOptional<z.ZodString>;
|
|
@@ -14378,6 +14703,177 @@ interface SchemaExport {
|
|
|
14378
14703
|
*/
|
|
14379
14704
|
declare function buildSchemaExports(): SchemaExport[];
|
|
14380
14705
|
|
|
14706
|
+
/**
|
|
14707
|
+
* 配置键的**全量**表 —— 从 `EpochConfigSchema` 派生,一个字都不手抄。
|
|
14708
|
+
*
|
|
14709
|
+
* ## 它存在的原因
|
|
14710
|
+
*
|
|
14711
|
+
* `epoch config set` 原来认 24 个键,而那 24 个是**手抄**在三张 `Record` 里的
|
|
14712
|
+
* (`SCALAR_FIELDS` / `SECTION_FIELDS` / `BUDGET_FIELDS`)。schema 有 45 个顶层键 /
|
|
14713
|
+
* 83 个叶子,于是「知道的」和「能改的」差着五十多个 —— 而那个差距在任何一屏上都
|
|
14714
|
+
* 看不见:用户(或模型)照着 schema / 文档敲一个键,收到的是「未知配置项」,
|
|
14715
|
+
* 它读起来和「这个功能没做」一模一样。
|
|
14716
|
+
*
|
|
14717
|
+
* `cli/commands/config.ts` 的注释里记着这个坑的三次前科(`permission` / `shell` /
|
|
14718
|
+
* 设置页那一串),每一次都是手抄名单落下的。这一份把它从根上断掉:**清单只有
|
|
14719
|
+
* schema 一个真源**,`set` / `unset` / 报错提示 / `config list` 全部查这张表。
|
|
14720
|
+
*
|
|
14721
|
+
* ## 值域也是派生的
|
|
14722
|
+
*
|
|
14723
|
+
* {@link checkConfigValue} 按 JSON Schema 的 `type` / `enum` / `minimum` /
|
|
14724
|
+
* `exclusiveMinimum` / `maximum` / `minLength` 校验 —— 那几格正是 zod 的
|
|
14725
|
+
* `.int().positive().max(10000)` / `.enum([...])` / `.min(1)` 编译出来的东西
|
|
14726
|
+
* (实测:`automation.keepRuns` 拿到 `exclusiveMinimum: 0, maximum: 10000`,
|
|
14727
|
+
* `budget.onUnknownPricing` 拿到 `enum: ['block','warn']`)。
|
|
14728
|
+
*
|
|
14729
|
+
* 于是 `epoch config set` 的值域**永远等于 schema**,而不再是「另一份人肉对齐的
|
|
14730
|
+
* 近似」。这一层原来最容易出错的形态是「放行 `1.5`,而引擎那侧是 `z.int()`,
|
|
14731
|
+
* 于是整份配置退回默认值」—— `sessions.retentionDays` 与 `automation.*` 两处
|
|
14732
|
+
* 的注释各记了一次。
|
|
14733
|
+
*
|
|
14734
|
+
* ## 三档可写性,判据写在每一档旁边
|
|
14735
|
+
*
|
|
14736
|
+
* | 档 | 判据 | 今天几个 |
|
|
14737
|
+
* | --- | --- | --- |
|
|
14738
|
+
* | `scalar` | 顶层标量,或**一层** `段.字段`,且不是 {@link BLOCKED} 里那三个 | 37 |
|
|
14739
|
+
* | `manual` | 两层以上的路径,或数组 / 对象 | 40 |
|
|
14740
|
+
* | `blocked` | 「位置 / 身份」类的三个键 | 3 |
|
|
14741
|
+
*
|
|
14742
|
+
* ### 为什么两层以上的路径不开放
|
|
14743
|
+
*
|
|
14744
|
+
* `setSectionField` 的就地改写只做一层(`infra/src/config-yaml.ts` 文件头那句
|
|
14745
|
+
* 「代价是只能改标量和一层嵌套——够用」)。把它扩成正则任意深度,要处理每一层
|
|
14746
|
+
* 的缩进、兄弟字段和注释归属,而那个手术碰坏用户注释的形态是静默的。
|
|
14747
|
+
*
|
|
14748
|
+
* 更硬的一条在 `display.currency` 上:它的 `code` / `rate` 在 schema 里是
|
|
14749
|
+
* **required 成对**的(JSON Schema 那句 `required: ['code','rate']`)。只写一个,
|
|
14750
|
+
* 整份配置过不了 `EpochConfigSchema`,而 loader 的语义是「不逐字段抢救」——
|
|
14751
|
+
* 结果是**整份配置连同模型和 key 一起退回默认值**。为一个货币单位付这个代价
|
|
14752
|
+
* 不值得,所以这一族留给人手改文件(手改时他看得见旁边那一行)。
|
|
14753
|
+
*
|
|
14754
|
+
* ### 为什么 {@link BLOCKED} 那三个键连手改都算「不是设置」
|
|
14755
|
+
*
|
|
14756
|
+
* 它们不是「某个开关的值」,是「数据放在哪 / 我是哪个档」。而这三个键今天的
|
|
14757
|
+
* 真源**不在 config.yaml 里**:
|
|
14758
|
+
*
|
|
14759
|
+
* - `profile`:唯一真源是环境变量 `EPOCH_PROFILE`(`infra/src/paths.ts` 的
|
|
14760
|
+
* `resolveHomeDir()` / `resolveProfile()` 都只读环境变量)。写进 yaml 一个字都
|
|
14761
|
+
* 不会切目录,只会让「关于」那一屏(`WireAbout.profile`)报一个假的当前档。
|
|
14762
|
+
* - `homeDir`:有两套解析真源 —— `paths.ts` 那一家只看 `EPOCH_HOME` /
|
|
14763
|
+
* `EPOCH_PROFILE`,而 runtime 到处读 `config.homeDir`。写它不会让配置文件搬家
|
|
14764
|
+
* (`configPath()` 照样在旧家),只会让**数据**跑去新家,于是同一个进程里
|
|
14765
|
+
* 配置文件、会话库、凭据分散在两个目录。
|
|
14766
|
+
* - `dbPath`:同族,而且切得更碎 —— `runtime/src/services.ts` 读
|
|
14767
|
+
* `config.dbPath`,而 `runtime/src/schedule/control.ts` 用的是
|
|
14768
|
+
* `dbPath(homeDir)`。写它只切走一半的库。
|
|
14769
|
+
*
|
|
14770
|
+
* 换句话说:把这三个键放行不会「让配置更灵活」,只会造出一台**看起来改了、
|
|
14771
|
+
* 其实只改了一半**的机器。要搬家的正路是环境变量(`EPOCH_HOME` /
|
|
14772
|
+
* `EPOCH_PROFILE`),那是它们本来的入口。
|
|
14773
|
+
*
|
|
14774
|
+
* ### 另外三个键的单独判据(写在这一层,是因为它们各自的原因不一样)
|
|
14775
|
+
*
|
|
14776
|
+
* - **`modelEntries`**:schema 上自己写着「写在 config.yaml 里不生效」——
|
|
14777
|
+
* 真源是 `models.json`,loader 读到这一格会报一条 `legacy_ignored`。
|
|
14778
|
+
* - **`hooks`**:旧格式,已搬去 `hooks.json`。这一格只保证「是个对象」,
|
|
14779
|
+
* 内部结构由 hook 自己的 schema 校验(这里给它写一个字段表就等于维护第二份)。
|
|
14780
|
+
* - **`display.currency.code` / `.rate`**:两格在 schema 里是 **required 成对**的
|
|
14781
|
+
* (`required: ['code','rate']`)。只写一个,整份配置过不了校验、按 loader
|
|
14782
|
+
* 一贯的「不逐字段抢救」退回默认值 —— 模型和 key 一起没。
|
|
14783
|
+
*/
|
|
14784
|
+
|
|
14785
|
+
/** 一个叶子能是的那几种标量。数组 / 对象不在这里 */
|
|
14786
|
+
type ConfigKeyKind = 'string' | 'integer' | 'number' | 'boolean';
|
|
14787
|
+
/**
|
|
14788
|
+
* 这个键能不能通过 `epoch config set` 写。
|
|
14789
|
+
*
|
|
14790
|
+
* 三档的含义和判据见文件头那张表 —— **别照着名字猜**,
|
|
14791
|
+
* `blocked` 不是「危险」,是「它不是设置」。
|
|
14792
|
+
*/
|
|
14793
|
+
type ConfigKeyWrite = 'scalar' | 'manual' | 'blocked';
|
|
14794
|
+
/**
|
|
14795
|
+
* 不能 `config set` 的**原因码**。
|
|
14796
|
+
*
|
|
14797
|
+
* ⚠️ 这一格是给 CLI 翻译用的,**不是给人读的** —— 人读的是 catalog 里那几句
|
|
14798
|
+
* (`cli.config.manual_nested` / `manual_structured` / `not_a_setting`)。
|
|
14799
|
+
*
|
|
14800
|
+
* 为什么不在表里存一句「为什么不能写」的中文描述:`config set` / `config list`
|
|
14801
|
+
* 会把它拼进输出,而英文界面上就长出一句英文夹中文的话。存原因码、
|
|
14802
|
+
* 让文案走 catalog,两边各自才是对的。
|
|
14803
|
+
*/
|
|
14804
|
+
type ConfigKeyReason = 'position' | 'structured' | 'nested';
|
|
14805
|
+
/** 键表里的一行 */
|
|
14806
|
+
interface ConfigKeyEntry {
|
|
14807
|
+
/** 点分路径,和 `config.yaml` 里的写法逐字一致(`budget.maxCostUsd`) */
|
|
14808
|
+
path: string;
|
|
14809
|
+
/** 段名;顶层键没有这一格 */
|
|
14810
|
+
section?: string;
|
|
14811
|
+
/** 段内的字段名;顶层键没有这一格 */
|
|
14812
|
+
field?: string;
|
|
14813
|
+
kind: ConfigKeyKind;
|
|
14814
|
+
write: ConfigKeyWrite;
|
|
14815
|
+
/** `write !== 'scalar'` 时**必有**:不能 `config set` 的原因码(CLI 据此选文案) */
|
|
14816
|
+
reason?: ConfigKeyReason;
|
|
14817
|
+
/** 枚举型键的可选值 */
|
|
14818
|
+
choices?: readonly string[];
|
|
14819
|
+
minimum?: number;
|
|
14820
|
+
exclusiveMinimum?: number;
|
|
14821
|
+
maximum?: number;
|
|
14822
|
+
exclusiveMaximum?: number;
|
|
14823
|
+
minLength?: number;
|
|
14824
|
+
/** schema 里写的内置默认值。没有默认值的键(`model` / `budget.maxCostUsd` …)不带这格 */
|
|
14825
|
+
builtin?: SettingValue;
|
|
14826
|
+
}
|
|
14827
|
+
/**
|
|
14828
|
+
* 全部配置键,按 schema 里的声明顺序排。
|
|
14829
|
+
*
|
|
14830
|
+
* 调用方**不许**改它(`readonly`),也不许在别处再抄一份 —— 报错提示、
|
|
14831
|
+
* `config list`、`config set` / `unset` 认的键必须来自这一个数组。
|
|
14832
|
+
*/
|
|
14833
|
+
declare function configKeyTable(): readonly ConfigKeyEntry[];
|
|
14834
|
+
/** 按点分路径查一行;不认识的键返回 `undefined`(调用方据此报「未知配置项」) */
|
|
14835
|
+
declare function configKeyByPath(path: string): ConfigKeyEntry | undefined;
|
|
14836
|
+
/**
|
|
14837
|
+
* 全部能 `config set` 的键。报错提示和 `config list --all` 都从这里取。
|
|
14838
|
+
*
|
|
14839
|
+
* 顺序就是 schema 的顺序 —— 分段天然相邻,不需要再排一次。
|
|
14840
|
+
*/
|
|
14841
|
+
declare function writableConfigKeys(): readonly ConfigKeyEntry[];
|
|
14842
|
+
/** 校验失败的原因。带格子是因为 CLI 要把它拼进一句人话(catalog 里那几条) */
|
|
14843
|
+
type ConfigValueProblem = {
|
|
14844
|
+
code: 'not-a-kind';
|
|
14845
|
+
kind: ConfigKeyKind;
|
|
14846
|
+
} | {
|
|
14847
|
+
code: 'not-in-choices';
|
|
14848
|
+
choices: readonly string[];
|
|
14849
|
+
} | {
|
|
14850
|
+
code: 'below-minimum';
|
|
14851
|
+
bound: number;
|
|
14852
|
+
exclusive: boolean;
|
|
14853
|
+
} | {
|
|
14854
|
+
code: 'above-maximum';
|
|
14855
|
+
bound: number;
|
|
14856
|
+
exclusive: boolean;
|
|
14857
|
+
} | {
|
|
14858
|
+
code: 'too-short';
|
|
14859
|
+
minLength: number;
|
|
14860
|
+
};
|
|
14861
|
+
/** {@link checkConfigValue} 的结论。成功时带上**该写进 yaml 的字面量** */
|
|
14862
|
+
type ConfigValueCheck = {
|
|
14863
|
+
ok: true;
|
|
14864
|
+
literal: string;
|
|
14865
|
+
} | {
|
|
14866
|
+
ok: false;
|
|
14867
|
+
problem: ConfigValueProblem;
|
|
14868
|
+
};
|
|
14869
|
+
/**
|
|
14870
|
+
* 一个字符串能不能当这个键的值,以及它该以什么字面量写进 yaml。
|
|
14871
|
+
*
|
|
14872
|
+
* 校验顺序是固定的:类型 → 枚举 → 边界 → 长度。顺序有意义 —— 反过来的话
|
|
14873
|
+
* `budget.warnAtPercent: abc` 会先撞上「不在 0~100 之间」,而真正的问题是它不是个数。
|
|
14874
|
+
*/
|
|
14875
|
+
declare function checkConfigValue(entry: ConfigKeyEntry, raw: string): ConfigValueCheck;
|
|
14876
|
+
|
|
14381
14877
|
/**
|
|
14382
14878
|
* `~/.epoch/keybindings.json` 的加载(方案 31 PR-1 / PR-2)。
|
|
14383
14879
|
*
|
|
@@ -15680,6 +16176,30 @@ interface Session {
|
|
|
15680
16176
|
/** 获取上下文窗口内的消息 [OpenCode] */
|
|
15681
16177
|
getContext(maxTokens?: number): Message[];
|
|
15682
16178
|
}
|
|
16179
|
+
/**
|
|
16180
|
+
* `delegate_task` 派出去的子任务,在 `sessions.source` 上记的那一档。
|
|
16181
|
+
*
|
|
16182
|
+
* ## 为什么要有一个自己的 source,而不是沿用 `'cli'`
|
|
16183
|
+
*
|
|
16184
|
+
* 子会话从 2026-10-27 起**真的会落盘**(在那之前只有一段临时 id,库里的
|
|
16185
|
+
* `sessions` 表根本没有它那一行 —— 判据在 `runtime` 的 `subRunner` 上)。
|
|
16186
|
+
* 落盘之后它就和用户自己的对话长得一模一样了,而这是两件事:
|
|
16187
|
+
*
|
|
16188
|
+
* - **它不是「用户的一段对话」**:`epoch -r`(最近一段)、`epoch -c`
|
|
16189
|
+
* (这个目录下最近一段)接上去都接错了对象 —— 用户想接着聊的是他自己那段,
|
|
16190
|
+
* 不是十分钟前派出去的那个子任务。
|
|
16191
|
+
* - **但它的过程必须读得到**:`session_trace` 从父会话沿着 `parent_id` 往下走,
|
|
16192
|
+
* 要能列出它;`session_messages_read` 要能读回它每一步调了什么工具。
|
|
16193
|
+
*
|
|
16194
|
+
* 所以这两条路被刻意分开了:**列表 / `-r` / `-c` 默认排除它**(判据在
|
|
16195
|
+
* `SessionDB.listSessions` 的 `includeDelegate` 上),**血缘和消息读回不排除**
|
|
16196
|
+
* (那两条走的是各自的 SQL,不经过列表)。
|
|
16197
|
+
*
|
|
16198
|
+
* ⚠️ 这是一个**跨包的名字**:`core`(写行 / 列表过滤)和 `runtime`(建行)各用
|
|
16199
|
+
* 一次,所以真源只在这儿一份。字符串抄两遍的下场是有人改了其中一处,
|
|
16200
|
+
* 而表现只是「子会话忽然出现在列表里」—— 没有一处会红。
|
|
16201
|
+
*/
|
|
16202
|
+
declare const DELEGATE_SESSION_SOURCE = "delegate";
|
|
15683
16203
|
interface CreateSessionInput {
|
|
15684
16204
|
id?: string;
|
|
15685
16205
|
title?: string;
|
|
@@ -15773,6 +16293,17 @@ interface ListSessionsInput {
|
|
|
15773
16293
|
* 再传进来(我们这边的同步层退 2s),代价只是重复拉几行、而那是幂等的。
|
|
15774
16294
|
*/
|
|
15775
16295
|
updatedSince?: number;
|
|
16296
|
+
/**
|
|
16297
|
+
* 要不要把 `delegate_task` 派出去的子任务会话一起列出来。**默认不要。**
|
|
16298
|
+
*
|
|
16299
|
+
* 判据在 {@link DELEGATE_SESSION_SOURCE} 上:子会话不是用户的一段对话,
|
|
16300
|
+
* 而 `epoch -r` / `epoch -c` / 侧栏列表问的都是「接着哪一段聊」。
|
|
16301
|
+
* 它落盘是为了 `session_trace` + `session_messages_read` 读得回过程,
|
|
16302
|
+
* 那条路上不经过这里。
|
|
16303
|
+
*
|
|
16304
|
+
* 只有「这个库里一共有哪些行」这一类调用方(增量备份、诊断)才该传 `true`。
|
|
16305
|
+
*/
|
|
16306
|
+
includeDelegate?: boolean;
|
|
15776
16307
|
}
|
|
15777
16308
|
interface ListSessionsOutput {
|
|
15778
16309
|
sessions: SessionMeta[];
|
|
@@ -16390,6 +16921,11 @@ declare class SessionManager implements SessionManager$1 {
|
|
|
16390
16921
|
* 那不是摘要,是残缺的原文,句子往往截在一半,喂回模型比不给更糟。
|
|
16391
16922
|
*/
|
|
16392
16923
|
compact(sessionId: string, summarize?: (transcript: string) => Promise<string | null>): Promise<CompactionResult>;
|
|
16924
|
+
/**
|
|
16925
|
+
* 把库里那几张图片下放成一行占位(2026-10-28)。判据全文在
|
|
16926
|
+
* {@link SessionDB.offloadImageParts} 上 —— 这一层只是转发,**一个数都不算**。
|
|
16927
|
+
*/
|
|
16928
|
+
offloadImageParts(sessionId: string): number;
|
|
16393
16929
|
/**
|
|
16394
16930
|
* 把引擎刚压完的那一次落进库里(方案 64 PR-1)。判据全文在
|
|
16395
16931
|
* {@link SessionDB.archiveAndCompact} 上 —— 这一层只是转发,**一个数都不算**。
|
|
@@ -17368,18 +17904,25 @@ declare const MAX_AUDIT_ENTRIES = 500;
|
|
|
17368
17904
|
* 拆的直接原因是 manager.ts 越过了 500 行硬线,但拆得动本身说明这一档确实
|
|
17369
17905
|
* 独立:它是「没有任何规则命中时的兜底」,语义上不该和规则匹配混在一个类里。
|
|
17370
17906
|
*
|
|
17371
|
-
*
|
|
17907
|
+
* 四档的意图(对标 Hermes `approval.py` + deepseek-harness 的两根轴):
|
|
17908
|
+
*
|
|
17909
|
+
* | 级别 | 审批 | 沙箱 | 意图 |
|
|
17910
|
+
* | ------------- | ---- | -------------------- | --------------------------------------------- |
|
|
17911
|
+
* | `auto` | never| `danger-full-access` | 全放行,**但底线那一层照旧**:灾难级拒、tier-2 拒、判不了放行 |
|
|
17912
|
+
* | `plan` | ask | `read-only` | 只读:写入 / 网络 / 执行代码一律拒,**只读命令放行**;区外**读**要问 |
|
|
17913
|
+
* | `acceptEdits` | ask | `workspace-write` | 同 `auto`,但**工作区外的文件**要确认 |
|
|
17914
|
+
* | `default` | ask | `workspace-write` | 只读操作免确认(**工作区外的读除外**),其余一律确认 |
|
|
17372
17915
|
*
|
|
17373
|
-
*
|
|
17374
|
-
*
|
|
17375
|
-
*
|
|
17376
|
-
*
|
|
17377
|
-
*
|
|
17378
|
-
*
|
|
17379
|
-
*
|
|
17916
|
+
* ## ⚠️ 2026-10-27:五档并成四档,`bypass` 并进 `auto`
|
|
17917
|
+
*
|
|
17918
|
+
* 实测(真 `PermissionManager` 跑 15 项日常操作)合并前的弹窗数是
|
|
17919
|
+
* **11 / 5 / 2 / 1**(default / acceptEdits / auto / bypass),而 `auto` 与
|
|
17920
|
+
* `bypass` 只差「判不了」那一格外加规则表 `ask` 那一族 —— 两档说不出
|
|
17921
|
+
* 「用户凭什么选它而不是另一个」。合并方向取宽的({@link ruleAskActive} 现在
|
|
17922
|
+
* 只对 `auto` 为假),老名字 `bypass` 走 protocol 的别名表静默映射过来。
|
|
17380
17923
|
*
|
|
17381
17924
|
* ⚠️ **「工作区外」那一格是 `plan` / `default` / `acceptEdits` 三档共用的**
|
|
17382
|
-
* (2026-10-08):`auto`
|
|
17925
|
+
* (2026-10-08):`auto` 放行,其余三档问一句,判据在
|
|
17383
17926
|
* {@link outsideWorkspace} 上。**档位管的是「问了之后算不算数」,不是「要不要问」**
|
|
17384
17927
|
* —— 而「算不算数」由权限层算出来的 `grantedPaths` 兑现,工具层照它放行
|
|
17385
17928
|
* (判据在 protocol 的 `ToolContext.grantedPaths` 上)。
|
|
@@ -17389,7 +17932,7 @@ declare const MAX_AUDIT_ENTRIES = 500;
|
|
|
17389
17932
|
*
|
|
17390
17933
|
* ## ⚠️ 这一档哪天要用「沙箱模式」,调 `sandboxModeForLevel()`,别在这儿长第二张表
|
|
17391
17934
|
*
|
|
17392
|
-
*
|
|
17935
|
+
* 上面那张四档表还有一个孪生兄弟:**同样四档 → 沙箱模式**(`read-only` /
|
|
17393
17936
|
* `workspace-write` / `danger-full-access`),它今天住在
|
|
17394
17937
|
* [infra/src/sandbox/policy.ts](../../../infra/src/sandbox/policy.ts)。
|
|
17395
17938
|
* 方案 46 §2.2 原文说那段推导本该住在这个文件旁边(「那是权限系统的知识,
|
|
@@ -17800,29 +18343,52 @@ declare class PermissionManager implements PermissionManager$1 {
|
|
|
17800
18343
|
* plan 模式下一条判不了的命令会弹给用户,用户点「允许」它就真跑了 ——
|
|
17801
18344
|
* 而 `checkPlan()` 那句「plan 模式禁止写入和命令执行」压根没机会说话。
|
|
17802
18345
|
*
|
|
17803
|
-
* 2. **`
|
|
18346
|
+
* 2. **`never` 档下要人确认的底线分成两小支,落点相反**(2026-10-27 定的第二支)。
|
|
18347
|
+
*
|
|
18348
|
+
* 2a. **`obfuscated` → 放行。** 排在缓存前面,于是「`never` 整段不查
|
|
17804
18349
|
* 审批缓存」({@link checkRulesAndCache} 那一节)对**规则那条路**逐字仍然成立。
|
|
18350
|
+
* 塌向「放行」的理由:这条判定的原话是「静态检查无法判定其真实行为,需人工确认」
|
|
18351
|
+
* —— 它是一句「我判不了」,不是一句「这危险」,而这一档的字面意思正是
|
|
18352
|
+
* 「别拿你判不了的事来问我」。逐字就是 Hermes 的 yolo。
|
|
17805
18353
|
*
|
|
17806
|
-
* ⚠️
|
|
17807
|
-
* `
|
|
17808
|
-
*
|
|
17809
|
-
*
|
|
17810
|
-
*
|
|
18354
|
+
* ⚠️ **代价说清楚**:这一档 + 提示注入 + `$(…)` 拼命令名这条路由此打通。
|
|
18355
|
+
* Hermes 在 `tools/approval.py` 那句 `# this and bypass every approval check
|
|
18356
|
+
* (prompt-injection escalation path)` 上承认的是同一个敞口。不接受的人该做的
|
|
18357
|
+
* 是**别用这一档**,而不是让这一档偷偷弹框 —— 一个说了「不问」却还在问的
|
|
18358
|
+
* 开关,会让用户学会闭眼点「允许」,那比敞口更坏。
|
|
17811
18359
|
*
|
|
17812
|
-
*
|
|
17813
|
-
* 判定其真实行为,需人工确认」—— 它是一句「我判不了」,不是一句「这危险」,
|
|
17814
|
-
* 而 `bypass` 的字面意思正是「别拿你判不了的事来问我」。这一档下**逐字就是
|
|
17815
|
-
* Hermes 的 yolo**(它的 floor 只有 hardline,判不了那一族住在 Tier-2、
|
|
17816
|
-
* 被 yolo 整段跳过)。
|
|
18360
|
+
* 2b. **`dangerous-command`(tier-2,危险但可恢复)→ 拒绝。**
|
|
17817
18361
|
*
|
|
17818
|
-
* ⚠️
|
|
17819
|
-
*
|
|
17820
|
-
*
|
|
17821
|
-
*
|
|
17822
|
-
*
|
|
18362
|
+
* ## ⚠️ 2026-10-27:这一支从「问一句」翻成「拒绝」(用户拍的)
|
|
18363
|
+
*
|
|
18364
|
+
* 原判据(2026-09-10)是「危险的问一句(点了就能干活)、判不了的不问」。
|
|
18365
|
+
* 它当时是对的 —— 那一版把「危险」和「判不了」一起塌成放行,而最高档下
|
|
18366
|
+
* `sudo apt install` 永远做不了是一句更坏的话。
|
|
18367
|
+
*
|
|
18368
|
+
* 翻过来的理由是**两家参照实现在这一点上一致,而只有我们不同**:
|
|
18369
|
+
*
|
|
18370
|
+
* - Codex `exec_policy.rs:812`:`AskForApproval::Never => Decision::Forbidden`,
|
|
18371
|
+
* 注释原文「we prefer to prompt the user rather than outright forbid the
|
|
18372
|
+
* command, but if the user has explicitly disabled prompts, we must forbid」;
|
|
18373
|
+
* - deepseek-harness `user-approval/src/index.ts` 的 `ApprovalPolicy`:`'never'`
|
|
18374
|
+
* 的定义是「every ask resolves `'rejected'` deterministically」。
|
|
18375
|
+
*
|
|
18376
|
+
* 两家都是**拒绝**,而这一档承诺的是「不问」—— 承诺兑现之后必须有一个落点,
|
|
18377
|
+
* 两家一致选了拒绝(fail closed),我们照此对齐。
|
|
18378
|
+
*
|
|
18379
|
+
* ⚠️ **落到用户身上的代价**:`auto` 档下 `sudo apt install` /
|
|
18380
|
+
* `git push --force` / `chmod 777` 这类**做不了**,模型会收到一句拒绝而不是
|
|
18381
|
+
* 一个可以点的出口。要干这些事得换回 `default` 或 `acceptEdits` 档 ——
|
|
18382
|
+
* 那两档照旧弹窗,点了就能干活。这条差别是刻意的:**这一档不再提供
|
|
18383
|
+
* 「点一下就放行」这个出口**,它只提供「不问」。
|
|
18384
|
+
*
|
|
18385
|
+
* ⚠️ **灾难级(`rm -rf /`)不受影响**:它在 `hard-limits.ts` 里直接
|
|
18386
|
+
* 不带 `requireApproval`,压根走不到这个方法。
|
|
18387
|
+
*
|
|
18388
|
+
* ⚠️ **`plan` 档不受影响**:第 1 条在它前面就 return 了。
|
|
17823
18389
|
*
|
|
17824
18390
|
* 3. **用户以前对这一条明确答过 → 照他的答复。** 这是另一个缺陷:审批缓存躺在
|
|
17825
|
-
*
|
|
18391
|
+
* 这一层**后面**,所以一条 tier-2 危险的命令上点一百次「永久允许」,
|
|
17826
18392
|
* 第一百零一次照样弹 —— 那个出口在这一族上是**画着但不通**的。
|
|
17827
18393
|
*
|
|
17828
18394
|
* ⚠️ 这里查缓存**不受 `approvalCacheActive()` 约束**(那条只管规则那条路):
|
|
@@ -17830,6 +18396,11 @@ declare class PermissionManager implements PermissionManager$1 {
|
|
|
17830
18396
|
* 2026-08-17 那条判据(`bypass` 下缓存的 deny 不该拦住任何东西)没有被翻 ——
|
|
17831
18397
|
* 它说的是**档位本来就放行**的操作,而这一支下面的操作档位从来不放行。
|
|
17832
18398
|
*
|
|
18399
|
+
* ⚠️ **2026-10-27 起它在「不问」那一档的 tier-2 拒绝之前**,这是刻意的:
|
|
18400
|
+
* 用户在 `default` / `acceptEdits` 档下点过「永久允许」的 `sudo apt install`,
|
|
18401
|
+
* 换到 `auto` 档之后**照旧放行** —— 那是一个真实的授权,`never` 的意思是
|
|
18402
|
+
* 「别拿没授权的事来问我」,不是「我批过的也不作数」。要撤销去审批面板撤。
|
|
18403
|
+
*
|
|
17833
18404
|
* 这不是「让缓存绕过黑名单」:绕不过的是 deny 形状的那两条(灾难级危险命令、
|
|
17834
18405
|
* 敏感路径),它们在 `hard.requireApproval` 为假时压根走不到这儿。
|
|
17835
18406
|
*
|
|
@@ -17838,12 +18409,16 @@ declare class PermissionManager implements PermissionManager$1 {
|
|
|
17838
18409
|
*/
|
|
17839
18410
|
private settleUnaskable;
|
|
17840
18411
|
/**
|
|
17841
|
-
* **规则那条路**上会不会查审批缓存(2026-08-17 的判据:`
|
|
18412
|
+
* **规则那条路**上会不会查审批缓存(2026-08-17 的判据:`never` 那一档整段不查,
|
|
17842
18413
|
* 全文在 {@link checkRulesAndCache} 上)。
|
|
17843
18414
|
*
|
|
17844
18415
|
* ⚠️ **它不是「这个档位记不记得住」**:安全底线那条路({@link settleUnaskable})
|
|
17845
18416
|
* 在任何档位下都查缓存。宿主要知道的是**这一次问的这道题**记不记得住,
|
|
17846
18417
|
* 那个答案在 `PermissionDecision.rememberable` 上,由 {@link rememberFlag} 打。
|
|
18418
|
+
*
|
|
18419
|
+
* ⚠️ 2026-10-27 起它和 {@link ruleAskActive} 走同一个判据(审批轴),但**仍是
|
|
18420
|
+
* 两个方法**:一个问「规则表说要问,这一档还问不问」,一个问「弹窗答案的记忆
|
|
18421
|
+
* 这一档查不查」。合并成一处的话,哪天其中一条改了判据,另一条会**无声地**跟着改。
|
|
17847
18422
|
*/
|
|
17848
18423
|
approvalCacheActive(): boolean;
|
|
17849
18424
|
/**
|
|
@@ -18551,7 +19126,7 @@ declare function nextRunAt(trigger: ScheduleTrigger, from?: number, startDate?:
|
|
|
18551
19126
|
* 那是「这个任务每天都失败,而你要三天后才发现」。所以保存时校验、
|
|
18552
19127
|
* 校验不过不许存 —— 定时任务的反馈回路按天算,能提前的每一步都值钱。
|
|
18553
19128
|
*
|
|
18554
|
-
* ## 「定时任务 +
|
|
19129
|
+
* ## 「定时任务 + 完全访问」的三条硬约束**挂在组合上**
|
|
18555
19130
|
*
|
|
18556
19131
|
* `bypass` 在对话里是一档现成的权限档,用户自己看着屏幕时选它是他的事;
|
|
18557
19132
|
* 但一个**无人值守、每天自己跑一次**的 `bypass` 是另一回事 —— 那正是
|
|
@@ -18569,7 +19144,6 @@ interface ValidateScheduleInput {
|
|
|
18569
19144
|
/** 绝对路径。空串 = 用户没绑工作区(`bypass` 下这是硬伤) */
|
|
18570
19145
|
workDir: string;
|
|
18571
19146
|
maxTurns: number;
|
|
18572
|
-
maxBudgetUsd: number;
|
|
18573
19147
|
timeoutMs: number;
|
|
18574
19148
|
trigger: ScheduleTrigger;
|
|
18575
19149
|
startDate?: string;
|
|
@@ -18661,8 +19235,22 @@ declare function parseScheduleDraft(raw: unknown): DraftParse;
|
|
|
18661
19235
|
* 这次提案**放宽**了什么。
|
|
18662
19236
|
*
|
|
18663
19237
|
* 三类都是授权面变大的方向(判据在 `ScheduleWideningKind` 上)。新建那一支的
|
|
18664
|
-
* 基线是**引擎那份缺省档**(`
|
|
18665
|
-
*
|
|
19238
|
+
* 基线是**引擎那份缺省档**(`SCHEDULE_DEFAULT_PERMISSION`)而不是「空」——
|
|
19239
|
+
* 拿空当基线的话每一条新任务都会被标成「放宽了」,而一枚恒亮的警示标等于没有警示标。
|
|
19240
|
+
*
|
|
19241
|
+
* ## 🔴 2026-10-27:基线从 `default` 抬到了 `auto`,于是「新建」那一支再也标不出来了
|
|
19242
|
+
*
|
|
19243
|
+
* 这不是失手,是抬档的必然结果:基线既然已经是**最宽那一档**,没有任何一档
|
|
19244
|
+
* 在它右边 —— `indexOf(level) > indexOf(base)` 对新建立永远不成立。
|
|
19245
|
+
*
|
|
19246
|
+
* 那一支的警示因此**没有消费者了**。留着它而不是删掉,是因为 `update` 那一支
|
|
19247
|
+
* 靠的正是同一个比较(拿那条任务现在的档当基线),而那一条照旧有效;
|
|
19248
|
+
* 把两支拆开会让「放宽」这个概念在两处各有一个定义。
|
|
19249
|
+
*
|
|
19250
|
+
* ⚠️ **新建那条路的警示不是丢了,是换了一个地方说**:权限档现在默认就是最宽
|
|
19251
|
+
* 那一档,于是「这条新任务将不经确认地做这些事」这句话由**卡片上那份清单** +
|
|
19252
|
+
* `validate.ts` 那三道网(工作目录不许宽得等于没绑 / 尺子必须有值 / 二次确认)
|
|
19253
|
+
* 接住。用户在卡片上看见的是它的绝对值,而不是一个「相对刚才变宽了」的相对值。
|
|
18666
19254
|
*/
|
|
18667
19255
|
declare function draftWidening(draft: ScheduleDraft, current?: ScheduleDefinition): ScheduleWideningKind[];
|
|
18668
19256
|
/**
|
|
@@ -18674,10 +19262,9 @@ declare function draftWidening(draft: ScheduleDraft, current?: ScheduleDefinitio
|
|
|
18674
19262
|
* 看见「未知命令」。那一支的真话是「改一条已有任务今天只有界面那条路」,
|
|
18675
19263
|
* 由工具输出说出来。
|
|
18676
19264
|
*
|
|
18677
|
-
* ⚠️
|
|
18678
|
-
*
|
|
18679
|
-
*
|
|
18680
|
-
* 因此真的可以直接粘贴跑起来 —— 打印的就是**已经落库的那个数**。
|
|
19265
|
+
* ⚠️ **命令里已经没有 `--budget` 了**(2026-10-29 撤掉了预算那把尺子,
|
|
19266
|
+
* `epoch schedule add` 也不再认那个旗子)。轮次和超时那两格走缺省,所以这一行
|
|
19267
|
+
* 拼出来的就是一份完整可用的 `add`。
|
|
18681
19268
|
*/
|
|
18682
19269
|
declare function draftCommandLine(draft: ScheduleDraft): string | undefined;
|
|
18683
19270
|
|
|
@@ -19339,6 +19926,30 @@ declare const DEFAULT_COMPLIANCE_SETTINGS: ComplianceSettings;
|
|
|
19339
19926
|
*
|
|
19340
19927
|
* 通过 shell 命令执行 hook 脚本,JSON 通过 stdin/stdout 通信。
|
|
19341
19928
|
* 退出码 2 = 关键阻止,其他非零 = 警告。
|
|
19929
|
+
*
|
|
19930
|
+
* ## 沙箱(2026-10-26 补上,方案 65 §2.3)
|
|
19931
|
+
*
|
|
19932
|
+
* 这条子进程以前是**完全无边界**的 `spawn(command, { shell: true })`,而同一个
|
|
19933
|
+
* 仓库里 `terminal` 是包在 `confine()` 里的 —— 同一能力两套边界。而 hook 的口子
|
|
19934
|
+
* 并不小:它是**任意 shell**,来源是七份配置文件(项目级那三份要过工作区信任闸门,
|
|
19935
|
+
* 通过之后就是永久授权),并且 `tool:before` / `verify:stop` 是**自动执行**的,
|
|
19936
|
+
* 没有人会在那一刻再回答一次「要不要跑」。
|
|
19937
|
+
*
|
|
19938
|
+
* 现在它在 macOS / Linux 上走和 `terminal` 同一条 `confine()`,边界见
|
|
19939
|
+
* {@link hookSandboxPolicy}。Windows 没有后端(判据在 infra 的
|
|
19940
|
+
* `sandbox/backend.ts` 文件头),所以那一支**逐字节保持改之前的样子**。
|
|
19941
|
+
*
|
|
19942
|
+
* ## 一条不许漏的:沙箱拒绝**不进表决**
|
|
19943
|
+
*
|
|
19944
|
+
* 被挡住时退出码是普通的非零(seatbelt 是 1),`blocked` 照旧只有 `exitCode === 2`
|
|
19945
|
+
* 才成立。这不是没顺手改 —— 是**不能**改:`verify:stop` 上「阻止」等于
|
|
19946
|
+
* 「不许收工」,而一条被沙箱挡住的 `verify:stop` 下一轮还是被挡住,于是
|
|
19947
|
+
* 模型永远收不了工(确定性死循环,不是概率问题)。沙箱拒绝那条路由
|
|
19948
|
+
* [manager.ts](./manager.ts) 的 `reportIfNotRun()` **如实说出口**,说清
|
|
19949
|
+
* 「这条 hook 没跑成」而不是「它通过了」。
|
|
19950
|
+
*
|
|
19951
|
+
* 「放行」这个方向本身沿用的是 2026-08-08 定下的取舍(hook 不是安全边界),
|
|
19952
|
+
* 判据在 `manager.ts` 的 `reportIfNotRun()` 上 —— 别在这里另开一套。
|
|
19342
19953
|
*/
|
|
19343
19954
|
|
|
19344
19955
|
/** Command hook 配置 */
|
|
@@ -19372,6 +19983,40 @@ interface CommandHookResult {
|
|
|
19372
19983
|
rejectReason?: string;
|
|
19373
19984
|
/** stdout 解析为 JSON 时的结构化输出 */
|
|
19374
19985
|
output?: Record<string, unknown>;
|
|
19986
|
+
/**
|
|
19987
|
+
* 这一次的沙箱账。**永远有值** —— 「没包上」也是一个要说出口的结论
|
|
19988
|
+
* (同 infra 的 `Confinement`:`confine()` 不返回 null 就是为了这个)。
|
|
19989
|
+
*/
|
|
19990
|
+
sandbox: CommandHookSandbox;
|
|
19991
|
+
/**
|
|
19992
|
+
* 非零退出时这次失败属于哪一种(判据在 infra 的 `sandbox/classify.ts` 文件头)。
|
|
19993
|
+
*
|
|
19994
|
+
* ⚠️ **只在包上了沙箱时才有值**:没有沙箱就没有「被沙箱挡了」和
|
|
19995
|
+
* 「沙箱没起来」这两种可能,硬跑一遍分类器只会拿当前平台压根不产生的方言
|
|
19996
|
+
* 去匹配(`terminal` 那条路也是这么分的,见 `plugin-terminal/src/sandbox.ts`
|
|
19997
|
+
* 的 `ConfinedShell.classify`)。
|
|
19998
|
+
*/
|
|
19999
|
+
failure?: FailureVerdict;
|
|
20000
|
+
}
|
|
20001
|
+
/** hook 这一次跑在什么边界里 —— 形状对齐 `plugin-terminal` 的 `SandboxOutcome` */
|
|
20002
|
+
interface CommandHookSandbox {
|
|
20003
|
+
/** 真包上了没有。`false` 时看 {@link skipped} */
|
|
20004
|
+
confined: boolean;
|
|
20005
|
+
/** 按哪一档包的。**恒为 `workspace-write`**,判据在 {@link hookSandboxPolicy} 上 */
|
|
20006
|
+
mode: SandboxMode;
|
|
20007
|
+
backend: IsolationBackend;
|
|
20008
|
+
/**
|
|
20009
|
+
* 没包上的原因。三档是**三句不同的话**(同 infra 的 `Confinement.reason`,
|
|
20010
|
+
* 但少了 `config-disabled` 一档 —— hook 这一侧今天没有自己的开关,
|
|
20011
|
+
* 判据在 {@link hookSandboxPolicy}):
|
|
20012
|
+
* `mode-disabled` 走不到(mode 是钉死的),留着它是为了形状对齐。
|
|
20013
|
+
*
|
|
20014
|
+
* ⚠️ `Confinement.reason` 2026-10-27 多了一档(`escalated`;
|
|
20015
|
+
* 方案 65 §2.1),**它在这里刻意不存在**:那一档的唯一产地
|
|
20016
|
+
* 是 `SandboxPolicy.bypass`,而 hook 的 policy 从来不设那一格(见
|
|
20017
|
+
* {@link hookSandboxPolicy})。收窄在 {@link hookSkipReason} 里。
|
|
20018
|
+
*/
|
|
20019
|
+
skipped?: 'config-disabled' | 'mode-disabled' | 'no-backend';
|
|
19375
20020
|
}
|
|
19376
20021
|
|
|
19377
20022
|
/**
|
|
@@ -21125,6 +21770,105 @@ declare function imagePartTokens(image: string): number | undefined;
|
|
|
21125
21770
|
*/
|
|
21126
21771
|
declare function pendingImageTokens(messages: readonly EpochMessage[]): number;
|
|
21127
21772
|
|
|
21773
|
+
/**
|
|
21774
|
+
* 「这一次请求里图片一共占多少**字节**」—— 和那条 token 预算**是两个量纲**。
|
|
21775
|
+
*
|
|
21776
|
+
* ## 为什么非要有这一条线(2026-10-28)
|
|
21777
|
+
*
|
|
21778
|
+
* 仓库里已经有一条按容量的预算:`isPromptOversize`(protocol 的 `usage.ts:202`),
|
|
21779
|
+
* 它判 token 占窗口的几成。那条线**看不见图片的字节**,而这两件事在图片上会
|
|
21780
|
+
* 彻底分家:
|
|
21781
|
+
*
|
|
21782
|
+
* | 量纲 | 谁在看 | 一张 2 MB 的截图记多少 |
|
|
21783
|
+
* | --- | --- | --- |
|
|
21784
|
+
* | token | `isPromptOversize` / `shouldCompress` / `pendingImageTokens` | **约一千出头**(按宽高估,`image-tokens.ts:48`) |
|
|
21785
|
+
* | 字节 | **本文件** | 2.7 MB(base64 是原文的 4/3) |
|
|
21786
|
+
*
|
|
21787
|
+
* 而 chat completions 是**无状态**的:每一轮都把整段历史重发一遍,历史里每张图
|
|
21788
|
+
* 都以 base64 再传一次。于是「几个 2 MB 的截图」在 token 账上还空着九成,请求体
|
|
21789
|
+
* 已经撞穿了网关那条上限 —— 表现是 `PROVIDER_BODY_TOO_LARGE`(1051)或者说
|
|
21790
|
+
* 「请求体过大」,而**两条 token 线一个都不会动**。
|
|
21791
|
+
*
|
|
21792
|
+
* ## 为什么只数图片,不数整份请求体
|
|
21793
|
+
*
|
|
21794
|
+
* 因为**只有图片是「token 少、字节大」的那一个**。文本这两个量纲是单调同向的
|
|
21795
|
+
* (一段一 MB 的日志在 token 账上就是几十万),它太大时 `isPromptOversize` 那条
|
|
21796
|
+
* 线早就先抓住了,轮不到这里。
|
|
21797
|
+
*
|
|
21798
|
+
* 反过来做的代价很大:要数整份请求体就得 `JSON.stringify(system + tools + messages)`
|
|
21799
|
+
* 一遍 —— 那是每轮几 MB 的字符串拼接,而且它会把「这一轮该不该发」这个判断
|
|
21800
|
+
* 绑在 SDK 的消息形状上(`toModelMessages` 是唯一认那个形状的地方,
|
|
21801
|
+
* 见 `provider/sdk-adapter.ts` 的文件头)。
|
|
21802
|
+
*
|
|
21803
|
+
* ## 三类图里只有一类有字节可数
|
|
21804
|
+
*
|
|
21805
|
+
* `EpochImagePart.image` 有三种形态(判据在 protocol 的 `message.ts:60`):
|
|
21806
|
+
*
|
|
21807
|
+
* | 形态 | 数不数 | 为什么 |
|
|
21808
|
+
* | --- | --- | --- |
|
|
21809
|
+
* | 裸 base64 / `data:` URL | 数 | 它就摆在请求体里 |
|
|
21810
|
+
* | `http(s)` URL | **不数** | provider 自己去取,我们连字节都没有 —— 猜一个数去拦人是最坏的选择(判据同 `image-tokens.ts` 的那两条取舍) |
|
|
21811
|
+
*
|
|
21812
|
+
* `data:` 前缀(`data:image/png;base64,`,约 22 字节)**剥掉再数**:它是个常数、
|
|
21813
|
+
* 量级无关,但剥掉之后数出来的就是真正的载荷,和小票上那两个数对得上账
|
|
21814
|
+
* (`artifact.bytes` 是原始字节,base64 是它的 4/3)。
|
|
21815
|
+
*/
|
|
21816
|
+
|
|
21817
|
+
/**
|
|
21818
|
+
* 这一组消息里**所有图片**的 base64 字节合计。
|
|
21819
|
+
*
|
|
21820
|
+
* ## 必须扫两处,不是一处
|
|
21821
|
+
*
|
|
21822
|
+
* 图有两条进请求体的路,而它们**恰好对应两种撑爆的现场**:
|
|
21823
|
+
*
|
|
21824
|
+
* | 从哪来 | 形状 | 对应哪种现场 |
|
|
21825
|
+
* | --- | --- | --- |
|
|
21826
|
+
* | 用户贴的图 | `message.parts[].type === 'image'` | 历史累积(第二轮那种,每条消息都发不出去) |
|
|
21827
|
+
* | **工具产物** | `toolResults[].artifacts[].data` | 一轮内累积(第一轮那种,工具跑几次就撑爆) |
|
|
21828
|
+
*
|
|
21829
|
+
* 只扫第一处的话,`stripHistoryImages`(`agent/loop.ts:269`)那种**只看 user 行
|
|
21830
|
+
* 的 `parts`** 的老盲区会原地复现一次:工具截图(`plugin-file` 的 `file_read` 读
|
|
21831
|
+
* png、`page_shot` 那类)全部漏掉,而它们恰恰是体积最大的一族。
|
|
21832
|
+
*
|
|
21833
|
+
* ## `artifacts[].data` 才是判据,不是 `artifacts` 非空
|
|
21834
|
+
*
|
|
21835
|
+
* 有没有 `data` 是闸门的结论(`context/artifact-gate.ts:183` 那段:有 `data` 就
|
|
21836
|
+
* 进上下文、没有就只是一句 summary)。被闸门拦下的图**一个字节都不进请求体**,
|
|
21837
|
+
* 把它算进预算会让下放发生在根本不需要的时候 —— 而那种误操作是有损的。
|
|
21838
|
+
*/
|
|
21839
|
+
declare function requestImageBytes(messages: readonly EpochMessage[]): number;
|
|
21840
|
+
/**
|
|
21841
|
+
* 把**最老的**几张图换成占位文本,直到剩下的字节数落在预算内。
|
|
21842
|
+
*
|
|
21843
|
+
* ## `keepFresh` 是这一整个特性的安全性所在
|
|
21844
|
+
*
|
|
21845
|
+
* 它说的是「最新的 N 条消息里的图一张都不摘」。**必须 ≥ 1**,理由是这一轮用户
|
|
21846
|
+
* 刚贴的那张图:他正等着模型看图回答,把它摘掉等于把这一轮的活直接干废 ——
|
|
21847
|
+
* 而模型还会一本正经地照着一句「图片已下放」去答,用户完全看不出发生了什么。
|
|
21848
|
+
*
|
|
21849
|
+
* 所以下放只从**旧**的一头开始。代价是「一张巨图 + 预算很小」这一档下放不动
|
|
21850
|
+
* (最老的那张就是最新的那张),那时回 `offloaded: 0`,调用方据此知道
|
|
21851
|
+
* 「这一招不管用」—— 别在那儿硬摘一张正在用的图。
|
|
21852
|
+
*
|
|
21853
|
+
* ## 为什么不是「摘到刚好够」而是「按张为单位」
|
|
21854
|
+
*
|
|
21855
|
+
* 一张图是不可分的:摘一半的 base64 是坏数据。所以这里逐张摘,直到总量进预算。
|
|
21856
|
+
* 最坏情况是超摘一点点(最后那一张其实可以留着),那个代价可以接受 ——
|
|
21857
|
+
* 反过来「差一点没摘够」会让这次救援白跑一趟,而重发的那一发是要么成功要么
|
|
21858
|
+
* 再撞一次墙。
|
|
21859
|
+
*
|
|
21860
|
+
* @param keepFresh 最新的多少条消息里的图不碰。**0 是不安全的**(见上),
|
|
21861
|
+
* 调用方给 `undefined` 时按 1 处理
|
|
21862
|
+
*/
|
|
21863
|
+
declare function offloadOldestImages(messages: readonly EpochMessage[], opts?: {
|
|
21864
|
+
budgetBytes: number;
|
|
21865
|
+
keepFresh?: number;
|
|
21866
|
+
}): {
|
|
21867
|
+
messages: EpochMessage[];
|
|
21868
|
+
offloaded: number;
|
|
21869
|
+
remainingBytes: number;
|
|
21870
|
+
};
|
|
21871
|
+
|
|
21128
21872
|
/**
|
|
21129
21873
|
* 上下文压缩器 — 默认 ContextEngine 实现。
|
|
21130
21874
|
* 4 阶段算法(Hermes agent/context_compressor.py),**中间多了一道闸**
|
|
@@ -21272,7 +22016,7 @@ declare class ContextCompressor implements ContextEngine {
|
|
|
21272
22016
|
*/
|
|
21273
22017
|
private cleanupOrphans;
|
|
21274
22018
|
/**
|
|
21275
|
-
* 一组消息的 token 总量。逐条过 {@link
|
|
22019
|
+
* 一组消息的 token 总量。逐条过 {@link messageTokens},不另立口径。
|
|
21276
22020
|
*
|
|
21277
22021
|
* 这里原来是三个私有函数(`estimateTokens` / `estimateTokenCount` /
|
|
21278
22022
|
* `tokensForChars`),各自写着 `chars / 4`,和 `model-metadata.ts` 里那份
|
|
@@ -21862,7 +22606,9 @@ interface RunCodeOutcome {
|
|
|
21862
22606
|
* 失败的分类。**给模型看的措辞按这个分叉**,因为每一档的正确下一步都不一样:
|
|
21863
22607
|
* 触顶要少调几次、超时要提 `timeout`、OOM 要少占内存、`throw` 要改程序。
|
|
21864
22608
|
*/
|
|
21865
|
-
type RunCodeFailure = 'timeout' | 'oom' | 'cap' | 'throw' | 'aborted' | 'worker-missing'
|
|
22609
|
+
type RunCodeFailure = 'timeout' | 'oom' | 'cap' | 'throw' | 'aborted' | 'worker-missing'
|
|
22610
|
+
/** 权限策略把 worker 自己拦在门外 —— 判据在 `policy.ts` 的文件头 */
|
|
22611
|
+
| 'policy';
|
|
21866
22612
|
declare function runCode(input: RunCodeInput): Promise<RunCodeOutcome>;
|
|
21867
22613
|
|
|
21868
22614
|
/**
|
|
@@ -21907,4 +22653,4 @@ declare function resolveCodeModeWorker(baseDir: string, exists?: typeof existsSy
|
|
|
21907
22653
|
*/
|
|
21908
22654
|
declare function codeModeWorkerPath(): string | undefined;
|
|
21909
22655
|
|
|
21910
|
-
export { ABOUT_DESC_MAX_CHARS, ABOUT_README_MAX_CHARS, AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, type AcquireResult, type ActivePlugin, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, AppearanceStore, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, type AttachmentRetention, BLOCKED_TOOLS, type BackendOptions, type BackendOutcome, type BackgroundTaskSource, type BaseOrigin, type BaseSlot, type BeginTurnInput, type BreakdownInput, BudgetGuard, type BudgetGuardOptions, type BudgetInfo, type BudgetLevel, type BudgetOptions, type BudgetStatus, BudgetStore, type BudgetStoreOptions, type BuildFireArgvInput, type BuildIndexOptions, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, type CachedApproval, type CachedDecision, type CheckpointCapture, type CheckpointFile, CheckpointManager, type CheckpointManagerOptions, type CheckpointManifest, CheckpointStore, type CheckpointStoreOptions, type CheckpointSummary, type ClaudeHooksParseOptions, type CodeModeLimits, type CodeRequest, type CodeResult, CodeSandbox, type CommandHookConfig, type CommandHookResult, type CommandLoadOutcome, type CommandLoadSummary, type CommandResult, type CommandRunner, type CompactionResult, type CompiledRules, type ComplianceDirSpec, type ComplianceDirsSummary, ComplianceEngine, type ComplianceEngineInput, type ComplianceGate, type ComplianceHit, type ComplianceRule, type ComplianceRuleSource, type ComplianceSettings, type ComplianceVerdict, type CompressConfig, type CompressResult, type ConfigMigration, type ConfigOrigins, ContextCompressor, type ContextEngine, type CreateScheduleInput, type CreateSessionInput, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, type DelegateArgs, type DelegateConfig, DelegateManager, type DelegateTaskResult, type DiagnoseOptions, type DiscoverOutcome, type DiscoveredFile, type DoctorReport, type DraftParse, EMPTY_RULES, EPOCH_DISK_LEDGER, type EntryProbeCode, type EntryProbeResult, EpochConfigSchema, type ExpandOptions, type ExtractOutcome, FTS_TABLES, FTS_TRIGGERS, type FallbackEvent, type FileSlots, type FileSourceKind, type ForkInput, type FrontmatterParse, type FrontmatterSplit, type FtsHealth, type FtsReclaim, type FtsSpace, type FtsTableHealth, GOAL_BLOCK_CODES, type GateAxis, type GateVerdict, type GenerateInput, type GenerateOutput, type Goal, type GoalBlockReason, type GoalClear, type GoalPhase, type GoalPromptView, type GoalRefusal, type GoalRoundResult, GoalService, GoalStore, type GoalToolDeps, type GoalWrite, HEADLESS_AUDIT_CODES, type HeadlessPolicy, type HookConfigEntry, HookManager, type HookManagerOptions, type HookMatcher, type HookSourceKind, type HookSourceStatus, type HookSourcesOptions, type HookSourcesSummary, type HooksParseOutcome, type MemoryManager$1 as IMemoryManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, type SessionManager$1 as ISessionManager, type SkillSystem$1 as ISkillSystem, ImageLoadError, type ImageSize, type ImportDecision, type ImportGate, type ImportGoal, type ImportMessage, type ImportNode, type ImportPartsResult, type ImportSessionInput, type ImportSessionMeta, type ImportSessionResult, type ImportSkipReason, type ImportTodo, ImportTrustStore, type InstallDependency, type InstallOptions, type InstallOutcome, type InstallPreview, type InstallStep, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, type LastOpenSession, LastOpenSessions, type LayerOutcome, type LayerScalars, type LayerStatus, type LearningContext, type LearningResult, type LearningSkipReason, type LexiconLoadOutcome, type LifecycleOutcome, type ListCandidatesInput, type ListSessionsInput, type ListSessionsOutput, type LoadCommandsOptions, type LoadConfigOptions, type LoadKeybindingsOptions, type LoadKeybindingsResult, type LoadRolesOptions, type LoadedPlugin, type LockHolder, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_ENTRIES_FILE, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceCategory, type MarketplaceDisplay, type MarketplaceDisplayField, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MarketplaceStatus, type MemoryConfig, type MemoryEntry, type MemoryImportRecord, type MemoryImportResult, MemoryManager, type MemoryManagerOptions, type MemoryNotice, type MemoryRemoval, type MemorySearchResult, type MemoryTarget, type MemoryWriteResult, type MentionPart, type MentionResolution, type Message, type MessageHit, type MessageRecord, type MessageSurface, type ModelCapability, ModelFailureTracker, type ModelMetaEntry, type ModelPricing, type MultimodalPolicy, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, type NonInteractiveProbe, type OsTaskSnapshot, type OutputGuard, PACK_EXCLUDES, PERMISSION_AUDIT_CODES, PLUGIN_ICON_MAX_BYTES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, type PackFile, type PackLimits, type PackOutcome, type PackPlan, type PackPlanOutcome, type PermissionAuditCode, type PermissionAuditEntry, type PermissionAuditOutcome, type PermissionAuditScope, type PermissionAuditSnapshot, PermissionManager, type PersistFailureKind, type PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginAbout, type PluginArtifacts, type PluginAuthor, PluginAuthorSchema, type PluginCommandDir, type PluginCounts, type PluginDoc, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginScope, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PluginVisibility, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type PricingAt, type PricingOverride, type ProjectContext, type ProjectExtensionInventory, ProviderError, ProviderRouter, type ProviderStreamChunk, type ProviderToolCall$1 as ProviderToolCall, type ProviderWarning, type PruneResult, type QuestionAskFn, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, type ReadMessagesInput, type ReadMessagesOutput, type RecentWorkspace, RecentWorkspaces, type RecordRunInput, type RecorderOptions, type RecoveryAction, type RegisterInput, type RegisterOutcome, type RegistrarOptions, type RegistrationPatch, type RepairOutcome, type ResolveMentionsOptions, type ResolveReferenceInput, type ResolveSettingsOptions, type ResolvedCompression, type ResolvedReference, type ResolvedSource, type ResponseFormat, type RestorePartsOptions, type RewindAction, type RewindDrift, type RewindFilePlan, type RewindOptions, type RewindOutcome, type RewindPreview, type RoleCreateFailure, type RoleCreateInput, type RoleCreateOptions, type RoleCreateOutcome, type RoleLoadOutcome, type RoleLoadSummary, type RoleMergeNotice, type RoleMergeResult, type RoleRemoveFailure, type RoleRemoveOptions, type RoleRemoveOutcome, type RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, type RunningSchedule, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_FORM_BUDGET_USD, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_ASSET_DIRS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_FILE, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, type ScalarKey, type ScanInstructionsOptions, type ScheduleArgvRefusal, type ScheduleArgvResult, type ScheduleArgvWarning, type ScheduleBackend, type ScheduleCliEntry, type ScheduleDraftDeps, type ScheduleDrift, type ScheduleDriftKind, type ScheduleImportInput, type ScheduleInstallForm, type ScheduleIssue, type ScheduleIssueCode, type ScheduleLock, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, type ScheduleValidation, type SchemaExport, type SearchHit, type SearchInput, type SearchMessagesInput, type SearchMessagesOutput, type SearchOutput, type SearchSessionsInput, type SelectionDeps, type SelfConnector, type SelfIndexInput, type SelfSettings, type Session, type SessionCandidate, type SessionHit, SessionManager, type SessionMentionDeps, type SessionMeta, SessionQueries, SessionReferences, type SessionSearchDeps, type SessionStats, type SessionSurface, type SessionTrace, type SessionVisibility, type SessionVisibilityInput, type SettingApply, type SettingApplyFacts, type SettingChain, type SettingFutile, type SettingLayer, type SettingStep, type SettingValue, type SettingValueKind, type SettingWriteFailure, type SettingWriteKey, type SettingWriteLayer, type SettingWriteOutcome, type SettingWriteRequest, type SettingWriteTarget, type SettingWriteTargetsOptions, type SettingsFile, SettingsFileError, SettingsFileSchema, type SettingsLayer, type SettingsResolution, type ShadowFinding, type ShadowKind, type Skill, type SkillDirSource, type SkillDirSpec, type SkillDirsSummary, type SkillImportConflict, type SkillImportDone, type SkillImportEntry, type SkillImportFailure, type SkillImportForm, type SkillImportOptions, type SkillImportPreview, type SkillImportResult, type SkillIndexEntry, type SkillIndexOptions, type SkillIndexResidency, type SkillIndexStats, SkillLearner, type SkillLearningProvider, type SkillMeta, type SkillStats, SkillSystem, type SkillSystemOptions, type SkillViewDeps, type SkillWriteDeps, type SteerSource, type StoredAppearance, type SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, type ToggleOutcome, type ToolCall, type ToolConflict, type ToolGate, type ToolNameFidelity, type ToolNameLookup, ToolRegistry, type ToolRevealState, type ToolScope, type ToolSearchDeps, type ToolTableCost, type TraceInput, type TraceNode, TrackerDB, type TrustDecision, type TrustGate, type TrustGateOptions, TrustManager, type TurnRecord, type TurnTiming, UNSETTABLE_USER_KEYS, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, approvalEntryFor, approvalRootFor, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, capabilityOfRef, checkEpochVersion, checkFtsHealth, checkShadowing, classifyPersistFailure, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createPluginScope, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, discoverySpec, displayAllows, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, grantedPathsFor, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, hasUsableModel, imageFromBase64, imageFromPath, imagePartTokens, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, isValidInterval, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listEntryModels, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadModelEntries, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelEntriesPath, modelListCandidates, needsAllowlist, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, normalizeModelEntry, normalizeTrigger, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelEntry, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistFailureCode, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readEntryKey, readImageSize, readMarketplaces, readPluginAbout, readPluginIcon, readPluginManifest, readPluginRecords, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, saveModelEntries, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, testModelEntry, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, unsetUserSetting, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|
|
22656
|
+
export { ABOUT_DESC_MAX_CHARS, ABOUT_README_MAX_CHARS, AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, type AcquireResult, type ActivePlugin, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, AppearanceStore, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, type AttachmentRetention, BLOCKED_TOOLS, type BackendOptions, type BackendOutcome, type BackgroundTaskSource, type BaseOrigin, type BaseSlot, type BeginTurnInput, type BreakdownInput, BudgetGuard, type BudgetGuardOptions, type BudgetInfo, type BudgetLevel, type BudgetOptions, type BudgetStatus, BudgetStore, type BudgetStoreOptions, type BuildFireArgvInput, type BuildIndexOptions, CHECKPOINT_MAX_TOTAL_BYTES, CLAUDE_EVENT_NAMES, CLAUDE_TOOL_NAMES, CODE_MODE_LIMITS, CODE_MODE_SDK_TAG, CONFIG_KEYS, CURRENT_CONFIG_VERSION, type CachedApproval, type CachedDecision, type CheckpointCapture, type CheckpointFile, CheckpointManager, type CheckpointManagerOptions, type CheckpointManifest, CheckpointStore, type CheckpointStoreOptions, type CheckpointSummary, type ClaudeHooksParseOptions, type CodeModeLimits, type CodeRequest, type CodeResult, CodeSandbox, type CommandHookConfig, type CommandHookResult, type CommandLoadOutcome, type CommandLoadSummary, type CommandResult, type CommandRunner, type CompactionResult, type CompiledRules, type ComplianceDirSpec, type ComplianceDirsSummary, ComplianceEngine, type ComplianceEngineInput, type ComplianceGate, type ComplianceHit, type ComplianceRule, type ComplianceRuleSource, type ComplianceSettings, type ComplianceVerdict, type CompressConfig, type CompressResult, type ConfigKeyEntry, type ConfigKeyKind, type ConfigKeyReason, type ConfigKeyWrite, type ConfigMigration, type ConfigOrigins, type ConfigValueCheck, type ConfigValueProblem, ContextCompressor, type ContextEngine, type CreateScheduleInput, type CreateSessionInput, DEFAULT_COMPLIANCE_ACTIONS, DEFAULT_COMPLIANCE_SETTINGS, DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_GOAL_MAX_ROUNDS, DEFAULT_MAX_HOLD_CHARS, DELEGATE_SESSION_SOURCE, type DelegateArgs, type DelegateConfig, DelegateManager, type DelegateTaskResult, type DiagnoseOptions, type DiscoverOutcome, type DiscoveredFile, type DoctorReport, type DraftParse, EMPTY_RULES, EPOCH_DISK_LEDGER, type EntryProbeCode, type EntryProbeResult, EpochConfigSchema, type ExpandOptions, type ExtractOutcome, FTS_TABLES, FTS_TRIGGERS, type FallbackEvent, type FileSlots, type FileSourceKind, type ForkInput, type FrontmatterParse, type FrontmatterSplit, type FtsHealth, type FtsReclaim, type FtsSpace, type FtsTableHealth, GOAL_BLOCK_CODES, type GateAxis, type GateVerdict, type GenerateInput, type GenerateOutput, type Goal, type GoalBlockReason, type GoalClear, type GoalPhase, type GoalPromptView, type GoalRefusal, type GoalRoundResult, GoalService, GoalStore, type GoalToolDeps, type GoalWrite, HEADLESS_AUDIT_CODES, type HeadlessPolicy, type HookConfigEntry, HookManager, type HookManagerOptions, type HookMatcher, type HookSourceKind, type HookSourceStatus, type HookSourcesOptions, type HookSourcesSummary, type HooksParseOutcome, type MemoryManager$1 as IMemoryManager, INSTRUCTION_BUDGET_CHARS, INSTRUCTION_FILES, type SessionManager$1 as ISessionManager, type SkillSystem$1 as ISkillSystem, ImageLoadError, type ImageSize, type ImportDecision, type ImportGate, type ImportGoal, type ImportMessage, type ImportNode, type ImportPartsResult, type ImportSessionInput, type ImportSessionMeta, type ImportSessionResult, type ImportSkipReason, type ImportTodo, ImportTrustStore, type InstallDependency, type InstallOptions, type InstallOutcome, type InstallPreview, type InstallStep, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, type LastOpenSession, LastOpenSessions, type LayerOutcome, type LayerScalars, type LayerStatus, type LearningContext, type LearningResult, type LearningSkipReason, type LexiconLoadOutcome, type LifecycleOutcome, type ListCandidatesInput, type ListSessionsInput, type ListSessionsOutput, type LoadCommandsOptions, type LoadConfigOptions, type LoadKeybindingsOptions, type LoadKeybindingsResult, type LoadRolesOptions, type LoadedPlugin, type LockHolder, MARKETPLACE_DISPLAY_FIELDS, MARKETPLACE_FILE, MAX_AUDIT_ENTRIES, MAX_COMMAND_DEPTH, MAX_GOAL_MAX_ROUNDS, MAX_IMPORT_DEPTH, MAX_LAST_OPEN_SESSIONS, MAX_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_ENTRIES_FILE, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceCategory, type MarketplaceDisplay, type MarketplaceDisplayField, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MarketplaceStatus, type MemoryConfig, type MemoryEntry, type MemoryImportRecord, type MemoryImportResult, MemoryManager, type MemoryManagerOptions, type MemoryNotice, type MemoryRemoval, type MemorySearchResult, type MemoryTarget, type MemoryWriteResult, type MentionPart, type MentionResolution, type Message, type MessageHit, type MessageRecord, type MessageSurface, type ModelCapability, ModelFailureTracker, type ModelMetaEntry, type ModelPricing, type MultimodalPolicy, NOMINAL_TOTAL_BYTES, NO_REVEALED_TOOLS, type NonInteractiveProbe, type OsTaskSnapshot, type OutputGuard, PACK_EXCLUDES, PERMISSION_AUDIT_CODES, PLUGIN_ICON_MAX_BYTES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_MANIFEST_KEYS, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, PLUGIN_VISIBILITY, POLICY_DECISIONS, PROBE_VERSION, PROJECT_AGENTS_SUBDIR, PROVIDER_NO_CREDENTIAL, type PackFile, type PackLimits, type PackOutcome, type PackPlan, type PackPlanOutcome, type PermissionAuditCode, type PermissionAuditEntry, type PermissionAuditOutcome, type PermissionAuditScope, type PermissionAuditSnapshot, PermissionManager, type PersistFailureKind, type PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginAbout, type PluginArtifacts, type PluginAuthor, PluginAuthorSchema, type PluginCommandDir, type PluginCounts, type PluginDoc, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginScope, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PluginVisibility, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type PricingAt, type PricingOverride, type ProjectContext, type ProjectExtensionInventory, ProviderError, ProviderRouter, type ProviderStreamChunk, type ProviderToolCall$1 as ProviderToolCall, type ProviderWarning, type PruneResult, type QuestionAskFn, RECORDING_KEEP_RUNS, RECORDING_MAX_BYTES, ROLE_FRONTMATTER_SCHEMA, RUN_CODE_TOOL, type ReadMessagesInput, type ReadMessagesOutput, type RecentWorkspace, RecentWorkspaces, type RecordRunInput, type RecorderOptions, type RecoveryAction, type RegisterInput, type RegisterOutcome, type RegistrarOptions, type RegistrationPatch, type RepairOutcome, type ResolveMentionsOptions, type ResolveReferenceInput, type ResolveSettingsOptions, type ResolvedCompression, type ResolvedReference, type ResolvedSource, type ResponseFormat, type RestorePartsOptions, type RewindAction, type RewindDrift, type RewindFilePlan, type RewindOptions, type RewindOutcome, type RewindPreview, type RoleCreateFailure, type RoleCreateInput, type RoleCreateOptions, type RoleCreateOutcome, type RoleLoadOutcome, type RoleLoadSummary, type RoleMergeNotice, type RoleMergeResult, type RoleRemoveFailure, type RoleRemoveOptions, type RoleRemoveOutcome, type RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, type RunningSchedule, SANDBOX_COVERS, SANDBOX_EXCLUDES, SCALAR_KEYS, SCHEDULE_DEFAULTS, SCHEDULE_DEFAULT_ALLOWLIST, SCHEDULE_ISSUE_CODES, SCHTASKS_FOLDER, SESSION_MESSAGES_READ_TOOL, SESSION_MESSAGES_SEARCH_TOOL, SESSION_QUERY_TOOLS, SESSION_SEARCH_TOOL, SESSION_TRACE_TOOL, SETTINGS_LAYER_ORDER, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_ASSET_DIRS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, SKILL_FILE, SKILL_PATCH_TOOL, SKILL_VIEW_TOOL, SKILL_WRITE_FILE_TOOL, SLASH_COMMANDS_DIAG_MODULE, type ScalarKey, type ScanInstructionsOptions, type ScheduleArgvRefusal, type ScheduleArgvResult, type ScheduleArgvWarning, type ScheduleBackend, type ScheduleCliEntry, type ScheduleDraftDeps, type ScheduleDrift, type ScheduleDriftKind, type ScheduleImportInput, type ScheduleInstallForm, type ScheduleIssue, type ScheduleIssueCode, type ScheduleLock, ScheduleRecorder, ScheduleRegistrar, ScheduleStore, type ScheduleValidation, type SchemaExport, type SearchHit, type SearchInput, type SearchMessagesInput, type SearchMessagesOutput, type SearchOutput, type SearchSessionsInput, type SelectionDeps, type SelfConnector, type SelfIndexInput, type SelfSettings, type Session, type SessionCandidate, type SessionHit, SessionManager, type SessionMentionDeps, type SessionMeta, SessionQueries, SessionReferences, type SessionSearchDeps, type SessionStats, type SessionSurface, type SessionTrace, type SessionVisibility, type SessionVisibilityInput, type SettingApply, type SettingApplyFacts, type SettingChain, type SettingFutile, type SettingLayer, type SettingStep, type SettingValue, type SettingValueKind, type SettingWriteFailure, type SettingWriteKey, type SettingWriteLayer, type SettingWriteOutcome, type SettingWriteRequest, type SettingWriteTarget, type SettingWriteTargetsOptions, type SettingsFile, SettingsFileError, SettingsFileSchema, type SettingsLayer, type SettingsResolution, type ShadowFinding, type ShadowKind, type Skill, type SkillDirSource, type SkillDirSpec, type SkillDirsSummary, type SkillImportConflict, type SkillImportDone, type SkillImportEntry, type SkillImportFailure, type SkillImportForm, type SkillImportOptions, type SkillImportPreview, type SkillImportResult, type SkillIndexEntry, type SkillIndexOptions, type SkillIndexResidency, type SkillIndexStats, SkillLearner, type SkillLearningProvider, type SkillMeta, type SkillStats, SkillSystem, type SkillSystemOptions, type SkillViewDeps, type SkillWriteDeps, type SteerSource, type StoredAppearance, type SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, type ToggleOutcome, type ToolCall, type ToolConflict, type ToolGate, type ToolNameFidelity, type ToolNameLookup, ToolRegistry, type ToolRevealState, type ToolScope, type ToolSearchDeps, type ToolTableCost, type TraceInput, type TraceNode, TrackerDB, type TrustDecision, type TrustGate, type TrustGateOptions, TrustManager, type TurnRecord, type TurnTiming, UNSETTABLE_USER_KEYS, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, approvalEntryFor, approvalRootFor, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, capabilityOfRef, checkConfigValue, checkEpochVersion, checkFtsHealth, checkShadowing, classifyPersistFailure, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, configKeyByPath, configKeyTable, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createPluginScope, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, discoverySpec, displayAllows, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, grantedPathsFor, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, hasUsableModel, imageFromBase64, imageFromPath, imagePartTokens, importParts, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isTransientPersistFailure, isValidInterval, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listEntryModels, listRunningSchedules, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadModelEntries, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelEntriesPath, modelListCandidates, needsAllowlist, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, normalizeModelEntry, normalizeTrigger, offloadOldestImages, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelEntry, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistFailureCode, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readEntryKey, readImageSize, readMarketplaces, readPluginAbout, readPluginIcon, readPluginManifest, readPluginRecords, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeRecordings, removeRoleFile, removeSessionArtifacts, removeSessionAttachments, renderImportTree, renderProjectContext, renderSdkDeclaration, renderSelfIndex, repairSchedules, requestImageBytes, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolvePricingAt, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, saveModelEntries, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, testModelEntry, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, unsetUserSetting, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writableConfigKeys, writeSettingValue };
|