@epoch-agent/core 0.9.0 → 0.10.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/dist/index.d.ts +1284 -59
- package/dist/index.js +825 -197
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ToolProvider, EpochTool, EpochPlugin, ToolExposure, EpochSkill, HookType, EpochHook, PluginContext, QuestionRequest, QuestionAnswer, AgentRole, PermissionLevel, PermissionManager as PermissionManager$1, PlanProposal, ApprovalRequest, ApprovalReply, ScheduleDefinition, DiagnosticSink, AgentRoleSource, CustomCommandDef, ModelRef, ExpandedCommand, CustomCommandSource, BackgroundTaskInfo, ContextBreakdown, EpochMessage, AgentRoleScope, ComplianceCategory, ComplianceAction, ToolArtifactInput, ToolArtifact, TrustLevel, TrustManager as TrustManager$1, TokenUsage, EpochConfig, BudgetBreach, ProviderType, JsonSchema, ModelSelection, EpochToolCall, Telemetry, HookManager as HookManager$1, EpochUserContent, EpochContentPart, AgentEvent, SelectionContext, SetSelectionResult, PermissionRuleLists, KeybindingTable, Diagnostic, KeybindingReport, FileOmitReason, SessionOmitReason, EpochToolResult, EpochTurnFacts, LocalizedDetail, OperationType, RuleValue, Operation, ApprovalOutcome, PermissionDecision, ScheduleTrigger, ScheduleAllowlist, ScheduleBackendKind, ScheduleRunStatus, ScheduleRun, SchedulePendingApproval, ScheduleDraft, ScheduleWideningKind, WireAgentEvent, WireAgentEnvelope, ScheduleRunnerSpec, HookEvent, LogFn, HookRegistration, HookHandler, HookContext, VerifyResult,
|
|
2
|
-
export { API_KEY_ENV_VARS, AgentEvent, AgentEventOf, AgentEventType, ApprovalAnswer, ApprovalOutcome, ApprovalReply, ApprovalRequest, 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, TrustLevel, TrustRecord, TrustScope, VerifyResult, apiKeyEnvVar, extractAllMentions, extractMentions, extractSessionMentions, getProviderInfo, isOperationType, isPermissionLevel, isPlanOutcome, isProviderType, normalizeApproval } from '@epoch-agent/protocol';
|
|
1
|
+
import { ToolProvider, EpochTool, EpochPlugin, ToolExposure, EpochSkill, HookType, EpochHook, PluginContext, QuestionRequest, QuestionAnswer, AgentRole, PermissionLevel, PermissionManager as PermissionManager$1, PlanProposal, ApprovalRequest, ApprovalReply, ScheduleDefinition, DiagnosticSink, AgentRoleSource, CustomCommandDef, ModelRef, ExpandedCommand, CustomCommandSource, BackgroundTaskInfo, ContextBreakdown, EpochMessage, AgentRoleScope, Lang, WireMcpConnector, ComplianceCategory, ComplianceAction, ToolArtifactInput, ToolArtifact, TrustLevel, TrustManager as TrustManager$1, TokenUsage, EpochConfig, BudgetBreach, ProviderType, JsonSchema, ModelSelection, EpochToolCall, Telemetry, HookManager as HookManager$1, EpochUserContent, EpochContentPart, AgentEvent, SelectionContext, SetSelectionResult, MoneyDigits, CurrencyDisplay, PermissionRuleLists, KeybindingTable, Diagnostic, KeybindingReport, FileOmitReason, SessionOmitReason, EpochToolResult, EpochTurnFacts, LocalizedDetail, OperationType, RuleValue, Operation, ApprovalOutcome, PermissionDecision, ScheduleTrigger, ScheduleAllowlist, ScheduleBackendKind, ScheduleRunStatus, ScheduleRun, SchedulePendingApproval, ScheduleDraft, ScheduleWideningKind, WireAgentEvent, WireAgentEnvelope, ScheduleRunnerSpec, 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, 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
3
|
import { IsolationBackend, SqliteDatabase, ParseIssue, ShellFlavor } 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';
|
|
@@ -4676,6 +4676,9 @@ declare function currentEpochVersion(): string;
|
|
|
4676
4676
|
* 不如解完之后看一眼:**清单不在顶层、而顶层恰好只有一个目录**,就把那一层
|
|
4677
4677
|
* 提上来。判据是「清单在哪」而不是「有几个条目」,所以一个本来就把
|
|
4678
4678
|
* `epoch-plugin.json` 放在顶层、旁边还有一个 `commands/` 的正常包不会被误摊。
|
|
4679
|
+
*
|
|
4680
|
+
* ⚠️ 数「有几个条目」时 `__MACOSX/` 和 `.DS_Store` **不算**,判据见
|
|
4681
|
+
* `ARCHIVE_NOISE`:不剔它们的话,Mac 上右键压缩出来的包一律摊不平。
|
|
4679
4682
|
*/
|
|
4680
4683
|
type ExtractOutcome = {
|
|
4681
4684
|
ok: true;
|
|
@@ -5358,10 +5361,10 @@ declare function installPlugin(source: string, opts: InstallOptions): Promise<In
|
|
|
5358
5361
|
*
|
|
5359
5362
|
* 环境变量单独用不了,两条:
|
|
5360
5363
|
*
|
|
5361
|
-
* 1.
|
|
5362
|
-
*
|
|
5363
|
-
*
|
|
5364
|
-
*
|
|
5364
|
+
* 1. **配置文件里读不到它。** `mcp.json` 的 `args` 和 `hooks.json` 的 `command`
|
|
5365
|
+
* 是我们自己解析的字符串,没有任何一层会去展开 `$EPOCH_PLUGIN_ROOT` ——
|
|
5366
|
+
* 环境变量只对**已经跑起来的子进程**有意义,而这两处要解决的正是
|
|
5367
|
+
* 「怎么把子进程叫起来」;
|
|
5365
5368
|
* 2. **Windows 上写法不通用。** hook 走 `shell: true`,那个 shell 在 win32 上是
|
|
5366
5369
|
* `cmd.exe`:`$EPOCH_PLUGIN_ROOT` 在那儿不展开(要写 `%EPOCH_PLUGIN_ROOT%`)。
|
|
5367
5370
|
* 一份想跨平台的 `hooks.json` 于是写不出一行两边都对的命令。
|
|
@@ -5372,12 +5375,21 @@ declare function installPlugin(source: string, opts: InstallOptions): Promise<In
|
|
|
5372
5375
|
* 而 `${EPOCH_PLUGIN_ROOT}/scripts/check.py` 变成 `/scripts/check.py` 之后
|
|
5373
5376
|
* 报的是「文件不存在」,一个字都不会提到插件。
|
|
5374
5377
|
*
|
|
5375
|
-
* ⚠️ hook
|
|
5376
|
-
* `
|
|
5377
|
-
*
|
|
5378
|
-
*
|
|
5379
|
-
*
|
|
5380
|
-
*
|
|
5378
|
+
* ⚠️ 替换之外,**两侧都额外注入一个同名环境变量**:hook 那边是
|
|
5379
|
+
* `command-runner.ts` 的 `injectEpochEnv`,MCP 那边是
|
|
5380
|
+
* `runtime/src/plugin-mcp-servers.ts` 的 `withPluginRoot`(2026-09-11 补上的,
|
|
5381
|
+
* 那之前 MCP 这一侧是空的)。理由是替换只管得到「怎么把进程叫起来」,
|
|
5382
|
+
* 而脚本**跑起来之后**要找自己包里的兄弟文件时,拿一个环境变量比让调用方
|
|
5383
|
+
* 把路径当参数传进来省事。
|
|
5384
|
+
*
|
|
5385
|
+
* ⚠️ MCP 那一侧原来空着的理由(「SDK 在 `env` 有值时拿它当整份环境,注入会把
|
|
5386
|
+
* `PATH` 弄丢」)**是错的**:实读 `@modelcontextprotocol/sdk@1.30.0` 的
|
|
5387
|
+
* `client/stdio.js`,它是 `{ ...getDefaultEnvironment(), ...serverParams.env }`,
|
|
5388
|
+
* 并上去的。全文判据在 `withPluginRoot` 的 JSDoc 上。
|
|
5389
|
+
*
|
|
5390
|
+
* ⚠️ 但**别把它当成 server 能拿到完整环境**:SDK 只往下传一张白名单
|
|
5391
|
+
* (`DEFAULT_INHERITED_ENV_VARS`,posix 六个 / win32 十二个)再并上这一份 ——
|
|
5392
|
+
* 用户 export 的变量到不了 server,那条路要走得让作者在 `mcp.json` 里写 `env`。
|
|
5381
5393
|
*
|
|
5382
5394
|
* ## ⚠️ 只在**插件带来的**那几份文件上替换
|
|
5383
5395
|
*
|
|
@@ -6488,6 +6500,38 @@ interface SystemPromptParams {
|
|
|
6488
6500
|
/** 认不认图。来自 provider 自己,不是配置项 */
|
|
6489
6501
|
supportsImages: boolean;
|
|
6490
6502
|
};
|
|
6503
|
+
/**
|
|
6504
|
+
* 用哪种语言回复用户(2026-09-11)。
|
|
6505
|
+
*
|
|
6506
|
+
* ## 它补的是一句**无条件的假话**
|
|
6507
|
+
*
|
|
6508
|
+
* `## 规则` 第一条在这一笔之前逐字是 `- 用中文回复用户`,**没有任何分叉** ——
|
|
6509
|
+
* 而 `display.language` 这个配置项存在、`locales/en.yaml` 有六千多行、
|
|
6510
|
+
* `resolveLang()` 还会按系统 locale 探测(一台法语机器解析出 `en`)。
|
|
6511
|
+
* 于是一个把界面切成英文的用户,拿到的回复仍然是中文。
|
|
6512
|
+
*
|
|
6513
|
+
* 2026-09-11 那一轮加 `<settings>` 之后这件事变得更难看:同一段 prompt 里
|
|
6514
|
+
* 上面印着「界面语言 en」、最后一段写着「用中文回复用户」,两句话直接打架。
|
|
6515
|
+
*
|
|
6516
|
+
* ## 为什么是「跟界面语言走」,不是「跟用户这条消息的语言走」
|
|
6517
|
+
*
|
|
6518
|
+
* 后者是 Codex 的做法 —— 它的 prompt 里**一个字都不提回复语言**,靠模型
|
|
6519
|
+
* 自己跟随用户(实读 `gpt_5_1_prompt.md`,零命中)。那条路对我们不成立:
|
|
6520
|
+
* 这个仓库的 `## 规则` 整段是中文、工具描述也是中文,什么都不说的话模型的
|
|
6521
|
+
* 回复语言会跟着上下文漂(一个英文代码库里做事的中文用户会收到英文回复)。
|
|
6522
|
+
*
|
|
6523
|
+
* 界面语言是**用户已经表过一次态**的那个信号,而且它和用户屏幕上其余的字
|
|
6524
|
+
* 同源 —— 拿它当判据,回复语言和界面语言从此不会说两套话。
|
|
6525
|
+
*
|
|
6526
|
+
* ## ⚠️ 不给 = 按 `zh` 走,**而不是**「与这一轮之前逐字节相同」
|
|
6527
|
+
*
|
|
6528
|
+
* 这一格和 {@link SystemPromptParams.model} 那一格不一样:那一格不给就整段
|
|
6529
|
+
* 不出现,这一格**总要出一行**(`## 规则` 里那条语言规则无条件存在)。
|
|
6530
|
+
* 而那一行的措辞这一天改了(旧的那句实测在弱模型上不够,判据在
|
|
6531
|
+
* {@link REPLY_LANG_RULE} 上),所以嵌入宿主不接这个参数**也会**看到
|
|
6532
|
+
* 一行新的字节。这是认下的代价,理由写在 `systemPromptSegments` 里那一行上。
|
|
6533
|
+
*/
|
|
6534
|
+
replyLang?: Lang;
|
|
6491
6535
|
}
|
|
6492
6536
|
/**
|
|
6493
6537
|
* system prompt 的**分段**形态(方案 25 §2.5 的 `/context` 要它)。
|
|
@@ -6604,6 +6648,220 @@ declare function systemPromptSegments(params: SystemPromptParams): SystemPromptS
|
|
|
6604
6648
|
*/
|
|
6605
6649
|
declare function buildSystemPrompt(params: SystemPromptParams): string;
|
|
6606
6650
|
|
|
6651
|
+
/**
|
|
6652
|
+
* `<self>` / `<settings>` —— 模型对**自己手上有什么**的那份自述,唯一产地。
|
|
6653
|
+
*
|
|
6654
|
+
* ## 它补的是什么
|
|
6655
|
+
*
|
|
6656
|
+
* 用户装了插件之后问「这个插件能干嘛」「我都有什么插件 / 连接器 / 自动化配置」,
|
|
6657
|
+
* 而模型在这一笔之前**一个字都答不上来**:一个插件对它只剩三样投影(技能索引里带
|
|
6658
|
+
* `<前缀>:` 的那几行、`delegate` 描述里的角色、工具表里的 `mcp__<前缀>__*`),
|
|
6659
|
+
* 清单里那句 `description` 只走 CLI 打印和 web 卡片,README 压根不在 `PLUGIN_LAYOUT`
|
|
6660
|
+
* 里。于是它唯一剩下的路是 `terminal` + `find`/`ls`/`cat` **盲摸用户的家目录**。
|
|
6661
|
+
*
|
|
6662
|
+
* ⚠️ 这**不是**「缺一个插件工具」。[docs/TOOLS.md](../../../../docs/TOOLS.md) 那节
|
|
6663
|
+
* 「模型做插件:这张表上一个插件工具都没有」守的是**做插件和装插件**
|
|
6664
|
+
* (`plugin_pack` / `plugin_validate` / `plugin_install`),判据分别是「那是知识不是
|
|
6665
|
+
* 能力面」和「不能让被审批的一方自己按确认」。**读自己手上有什么**两条都不沾 ——
|
|
6666
|
+
* 那一节压根没覆盖它,所以这一轮加的是数据不是工具。
|
|
6667
|
+
*
|
|
6668
|
+
* ## ⚠️ 这是同一类病的第四次复发,前三次都修在同一个地方
|
|
6669
|
+
*
|
|
6670
|
+
* `## 规则` 里那条「被问到你是谁……**再说清楚你能做什么**」指着空气 —— 和
|
|
6671
|
+
* 2026-09-02 那条「照实说(界面上本来就印着模型名)」一模一样:规则约束的是模型的
|
|
6672
|
+
* 嘴,而它的上下文里没有对应的事实。那次的处置是往 `## 环境` 补两行真值
|
|
6673
|
+
* (判据在 `SystemPromptParams.model` 上),这次是这个文件。
|
|
6674
|
+
*
|
|
6675
|
+
* 所以**下面每一句话都必须是现读的真值**。一句写死的「你可以管理插件」比没有更坏:
|
|
6676
|
+
* 模型会照着它回答,而用户那台机器上可能一个插件都没装。
|
|
6677
|
+
*
|
|
6678
|
+
* ## 一、为什么只给**计数 + 去哪儿找**,不列名字
|
|
6679
|
+
*
|
|
6680
|
+
* 这是一次预算决定,判据是「**知道去哪儿找 ≠ 到处找**」:插件名靠一次
|
|
6681
|
+
* `file_list ~/.epoch/plugins/` 一把拿全,那是一次定点读;而列进这一段的字
|
|
6682
|
+
* **每一轮都付**。技能名更不该在这儿重复 —— 它们已经逐条列在
|
|
6683
|
+
* `<available_skills>` 里了(`skill/prompt-index.ts`),抄第二遍是纯重复,
|
|
6684
|
+
* 下场写在 `SystemPromptSegments` 上那段「工具表在一次请求里出现两遍」里。
|
|
6685
|
+
*
|
|
6686
|
+
* 📌 **想升级成「插件名也列出来」是改一行**(每个插件 ≈5 tokens)。Hermes 的
|
|
6687
|
+
* `_skills_prompt()` 走的就是那一档(「名字永远可见,描述按需降级」)。
|
|
6688
|
+
* 但那是一次独立的决定,别顺手做 —— 它会让这一段随着用户装插件线性变长。
|
|
6689
|
+
*
|
|
6690
|
+
* ## 二、⚠️ 连接器和 hook 为什么破例**投影**,而不是给一条「去哪儿找」
|
|
6691
|
+
*
|
|
6692
|
+
* 因为它们的文件**带凭据**,永远不会进读窗口:
|
|
6693
|
+
*
|
|
6694
|
+
* - `~/.epoch/mcp.json` —— `RawServerSchema` 上就有 `headers` 和 `env`
|
|
6695
|
+
* (`plugin-mcp/src/schema.ts`),那是 bearer token 的常驻地;
|
|
6696
|
+
* - `~/.epoch/hooks.json` —— 整行 shell 命令,凭据经常写在参数里。
|
|
6697
|
+
*
|
|
6698
|
+
* 「去哪儿找」这条路对一个读不到的文件不成立,所以这两类只能把**结论**投影进来。
|
|
6699
|
+
* 好在它们恰好最便宜:一台连接器 ≈10 tokens,hook 只给一个总数
|
|
6700
|
+
* (连事件分组都不给,判据在 {@link SelfIndexInput.hooks} 上)。
|
|
6701
|
+
* 完整的拒绝名单和判据在 `plugin-file/src/utils.ts` 的 `resolveReadablePath` 上。
|
|
6702
|
+
*
|
|
6703
|
+
* ## 三、那几条「约定」是整段里最便宜的准确度
|
|
6704
|
+
*
|
|
6705
|
+
* 形状抄 Codex 的 `context/available_plugins_instructions.rs`(那份 `## Plugins`
|
|
6706
|
+
* 片段同样**不列插件清单**,只讲命名约定和触发规则)。它值钱在于零数据成本:
|
|
6707
|
+
* `<前缀>:` 这个约定今天对模型只是一串字符 —— 没有任何一处告诉过它那是出处。
|
|
6708
|
+
* 讲了之后,「这个插件带来了什么」就变成一次在已有上下文里按前缀筛,一次工具调用都不用。
|
|
6709
|
+
*
|
|
6710
|
+
* ## 四、条件注入:没有的东西一个字都不说
|
|
6711
|
+
*
|
|
6712
|
+
* 一个插件都没装时,插件那一行**和**它那几条约定一起不出现 —— 口径同
|
|
6713
|
+
* `formatSkillIndex` 回空串、同 `projectBlock()` 里那五个按工具存在与否开的策略块。
|
|
6714
|
+
* 讲一个这台机器上不存在的概念是纯噪音,而且它会让模型去猜一个不存在的路径。
|
|
6715
|
+
* 全空时整段回空串,那时 `buildSystem()` 的 `filter` 会把它丢掉。
|
|
6716
|
+
*
|
|
6717
|
+
* ## 五、措辞是中文、写在代码里、不进 locales
|
|
6718
|
+
*
|
|
6719
|
+
* 整份是**给模型读的字**,判据逐字同 `tools/builtin/schedule-draft.ts` 文件头最后
|
|
6720
|
+
* 一节和 `skill/prompt-index.ts`:换界面语言不该换模型看到的东西。
|
|
6721
|
+
* ⚠️ 这个文件因此在 `scripts/i18n-scan.mjs` 的 `SKIP_FILES` 里。
|
|
6722
|
+
*/
|
|
6723
|
+
|
|
6724
|
+
/**
|
|
6725
|
+
* 一台连接器在这一段里的样子。
|
|
6726
|
+
*
|
|
6727
|
+
* ⚠️ **不收 `lastError` 的原文**。三条:那句话来自第三方 server(内容不可控、
|
|
6728
|
+
* 可能很长、也可能带 URL 里的 token);它每次重连都可能变,而这一段一变就作废
|
|
6729
|
+
* 后面整段 prompt cache;而模型对它没有下一步动作 —— 「连不上」和「要登录」
|
|
6730
|
+
* 这两档已经把用户该做什么说完了(重连 / `epoch mcp login`)。
|
|
6731
|
+
* 要看原文的地方是能力页和 `/mcp`,那两处给的是人。
|
|
6732
|
+
*/
|
|
6733
|
+
interface SelfConnector {
|
|
6734
|
+
name: string;
|
|
6735
|
+
/**
|
|
6736
|
+
* 三档不是三种颜色,是**三种下一步**(重连 / `epoch mcp login` / 没有下一步)。
|
|
6737
|
+
*
|
|
6738
|
+
* ⚠️ **类型直接引 `WireMcpConnector['state']`,不在这儿抄一份联合。** 能力页
|
|
6739
|
+
* 那一栏用的就是这一组,而两处各写一份字面量联合的话,哪天加一档(比如
|
|
6740
|
+
* 「正在连」)这边不会红 —— 表现是界面上多一档而模型这侧静默把它归进
|
|
6741
|
+
* `failed`。判序同样不在这儿:那是 protocol 的 `mcpConnectorState()`。
|
|
6742
|
+
*/
|
|
6743
|
+
state: WireMcpConnector['state'];
|
|
6744
|
+
toolCount: number;
|
|
6745
|
+
}
|
|
6746
|
+
/**
|
|
6747
|
+
* 渲染 `<self>` 要的全部数字。**全部现读**,判据见文件头。
|
|
6748
|
+
*
|
|
6749
|
+
* ⚠️ **这几个数一个都不许在这儿重算**。真源各有出处,调用方从那儿取:
|
|
6750
|
+
* 技能走 `skillIndexStats()`(`skill/prompt-index.ts`,`/context` 用的同一个),
|
|
6751
|
+
* 插件走 `LoadedPlugin.counts` / 加载结果(`plugin/loader.ts`),
|
|
6752
|
+
* hook 走 `hook/config-loader.ts` 那份解析。在这儿数第二遍的下场写在
|
|
6753
|
+
* `inventoryTotal()` 的 JSDoc 上:两处口径走散之后**两边都答得出「我算了」**。
|
|
6754
|
+
*/
|
|
6755
|
+
interface SelfIndexInput {
|
|
6756
|
+
/**
|
|
6757
|
+
* 这一程真正在用的家目录。**必须由调用方给**,不许在这儿 `resolveHomeDir()` ——
|
|
6758
|
+
* 判据逐字同 `resolveReadablePath` 的「`homeDir` 不能省」:嵌入宿主的数据目录
|
|
6759
|
+
* 和全局那份不是同一个,印错了等于告诉模型一条它读不到的路径。
|
|
6760
|
+
*/
|
|
6761
|
+
homeDir: string;
|
|
6762
|
+
/**
|
|
6763
|
+
* 当前 profile 名(`resolveProfile()`,`default` = 没启用)。
|
|
6764
|
+
*
|
|
6765
|
+
* ⚠️ **这一行不是装饰**。`infra/src/paths.ts` 文件头记着一次真实故障:
|
|
6766
|
+
* 设了 `EPOCH_PROFILE=work` 之后写和读落在两个目录上,设置静默失效。
|
|
6767
|
+
* Hermes 的 `_active_profile_line()` 为同一个坑专门在 prompt 里留了一行
|
|
6768
|
+
* (原话是「免得 agent 把 `~/.hermes/skills` 和
|
|
6769
|
+
* `~/.hermes/profiles/<active>/skills` 搞混」)—— 这一格是同一条。
|
|
6770
|
+
*/
|
|
6771
|
+
profile: string;
|
|
6772
|
+
/** 装了几个、其中几个被用户停用了(停用的不加载,但它确实装着) */
|
|
6773
|
+
plugins: {
|
|
6774
|
+
active: number;
|
|
6775
|
+
disabled: number;
|
|
6776
|
+
};
|
|
6777
|
+
/** 真进了 `<available_skills>` 的条数 —— 取 `skillIndexStats().indexed` */
|
|
6778
|
+
skills: number;
|
|
6779
|
+
connectors: readonly SelfConnector[];
|
|
6780
|
+
/** 斜杠命令条数(用户级 + 项目级 + 插件带的,同名覆盖之后的总数) */
|
|
6781
|
+
commands: number;
|
|
6782
|
+
/**
|
|
6783
|
+
* **生效**的 hook 条数(跨全部来源和事件)。
|
|
6784
|
+
*
|
|
6785
|
+
* ## 为什么只给一个总数,连事件分组都不给
|
|
6786
|
+
*
|
|
6787
|
+
* 三条,第三条是硬的:
|
|
6788
|
+
*
|
|
6789
|
+
* 1. 用户问「我有什么自动化配置」时要的是「有没有、在哪改」,
|
|
6790
|
+
* 而不是 `PreToolUse 2 / Stop 1` 这种分布 —— 后者对他没有下一步动作;
|
|
6791
|
+
* 2. 分组要么走 `HookManager.count(type)`(它把**宿主用 `register()` 注册的
|
|
6792
|
+
* JS hook** 和用户配的 command hook 加在一起数,于是一台没配过 hook 的机器
|
|
6793
|
+
* 可能印出「hook 3 条」—— 那是假话),要么在装配层按
|
|
6794
|
+
* `HookSourceKind` 映一遍档名,而那等于把这一段的措辞劈成两个文件;
|
|
6795
|
+
* 3. **模型对 hook 没有任何下一步动作** —— 它既看不到 hook 的正文
|
|
6796
|
+
* (`hooks.json` 在读窗口的拒绝名单里,里面是整行 shell 命令),
|
|
6797
|
+
* 也不该去改。它只需要答得出「有」和「在哪」。
|
|
6798
|
+
*
|
|
6799
|
+
* 真源是 `HookStatus.sources` 的 `count` 之和(「这个来源实际装进去的条数,
|
|
6800
|
+
* 坏项已经跳掉」),装配层加总。⚠️ **别换成 `HookManager.count()`** ——
|
|
6801
|
+
* 上面第 2 条说的就是它。
|
|
6802
|
+
*/
|
|
6803
|
+
hooks: number;
|
|
6804
|
+
/** `<settings>` 那一段。不给就整段不出现 */
|
|
6805
|
+
settings?: SelfSettings;
|
|
6806
|
+
}
|
|
6807
|
+
/**
|
|
6808
|
+
* `<settings>` 里允许出现的**全部**字段 —— 这是一份白名单,不是 `EpochConfig` 的投影。
|
|
6809
|
+
*
|
|
6810
|
+
* ## ⚠️ 凭据族永远不进这一格,而且要在类型上说不出口
|
|
6811
|
+
*
|
|
6812
|
+
* 收一个窄接口而**不是** `EpochConfig`(或者它的 `Partial`),理由不是洁癖:
|
|
6813
|
+
* 收整份配置之后,「这一段里会不会出现 `provider.apiKey`」就变成一个要靠人每次
|
|
6814
|
+
* review 的问题,而它今天的正确答案必须由**类型**给出。`credentials[]`、
|
|
6815
|
+
* MCP 的 `env` / `headers`、`.env` 里的一切,同理。
|
|
6816
|
+
*
|
|
6817
|
+
* 形状上抄的是 Codex 的 `context/environment_context.rs`:它也不投影整份 config,
|
|
6818
|
+
* 只发 `<filesystem>`(可写根 + 权限档)和 `<network>`(域名白名单)——
|
|
6819
|
+
* **只投影边界**。加一格之前先问一句:用户真的会问它吗,而模型答错会怎样。
|
|
6820
|
+
*
|
|
6821
|
+
* ## 这里**没有**权限级别和模型型号,那不是漏了
|
|
6822
|
+
*
|
|
6823
|
+
* `<permission_level>` 由 `projectBlock()` 印(`agent/prompt.ts`),
|
|
6824
|
+
* 「当前模型 / 图片输入」两行由 `## 环境` 印(`agent/message-utils.ts`)。
|
|
6825
|
+
* 在这儿再印一遍就是同一个事实的第二处产地,而两处一旦走散,模型会照着
|
|
6826
|
+
* **排在后面**的那一份回答。
|
|
6827
|
+
*/
|
|
6828
|
+
interface SelfSettings {
|
|
6829
|
+
/** 界面语言(`display.language`)。没配 = 探测出来的,说不出确定值就别给 */
|
|
6830
|
+
language?: string;
|
|
6831
|
+
/** `maxTurns`。`0` 是「不限」那一档(`UNLIMITED_TURNS`),别读成「一轮都不许跑」 */
|
|
6832
|
+
maxTurns: number;
|
|
6833
|
+
contextLength: number;
|
|
6834
|
+
/**
|
|
6835
|
+
* `compression.enabled` / `compression.threshold`,**缺省已经解开**。
|
|
6836
|
+
*
|
|
6837
|
+
* ⚠️ 这两格在 protocol 的 `EpochConfig` 上是可选的,但**缺席不是「不知道」** ——
|
|
6838
|
+
* 那份契约明写着缺省语义(`enabled` 缺省 = `true`、`threshold` 缺省 =
|
|
6839
|
+
* `DEFAULT_COMPRESSION_THRESHOLD`)。所以解缺省的活归**取数那一层**
|
|
6840
|
+
* (`runtime/src/self-index.ts`),这儿收的是已经解完的值:
|
|
6841
|
+
* 渲染器认一个 `undefined` 档就等于在这里长出第二处默认值,
|
|
6842
|
+
* 而「默认值只有那一处」是那份契约自己写的。
|
|
6843
|
+
*/
|
|
6844
|
+
compression: {
|
|
6845
|
+
enabled: boolean;
|
|
6846
|
+
threshold: number;
|
|
6847
|
+
};
|
|
6848
|
+
/** `sandbox.terminal`(缺省 = `true`)—— 关掉等于命令能写整个文件系统 */
|
|
6849
|
+
sandboxTerminal: boolean;
|
|
6850
|
+
/** `budget.maxCostUsd` / `budget.maxTokens`,两格都可能没设 */
|
|
6851
|
+
budget?: {
|
|
6852
|
+
maxCostUsd?: number;
|
|
6853
|
+
maxTokens?: number;
|
|
6854
|
+
};
|
|
6855
|
+
}
|
|
6856
|
+
/**
|
|
6857
|
+
* `<self>` + `<settings>` 的成品串。**一样都没有时回空串。**
|
|
6858
|
+
*
|
|
6859
|
+
* 回空串这件事是接口的一部分:空段被 `buildSystem()` 的 `filter` 丢掉,
|
|
6860
|
+
* 于是一台什么都没装的机器拿到的 prompt 与这个功能存在之前**逐字节相同**。
|
|
6861
|
+
* 判据逐字同 `formatSkillIndex`。
|
|
6862
|
+
*/
|
|
6863
|
+
declare function renderSelfIndex(input: SelfIndexInput): string;
|
|
6864
|
+
|
|
6607
6865
|
/**
|
|
6608
6866
|
* Nudge 检测器。
|
|
6609
6867
|
*
|
|
@@ -7069,6 +7327,11 @@ declare function admitArtifacts(raws: readonly ToolArtifactInput[], policy: Mult
|
|
|
7069
7327
|
/**
|
|
7070
7328
|
* 信任闸门 —— 把「这个目录能不能加载项目级配置」折成一次判定。
|
|
7071
7329
|
*
|
|
7330
|
+
* ⚠️ **2026-09-11 起这一次判定有两档**(`trusted` / `exec`,见
|
|
7331
|
+
* {@link TrustDecision})。档位本身的判据全文在 protocol 的 `TrustTier` 上,
|
|
7332
|
+
* 这儿只说降级规则怎么作用在它们身上:**两条规则同时作用于两档**,
|
|
7333
|
+
* 没有「读类走一套、执行类走另一套」那种不对称。
|
|
7334
|
+
*
|
|
7072
7335
|
* 判定 = 存储里的 `TrustLevel` + 两条降级规则:
|
|
7073
7336
|
* 1. `config.trust.enabled === false` → 闸门整体不生效(回到最初行为)
|
|
7074
7337
|
* 2. `unknown` + 非交互(没有 TTY)→ 按 `untrusted` 处理。
|
|
@@ -7101,8 +7364,25 @@ declare function admitArtifacts(raws: readonly ToolArtifactInput[], policy: Mult
|
|
|
7101
7364
|
|
|
7102
7365
|
/** 一次已决的工作区信任判定 */
|
|
7103
7366
|
interface TrustDecision {
|
|
7104
|
-
/**
|
|
7367
|
+
/**
|
|
7368
|
+
* **读类**:允许把这个目录里的文件当指令读(指令文件 / 技能 / 角色 / 命令)。
|
|
7369
|
+
*
|
|
7370
|
+
* ⚠️ 名字没改成 `read`,那是刻意的:这一格的语义**一个字节都没变**,
|
|
7371
|
+
* 改名只会让 70 多个调用点和用例产生一片与本次判断无关的 diff,
|
|
7372
|
+
* 真正的新东西藏在里头看不见。新增的那一档是下面的 {@link exec}。
|
|
7373
|
+
*/
|
|
7105
7374
|
trusted: boolean;
|
|
7375
|
+
/**
|
|
7376
|
+
* **执行类**:允许这个目录里的 `hooks.json` / `.claude/settings*.json` /
|
|
7377
|
+
* `policies/` 生效,以及 `.epoch/settings.json` 里 allow 那一半
|
|
7378
|
+
* (2026-09-11,档位判据见 [protocol 的 `TrustTier`](../../../protocol/src/trust.ts))。
|
|
7379
|
+
*
|
|
7380
|
+
* ⚠️ **`exec` 为真必然 `trusted` 为真,反过来不成立**,而「反过来不成立」正是
|
|
7381
|
+
* 这一格存在的全部意义。想合并成一个三态枚举的人先读那一份 `TrustTier`:
|
|
7382
|
+
* 两档是相加的,而调用点各自只关心其中一档 —— 合成枚举之后每个调用点都要
|
|
7383
|
+
* 自己写一次 `>= exec` 的比较,那才是真会写错的地方。
|
|
7384
|
+
*/
|
|
7385
|
+
exec: boolean;
|
|
7106
7386
|
/** 存储里的原始判定,未经上面两条降级规则处理 */
|
|
7107
7387
|
level: TrustLevel;
|
|
7108
7388
|
/** 人类可读的判定依据,进启动 diagnostics */
|
|
@@ -7115,6 +7395,14 @@ interface TrustGateOptions {
|
|
|
7115
7395
|
manager: TrustManager$1;
|
|
7116
7396
|
/** 有 TTY = 有人能回答「要不要信任」 */
|
|
7117
7397
|
interactive: boolean;
|
|
7398
|
+
/**
|
|
7399
|
+
* 执行类内容指纹的算法,缺省 `computeExecHash`。**只给用例注入用。**
|
|
7400
|
+
*
|
|
7401
|
+
* ⚠️ 缺省值就是真算法,所以忘了传的人拿到的是**正确行为**而不是「不校验」——
|
|
7402
|
+
* 与 `LoadCommandsOptions.trusted` 那条「不给默认参数」刚好相反,判据也相反:
|
|
7403
|
+
* 那一个的默认值会**放宽**(漏传 = 自动获得信任),这一个的默认值只会**收紧**。
|
|
7404
|
+
*/
|
|
7405
|
+
execHash?: (root: string) => string;
|
|
7118
7406
|
}
|
|
7119
7407
|
declare function createTrustGate(opts: TrustGateOptions): TrustGate;
|
|
7120
7408
|
/** 信任记录本身读不出来时的闸门:fail closed */
|
|
@@ -7739,6 +8027,22 @@ interface BudgetStatus {
|
|
|
7739
8027
|
justWarned: boolean;
|
|
7740
8028
|
/** 本次调用是否**首次**遇到「模型无定价数据」 */
|
|
7741
8029
|
justWarnedUnknownPricing: boolean;
|
|
8030
|
+
/**
|
|
8031
|
+
* **刚加进去的这一笔**折成多少钱(美元)。算不出来时 `undefined`,不是 0
|
|
8032
|
+
* (会话库 v9,2026-09-13)。
|
|
8033
|
+
*
|
|
8034
|
+
* ## 为什么这个数必须由闸门给出来,而不是调用方自己算一遍
|
|
8035
|
+
*
|
|
8036
|
+
* 落盘那条路要记「这一轮花了多少」(`SessionDB.recordUsage`),而**只有闸门
|
|
8037
|
+
* 知道这一笔是按哪份单价算的** —— `add()` 里那句
|
|
8038
|
+
* `rate ? rate.pricing : this.defaultPricing` 有两个分支,provider 不报 model
|
|
8039
|
+
* 的时候走的是后者。调用方拿 `rateOf(model)?.pricing` 自己乘一遍,在那一档上
|
|
8040
|
+
* **会得到 undefined,而闸门记的是一个真数** —— 于是会话列表说「查不到单价」,
|
|
8041
|
+
* 预算闸门却在照常扣钱。两个数出自同一次请求,却讲两个故事。
|
|
8042
|
+
*
|
|
8043
|
+
* 所以它和 {@link cumulative} 是同一条原则的两半:**一次请求的账只有一个说法。**
|
|
8044
|
+
*/
|
|
8045
|
+
turnCostUsd?: number;
|
|
7742
8046
|
}
|
|
7743
8047
|
|
|
7744
8048
|
/**
|
|
@@ -7895,6 +8199,30 @@ interface GenerateOutput {
|
|
|
7895
8199
|
*/
|
|
7896
8200
|
model: string;
|
|
7897
8201
|
provider: ProviderType;
|
|
8202
|
+
/**
|
|
8203
|
+
* 这次请求**从哪个模型起步** —— 和上面的 {@link model}(落到哪)是一次请求的两头。
|
|
8204
|
+
*
|
|
8205
|
+
* ## 为什么光有 `model` 不够
|
|
8206
|
+
*
|
|
8207
|
+
* 上面那段注释治的是「记账按错误的单价算」,而它**没有**回答
|
|
8208
|
+
* 「`model` 和别处那个不一样,是谁改的」。落点和任何一个「当前模型」不等,
|
|
8209
|
+
* 至少有四种成因(`agent/loop.ts` 那段列得全):用户 `/model` 换了、
|
|
8210
|
+
* 命令 frontmatter 的 `model:` 覆盖了、provider 失败降级、路由 404 换模型。
|
|
8211
|
+
* **前两种不是故障,后两种是**,而一个落点答不出是哪一种 ——
|
|
8212
|
+
* web 脚注那枚「故障转移」徽标就是拿落点去和 `GET /api/config` 那一发的快照比,
|
|
8213
|
+
* 于是用户在顶栏换一次模型,整段会话的轮次集体被标成「故障转移」。
|
|
8214
|
+
*
|
|
8215
|
+
* 起点接出来之后那个判断落在**同一次请求的两个值**上:不等就是真降级,
|
|
8216
|
+
* 用户换模型时两者相等(起点读的就是换过之后那个选择)。
|
|
8217
|
+
*
|
|
8218
|
+
* ⚠️ **它是「进 while 之前」那个值**,不是循环里的当前值。`escalate()` 就地改
|
|
8219
|
+
* `state.ct` / `state.cm`,在出口处读 `state.cm` 拿到的是落点 —— 那就又成了
|
|
8220
|
+
* 一个恒等于 `model` 的字段,比不加更糟(它会让上面那枚徽标永远不亮)。
|
|
8221
|
+
*
|
|
8222
|
+
* 缺席规则同 {@link usage}:拿不到就整个不给。**不拿 `model` 顶上** ——
|
|
8223
|
+
* 「不知道起点」和「起点就是落点」在读侧是两件事,后者会被读成「这一轮没降级」。
|
|
8224
|
+
*/
|
|
8225
|
+
requestedModel?: string;
|
|
7898
8226
|
/**
|
|
7899
8227
|
* 这一次的 `responseFormat` **真的到了 provider 那一侧吗**(方案 59 §2.3.1)。
|
|
7900
8228
|
*
|
|
@@ -7954,6 +8282,18 @@ interface ProviderStreamChunk {
|
|
|
7954
8282
|
*/
|
|
7955
8283
|
model?: string;
|
|
7956
8284
|
provider?: ProviderType;
|
|
8285
|
+
/**
|
|
8286
|
+
* 这次请求从哪个模型起步,**只在 `finish` chunk 上给**。
|
|
8287
|
+
*
|
|
8288
|
+
* 语义与缺席规则逐条同 `GenerateOutput.requestedModel`(连「别拿落点顶上」
|
|
8289
|
+
* 那条一起),别在这儿另立一套。挂在 finish 而不是每个 delta 上的判据同上面的
|
|
8290
|
+
* {@link model} / {@link provider}。
|
|
8291
|
+
*
|
|
8292
|
+
* ⚠️ **这一格在流式这条路上格外要紧**:web 走的是 `stream()`,
|
|
8293
|
+
* 而两条路的 finish 出口是两段独立代码 —— 只在 `generate()` 那边填,
|
|
8294
|
+
* 症状是「命令行下对、浏览器里那枚徽标永远不亮」,两边都不报错。
|
|
8295
|
+
*/
|
|
8296
|
+
requestedModel?: string;
|
|
7957
8297
|
/**
|
|
7958
8298
|
* 强制 JSON 生效了没有 / provider 抱怨了什么,**只在 `finish` chunk 上给**
|
|
7959
8299
|
* (方案 59 §2.3)。
|
|
@@ -8055,6 +8395,19 @@ interface ProviderGenerateOutput {
|
|
|
8055
8395
|
* (即改造前的行为)。
|
|
8056
8396
|
*/
|
|
8057
8397
|
model?: string;
|
|
8398
|
+
/**
|
|
8399
|
+
* 这一轮**要求**跑的那个模型 —— 和上面的 {@link model}(实际跑的)是一对。
|
|
8400
|
+
*
|
|
8401
|
+
* 两个都在、且不等 = 这一轮真的降级了。**光看 `model` 分不出成因**:
|
|
8402
|
+
* 用户换模型、命令 frontmatter 覆盖、provider 降级、路由 404 换模型,
|
|
8403
|
+
* 四种都会让 `model` 和别处那个模型名不一样,而前两种不是故障。
|
|
8404
|
+
* 判据全文在 `provider/types.ts` 的 `GenerateOutput.requestedModel` 上。
|
|
8405
|
+
*
|
|
8406
|
+
* **可选**,理由逐字同上面那条:脚本化的假 provider 没有「模型」这个概念。
|
|
8407
|
+
* 缺席时读侧一律按「不知道这一轮要的是谁」处理 —— 那时不许拿 `model`
|
|
8408
|
+
* 自比(恒相等,会被读成「确认没降级」)。
|
|
8409
|
+
*/
|
|
8410
|
+
requestedModel?: string;
|
|
8058
8411
|
/**
|
|
8059
8412
|
* provider 对这一次请求的抱怨(2026-09-01)。
|
|
8060
8413
|
*
|
|
@@ -8104,7 +8457,32 @@ interface AgentProvider {
|
|
|
8104
8457
|
*/
|
|
8105
8458
|
capabilities?: {
|
|
8106
8459
|
supportsImages: boolean;
|
|
8460
|
+
/**
|
|
8461
|
+
* `supportsImages: false` 到底是「查到了,不支持」还是「查不到」
|
|
8462
|
+
* (2026-09-11)。判据全文在 core 的 `ModelCapability.imagesUnknown` 上。
|
|
8463
|
+
*
|
|
8464
|
+
* 为真时闸门不再当场拒绝,而是调 {@link AgentProvider.probeImageSupport}
|
|
8465
|
+
* 实测一次。**不给 = 当成「查到了」** —— 脚本化的假 provider(用例里那些)
|
|
8466
|
+
* 不该被迫长出一个探测器。
|
|
8467
|
+
*/
|
|
8468
|
+
imagesUnknown?: boolean;
|
|
8107
8469
|
};
|
|
8470
|
+
/**
|
|
8471
|
+
* 「这个模型到底认不认图」——**发一张图问它本人**(2026-09-11)。
|
|
8472
|
+
*
|
|
8473
|
+
* ## 为什么倒置接口上要有这一格
|
|
8474
|
+
*
|
|
8475
|
+
* 上面 `capabilities` 答的是「我们**查到**它认不认图」,而这一轮的病就出在
|
|
8476
|
+
* 「查」这个动作上:上游改一次模型名字,静态表和 OpenRouter 两层同时 miss,
|
|
8477
|
+
* 默认值 `false` 让一个认图的模型静默瞎掉。实测是唯一不会过期的那一层,
|
|
8478
|
+
* 而它需要一个真的 `LanguageModel` 实例 —— 那是 router 的东西,循环够不着。
|
|
8479
|
+
*
|
|
8480
|
+
* ⚠️ **只在 `imagesUnknown` 且这一轮真有图时才调**。它是一发真的网络请求
|
|
8481
|
+
* (约 225 token),无条件调等于给每一轮凭空加一次往返和一笔钱。
|
|
8482
|
+
*
|
|
8483
|
+
* 不给(脚本化的假 provider)= 退回这一轮之前的行为:查不到就拒发。
|
|
8484
|
+
*/
|
|
8485
|
+
probeImageSupport?: () => Promise<boolean>;
|
|
8108
8486
|
/**
|
|
8109
8487
|
* **此刻这一轮会用哪个模型**(2026-09-02)。
|
|
8110
8488
|
*
|
|
@@ -8347,6 +8725,28 @@ interface AgentConfig {
|
|
|
8347
8725
|
* `AgentRole.skills` 上)。
|
|
8348
8726
|
*/
|
|
8349
8727
|
roleSkills?: () => readonly string[] | undefined;
|
|
8728
|
+
/**
|
|
8729
|
+
* `<self>` / `<settings>` 那两段的现读出口(2026-09-11)——「我手上有什么」。
|
|
8730
|
+
*
|
|
8731
|
+
* 纯透传给 `PromptBuilder`,循环体一处都不读它。立项理由、每一格的判据、
|
|
8732
|
+
* 以及为什么是**串**而不是那堆数字,全文在
|
|
8733
|
+
* [agent/self-index.ts](./self-index.ts) 的文件头和 `PromptBuilderDeps.selfIndex` 上。
|
|
8734
|
+
*
|
|
8735
|
+
* 不接 = 那两段整个不出现 = 这一轮之前逐字节相同。**代价要说清**:不接它的
|
|
8736
|
+
* 宿主,它的模型答不出用户装了什么插件、连了哪几台 server —— 而 `## 规则` 里
|
|
8737
|
+
* 那条「说清楚你能做什么」还在,于是它只能猜或者拒答。
|
|
8738
|
+
*/
|
|
8739
|
+
selfIndex?: () => string;
|
|
8740
|
+
/**
|
|
8741
|
+
* 用哪种语言回复用户(2026-09-11)。纯透传给 `PromptBuilder`,循环体不读它。
|
|
8742
|
+
*
|
|
8743
|
+
* 判据全文在 `agent/message-utils.ts` 的 `SystemPromptParams.replyLang` 上。
|
|
8744
|
+
* 一句话:`## 规则` 第一条原来无条件是「用中文回复用户」,而
|
|
8745
|
+
* `display.language` 一直存在 —— 切英文界面的用户拿到的仍然是中文回复。
|
|
8746
|
+
*
|
|
8747
|
+
* 不接 = 那条规则逐字保持原样 = 这一轮之前逐字节相同。
|
|
8748
|
+
*/
|
|
8749
|
+
replyLang?: () => Lang | undefined;
|
|
8350
8750
|
/**
|
|
8351
8751
|
* 技能学习器(可选——Nudge 触发时自动学习)。
|
|
8352
8752
|
*
|
|
@@ -8911,6 +9311,29 @@ interface ModelCapability {
|
|
|
8911
9311
|
maxOutputTokens: number;
|
|
8912
9312
|
supportsTools: boolean;
|
|
8913
9313
|
supportsImages: boolean;
|
|
9314
|
+
/**
|
|
9315
|
+
* **`supportsImages: false` 说的是「不知道」而不是「不支持」**(2026-09-11)。
|
|
9316
|
+
*
|
|
9317
|
+
* ## 为什么需要第二格,而不是把 `supportsImages` 改成三态
|
|
9318
|
+
*
|
|
9319
|
+
* 三态(`true | false | 'unknown'`)在这儿是个陷阱:`'unknown'` 在 JS 里是
|
|
9320
|
+
* **真值**,任何一处漏改的 `if (cap.supportsImages)` 会静默变成「支持」——
|
|
9321
|
+
* 也就是把图发给一个看不见它的模型,然后收一份对着空气的胡说。多一格布尔的
|
|
9322
|
+
* 话,漏改的那一处拿到的是 `false`,行为和这一轮之前逐字节相同(拒发)。
|
|
9323
|
+
* **失败要落在安全的那一侧**,判据同 `AgentProvider.capabilities` 那条
|
|
9324
|
+
* 「不给就按不支持处理」。
|
|
9325
|
+
*
|
|
9326
|
+
* ## 它是干什么用的:触发一次实测
|
|
9327
|
+
*
|
|
9328
|
+
* 这一格为 `true` 时,闸门(`loop.ts` 闸门 1 的输入侧)不再当场拒绝,而是
|
|
9329
|
+
* 先发一次语义探针问模型本人(见 [capability-probe.ts](./capability-probe.ts)),
|
|
9330
|
+
* 把答案记进缓存。少了这一格,一个上游刚改过名字的模型在我们这儿是**静默**
|
|
9331
|
+
* 瞎掉的 —— 2026-09-11 的现场是 DeepSeek 把 `deepseek-v4-flash-vision-exp`
|
|
9332
|
+
* 改名成 `deepseek-flash`,静态表和 OpenRouter 两层同时 miss。
|
|
9333
|
+
*
|
|
9334
|
+
* 缺席 = `false` = 「这个答案是查到的,不用再探」。
|
|
9335
|
+
*/
|
|
9336
|
+
imagesUnknown?: boolean;
|
|
8914
9337
|
supportsStreaming: boolean;
|
|
8915
9338
|
supportsPromptCaching: boolean;
|
|
8916
9339
|
supportsReasoning: boolean;
|
|
@@ -8931,6 +9354,15 @@ interface ModelMetaEntry {
|
|
|
8931
9354
|
prompt: string;
|
|
8932
9355
|
completion: string;
|
|
8933
9356
|
input_cache_read?: string;
|
|
9357
|
+
/**
|
|
9358
|
+
* 分时价(2026-09-13)。DeepSeek 那一族有,多数模型没有。
|
|
9359
|
+
*
|
|
9360
|
+
* ⚠️ **基础那三格不是「平均价」,是某一档的价**(实测 `deepseek-v4.1-flash`:
|
|
9361
|
+
* 基础 = 闲时 0.15/0.6,峰时 override 到 0.3/1.2)。所以**忽略 overrides
|
|
9362
|
+
* 不是「差一点」,是峰时整整少记一半** —— 而「成本看起来很便宜」正是这个仓
|
|
9363
|
+
* 最不想要的那一类静默错误。判据在 {@link resolvePricingAt}。
|
|
9364
|
+
*/
|
|
9365
|
+
overrides?: readonly PricingOverride[];
|
|
8934
9366
|
};
|
|
8935
9367
|
/** OpenRouter 的 `supported_parameters` / `architecture` 能推出的几项能力 */
|
|
8936
9368
|
supportsTools?: boolean;
|
|
@@ -8942,6 +9374,19 @@ interface ModelMetaEntry {
|
|
|
8942
9374
|
* 失败静默,不阻挡启动。
|
|
8943
9375
|
*/
|
|
8944
9376
|
declare function refreshOpenRouterMetadata(homeDir: string): Promise<void>;
|
|
9377
|
+
/**
|
|
9378
|
+
* 查单价,**并告诉调用方这份价管到什么时候**(2026-09-13)。
|
|
9379
|
+
*
|
|
9380
|
+
* `getCapability().pricing` 给的是「此刻」的价,够绝大多数调用点用;只有
|
|
9381
|
+
* **逐轮调用且会把结果缓存住**的那一个(`runtime` 的 `makePricingLookup`)
|
|
9382
|
+
* 需要多知道一格 —— 一份会过期的价被永久缓存住,症状是跨过峰谷分界之后
|
|
9383
|
+
* 整段会话继续按旧价记账,而**一次都不会红**。
|
|
9384
|
+
*
|
|
9385
|
+
* 优先级和 {@link getCapability} 逐字相同:`STATIC_PRICING` → 磁盘缓存
|
|
9386
|
+
* (含 {@link PRICING_ALIASES})。静态价不随时间变,所以那一支 `validUntil`
|
|
9387
|
+
* 是 `Infinity`。
|
|
9388
|
+
*/
|
|
9389
|
+
declare function pricingFor(modelId: string, homeDir: string, at?: number): PricingAt;
|
|
8945
9390
|
/**
|
|
8946
9391
|
* 获取模型的 Capability。
|
|
8947
9392
|
* 优先级:静态配置 > 磁盘缓存 > 默认值 [Hermes]
|
|
@@ -8949,7 +9394,72 @@ declare function refreshOpenRouterMetadata(homeDir: string): Promise<void>;
|
|
|
8949
9394
|
* **「优先」是逐格的,不是整条记录的**(2026-09-01 改):静态表里没写单价的
|
|
8950
9395
|
* 条目,单价回落到磁盘缓存那一份。见下面静态分支里的判据。
|
|
8951
9396
|
*/
|
|
8952
|
-
declare function getCapability(modelId: string, homeDir: string
|
|
9397
|
+
declare function getCapability(modelId: string, homeDir: string,
|
|
9398
|
+
/**
|
|
9399
|
+
* 哪一家的这个型号。**只有 `supportsImages` 那一格用得到它** —— 实测缓存
|
|
9400
|
+
* 按 `provider:model` 记(同一个裸名在两家下面可以是两个模型)。
|
|
9401
|
+
*
|
|
9402
|
+
* 可选是因为它的调用方分两种:router 知道自己此刻路由到哪一家(一定传),
|
|
9403
|
+
* 而装配期那次只为了拿 `contextLength` / 单价(不传,也不需要)。不传 =
|
|
9404
|
+
* 跳过实测那一层,剩下三层原样。
|
|
9405
|
+
*/
|
|
9406
|
+
provider?: string): ModelCapability;
|
|
9407
|
+
/** 一档分时价。字段全可选 —— 缺了 `utc_days` / 时段就是「一直适用」 */
|
|
9408
|
+
interface PricingOverride {
|
|
9409
|
+
/** UTC 星期几,小写全名(`'monday'`…)。缺席 = 每天 */
|
|
9410
|
+
utc_days?: readonly string[];
|
|
9411
|
+
/** UTC 时刻,**HHMM 形式的整数**(`100` = 01:00,`1000` = 10:00)。缺席 = 0 */
|
|
9412
|
+
utc_start?: number;
|
|
9413
|
+
utc_end?: number;
|
|
9414
|
+
prompt?: string;
|
|
9415
|
+
completion?: string;
|
|
9416
|
+
input_cache_read?: string;
|
|
9417
|
+
}
|
|
9418
|
+
/** 一份**在某个时刻有效**的单价,外加它什么时候失效 */
|
|
9419
|
+
interface PricingAt {
|
|
9420
|
+
pricing: ModelPricing | undefined;
|
|
9421
|
+
/**
|
|
9422
|
+
* 这份单价管到哪一刻(epoch ms,闭区间外)。没有分时价时是 `Infinity`。
|
|
9423
|
+
*
|
|
9424
|
+
* **存在的理由是记忆化**:`runtime` 那个逐轮调用的查价函数把结果 Map 住了,
|
|
9425
|
+
* 而一份会过期的单价被永久 Map 住,症状是**跨过峰谷分界之后整段会话继续按
|
|
9426
|
+
* 旧价记账** —— 一次都不会红。判据在 `build.ts` 的 `makePricingLookup`。
|
|
9427
|
+
*/
|
|
9428
|
+
validUntil: number;
|
|
9429
|
+
}
|
|
9430
|
+
/**
|
|
9431
|
+
* 按**某个时刻**解出这个模型此刻的单价。
|
|
9432
|
+
*
|
|
9433
|
+
* ## 为什么非要解 overrides
|
|
9434
|
+
*
|
|
9435
|
+
* DeepSeek 是分时价,而 OpenRouter 那条记录里**基础价不是平均价,是某一档的价**。
|
|
9436
|
+
* 实测 `deepseek-v4.1-flash`(2026-09-13 快照):基础 `0.15 / 0.6`,而工作日
|
|
9437
|
+
* UTC 01:00–04:00 与 06:00–10:00 两段 override 到 `0.3 / 1.2`。
|
|
9438
|
+
* 只读基础那三格 = **峰时每一笔都只记一半**,而屏幕上那个数看起来完全正常。
|
|
9439
|
+
*
|
|
9440
|
+
* 这也正是 `STATIC_PRICING` 上那条「单价故意不进静态表」当初担心的东西的另一面:
|
|
9441
|
+
* 静态表会把价钉死在**峰值**,而只读基础字段会把它钉死在**谷值**。两个都是错的,
|
|
9442
|
+
* 对的那个答案是「现在几点」。
|
|
9443
|
+
*
|
|
9444
|
+
* ## 匹配规则(逐条照着真实响应核过)
|
|
9445
|
+
*
|
|
9446
|
+
* - `utc_days` 缺席 = 每天;给了就按**UTC 星期几**匹配(不是本地星期几 ——
|
|
9447
|
+
* 字段名里那个 `utc` 是字面意思,而东八区和 UTC 跨日差 8 小时);
|
|
9448
|
+
* - 时段是 HHMM 的整数,**左闭右开** `[utc_start, utc_end)`;
|
|
9449
|
+
* - `utc_end` 为 `0` 表示**到当日 24:00**(真实数据里最后一档就是
|
|
9450
|
+
* `{utc_start: 1000, utc_end: 0}`),不是一个零长度窗口;
|
|
9451
|
+
* - `utc_start > utc_end` 表示**跨午夜**;
|
|
9452
|
+
* - **第一条命中的赢**,同真实数据里那张表互不重叠的排法;
|
|
9453
|
+
* - 一条都没命中就用基础价 —— 那是「这一刻没有折扣」,不是「不知道」。
|
|
9454
|
+
*
|
|
9455
|
+
* ## `validUntil` 怎么算
|
|
9456
|
+
*
|
|
9457
|
+
* 取**所有档的所有边界**(每档的 start 和 end)折成今天的 UTC 时刻,加上次日
|
|
9458
|
+
* 零点,然后取其中第一个晚于 `at` 的。这样算而不是「命中那一档的 end」,
|
|
9459
|
+
* 是因为**没命中**的那一支也需要一个正确的过期点(下一档随时会开始)。
|
|
9460
|
+
* 没有 overrides 时返回 `Infinity`:那份价不随时间变,记忆化可以一直留着。
|
|
9461
|
+
*/
|
|
9462
|
+
declare function resolvePricingAt(raw: ModelMetaEntry['pricing'], at: number): PricingAt;
|
|
8953
9463
|
/**
|
|
8954
9464
|
* 检查模型是否支持 Prompt Caching [Hermes]
|
|
8955
9465
|
*/
|
|
@@ -8985,6 +9495,15 @@ declare class ProviderRouter {
|
|
|
8985
9495
|
*
|
|
8986
9496
|
* 单独存一份而不是每次去读 `config` 现算:`/model --reset` 要回到的是
|
|
8987
9497
|
* 「启动时那个」,而 config 上的字段将来会被别的方案改(方案 22 的分层来源)。
|
|
9498
|
+
*
|
|
9499
|
+
* ⚠️ **「将来」是 2026-09-13,而这一格刻意不跟着它走。** 设置页改 `model` 从那天起
|
|
9500
|
+
* 会推进进程那份 `config.model`(`SettingApply` 的 `new-session` 一档),于是
|
|
9501
|
+
* `this.config.model` 和这一格会分家 —— **那是对的**:这个 router 服务的那段会话
|
|
9502
|
+
* 是用旧值开出来的,把它 `reset()` 到一个它从没待过的模型上,就是拿「以后默认用它」
|
|
9503
|
+
* 去回答「回到我开始时那个」。判据全文在 core 的 `config/write.ts` 的 `SettingApply` 上。
|
|
9504
|
+
*
|
|
9505
|
+
* 分家之后「`reset` 会把你送回哪儿」只有这一格答得上,所以它有了一个读口:
|
|
9506
|
+
* {@link getConfiguredModel}。
|
|
8988
9507
|
*/
|
|
8989
9508
|
private readonly configSelection;
|
|
8990
9509
|
/** 模型连续失败的节流状态(方案 26 验收 #8)。只在本会话内有效,不落盘 */
|
|
@@ -9004,6 +9523,16 @@ declare class ProviderRouter {
|
|
|
9004
9523
|
constructor(config: EpochConfig);
|
|
9005
9524
|
/** 当前生效的选择。回一份拷贝,免得调用方改到内部状态 */
|
|
9006
9525
|
getSelection(): ModelSelection;
|
|
9526
|
+
/**
|
|
9527
|
+
* `resetSelection()` 会把这段会话送回哪个模型 —— 也就是**开这段会话那一刻**
|
|
9528
|
+
* 配置里写的那个。
|
|
9529
|
+
*
|
|
9530
|
+
* ⚠️ **宿主别拿 `config.model` 顶替它**(2026-09-13):那一格从设置页那条写路
|
|
9531
|
+
* 起会往前走,而这一格刻意不跟(判据在 {@link configSelection} 上)。顶替的表现是
|
|
9532
|
+
* 换模型菜单里「回到配置里那个」显示一个名字、按下去回到另一个 —— 而两个都是
|
|
9533
|
+
* 真实存在的模型,屏幕上没有任何东西会红。
|
|
9534
|
+
*/
|
|
9535
|
+
getConfiguredModel(): string;
|
|
9007
9536
|
/**
|
|
9008
9537
|
* 换模型。`next.provider` 不给就是「同一家换个模型」。
|
|
9009
9538
|
*
|
|
@@ -9157,6 +9686,26 @@ declare class ProviderRouter {
|
|
|
9157
9686
|
*/
|
|
9158
9687
|
getApiKeyHint(): string;
|
|
9159
9688
|
getCapability(): ModelCapability;
|
|
9689
|
+
/**
|
|
9690
|
+
* 「此刻这个模型到底认不认图」—— **实测一次**(2026-09-11)。
|
|
9691
|
+
*
|
|
9692
|
+
* 只在 `getCapability().imagesUnknown` 为真、而且用户这一轮真的发了图的时候
|
|
9693
|
+
* 才会被调到(判据在 `loop.ts` 闸门 1 的输入侧)。也就是说:**没人发图就
|
|
9694
|
+
* 永远不花这笔钱**,而发了图的那一次,用户本来就打算为这一轮付费。
|
|
9695
|
+
*
|
|
9696
|
+
* ## 为什么它在 router 上而不是在 loop 里
|
|
9697
|
+
*
|
|
9698
|
+
* 探针要一个**具体的 `LanguageModel` 实例**,而「此刻路由到哪一家、用哪把
|
|
9699
|
+
* key、走不走自建 baseUrl」整个只有 router 知道。放 loop 里等于让循环第二次
|
|
9700
|
+
* 学会造模型实例 —— 而它连 model id 都不该知道(`AgentProvider` 的判据)。
|
|
9701
|
+
*
|
|
9702
|
+
* ## ⚠️ 不走 `generate()`,也就是**不走降级**
|
|
9703
|
+
*
|
|
9704
|
+
* 这一发的宾语是「**这个**型号认不认图」。让它掉进 fallback 的话,回答会变成
|
|
9705
|
+
* 「降级之后那个型号认不认图」,然后被写进**原来那个型号**的缓存里 ——
|
|
9706
|
+
* 一个张冠李戴的实测结论比没有结论更难查。
|
|
9707
|
+
*/
|
|
9708
|
+
probeImageSupport(): Promise<boolean>;
|
|
9160
9709
|
hasPromptCaching(): boolean;
|
|
9161
9710
|
/**
|
|
9162
9711
|
* 估算一段文本占多少 token(真分词,见 `tokenizer.ts`)。
|
|
@@ -9169,6 +9718,89 @@ declare class ProviderRouter {
|
|
|
9169
9718
|
refreshMetadata(): void;
|
|
9170
9719
|
}
|
|
9171
9720
|
|
|
9721
|
+
/**
|
|
9722
|
+
* 「这个模型认不认图」—— **现问模型本人,不查表**(2026-09-11)。
|
|
9723
|
+
*
|
|
9724
|
+
* ## 为什么需要它:查表这条路有一个它永远答不出的问题
|
|
9725
|
+
*
|
|
9726
|
+
* `model-metadata.ts` 的三层(静态表 → OpenRouter 缓存 → 默认值)全都是
|
|
9727
|
+
* **别人对这个模型的描述**。上游改一次名字,两层同时失效,第三层的默认值是
|
|
9728
|
+
* `supportsImages: false` —— 于是一个认图的模型在我们眼里瞎掉,而且是**静默**
|
|
9729
|
+
* 瞎掉:用户得到的是「当前模型不支持图片输入」,一句可核对的理由都没有。
|
|
9730
|
+
*
|
|
9731
|
+
* 2026-09-11 实测的现场:DeepSeek 把 `deepseek-v4-flash-vision-exp` 改名成
|
|
9732
|
+
* `deepseek-flash`,静态表 miss、OpenRouter 那份 872 条里**根本没有这个裸名**,
|
|
9733
|
+
* 于是 `epoch -i 图.png` 被我们自己拦死。而同一张图直接发给它,它答得一字不差。
|
|
9734
|
+
*
|
|
9735
|
+
* ## 判据是 **input token 涨没涨**,而这一格换过两次,两次都是被实测逼的
|
|
9736
|
+
*
|
|
9737
|
+
* ### 第一版:靠 warning —— 当天就否掉了
|
|
9738
|
+
*
|
|
9739
|
+
* 最省事的做法是不确定就照发,SDK 报了 warning(`droppedUserContentParts`)
|
|
9740
|
+
* 就说明它不认。**走不通**,同一天的 A/B:
|
|
9741
|
+
*
|
|
9742
|
+
* | 模型 | 出站 body | warnings | 回答 | input token |
|
|
9743
|
+
* | ----------------- | --------- | -------- | ----------- | ----------- |
|
|
9744
|
+
* | `deepseek-flash` | 带图 | `[]` | `"Red"` | 225 |
|
|
9745
|
+
* | `deepseek-v4-pro` | 带图 | `[]` | `"Unknown"` | 99 |
|
|
9746
|
+
*
|
|
9747
|
+
* 第二行就是那个坑:**它把图无声吞了,一条 warning 都不报**,SDK 和 provider
|
|
9748
|
+
* 两侧都认为这次请求很正常。同理「不报错就算认图」「答了话就算认图」也都被这一行
|
|
9749
|
+
* 否掉 —— 它不报错,它也答了话。
|
|
9750
|
+
*
|
|
9751
|
+
* ### 第二版:靠**回答**(发一张纯红图问颜色,答得出红就算)—— 2026-09-12 否掉
|
|
9752
|
+
*
|
|
9753
|
+
* 它把断言落在了模型的**识图准确率**上,而那个东西既不稳定、也不是我们的责任。
|
|
9754
|
+
* 同一张 132 字节的红方块、同一个型号(`deepseek-v4-flash-vision-exp`)、
|
|
9755
|
+
* **逐字节相同的出站 body**(钩 `fetch` 抓的,四次都是 `bodyLen=50948`),
|
|
9756
|
+
* 连着跑四次的回答是:
|
|
9757
|
+
*
|
|
9758
|
+
* | run | 回答 |
|
|
9759
|
+
* | --- | --------- |
|
|
9760
|
+
* | 1 | `Red` |
|
|
9761
|
+
* | 2 | `White` |
|
|
9762
|
+
* | 3 | `Magenta` |
|
|
9763
|
+
* | 4 | `Blue` |
|
|
9764
|
+
*
|
|
9765
|
+
* 也就是说这一版探针在这个型号上有约 3/4 的概率把一个**确实收到了图**的模型
|
|
9766
|
+
* 判成瞎子,然后把 `false` 写进缓存。
|
|
9767
|
+
*
|
|
9768
|
+
* ### 这一版:靠 input token 的**增量**
|
|
9769
|
+
*
|
|
9770
|
+
* 同一批运行里,回答四选一,而 `inputTokens` 纹丝不动 ——
|
|
9771
|
+
* 带图 21088、不带图 20904(各跑两次,两两分毫不差)。差的那 184 个 token
|
|
9772
|
+
* 就是那张图:**模型为它计了费,也就意味着它真的收下并处理了。**
|
|
9773
|
+
*
|
|
9774
|
+
* 于是探针发两发(同一句话,一发带图一发不带),比 `inputTokens`:
|
|
9775
|
+
*
|
|
9776
|
+
* - 涨了 → 图被接收(上表第一行,225 vs 99 也正是这个形状);
|
|
9777
|
+
* - 没涨 → 被无声吞了(上表第二行);
|
|
9778
|
+
* - 拿不到 usage → `inconclusive`,**不写缓存**。
|
|
9779
|
+
*
|
|
9780
|
+
* ⚠️ **这一版探不出「收了图但看不懂」**,这是刻意放弃的:那是模型质量,
|
|
9781
|
+
* 不在我们的责任边界内。上面那四次 `White` / `Magenta` / `Blue` 在新判据下
|
|
9782
|
+
* 全部算「认图」—— 而它们确实都认图,这正是想要的。
|
|
9783
|
+
*
|
|
9784
|
+
* ⚠️ 探针的两发**不共享长前缀、也够不着任何 prompt 缓存**(裸 `generateText`,
|
|
9785
|
+
* 没有 system prompt,整条消息一百多 token)。这一条是承重的:provider 一旦
|
|
9786
|
+
* 把 `inputTokens` 按「未命中缓存的部分」报,两发的数就不可比了。
|
|
9787
|
+
*
|
|
9788
|
+
* ## ⚠️ 第三档 `inconclusive` 的含义跟着换了
|
|
9789
|
+
*
|
|
9790
|
+
* 第二版里它指「正文是空的」(推理型号把输出预算花在思考上)。这一版**不看正文**,
|
|
9791
|
+
* 所以那一档现在指「**拿不到 usage**」(provider 不报、或基线那一发自己失败了)。
|
|
9792
|
+
* 处置没变:这一次按「不认图」走,但**一个字都不写缓存** —— 写进去会把一个
|
|
9793
|
+
* 认图的模型钉死(`true` 的缓存是 30 天)。
|
|
9794
|
+
*/
|
|
9795
|
+
|
|
9796
|
+
/**
|
|
9797
|
+
* ⚠️ 2026-09-12 从 1 提到 2:判据从「答不答得出红」换成「input token 涨没涨」
|
|
9798
|
+
* (判据全文在文件头)。**旧结论是用另一把尺子量的**,其中的 `false` 有相当一部分
|
|
9799
|
+
* 是第二版那个 3/4 误判率产出的 —— 继续信它等于把一次已经作废的实验的结果
|
|
9800
|
+
* 当成这次的。整份丢掉,重新探。
|
|
9801
|
+
*/
|
|
9802
|
+
declare const PROBE_VERSION = 2;
|
|
9803
|
+
|
|
9172
9804
|
/**
|
|
9173
9805
|
* Provider 错误的分类:一个异常对象 → 「该怎么恢复」。
|
|
9174
9806
|
*
|
|
@@ -9706,9 +10338,24 @@ declare function usdToMicros(usd: number): number;
|
|
|
9706
10338
|
/**
|
|
9707
10339
|
* 金额的人类可读形式。
|
|
9708
10340
|
*
|
|
9709
|
-
* 不到 1 分钱的时候 `$0.00`
|
|
10341
|
+
* 不到 1 分钱的时候 `$0.00` 等于没说,所以小额多给两位有效数字 ——
|
|
10342
|
+
* 那条规则现在是 protocol 里 `formatMoney()` 的 `'adaptive'` 档,行为一字未改。
|
|
10343
|
+
*
|
|
10344
|
+
* ## ⚠️ 名字里的 `Usd` 说的是**入参**,不是输出
|
|
10345
|
+
*
|
|
10346
|
+
* 入参恒为美元(全仓的算术都是),而印出来的那一串跟着
|
|
10347
|
+
* `display.currency` 走 —— 配了人民币就是 `¥6.10`。这两件事的分界全文在
|
|
10348
|
+
* [protocol/src/money.ts](../../../protocol/src/money.ts) 文件头那张表。
|
|
10349
|
+
*
|
|
10350
|
+
* 名字**刻意没改成 `formatMoney`**:这个仓里 `Usd` 后缀的一贯含义就是
|
|
10351
|
+
* 「这一格装的是美元」(`costUsd`、`maxCostUsd`、`microUsd`),而它的入参正是。
|
|
10352
|
+
* 改名会让调用点看起来像是可以传别的币种进来 —— 那是这里最不想要的误解。
|
|
10353
|
+
*
|
|
10354
|
+
* @param digits 定死几位。缺省 `'adaptive'` = 这个函数的历史行为。
|
|
10355
|
+
* 闸门那几句文案给的是 `4`(**不是**口味:那几句印的是单轮 / 累计成本,
|
|
10356
|
+
* 常在 $0.003 这一档,两位会印成一个「免费」的假象)
|
|
9710
10357
|
*/
|
|
9711
|
-
declare function formatUsd(usd: number): string;
|
|
10358
|
+
declare function formatUsd(usd: number, digits?: MoneyDigits): string;
|
|
9712
10359
|
/**
|
|
9713
10360
|
* 累加两份用量(含缓存 / 思考 / 总数四个可选维度),返回新对象。
|
|
9714
10361
|
*
|
|
@@ -9763,6 +10410,58 @@ declare function estimateImageTokens(width?: number, height?: number): number |
|
|
|
9763
10410
|
*/
|
|
9764
10411
|
declare function totalTokens(usage: TokenUsage): number;
|
|
9765
10412
|
|
|
10413
|
+
/**
|
|
10414
|
+
* 进程级的展示币种(2026-09-13)。
|
|
10415
|
+
*
|
|
10416
|
+
* ## 为什么是模块级插槽,而不是逐处穿参
|
|
10417
|
+
*
|
|
10418
|
+
* 判据逐条借 infra 的 `setLang()`,在这儿是原样成立的:金额的格式化点散在
|
|
10419
|
+
* core / runtime / cli / tui / web **五个包十几处**,而币种对它们中的每一个都是
|
|
10420
|
+
* **同一个进程级的一次性决定** —— 一个进程不会一半印美元一半印人民币。
|
|
10421
|
+
* 逐处穿参等于把一个显示偏好变成一次全仓签名改造,而 infra 里 `setLogLevel` /
|
|
10422
|
+
* `setShell` / `setSecretStore` 早就是这个形态。
|
|
10423
|
+
*
|
|
10424
|
+
* ## ⚠️ 它住在 core,不是 infra —— 因为 `CurrencyDisplay` 住在 protocol
|
|
10425
|
+
*
|
|
10426
|
+
* infra 是**零内部依赖包**(`check-layers.mjs` 的 `ALLOWED` 里它的内部依赖是空的),
|
|
10427
|
+
* import 不了 protocol,而这个插槽装的正是一个 protocol 类型。放 infra 就得在
|
|
10428
|
+
* infra 里再声明一遍那个形状 —— 那是 `LANGS` 在两边各写一份的老问题,而那一份
|
|
10429
|
+
* 有一条「两边行为逐项相等」的门禁兜着,这一份不值得再开一条。
|
|
10430
|
+
*
|
|
10431
|
+
* 代价是 **tui 够不着**(它不许 import core)。那一侧走宿主注入,形状和它那份
|
|
10432
|
+
* `t()` 逐字一样 —— 判据在 [tui/src/money.ts](../../../tui/src/money.ts)。
|
|
10433
|
+
*
|
|
10434
|
+
* ## 没设过的时候:`undefined` = 美元
|
|
10435
|
+
*
|
|
10436
|
+
* 这不是兜底的敷衍,它是**默认路径本身**:绝大多数用户没配 `display.currency`,
|
|
10437
|
+
* 而 `formatMoney()` 在 `currency` 缺席时的输出与 2026-09-13 之前逐字节相同
|
|
10438
|
+
* (判据在 protocol 的 `money.ts` 文件头最后一节)。
|
|
10439
|
+
*
|
|
10440
|
+
* ⚠️ 所以这里**不给一个 `{code:'USD', rate:1}` 的默认值**。给了的话「没配过」和
|
|
10441
|
+
* 「配了美元」在下游就分不出来了,而 `WireConfigResponse.currency` 那一格的语义
|
|
10442
|
+
* 恰恰是「没配就没有这个键」。
|
|
10443
|
+
*/
|
|
10444
|
+
|
|
10445
|
+
/**
|
|
10446
|
+
* 钉住这个进程的展示币种。装配层读完配置后调一次。
|
|
10447
|
+
*
|
|
10448
|
+
* **生产路径上只有 `cli/src/language.ts` 的 `applyConfiguredCurrency()` 调它**,
|
|
10449
|
+
* 和 `setLang()` 在同两个入口、同一个位置 —— 理由也一样:它必须跑在**任何一句
|
|
10450
|
+
* 带金额的文案之前**,而最早那几句是启动诊断里的预算行(`boot.budget_cost`)。
|
|
10451
|
+
*
|
|
10452
|
+
* 传 `undefined` 可以把它清回美元 —— 用例需要这条(进程是复用的,
|
|
10453
|
+
* 一个用例设过币种之后不还原,下一个用例会莫名其妙拿到人民币)。
|
|
10454
|
+
*/
|
|
10455
|
+
declare function setDisplayCurrency(next: CurrencyDisplay | undefined): void;
|
|
10456
|
+
/**
|
|
10457
|
+
* 当前展示币种,没设过就是 `undefined`(= 美元)。
|
|
10458
|
+
*
|
|
10459
|
+
* ⚠️ **现读,别存成模块级常量。** 常量在 `setDisplayCurrency()` 之前就求值完了,
|
|
10460
|
+
* 币种会被永久钉在「没设过」那一档 —— 同 tui 那份 `t()` 文件头「别在模块级调
|
|
10461
|
+
* `t()`」那条,失败形态一模一样:不报错,只是永远印美元。
|
|
10462
|
+
*/
|
|
10463
|
+
declare function displayCurrency(): CurrencyDisplay | undefined;
|
|
10464
|
+
|
|
9766
10465
|
/**
|
|
9767
10466
|
* 设置文件的形状与读取 —— 项目级 / 项目本地 / `--settings` / 企业托管**共用这一份**。
|
|
9768
10467
|
*
|
|
@@ -10100,9 +10799,21 @@ declare function countRules(lists: PermissionRuleLists | undefined): number;
|
|
|
10100
10799
|
* @param base `loadConfig()` 的产物(第 ①② 层)。**不会被修改**
|
|
10101
10800
|
* @param projectRoot 项目根,取自 `resolveProjectRoot()` —— 必须和信任判定用的是
|
|
10102
10801
|
* 同一个答案,否则会出现「诊断说未信任、实际却加载了」
|
|
10103
|
-
* @param
|
|
10802
|
+
* @param execTrusted 工作区授过**执行类**吗(`TrustDecision.exec`),取自
|
|
10803
|
+
* `decideTrust()`。本文件不自己判
|
|
10804
|
+
*
|
|
10805
|
+
* ## ⚠️ ③④ 两层**整份**归执行类,不按字段拆(2026-09-11)
|
|
10806
|
+
*
|
|
10807
|
+
* 拆档之后有一个看着更细的选法:`permissions.allow` 归执行类,`model` /
|
|
10808
|
+
* `maxTurns` 那两个标量跟着读类回来。**不这么做**,判据是这一层的 `gated`
|
|
10809
|
+
* 语义已经是「读到了、也解析了,但只有 deny 被采纳」——再按字段切一刀,
|
|
10810
|
+
* 这一层就有了三种半生不熟的状态,而设置页那条六层来源链要为每一格分别解释
|
|
10811
|
+
* 「这一格为什么在、隔壁那格为什么不在」。
|
|
10812
|
+
*
|
|
10813
|
+
* 代价如实写着:只授了读类的工作区,它 `.epoch/settings.json` 里的 `model`
|
|
10814
|
+
* 不生效 —— 和拆档之前「未信任」那一档的行为**逐字节相同**,不是新增的限制。
|
|
10104
10815
|
*/
|
|
10105
|
-
declare function resolveSettings(base: EpochConfig, projectRoot: string,
|
|
10816
|
+
declare function resolveSettings(base: EpochConfig, projectRoot: string, execTrusted: boolean, opts?: ResolveSettingsOptions): SettingsResolution;
|
|
10106
10817
|
|
|
10107
10818
|
/**
|
|
10108
10819
|
* 「为什么是这个值」—— 一个配置键赢在哪一层,以及被压住的层各自写了什么。
|
|
@@ -10359,14 +11070,47 @@ declare function hasProviderCredentials(homeDir?: string): boolean;
|
|
|
10359
11070
|
*
|
|
10360
11071
|
* **默认值的单一真源就是这一行**(本文件头那句话对它同样成立)。
|
|
10361
11072
|
* `ContextCompressor` 直接 `new` 出来、没给 `threshold` 时也回落到它,
|
|
10362
|
-
* 走的是 import
|
|
11073
|
+
* 走的是 import 而不是在那边再写一个数 —— 两处各写一份的话,
|
|
10363
11074
|
* 调了这个数之后「配置里读到的默认值」和「引擎真的在用的默认值」会分叉,
|
|
10364
11075
|
* 而设置页印的恰好是前者。
|
|
10365
11076
|
*
|
|
10366
11077
|
* ⚠️ 改这个数对**所有没配过这个键的人**生效,是一次用户能感知的行为变更
|
|
10367
11078
|
* (压缩来得更早或更晚),要写 changeset。
|
|
11079
|
+
*
|
|
11080
|
+
* ## ⚠️ 2026-09-11:`0.5` → `0.8`
|
|
11081
|
+
*
|
|
11082
|
+
* `0.5` 从来不是推出来的 —— 这一格的 JSDoc 自己写着它编码的是「改造前的行为」。
|
|
11083
|
+
* 它的实际含义是:**一个 200k 窗口的模型,提示词到 100k 就开始丢真实上下文,
|
|
11084
|
+
* 而那一半窗口永远用不到。**
|
|
11085
|
+
*
|
|
11086
|
+
* 丢的是什么不抽象:压缩留下 `protectFirstN: 1` + 一段摘要 + `protectLastN: 5`,
|
|
11087
|
+
* 而那个 5 是**消息条数不是轮数** —— agent 循环里一次工具往返就占两条
|
|
11088
|
+
* (assistant 的 tool-call + tool 的结果),所以压完之后模型手上真实的工具记录
|
|
11089
|
+
* 只剩最近两次往返。读过的文件正文、diff、报错原文,一律降级成摘要里的一句
|
|
11090
|
+
* 「曾经读过某个文件」。
|
|
11091
|
+
*
|
|
11092
|
+
* ### 为什么抬它是安全的:安全那一半根本不归它管
|
|
11093
|
+
*
|
|
11094
|
+
* 这条是**软线**,判据在 protocol 的 `isContextNearlyFull` / `OVERSIZE_RATIO`
|
|
11095
|
+
* 那张表上:软线问的是「该压了吗(省钱)」,越线之后**冷却期和熔断说不压就不压**;
|
|
11096
|
+
* 而「这一发还发得出去吗」是另一条**硬线**(`OVERSIZE_RATIO = 0.9`,冷却期让路)。
|
|
11097
|
+
* 也就是说撞窗口那一档 2026-09-10 起已经由硬线兜住,软线纯粹是一个成本旋钮。
|
|
11098
|
+
*
|
|
11099
|
+
* ### 为什么是 0.8 而不是照抄 0.9
|
|
11100
|
+
*
|
|
11101
|
+
* 同类产品的数:**Codex 的自动压缩线是窗口的 90%**,而且配置只能把它调更小
|
|
11102
|
+
* (`ModelInfo::auto_compact_token_limit()`:`(context_window * 9) / 10`,
|
|
11103
|
+
* 再 `min(config_limit, …)`;用例钉着 400k → 360k)。
|
|
11104
|
+
*
|
|
11105
|
+
* 我们**不取 0.9**,因为那会和硬线重合,而两条线在这个仓库里是**不同的机制**:
|
|
11106
|
+
* 重合之后软线永远不会先开火,每一次压缩都从硬线那条路走 —— 而硬线**不认冷却期**。
|
|
11107
|
+
* 结果是摘要调用变多而不是变少,等于把 2026-09-10 那一笔的冷却期删掉。
|
|
11108
|
+
* 0.8 留出 10% 的带宽给软线先试一次(它带冷却和熔断),硬线照旧在 0.9 兜底。
|
|
11109
|
+
*
|
|
11110
|
+
* ⚠️ 顺带一个正向效果:`prune.ts` 那一步(裁完重新量、够了就不调模型)的判定
|
|
11111
|
+
* 也吃这个阈值,抬高之后「裁一裁就够了、不用打摘要请求」的场景变多。
|
|
10368
11112
|
*/
|
|
10369
|
-
declare const DEFAULT_COMPRESSION_THRESHOLD = 0.
|
|
11113
|
+
declare const DEFAULT_COMPRESSION_THRESHOLD = 0.8;
|
|
10370
11114
|
declare const EpochConfigSchema: z.ZodObject<{
|
|
10371
11115
|
provider: z.ZodPrefault<z.ZodObject<{
|
|
10372
11116
|
type: z.ZodDefault<z.ZodEnum<{
|
|
@@ -10555,6 +11299,13 @@ declare const EpochConfigSchema: z.ZodObject<{
|
|
|
10555
11299
|
zh: "zh";
|
|
10556
11300
|
en: "en";
|
|
10557
11301
|
}>>;
|
|
11302
|
+
currency: z.ZodOptional<z.ZodObject<{
|
|
11303
|
+
code: z.ZodEnum<{
|
|
11304
|
+
USD: "USD";
|
|
11305
|
+
CNY: "CNY";
|
|
11306
|
+
}>;
|
|
11307
|
+
rate: z.ZodNumber;
|
|
11308
|
+
}, z.core.$strip>>;
|
|
10558
11309
|
}, z.core.$strip>>;
|
|
10559
11310
|
brand: z.ZodOptional<z.ZodString>;
|
|
10560
11311
|
sidebarMenu: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -10671,7 +11422,7 @@ interface ConfigMigration {
|
|
|
10671
11422
|
* 见下面 {@link SETTING_WRITE_LAYERS} 和 {@link settingWriteTargets}。这是三件里
|
|
10672
11423
|
* 唯一有硬约束的一件。
|
|
10673
11424
|
*
|
|
10674
|
-
* ### 3.
|
|
11425
|
+
* ### 3. 写完要重启 —— 除了 `model`,它 2026-09-13 分叉成了「新开的会话就生效」
|
|
10675
11426
|
*
|
|
10676
11427
|
* 见 {@link SettingApply}。
|
|
10677
11428
|
*
|
|
@@ -10844,33 +11595,87 @@ declare function settingWriteLayers(key: string): readonly SettingWriteLayer[];
|
|
|
10844
11595
|
/**
|
|
10845
11596
|
* 写完要做什么它才生效。
|
|
10846
11597
|
*
|
|
10847
|
-
* ##
|
|
11598
|
+
* ## 两档,而它们都是关于**进程**的话
|
|
10848
11599
|
*
|
|
10849
11600
|
* `loadConfig()` 在装配时跑一次,之后这个进程手上那份 `config` 再也不重读。
|
|
10850
|
-
*
|
|
11601
|
+
* 所以对绝大多数键,落盘的那一刻:
|
|
10851
11602
|
*
|
|
10852
11603
|
* - 正在跑的这一轮当然不变(`maxTurns` 在 `AgentLoop` 构造时就定死了)
|
|
10853
11604
|
* - **新开一个会话也不变** —— 新会话用的还是同一份进程级 `config`
|
|
10854
11605
|
* - 连 `GET /api/sessions/:id/settings` 回的值都还是旧的(它读
|
|
10855
11606
|
* `services.baseConfig` / `services.settingsLayers`,那两样都是装配期的快照)
|
|
10856
11607
|
*
|
|
10857
|
-
*
|
|
10858
|
-
*
|
|
10859
|
-
*
|
|
11608
|
+
* 于是 `restart` 的准确含义是**重启 `epoch web` 那个进程**,不是「新开一个会话」。
|
|
11609
|
+
* 这条必须说破:不说的话,用户改完、新建一个会话、发现行为没变,然后对着一个
|
|
11610
|
+
* 没动静的界面发呆 —— 而这正是设计稿第三问要防的事。
|
|
11611
|
+
*
|
|
11612
|
+
* ## ✅ `model` 2026-09-13 分叉出去了,它是 `new-session`
|
|
11613
|
+
*
|
|
11614
|
+
* 这一节上一版写着「今天只有 `restart` 一档」,并且逐字预告了这一天:
|
|
11615
|
+
*
|
|
11616
|
+
* > 「什么时候生效」将来真会按键分叉:`model` 这个进程里已经有一条运行期换模型的
|
|
11617
|
+
* > 路(`ModelControl`),哪天设置页接上它,`model` 就先变成另一档,而 `maxTurns`
|
|
11618
|
+
* > 还是 `restart`。那一天加的是这个联合的第二个成员。
|
|
11619
|
+
*
|
|
11620
|
+
* 接上的那根线只有一处(runtime 的 `advanceModelDefault`):写赢了就推进进程那份
|
|
11621
|
+
* `config.model`,而 `SessionModels.open()` 建新会话的 router 时**现读**它。
|
|
11622
|
+
*
|
|
11623
|
+
* ⚠️ **是 `new-session` 不是 `live`,这个名字是判据本身。** 已经在跑的那些会话
|
|
11624
|
+
* 一个都不动,连它们 `reset()` 的目标(`ProviderRouter.configSelection`)都不动 ——
|
|
11625
|
+
* 每段会话带着它出生那一刻的配置跑。两条理由:
|
|
10860
11626
|
*
|
|
10861
|
-
*
|
|
11627
|
+
* 1. `wire-model.ts` 那张对照表把两条路分成「现在换个脑子试试」(顶栏,会话级、
|
|
11628
|
+
* 立刻、不写盘)和「以后默认用它」(这一条,写盘)。`new-session` 正好是第二句,
|
|
11629
|
+
* 而 `live` 会把用户在顶栏明确挑过的那个选择顶掉 —— 那恰恰是那张表在防的事;
|
|
11630
|
+
* 2. 判据逐字照 `SessionFactoryOptions.mainRole` 的「它是**这次启动**的参数」,
|
|
11631
|
+
* 这里只是把「这次启动」收窄成「开这段会话那一刻」。
|
|
11632
|
+
*
|
|
11633
|
+
* 于是这条路上**没有半失败这回事**:不过 `applySelection` 那两道前置检查
|
|
11634
|
+
* (会话里有图片 / 窗口装不装得下),一次赋值就完了。MCP 那条 `保存 → 应用`
|
|
11635
|
+
* 拆成两发的判据(「写盘是毫秒、握手不是,半失败是常态」)在这儿不成立。
|
|
11636
|
+
*
|
|
11637
|
+
* ## 仍然不摆 `live` 那一档占位
|
|
10862
11638
|
*
|
|
10863
11639
|
* 同 `WireSettingLayer` 里 `plugin` 那一档刻意缺席的判据:摆一档永远不会出现的
|
|
10864
|
-
*
|
|
11640
|
+
* 值,等于告诉读代码的人「有些键改完当场就生效」,而那是假的。哪天真做了再加。
|
|
11641
|
+
*/
|
|
11642
|
+
type SettingApply =
|
|
11643
|
+
/** 要重启 `epoch web` 那个进程。除 `model` 外所有可写键都是这一档 */
|
|
11644
|
+
'restart'
|
|
11645
|
+
/**
|
|
11646
|
+
* **此后新开的会话**用新值,这个进程正在跑的那些不变、也不用重启。
|
|
11647
|
+
*
|
|
11648
|
+
* 今天只有 `model` 走得到,而且还要 {@link SettingApplyFacts.canOpenSessions}
|
|
11649
|
+
* 为真 —— 见那个字段。
|
|
11650
|
+
*/
|
|
11651
|
+
| 'new-session';
|
|
11652
|
+
/**
|
|
11653
|
+
* 算 {@link SettingApply} 要的那一件**事实**(规则在 core,事实在装配层)。
|
|
11654
|
+
*
|
|
11655
|
+
* 分法逐字照 `SelectionContext` 那句「判据在 core,事实在会话,runtime 不替宿主猜」:
|
|
11656
|
+
* 「`model` 改完新会话就生效」这条规则属于这个文件,而「这个进程开不开得出新会话」
|
|
11657
|
+
* 只有 runtime 知道。
|
|
11658
|
+
*/
|
|
11659
|
+
interface SettingApplyFacts {
|
|
11660
|
+
/**
|
|
11661
|
+
* 这个进程建得出新会话吗(`services.provider !== null`)。
|
|
11662
|
+
*
|
|
11663
|
+
* ⚠️ **为假时 `model` 退回 `restart`,这一条不是保守起见。** provider 层起不来时
|
|
11664
|
+
* `SessionRuntimeFactory.assemble()` 当场回 null,这个进程**一个会话都建不出来** ——
|
|
11665
|
+
* 那时说「新开的会话会用它」是一句假话,而用户的下一步确实是重启。
|
|
11666
|
+
*
|
|
11667
|
+
* 这也正是「还没配 key,先存一个模型名」那一屏(`web/src/settings/config.tsx` 的
|
|
11668
|
+
* `no_provider_restart`)照旧要说「存完要重启」的原因:那一屏的前提就是这里为假。
|
|
11669
|
+
*/
|
|
11670
|
+
canOpenSessions: boolean;
|
|
11671
|
+
}
|
|
11672
|
+
/**
|
|
11673
|
+
* 这个键写完要做什么才生效。**全仓唯一一处按键分叉的地方。**
|
|
10865
11674
|
*
|
|
10866
|
-
*
|
|
10867
|
-
*
|
|
10868
|
-
* 哪天设置页接上它,`model` 就先变成另一档,而 `maxTurns` 还是 `restart`。
|
|
10869
|
-
* 那一天加的是这个联合的第二个成员,不是把一句话从响应上拆到行上。
|
|
11675
|
+
* 不做成一张 `Record<string, SettingApply>`:可写键有十几个而分叉的只有一个,
|
|
11676
|
+
* 一张表会让「除了 model 全是 restart」这句话散在十几行里,加键的人得挨个填。
|
|
10870
11677
|
*/
|
|
10871
|
-
|
|
10872
|
-
/** 见 {@link SettingApply}。落在这一层是因为「写完怎么办」的判据在这个文件里 */
|
|
10873
|
-
declare const SETTING_WRITE_APPLY: SettingApply;
|
|
11678
|
+
declare function settingWriteApply(key: string, facts: SettingApplyFacts): SettingApply;
|
|
10874
11679
|
/**
|
|
10875
11680
|
* 这一层排第几。**`unknown` 回 `null`,而那不是兜底**。
|
|
10876
11681
|
*
|
|
@@ -10928,6 +11733,14 @@ interface SettingWriteTargetsOptions {
|
|
|
10928
11733
|
* ⚠️ 它必须和 `paths.projectLocal` 来自**同一个工作区**,判据见文件头第四节。
|
|
10929
11734
|
*/
|
|
10930
11735
|
trusted: boolean;
|
|
11736
|
+
/**
|
|
11737
|
+
* 算 {@link SettingWriteTarget.apply} 要的那件事实。见 {@link SettingApplyFacts}。
|
|
11738
|
+
*
|
|
11739
|
+
* ⚠️ **`rows()` 和 `write()` 两条路必须递同一份。** 递不同的话,用户按下去之前
|
|
11740
|
+
* 看到的是「新开的会话就生效」、按完回执说「要重启」—— 而这一屏存在的全部理由
|
|
11741
|
+
* 就是「写之前那句话是真的」。
|
|
11742
|
+
*/
|
|
11743
|
+
apply: SettingApplyFacts;
|
|
10931
11744
|
}
|
|
10932
11745
|
/**
|
|
10933
11746
|
* 一行能写进哪几层,以及**写之前**就说得出来的那句话。
|
|
@@ -12024,7 +12837,54 @@ interface SessionMeta {
|
|
|
12024
12837
|
cacheReadTokens: number;
|
|
12025
12838
|
cacheWriteTokens: number;
|
|
12026
12839
|
reasoningTokens: number;
|
|
12027
|
-
|
|
12840
|
+
/**
|
|
12841
|
+
* 这段会话累计**估算**花费(美元)。`recordUsage()` 逐轮累加(会话库 v9,2026-09-13)。
|
|
12842
|
+
*
|
|
12843
|
+
* ## ⚠️ `undefined` ≠ `0`,而这一格在 v9 之前**永远是 0**
|
|
12844
|
+
*
|
|
12845
|
+
* 它和上面五个 token 列是同一批从 Hermes 抄来的坑位,但那五列 2026-08 接上了
|
|
12846
|
+
* 真实来源,**这一格没有**:`manager.ts` 建行时写个 `0`,此后全仓没有第二个
|
|
12847
|
+
* 写入点。于是 `SessionSummary.costUsd`(`epoch sessions list` 和网线上那一格
|
|
12848
|
+
* 的来源)一直是 `0` —— 而按这个仓一以贯之的口径,**0 的意思是「免费」**。
|
|
12849
|
+
* 今天还没人把它画出来(`web/src/state/store.tsx` 那句「全仓没有一处读」),
|
|
12850
|
+
* 所以它是一个**等着被渲染的谎**,不是一个正在撒的谎。
|
|
12851
|
+
*
|
|
12852
|
+
* v9 之后两件事都对上了:
|
|
12853
|
+
*
|
|
12854
|
+
* | 这一格 | 意思 |
|
|
12855
|
+
* | --- | --- |
|
|
12856
|
+
* | `undefined` | **这段会话一轮都没算出过钱** —— 查不到单价(见 `cost/pricing.ts`),或者压根没跑过模型请求 |
|
|
12857
|
+
* | `0` | 算出来了,是零(免费模型) |
|
|
12858
|
+
* | `> 0` | 至少花了这么多 |
|
|
12859
|
+
*
|
|
12860
|
+
* 两者靠 `priced_call_count` 那一列分开(`estimated_cost_usd` 是
|
|
12861
|
+
* `REAL NOT NULL DEFAULT 0`,它自己装不下「不知道」)。
|
|
12862
|
+
*
|
|
12863
|
+
* ## 口径是「**至少**这么多」,同上面那五列
|
|
12864
|
+
*
|
|
12865
|
+
* 只累加 `TokenUsage.costUsd` 报得出来的那些轮;查不到单价的轮次一笔不记,
|
|
12866
|
+
* 不补 0 冒充。所以一段「有几轮算得出、有几轮算不出」的会话,这个数偏小 ——
|
|
12867
|
+
* 和花费页那一屏「总额自报是其中几轮的」是同一条规矩。
|
|
12868
|
+
*/
|
|
12869
|
+
estimatedCostUsd?: number;
|
|
12870
|
+
/**
|
|
12871
|
+
* provider 账单上的**实际**花费。**今天永远是 `undefined`,这是有意的。**
|
|
12872
|
+
*
|
|
12873
|
+
* ⚠️ **别拿估算值填它。** 这一格的全部价值在于它和 {@link estimatedCostUsd}
|
|
12874
|
+
* 是两个不同的东西:一个是我们乘出来的,一个是对方收的。填成同一个数之后,
|
|
12875
|
+
* 「这个账对过没有」就再也问不出来了。
|
|
12876
|
+
*
|
|
12877
|
+
* 我们今天**拿不到**这个数:epoch-agent 的 provider 全是 OpenAI 兼容端点
|
|
12878
|
+
* (见 `config/schema.ts`),它们的响应里只有 token 用量,没有金额。
|
|
12879
|
+
* 隔壁两家能填是因为它们是自家后端的第一方客户端 —— codex 的
|
|
12880
|
+
* `turn_cost_worker` 每 150s 向自家 API 轮询已结算金额,hermes 走
|
|
12881
|
+
* `x-nous-credits-*` 响应头和 portal 账户。**这条路我们没有,所以留空是诚实的。**
|
|
12882
|
+
*
|
|
12883
|
+
* 将来真要接(比如某个 provider 开始在响应头里报账单),它要连着
|
|
12884
|
+
* `cost_source` / `cost_status` 一起来 —— 「这个数是谁说的、结算没有」
|
|
12885
|
+
* 和数字本身一样重要(那是 hermes 那套的形状)。只加一个数字列会让
|
|
12886
|
+
* 「估算」和「账单」在读侧分不出来。
|
|
12887
|
+
*/
|
|
12028
12888
|
actualCostUsd?: number;
|
|
12029
12889
|
compressionIneffectiveCount: number;
|
|
12030
12890
|
expiryFinalized: number;
|
|
@@ -13074,7 +13934,7 @@ declare const MAX_AUDIT_ENTRIES = 500;
|
|
|
13074
13934
|
* | `bypass` | 全放行 —— 但**挡不住第 1 层那两条 deny**,那层在前面 |
|
|
13075
13935
|
* | `auto` | 信任 agent:这一档自己不拦,边界全在第 1 层 |
|
|
13076
13936
|
* | `plan` | 只读:写入 / 命令 / 网络 / 执行代码一律拒 |
|
|
13077
|
-
* | `acceptEdits` |
|
|
13937
|
+
* | `acceptEdits` | 同 `auto`,但**工作区外的文件**要确认 |
|
|
13078
13938
|
* | `default` | 只读操作免确认,其余一律确认 |
|
|
13079
13939
|
*
|
|
13080
13940
|
* ⚠️ 这一层**只负责「没有规则命中时怎么办」**。它给出的 allow 不是最终答案 ——
|
|
@@ -15329,11 +16189,15 @@ interface ResolvePolicyDirsOptions {
|
|
|
15329
16189
|
/** 项目根目录。不给就不加载项目级策略 */
|
|
15330
16190
|
projectRoot?: string;
|
|
15331
16191
|
/**
|
|
15332
|
-
*
|
|
15333
|
-
* 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」,
|
|
16192
|
+
* 工作区授过**执行类**吗(`TrustDecision.exec`,不是 `trusted`)。**必传**,
|
|
16193
|
+
* 没有默认值 —— 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」,
|
|
15334
16194
|
* 与 trust/gate.ts 的 fail closed 立场相反。
|
|
16195
|
+
*
|
|
16196
|
+
* ⚠️ 2026-09-11 从 `trusted` 改名到这一格,判据同 `hook/sources.ts` 上那一条:
|
|
16197
|
+
* 两个都是 `boolean`,只有改名才能让漏改的调用点编译不过。
|
|
16198
|
+
* 策略规则和 hook 归同一档 —— 它不进上下文,但它直接改「哪些操作不用问就放行」。
|
|
15335
16199
|
*/
|
|
15336
|
-
|
|
16200
|
+
execTrusted: boolean;
|
|
15337
16201
|
/** 给了就把取舍写进启动诊断 */
|
|
15338
16202
|
diags?: DiagnosticSink;
|
|
15339
16203
|
}
|
|
@@ -15434,10 +16298,15 @@ interface ResolveComplianceDirsOptions {
|
|
|
15434
16298
|
/** 项目根目录。不给就不加载项目级词库 */
|
|
15435
16299
|
projectRoot?: string;
|
|
15436
16300
|
/**
|
|
15437
|
-
*
|
|
15438
|
-
* 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」。
|
|
16301
|
+
* 工作区授过**执行类**吗(`TrustDecision.exec`,不是 `trusted`)。**必传**,
|
|
16302
|
+
* 没有默认值 —— 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」。
|
|
16303
|
+
*
|
|
16304
|
+
* ⚠️ **2026-09-11 归到执行类那一档,而这一条比 hook / policy 更容易判错。**
|
|
16305
|
+
* 词库看着像「只读的一张表」,但项目级的 `exempt.txt` 能把内置规则一条条
|
|
16306
|
+
* 豁免掉 —— 它**能放松**合规(文件头第二节写着这件事)。档位的判据从来不是
|
|
16307
|
+
* 「它执行不执行命令」,是「它能不能放宽一个安全判定」,而这一样能。
|
|
15439
16308
|
*/
|
|
15440
|
-
|
|
16309
|
+
execTrusted: boolean;
|
|
15441
16310
|
/** 给了就把取舍写进启动诊断 */
|
|
15442
16311
|
diags?: DiagnosticSink;
|
|
15443
16312
|
}
|
|
@@ -15737,11 +16606,19 @@ declare class HookManager implements HookManager$1 {
|
|
|
15737
16606
|
*
|
|
15738
16607
|
* ## 项目级 hook 的闸门比别的来源严一档
|
|
15739
16608
|
*
|
|
15740
|
-
* | 信任状态
|
|
15741
|
-
* |
|
|
15742
|
-
* | 已信任 | 生效 |
|
|
15743
|
-
* |
|
|
15744
|
-
* |
|
|
16609
|
+
* | 信任状态 | 项目级 hook |
|
|
16610
|
+
* | ----------------- | ----------- |
|
|
16611
|
+
* | 已信任 + 执行类 | 生效 |
|
|
16612
|
+
* | 已信任,仅读类 | **不生效** |
|
|
16613
|
+
* | 未决定 | **不生效** |
|
|
16614
|
+
* | 已拒绝 | **不生效** |
|
|
16615
|
+
*
|
|
16616
|
+
* ⚠️ **第二行是 2026-09-11 新长出来的一档**,也是这个文件本轮唯一的改动:
|
|
16617
|
+
* 它读的不再是 `TrustDecision.trusted` 而是 `.exec`({@link LoadHookSourcesOptions.execTrusted})。
|
|
16618
|
+
* 那之前,用户在一句只说了「本目录的项目指令会加载」的问话下点的「信任」,
|
|
16619
|
+
* 同时把这张表上的第一行也给了 —— 而这张表上的每一项都是一条要 spawn 子进程的
|
|
16620
|
+
* 命令。换句话说下面那段「clone 完还没看过的仓库里一行 `command: curl … | sh`
|
|
16621
|
+
* 就是任意代码执行」**在闸门自己这一侧也曾经成立**:问话没提过它。
|
|
15745
16622
|
*
|
|
15746
16623
|
* 方案 22 对项目级设置留了个不对称 —— 未信任时 `deny` 照样生效(一份提交进仓库的
|
|
15747
16624
|
* `settings.json` 能替你收紧、不能替你放开)。**这里没有对应的例外**:hook 的每一项
|
|
@@ -15802,11 +16679,16 @@ interface HookSourcesOptions {
|
|
|
15802
16679
|
*/
|
|
15803
16680
|
projectRoot?: string;
|
|
15804
16681
|
/**
|
|
15805
|
-
*
|
|
15806
|
-
* 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」,
|
|
16682
|
+
* 工作区授过**执行类**吗(`TrustDecision.exec`,不是 `trusted`)。**必传**,
|
|
16683
|
+
* 没有默认值 —— 给个 `= true` 的默认参数就等于「忘了传的人自动获得信任」,
|
|
15807
16684
|
* 与 trust/gate.ts 的 fail closed 立场相反。
|
|
16685
|
+
*
|
|
16686
|
+
* ⚠️ **2026-09-11 从 `trusted` 改名到这一格,而改名本身就是这次改动的一半。**
|
|
16687
|
+
* 两个都是 `boolean`,传错了类型检查一个字都不报 —— 改名之后漏改的调用点
|
|
16688
|
+
* 当场编译不过,那是这次唯一一道编译期能给的保护。
|
|
16689
|
+
* 档位判据在 [protocol 的 `TrustTier`](../../../protocol/src/trust.ts)。
|
|
15808
16690
|
*/
|
|
15809
|
-
|
|
16691
|
+
execTrusted: boolean;
|
|
15810
16692
|
/** `config.yaml` 里遗留的 `hooks` 字段(旧格式)。给了就照常生效,并报一条迁移提示 */
|
|
15811
16693
|
legacyHooks?: Record<string, unknown>;
|
|
15812
16694
|
/** 给了就把取舍和问题写进启动诊断 */
|
|
@@ -16278,7 +17160,7 @@ declare function scanSkillDirs(dirs: readonly SkillDirSpec[]): SkillScanOutcome;
|
|
|
16278
17160
|
* | -------------- | -------------------------------------------- | ------------------------------- |
|
|
16279
17161
|
* | 单个 `.md` | 路径是文件且以 `.md` 结尾 | `general/<名字>/SKILL.md` |
|
|
16280
17162
|
* | 技能文件夹 | 目录里**顶层**就有 `SKILL.md` | `general/<名字>/…` |
|
|
16281
|
-
* | 技能树 |
|
|
17163
|
+
* | 技能树 | 顶层没有 `SKILL.md` —— **递归找**,见下 | `<分类>/<名字>/…` |
|
|
16282
17164
|
* | `.zip`/`.tgz` | 路径是文件且不是 `.md` | 解开之后按上面两种目录形态再判 |
|
|
16283
17165
|
*
|
|
16284
17166
|
* 「技能树」这一档不在那句承诺里,是顺带的:`scanPluginDir` 数插件技能用的就是
|
|
@@ -16286,6 +17168,59 @@ declare function scanSkillDirs(dirs: readonly SkillDirSpec[]): SkillScanOutcome;
|
|
|
16286
17168
|
* 判据是**顶层有没有 `SKILL.md`**,不是「有几个条目」—— 同 `extractArchive`
|
|
16287
17169
|
* 摊平单根目录时那条「判据是清单在哪」。
|
|
16288
17170
|
*
|
|
17171
|
+
* ## ⚠️ 「技能树」那一档是**递归**的,不是固定两层(2026-09-13 改)
|
|
17172
|
+
*
|
|
17173
|
+
* 原来 `stageTree` 只下潜**恰好两层**(`<分类>/<名字>/SKILL.md`)。那条规矩对
|
|
17174
|
+
* `~/.epoch/skills/` 自己是对的(`scanSkillDirs` 就是两层),但它让这条路在
|
|
17175
|
+
* **别人的技能目录**上整个失效:`~/.claude/skills/` 是**一层**
|
|
17176
|
+
* (`<名字>/SKILL.md`),指它进来时顶层没有 `SKILL.md` ⇒ 判成 `tree` ⇒ 去找
|
|
17177
|
+
* `<名字>/<子目录>/SKILL.md` ⇒ 一个都找不到 ⇒ 回 `empty`,而 issues 里**没有一句话
|
|
17178
|
+
* 解释为什么**。而 web 那一屏的文件头恰恰把 `~/.claude/skills` 列为「最常被导入的」。
|
|
17179
|
+
*
|
|
17180
|
+
* 所以改成 {@link findSkillDirs}:从根往下走,**任何深度**的 `SKILL.md` 都算。
|
|
17181
|
+
* 判据抄的是隔壁两家的交集(两边都这么干,形状高度一致):
|
|
17182
|
+
*
|
|
17183
|
+
* - codex `codex-rs/ext/skills/src/loader/discovery.rs` —— 递归走,深度上限 6,
|
|
17184
|
+
* 跳过 `.` 开头的目录,名字取 frontmatter 的 `name` 否则**父目录名**;
|
|
17185
|
+
* - hermes-agent `agent/skill_utils.py:736` 的 `iter_skill_index_files` ——
|
|
17186
|
+
* `os.walk` 不限深度,带一张噪声黑名单,名字同样是 frontmatter 否则父目录名。
|
|
17187
|
+
*
|
|
17188
|
+
* 四条规矩,每条都有它自己的理由:
|
|
17189
|
+
*
|
|
17190
|
+
* 1. **找到 `X/SKILL.md` 就不再往 X 里面钻。** X 里除了那四个白名单子目录本来
|
|
17191
|
+
* 也一个字节都不收(见下一节),继续钻只会把一份技能自带的**示例**
|
|
17192
|
+
* (`references/examples/xxx/SKILL.md` 这种)当成另一份技能收进来。
|
|
17193
|
+
* hermes 那边是只剪掉支持目录,我们比它更硬一档 —— 因为我们的技能目录布局
|
|
17194
|
+
* 本来就封死了;
|
|
17195
|
+
* 2. **`.` 开头的目录不进**(同 `scanSkillDirs`,也同 codex)。顺带盖住
|
|
17196
|
+
* `.git` / `.venv` / `.tox` 这一整族,staging 目录自己也靠这一条不被扫到;
|
|
17197
|
+
* 3. **{@link SCAN_SKIP_DIRS} 那几个不进。** 只有非点开头的那几个,逐个抄
|
|
17198
|
+
* hermes 的 `EXCLUDED_SKILL_DIRS`。⚠️ **`dist` / `build` / `target` 不在里面** ——
|
|
17199
|
+
* 两家都没剪它们,而剪掉的代价是一个真叫 `build` 的分类底下的技能静默消失;
|
|
17200
|
+
* 4. **三道上限**(深度 / 目录数 / 技能数)。防的是有人把一整个 monorepo 拖进来,
|
|
17201
|
+
* 而它们撞上时**要说一句话**(`import_scan_truncated`)—— 静默截断在这条路上
|
|
17202
|
+
* 读起来就是「你那儿只有这些」。
|
|
17203
|
+
*
|
|
17204
|
+
* ## 分类和名字怎么从一条深路径上取出来
|
|
17205
|
+
*
|
|
17206
|
+
* 引擎自己的布局只有两层(`<分类>/<名字>`),而递归找到的路径可以有任意多层,
|
|
17207
|
+
* 所以要把它压回两层。规矩在 {@link placeOf}:**倒数第一段是名字,倒数第二段是
|
|
17208
|
+
* 分类**,没有倒数第二段就落 `general`。于是:
|
|
17209
|
+
*
|
|
17210
|
+
* | 找到的位置 | 分类 | 名字 |
|
|
17211
|
+
* | ----------------------- | --------- | -------- |
|
|
17212
|
+
* | `<根>/SKILL.md` | `general` | 根目录名 |
|
|
17213
|
+
* | `<根>/foo/SKILL.md` | `general` | `foo` |
|
|
17214
|
+
* | `<根>/cat/foo/SKILL.md` | `cat` | `foo` |
|
|
17215
|
+
* | `<根>/a/b/c/SKILL.md` | `b` | `c` |
|
|
17216
|
+
*
|
|
17217
|
+
* 第三行就是**原来那条两层规矩**,逐字不变;第二行是这次修的那格。
|
|
17218
|
+
*
|
|
17219
|
+
* ⚠️ 分类那一段**不合法时退回 `general`,不是把整份技能丢掉**:名字非法是「这一份
|
|
17220
|
+
* 没法要」(它要当目录名,而且是技能的身份),分类非法只是「没法照着分」——
|
|
17221
|
+
* 为后者丢掉一份好技能,用户拿到的是一条他改不动的路(那个目录名不是他起的)。
|
|
17222
|
+
* 名字那一道仍然在 {@link stageSkillDir} 里,一个字没松。
|
|
17223
|
+
*
|
|
16289
17224
|
* ## ⚠️ 抄过去的东西有白名单,而且它和 `skill_write_file` 是同一份
|
|
16290
17225
|
*
|
|
16291
17226
|
* {@link SKILL_ASSET_DIRS} 就是 `SkillSystem.writeFile` 那个 `allowedPrefixes`。
|
|
@@ -16827,7 +17762,85 @@ declare function readImageSize(bytes: Uint8Array): ImageSize | undefined;
|
|
|
16827
17762
|
declare function sniffMediaType(bytes: Uint8Array): string | undefined;
|
|
16828
17763
|
|
|
16829
17764
|
/**
|
|
16830
|
-
*
|
|
17765
|
+
* 附件目录的清理策略(2026-09-11)。
|
|
17766
|
+
*
|
|
17767
|
+
* 用户从输入框附上来的文件落在 `~/.epoch/attachments/<会话 id>/`
|
|
17768
|
+
* (判据在 infra 的 `attachmentsDir` 上)。**单个附件不设上限**是拍过的决定,
|
|
17769
|
+
* 于是「攒起来的总量」这一格就成了这条路上唯一的闸 —— 不设它的话,
|
|
17770
|
+
* 一个天天拖日志进来的用户几周就能攒出几个 GB,而这些文件在会话结束后
|
|
17771
|
+
* 基本没人再看。
|
|
17772
|
+
*
|
|
17773
|
+
* ## 算法一个字都不重写:直接复用 `pruneArtifacts`
|
|
17774
|
+
*
|
|
17775
|
+
* 那个函数**第一个参数就是根目录**,artifact 相关的东西只剩名字和默认配额。
|
|
17776
|
+
* 照着抄一份「按天 + 按容量 + 当前会话永不删」的实现出来,代价是同一条规矩
|
|
17777
|
+
* 有了两个真源:哪天有人给 artifact 那份加了「软链不跟随」,attachment 这份
|
|
17778
|
+
* 静悄悄地还是老样子,而两处的差异要等到一次事故才有人发现。
|
|
17779
|
+
*
|
|
17780
|
+
* 所以这一份只提供**两样 attachment 自己的东西**:根目录,和配额。
|
|
17781
|
+
*
|
|
17782
|
+
* ## ⚠️ 这条线兑现的不是「盘写不满」
|
|
17783
|
+
*
|
|
17784
|
+
* 驱逐按会话目录整个来、从最旧的删起,而**当前会话目录永不参与**
|
|
17785
|
+
* (那是 `pruneArtifacts` 的语义,判据在它自己那一格上:正在跑的会话把自己的
|
|
17786
|
+
* 附件删掉,是比磁盘涨得慢更糟的事)。于是一次 2 GB 的上传照样落得进来。
|
|
17787
|
+
* 它兑现的是「历史会话的附件不会无限攒着」,仅此而已 ——
|
|
17788
|
+
* 全文在 [disk-ledger.ts](../disk-ledger.js) 的 `ATTACHMENT_MAX_TOTAL_BYTES` 上。
|
|
17789
|
+
*/
|
|
17790
|
+
/**
|
|
17791
|
+
* 保留策略。**结构上与 `ArtifactRetention` 相同,名字刻意分开**。
|
|
17792
|
+
*
|
|
17793
|
+
* 共用一个类型名的代价是「调 artifact 的保留天数」和「调 attachment 的保留天数」
|
|
17794
|
+
* 在类型系统里长得一模一样 —— 而它们是两个可以各自调的数(判据同 disk-ledger
|
|
17795
|
+
* 那张表:两者丢了的代价不一样)。两个名字之后,配置层要分开暴露哪一个,
|
|
17796
|
+
* 是一次看得见的选择而不是一次手滑。
|
|
17797
|
+
*/
|
|
17798
|
+
interface AttachmentRetention {
|
|
17799
|
+
/** 超过这个天数的会话目录整个删掉 */
|
|
17800
|
+
maxAgeDays: number;
|
|
17801
|
+
/** attachments 根目录的总容量上限(字节) */
|
|
17802
|
+
maxTotalBytes: number;
|
|
17803
|
+
}
|
|
17804
|
+
/**
|
|
17805
|
+
* 内置默认。天数跟 artifact 走(7 天),容量来自 [disk-ledger.ts](../disk-ledger.js)。
|
|
17806
|
+
*
|
|
17807
|
+
* ⚠️ **天数这一格是「跟着走」,不是「必须一样」**:它今天等于 artifact 那个数,
|
|
17808
|
+
* 是因为没有任何测量支撑把它们分开,不是因为有一条规矩要求它们相等。
|
|
17809
|
+
* 哪天要调,调一个不影响另一个 —— 这正是上面那两个类型名分开的用处。
|
|
17810
|
+
*/
|
|
17811
|
+
declare const ATTACHMENT_RETENTION_DEFAULTS: AttachmentRetention;
|
|
17812
|
+
/**
|
|
17813
|
+
* 清理 attachments 根目录。返回删掉的会话目录数(给诊断用)。
|
|
17814
|
+
*
|
|
17815
|
+
* @param root attachments 根目录(`attachmentsDir()` **不带 sessionId** 的那个)
|
|
17816
|
+
* @param keepSession 当前会话目录名,永不删除
|
|
17817
|
+
* @param now 当前时间戳。**显式传入**是为了让测试可复现,
|
|
17818
|
+
* 而不是在实现里埋一个 `Date.now()`
|
|
17819
|
+
*/
|
|
17820
|
+
declare function pruneAttachments(root: string, keepSession?: string, retention?: AttachmentRetention, now?: number): number;
|
|
17821
|
+
/**
|
|
17822
|
+
* 删一段会话时连带删掉它的附件目录。
|
|
17823
|
+
*
|
|
17824
|
+
* 三处刻意和 {@link pruneAttachments} 不一样,判据逐字同 `removeSessionArtifacts`:
|
|
17825
|
+
* **不吞异常**(这是用户按下去的动作,不是 housekeeping)、**异步**、
|
|
17826
|
+
* **`force: true` 所以「本来就没有」= 成功**(绝大多数会话一个附件都没有)。
|
|
17827
|
+
*
|
|
17828
|
+
* ⚠️ 这一条比 artifact 那一条更要紧:附件是**用户自己的文件**(一份合同、
|
|
17829
|
+
* 一份体检报告)。点了删除的人以为它跟着没了,而不设这一条的话它还会在盘上
|
|
17830
|
+
* 躺最多 7 天。
|
|
17831
|
+
*
|
|
17832
|
+
* @param homeDir `~/.epoch` 那一层。**不能省** —— 省了就落回全局家目录,
|
|
17833
|
+
* 于是宿主自己那份数据目录里的附件永远删不掉,而用户全局的那份被误删
|
|
17834
|
+
* (同 `removeSessionArtifacts`,方案 54 §二那条漏接)
|
|
17835
|
+
*/
|
|
17836
|
+
declare function removeSessionAttachments(sessionId: string, homeDir?: string): Promise<void>;
|
|
17837
|
+
|
|
17838
|
+
/**
|
|
17839
|
+
* `~/.epoch/` 的磁盘总账 —— 几条各管各的上限,从此写在同一张表里(方案 47 PR-4)。
|
|
17840
|
+
*
|
|
17841
|
+
* > 2026-09-11 进来第三条(`attachments`,用户从输入框附上来的文件)。
|
|
17842
|
+
* > 下面这段讲的是当初为什么要有这张表,**它的理由没变**:新加的那一条同样
|
|
17843
|
+
* > 只在这里写一次数,执行者在别处取值。
|
|
16831
17844
|
*
|
|
16832
17845
|
* ## 这张表答的是一个一直没人答的问题
|
|
16833
17846
|
*
|
|
@@ -16837,7 +17850,7 @@ declare function sniffMediaType(bytes: Uint8Array): string | undefined;
|
|
|
16837
17850
|
* **差 2.5 倍而谁也没参照过谁**。于是 `~/.epoch/` 的真实天花板是
|
|
16838
17851
|
* 「200 + 512 + 会话库随便涨」——这句话谁都没写下来过,也就没人能说它对不对。
|
|
16839
17852
|
*
|
|
16840
|
-
*
|
|
17853
|
+
* 现在每一处都从这里取值。**改一个数就得在这张表上改**,那句天花板随之算得出来。
|
|
16841
17854
|
*
|
|
16842
17855
|
* ## 立的是「一本账」,不是一条会驱逐的联合上限 —— 三条判据
|
|
16843
17856
|
*
|
|
@@ -16883,25 +17896,52 @@ declare function sniffMediaType(bytes: Uint8Array): string | undefined;
|
|
|
16883
17896
|
declare const CHECKPOINT_MAX_TOTAL_BYTES: number;
|
|
16884
17897
|
/** 全部会话的 artifact 合计。执行者:`pruneArtifacts` */
|
|
16885
17898
|
declare const ARTIFACT_MAX_TOTAL_BYTES: number;
|
|
17899
|
+
/**
|
|
17900
|
+
* 全部会话的 attachment 合计(2026-09-11)。执行者:`pruneAttachments`。
|
|
17901
|
+
*
|
|
17902
|
+
* ## 这个数的来历,和上面两个一样诚实:**没有测量依据**
|
|
17903
|
+
*
|
|
17904
|
+
* 取和 artifact 同一个数,判据是上面那张对照表里的同两栏 —— attachment 也是
|
|
17905
|
+
* 「单件大、丢了还能再有」那一族(原件在用户自己盘上,重新拖一次就回来了),
|
|
17906
|
+
* 所以它该站在 512 这一边而不是 checkpoint 的 200 那一边。
|
|
17907
|
+
*
|
|
17908
|
+
* ## ⚠️ 它**不是**单个附件的上限,两件事别混
|
|
17909
|
+
*
|
|
17910
|
+
* 单个附件**不设上限**(2026-09-11 拍的:上传走流式落盘,不整份读进内存)。
|
|
17911
|
+
* 这一格管的是「攒起来的总量」,执行方式同 artifact —— 按会话目录整个删、
|
|
17912
|
+
* 从最旧的删起、**当前会话永不删**。
|
|
17913
|
+
*
|
|
17914
|
+
* 于是有一个必须说清楚的后果:**一次 2 GB 的上传不会被这条线拦住**,
|
|
17915
|
+
* 它落在当前会话目录里,而当前会话目录不参与驱逐。这条线兑现的是
|
|
17916
|
+
* 「历史会话的附件不会无限攒着」,不是「这台机器的盘写不满」。
|
|
17917
|
+
* 真要后者,得给单文件加上限 —— 而那是被明确拒过的那条路。
|
|
17918
|
+
*/
|
|
17919
|
+
declare const ATTACHMENT_MAX_TOTAL_BYTES: number;
|
|
16886
17920
|
/**
|
|
16887
17921
|
* 一本账,`null` = 这一格不受管。
|
|
16888
17922
|
*
|
|
16889
|
-
* `rest` 那一格是这张表里最要紧的一行 ——
|
|
16890
|
-
* 「`~/.epoch/` 最多
|
|
17923
|
+
* `rest` 那一格是这张表里最要紧的一行 —— 少了它,三个有限的数字摆在一起会读成
|
|
17924
|
+
* 「`~/.epoch/` 最多 1224MB」,而那是假的。
|
|
16891
17925
|
*/
|
|
16892
17926
|
declare const EPOCH_DISK_LEDGER: {
|
|
16893
17927
|
/** `~/.epoch/checkpoints/` */
|
|
16894
17928
|
readonly checkpoints: number;
|
|
16895
17929
|
/** `~/.epoch/artifacts/` */
|
|
16896
17930
|
readonly artifacts: number;
|
|
17931
|
+
/** `~/.epoch/attachments/` */
|
|
17932
|
+
readonly attachments: number;
|
|
16897
17933
|
/** `sessions.db` + `telemetry.jsonl` + `workspaces.json` + 日志:**没有上限** */
|
|
16898
17934
|
readonly rest: null;
|
|
16899
17935
|
};
|
|
16900
17936
|
/**
|
|
16901
|
-
*
|
|
17937
|
+
* 三条受管上限之和 —— **名义**天花板,不是实际上限。
|
|
16902
17938
|
*
|
|
16903
17939
|
* 拿它去跟 `du -sh ~/.epoch` 比会对不上,那不是 bug:差出来的部分就是
|
|
16904
17940
|
* `EPOCH_DISK_LEDGER.rest` 那一格。
|
|
17941
|
+
*
|
|
17942
|
+
* ⚠️ 从 2026-09-11 起它**更不像**一个天花板了:attachment 那一格的单件不设上限,
|
|
17943
|
+
* 而当前会话目录不参与驱逐(判据在 {@link ATTACHMENT_MAX_TOTAL_BYTES} 上)。
|
|
17944
|
+
* 也就是说这个和现在同时被两件事架空 —— `rest` 那一格,和「正在跑的那一段会话」。
|
|
16905
17945
|
*/
|
|
16906
17946
|
declare const NOMINAL_TOTAL_BYTES: number;
|
|
16907
17947
|
|
|
@@ -17334,8 +18374,33 @@ declare class TrustManager implements TrustManager$1 {
|
|
|
17334
18374
|
*/
|
|
17335
18375
|
readonly loadErrors: string[];
|
|
17336
18376
|
constructor(filePath?: string);
|
|
18377
|
+
/**
|
|
18378
|
+
* 管到这个目录的那一条记录(最长匹配),没有就 undefined。
|
|
18379
|
+
*
|
|
18380
|
+
* ⚠️ **`check()` 和 `checkExec()` 必须共用它,不许各走一遍循环。** 两处各写一份
|
|
18381
|
+
* 的话,「哪条记录说了算」就有了两个答案,而它们分叉的表现是:某个目录判成
|
|
18382
|
+
* 「已信任」却拿着**另一条**记录的 `exec` —— 一次没人授过的执行类放行。
|
|
18383
|
+
*/
|
|
18384
|
+
private bestRecord;
|
|
17337
18385
|
check(dir: string): TrustLevel;
|
|
17338
|
-
|
|
18386
|
+
/**
|
|
18387
|
+
* 执行类授信。**`=== true` 而不是真值判断**:存量记录压根没有这一格
|
|
18388
|
+
* (`undefined` → false,那就是迁移本身),而一条手改坏的 `exec: "no"`
|
|
18389
|
+
* 在 JS 里是真值 —— 那会让一个谁也没授过的目录拿到执行权。
|
|
18390
|
+
*
|
|
18391
|
+
* 只回记录里写的,**不做新鲜度校验**(那要读仓库里的文件,不归这张表管)。
|
|
18392
|
+
*/
|
|
18393
|
+
checkExec(dir: string): TrustExecGrant;
|
|
18394
|
+
/**
|
|
18395
|
+
* 记一次决策。
|
|
18396
|
+
*
|
|
18397
|
+
* ⚠️ **授 `exec` 时指纹是这里自己算的**(`grant.execHash` 只是给用例的覆盖口)。
|
|
18398
|
+
* 让调用方去算的话,三个写入口(CLI 的 `trust add --exec`、交互式询问、宿主的
|
|
18399
|
+
* `runtime.trust.record()`)里**任何一个漏传**,那条记录就永远校验不了 ——
|
|
18400
|
+
* 而漏传的表现是「一切正常」:授信成功、hook 生效,只是「变了就重新问」
|
|
18401
|
+
* 这件事从此对这个目录不成立。谁也不会发现。
|
|
18402
|
+
*/
|
|
18403
|
+
record(dir: string, level: DecidedTrustLevel, scope: TrustScope, grant?: TrustGrant): void;
|
|
17339
18404
|
list(): readonly TrustRecord[];
|
|
17340
18405
|
revoke(dir: string): void;
|
|
17341
18406
|
private load;
|
|
@@ -17351,6 +18416,166 @@ declare class TrustManager implements TrustManager$1 {
|
|
|
17351
18416
|
private save;
|
|
17352
18417
|
}
|
|
17353
18418
|
|
|
18419
|
+
/**
|
|
18420
|
+
* 执行类输入的内容指纹 —— 「授信之后这些文件被改过吗」(2026-09-11)。
|
|
18421
|
+
*
|
|
18422
|
+
* 授 `exec` 那一刻把这个值记进 `TrustRecord.execHash`;之后每次判定重算一遍,
|
|
18423
|
+
* 对不上就把 `exec` 降回未授、重新问一次。
|
|
18424
|
+
*
|
|
18425
|
+
* ## 它挡的是哪一种事
|
|
18426
|
+
*
|
|
18427
|
+
* 信任按路径存、而且是**一次性**的(`manager.ts` 文件头「两条明确不做」第 2 条)。
|
|
18428
|
+
* 于是 `git pull` 之后,一个当初被授了执行类的仓库可以凭空多出一条
|
|
18429
|
+
* `command: curl … | sh`,而没有任何地方会再问一次。hermes 为这件事在项目技能上
|
|
18430
|
+
* 挂了一整个扫描器(`agent/skill_utils.py` 的 `_PROJECT_QUARANTINE_CACHE`,
|
|
18431
|
+
* 注释里写着「trust 是一次性的 repo 级决定,而 repo 的内容每次 pull 都在变」);
|
|
18432
|
+
* codex 的做法便宜得多也窄得多 —— 只给 hook 记一个 `trusted_hash`
|
|
18433
|
+
* (`codex-rs/config/src/hook_config.rs`)。这一份跟 codex 走。
|
|
18434
|
+
*
|
|
18435
|
+
* ## ⚠️ 为什么这不是把「两条明确不做」整条作废
|
|
18436
|
+
*
|
|
18437
|
+
* 那一条否掉的是**给指令文件记 hash**,理由是「改一行 AGENTS.md 就被打断一次」。
|
|
18438
|
+
* 那个结论在读类上照旧成立,这一份一个字都没碰它 —— {@link EXEC_INPUTS} 里
|
|
18439
|
+
* 没有任何一个指令文件,也不该有。完整的两侧对照在 protocol 的
|
|
18440
|
+
* `TrustRecord.execHash` 上。
|
|
18441
|
+
*
|
|
18442
|
+
* ## 三条实现上的规矩
|
|
18443
|
+
*
|
|
18444
|
+
* 1. **「不存在」和「空文件」必须是两个指纹。** 前者不进摘要、后者进,
|
|
18445
|
+
* 所以删掉 `hooks.json` 和把它清空会得到不同的值 —— 两件事本来就不同;
|
|
18446
|
+
* 2. **读不出来的文件按「有内容但读不到」算,不按不存在算**(见 {@link digestOf})。
|
|
18447
|
+
* fail closed:一个读不出来的 `hooks.json` 不该和没有 `hooks.json` 长得一样;
|
|
18448
|
+
* 3. **相对路径进摘要,绝对路径不进。** 否则把仓库换个目录放就换了指纹,
|
|
18449
|
+
* 而那时文件一个字节都没变。
|
|
18450
|
+
*/
|
|
18451
|
+
/**
|
|
18452
|
+
* 算一个项目根的执行类指纹。**纯函数式的读,不写任何东西。**
|
|
18453
|
+
*
|
|
18454
|
+
* ⚠️ 调用方要先短路:只有在「这条记录真的授过 exec 且真的记了指纹」时才值得算。
|
|
18455
|
+
* 无条件调用的代价是每次判定都去 stat 六个路径 + 列一个目录,而
|
|
18456
|
+
* `TrustGate.decide()` 被安全中心那一屏按行调用(`server/src/security.ts`
|
|
18457
|
+
* 的 `toWireTrustList` 逐行问一次,判据写在那儿)。
|
|
18458
|
+
*/
|
|
18459
|
+
declare function computeExecHash(root: string): string;
|
|
18460
|
+
|
|
18461
|
+
/**
|
|
18462
|
+
* 未信任工作区里**有什么被挡着** —— 数得出来的那一份清单(2026-09-11)。
|
|
18463
|
+
*
|
|
18464
|
+
* ## 它推翻了一句写在 wire 上的话,推翻得有条件
|
|
18465
|
+
*
|
|
18466
|
+
* `protocol/src/wire-capability.ts` 的 `WireCapabilityProject.trusted` 上写着:
|
|
18467
|
+
*
|
|
18468
|
+
* > 界面上那句话必须照实说,不能写成「已屏蔽 N 个」—— 那个 N 根本不存在,
|
|
18469
|
+
* > 谁也没数过。
|
|
18470
|
+
*
|
|
18471
|
+
* 那句话在它写下的那天是对的:闸门那一侧**连 `readdir` 都不做**,所以 N 确实
|
|
18472
|
+
* 不存在。这一份把闸门的下限从「不 readdir」放宽到「readdir 但不读任何文件
|
|
18473
|
+
* 内容」,于是 N 真的被数出来了 —— 而上面那句话的约束(不许编一个没人数过的数)
|
|
18474
|
+
* 一个字都没松。
|
|
18475
|
+
*
|
|
18476
|
+
* 放宽的理由是宿主那条路:用户看到的是一句「这个工作区还没被信任,它的技能一个
|
|
18477
|
+
* 都没读」加一条他跑不了的命令。而「这个仓库里有 7 个技能、1 个 `hooks.json`」
|
|
18478
|
+
* 是把「要不要信任」从一道信仰题变成一道判断题的**唯一**材料。
|
|
18479
|
+
* hermes 的启动横幅是同一个形态(`◆ N 个项目技能…但没加载`,
|
|
18480
|
+
* `hermes_cli/cli_info_mixin.py`)——它同样是「不信任也数得出来」。
|
|
18481
|
+
*
|
|
18482
|
+
* ## ⚠️ 唯一的硬约束:**这个文件不读任何文件内容**
|
|
18483
|
+
*
|
|
18484
|
+
* 全文只用 `existsSync` / `readdirSync` / `statSync`,**一次 `readFileSync` 都没有**,
|
|
18485
|
+
* 而这不是「暂时没用上」。两条理由,第二条才是硬的:
|
|
18486
|
+
*
|
|
18487
|
+
* 1. 读了内容就等于读了 `SKILL.md` 的 frontmatter,那和「连读都不读」的承诺
|
|
18488
|
+
* 直接冲突 —— 闸门那一侧的措辞会当场变成假话;
|
|
18489
|
+
* 2. **这份清单会被画进一个用户正要点「确认」的对话框里。** frontmatter 的
|
|
18490
|
+
* `description`、hook 的 `command` 全是仓库作者写的散文,把它们渲染在授权按钮
|
|
18491
|
+
* 旁边,等于给人看一段攻击者可控的劝说词,而且是在最坏的时机。
|
|
18492
|
+
* **路径和个数是结构,散文不是** —— 只发结构。
|
|
18493
|
+
*
|
|
18494
|
+
* 所以这里数不出「有几条 hook」(那要解析 JSON)。`hooks.json` 存不存在就是
|
|
18495
|
+
* 这一格能给的全部,而它已经足够把两种仓库分开了。
|
|
18496
|
+
*/
|
|
18497
|
+
/**
|
|
18498
|
+
* 一个项目根里、被两道闸门各自挡着的东西。**全是个数和路径,没有一句散文。**
|
|
18499
|
+
*
|
|
18500
|
+
* 路径一律是**相对项目根**的:这份清单会原样上网线进浏览器,而绝对路径在那儿
|
|
18501
|
+
* 只会让一行装不下,也没给用户多一个字的信息(他知道自己在哪个仓库)。
|
|
18502
|
+
*/
|
|
18503
|
+
interface ProjectExtensionInventory {
|
|
18504
|
+
/** 读类:项目指令文件(`EPOCH.md` / `AGENTS.md` / `CLAUDE.md`),相对路径 */
|
|
18505
|
+
instructionFiles: string[];
|
|
18506
|
+
/** 读类:`.epoch/skills/<分类>/<名字>/SKILL.md` 的个数 */
|
|
18507
|
+
skills: number;
|
|
18508
|
+
/** 读类:`.epoch/agents/*.md` 的个数 */
|
|
18509
|
+
roles: number;
|
|
18510
|
+
/** 读类:`.epoch/commands/**\/*.md` 的个数 */
|
|
18511
|
+
commands: number;
|
|
18512
|
+
/** 执行类:存在的那几份 hook 配置,相对路径 */
|
|
18513
|
+
hookFiles: string[];
|
|
18514
|
+
/** 执行类:`.epoch/policies/*.toml` 的个数 */
|
|
18515
|
+
policies: number;
|
|
18516
|
+
/** 执行类:存在的那几份项目设置,相对路径 */
|
|
18517
|
+
settingsFiles: string[];
|
|
18518
|
+
}
|
|
18519
|
+
/**
|
|
18520
|
+
* 数一遍这个项目根里有什么。**不受信任的目录也能调**,那正是它存在的理由。
|
|
18521
|
+
*
|
|
18522
|
+
* 目录不存在 / 读不动 / `root` 是空串,一律回全零的清单而不是抛 ——
|
|
18523
|
+
* 这个函数的每一个调用点都在「顺便告诉用户一句」的路径上,
|
|
18524
|
+
* 为它中断一次装配或者让一屏画不出来,代价和收益完全不成比例。
|
|
18525
|
+
*/
|
|
18526
|
+
declare function inventoryProjectExtensions(root: string | null | undefined): ProjectExtensionInventory;
|
|
18527
|
+
/** 读类那一档有东西被挡着吗 —— 「授了读类会多出什么」 */
|
|
18528
|
+
declare function hasReadTierContent(inv: ProjectExtensionInventory): boolean;
|
|
18529
|
+
/**
|
|
18530
|
+
* 授了执行类**会多出什么** —— 给对话框和安全中心那份清单用。
|
|
18531
|
+
*
|
|
18532
|
+
* ⚠️ **别拿它当「要不要报警」的判据**,那是下面 {@link hasDedicatedExecContent}
|
|
18533
|
+
* 的活。两者答的是两个问题,而混用的代价当场就付了,见那一个的文件注释。
|
|
18534
|
+
*/
|
|
18535
|
+
declare function hasExecTierContent(inv: ProjectExtensionInventory): boolean;
|
|
18536
|
+
/**
|
|
18537
|
+
* 这个仓库里有**存在的唯一目的就是执行类**的文件吗 —— 「该不该主动说一句」。
|
|
18538
|
+
*
|
|
18539
|
+
* ## ⚠️ 这个函数是 2026-09-11 当天补的,因为上面那个用在这儿是错的
|
|
18540
|
+
*
|
|
18541
|
+
* 一开始「要不要报警」读的是 {@link hasExecTierContent},而它判的是**文件在不在**。
|
|
18542
|
+
* 现场(epoch-agent 自己这个仓库)当场打出一条假警告:
|
|
18543
|
+
*
|
|
18544
|
+
* > Trust: … is trusted (read tier only): … but its hooks and policies do not take effect
|
|
18545
|
+
*
|
|
18546
|
+
* 而那个仓库**一个 hook 都没有**。触发它的是 `.claude/settings.json` ——
|
|
18547
|
+
* 那份文件里只有一张 `permissions.deny` 表,而**那张表 epoch 压根不读**
|
|
18548
|
+
* (这个路径在 core 里只有一个消费方:hook 加载器的 `parseClaudeSettingsHooks`,
|
|
18549
|
+
* 它只从里面取 hooks)。也就是说那句话字面上是假的:什么都没少。
|
|
18550
|
+
*
|
|
18551
|
+
* 而 [hook/sources.ts](../hook/sources.ts) 的文件头自己就写着「仓库里带
|
|
18552
|
+
* `.claude/settings.json` 是今天的常态」—— 也就是说那条假警告会打在**几乎每一个**
|
|
18553
|
+
* 仓库上。它正是 `hasExecTierContent` 原来那段注释要防的「别无谓地吓人」,
|
|
18554
|
+
* 只是判据放错了一层。
|
|
18555
|
+
*
|
|
18556
|
+
* ## 判据:这份文件存在,本身就说明有东西被挡住了吗
|
|
18557
|
+
*
|
|
18558
|
+
* | 文件 | 算不算 | 为什么 |
|
|
18559
|
+
* | --------------------------- | ------- | ---------------------------------------------------------- |
|
|
18560
|
+
* | `.epoch/hooks.json` | **算** | 它存在的唯一目的就是装 hook |
|
|
18561
|
+
* | `.epoch/policies/*.toml` | **算** | 同上,一个 `.toml` 放在那儿就是为了带规则 |
|
|
18562
|
+
* | `.claude/settings*.json` | 不算 | 别的工具的文件,常见内容是 epoch 根本不读的 permissions |
|
|
18563
|
+
* | `.epoch/settings*.json` | 不算 | 它的 deny 那一半**未信任时照旧生效**,被挡的只有 allow 和标量 |
|
|
18564
|
+
*
|
|
18565
|
+
* ## 代价,如实写着
|
|
18566
|
+
*
|
|
18567
|
+
* 只把 hook 写在 `.claude/settings.json` 里、而且之前授过信任的仓库,
|
|
18568
|
+
* 启动时**不会**收到这句提醒(hook 照旧不跑 —— 闸门一个字没松,只是没人主动说)。
|
|
18569
|
+
* 那一档不是看不见:安全中心那一屏照旧把它列出来(那儿用的是
|
|
18570
|
+
* {@link hasExecTierContent},列全)。**这是「不主动打扰」和「不漏说」之间的取舍**,
|
|
18571
|
+
* 而站在假警告会打给所有人这一边,取舍是清楚的。
|
|
18572
|
+
*
|
|
18573
|
+
* ⚠️ 想把 `.claude/settings.json` 也变成「算」的人:正确的做法不是把它加回这张表,
|
|
18574
|
+
* 是让 hook 加载器回答「这份被挡下的文件里**真的有** hook 吗」—— 它手里就有那个
|
|
18575
|
+
* 解析器。那要动「不受信任时连读都不读」那条纪律的措辞,是一次单独的改动。
|
|
18576
|
+
*/
|
|
18577
|
+
declare function hasDedicatedExecContent(inv: ProjectExtensionInventory): boolean;
|
|
18578
|
+
|
|
17354
18579
|
/**
|
|
17355
18580
|
* `code` 档下**哪些工具从模型的工具表里切走**(方案 51 PR-2)。
|
|
17356
18581
|
*
|
|
@@ -17642,4 +18867,4 @@ declare function resolveCodeModeWorker(baseDir: string, exists?: typeof existsSy
|
|
|
17642
18867
|
*/
|
|
17643
18868
|
declare function codeModeWorkerPath(): string | undefined;
|
|
17644
18869
|
|
|
17645
|
-
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, type AcquireResult, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ApprovalScope, type ArtifactOpenRefusal, type ArtifactRetention, type AskQuestionDeps, 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, 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 ImportNode, type ImportSkipReason, ImportTrustStore, type InstallOptions, type InstallOutcome, type InstallPreview, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, 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_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceDisplay, type MarketplaceDisplayField, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MarketplaceStatus, type MemoryConfig, type MemoryEntry, MemoryManager, MemoryReviewer, 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, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, POLICY_DECISIONS, 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 PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginArtifacts, type PluginAuthor, PluginAuthorSchema, type PluginCommandDir, type PluginCounts, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, type PolicyDirSpec, type PolicyDirsSummary, type PolicyLoadOutcome, type PolicyRule, PolicyRuleSchema, type ProjectContext, 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 ReviewIssue, 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 RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, 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_APPLY, SETTING_WRITE_KEYS, SETTING_WRITE_LAYERS, SKILL_CREATE_TOOL, SKILL_EDIT_TOOL, 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 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 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 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 SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, 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, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasPromptCaching, hasProviderCredentials, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, projectEntryForDisplay, pruneArtifacts, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, removeSessionArtifacts, renderImportTree, renderProjectContext, renderSdkDeclaration, repairSchedules, resolveArtifactRetention, resolveCodeModeWorker, resolveComplianceDirs, resolveEntrySource, resolveInWorkspace, resolveMarketplaceRef, resolveMentions, resolveMultimodalPolicy, resolvePolicyDirs, resolveProjectRoot, resolveScheduleBackend, resolveSessionReference, resolveSessionVisibility, resolveSettings, resolveSkillDirs, resolveSource, resolveTar, resolveWorkspace, restoreParts, revealScopedProvider, roleScopedProvider, roleSourceLabel, ruleCovers, ruleFromString, ruleToString, runCode, runCommand, sanitizeArgNames, sanitizeCommand, sanitizeFtsQuery, sanitizePath, sanitizeToolOutput, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|
|
18870
|
+
export { AGENT_ROLE_DIAG_MODULE, ARTIFACT_MAX_TOTAL_BYTES, ARTIFACT_RETENTION_DEFAULTS, ATTACHMENT_MAX_TOTAL_BYTES, ATTACHMENT_RETENTION_DEFAULTS, type AcquireResult, type AgentConfig, AgentLoop, type AgentProvider, type AgentSite, type AgentSiteRef, type AppendMessageInput, ApprovalCache, type ApprovalDecision, type ApprovalScope, 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, 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 ImportNode, type ImportSkipReason, ImportTrustStore, type InstallOptions, type InstallOutcome, type InstallPreview, type InstructionScan, type InstructionSource, type IsolationReason, type IsolationReport, type JsonSchemaDocument, LAUNCHD_LABEL_PREFIX, LOCK_HEARTBEAT_MS, LOCK_STALE_MS, 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_OBJECTIVE_CHARS, MAX_REASON_CHARS, MAX_RECENT_WORKSPACES, MODEL_GIVE_UP_THRESHOLD, MULTIMODAL_DEFAULTS, type ManagedPolicy, ManagedPolicyError, type ManagedSettings, ManagedSettingsSchema, type MarketplaceCatalog, type MarketplaceDisplay, type MarketplaceDisplayField, type MarketplaceEntry, type MarketplaceOutcome, type MarketplaceRecord, type MarketplaceStatus, type MemoryConfig, type MemoryEntry, MemoryManager, MemoryReviewer, 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, PACK_MAX_BYTES, PACK_MAX_FILES, PERMISSION_AUDIT_CODES, PLUGIN_LAYOUT, PLUGIN_MANIFEST_FILE, PLUGIN_NAME_PATTERN, PLUGIN_ROOT_ENV, PLUGIN_ROOT_TOKEN, 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 PersistedBudget, type PersistedPart, type PlanApprovalFn, type PlanEnterResult, type PlanModeDeps, PlanModeState, type PlanSettlement, type PluginArtifacts, type PluginAuthor, PluginAuthorSchema, type PluginCommandDir, type PluginCounts, type PluginHookFile, type PluginInventory, type PluginLoadOptions, type PluginManifest, type PluginPathRef, type PluginRecord, type PluginSettingsFile, type PluginSourceType, type PluginStateReadOutcome, PluginStore, 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 ReviewIssue, 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 RoleScope, type RuleMatch, type RuleSuggestion, type RuleVerdict, type RunCodeFailure, type RunCodeInput, type RunCodeOutcome, type RunCodeToolDeps, type RunEstimateInput, type RunInput, type RunResult, 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_CREATE_TOOL, SKILL_EDIT_TOOL, 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 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 SubAgentRunner, type SubTask, type SubToolCaller, type SummarizeOutput, type SurfaceMessage, type SystemPromptParams, type SystemPromptSegments, TOOL_SEARCH_TOOL, TaskNoticeTracker, type TodoItem, 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, type UpdateScheduleInput, type UtilityModelInfo, type ValidateScheduleInput, type VersionCheck, Workspace, type WorkspaceFiles, type WorkspaceIssue, type WorkspaceIssueKind, acquireScheduleLock, addMarketplace, addUsage, admitArtifact, admitArtifacts, affectedPaths, artifactLaunchArgv, artifactOpenRefusal, assertLevelAllowed, blockedRoleTools, buildContextBreakdown, buildFireArgv, buildFtsMatchQuery, buildSchemaExports, buildSystemPrompt, buildTrigramMatchQuery, builtinRoles, checkEpochVersion, checkFtsHealth, checkShadowing, classifyProviderError, clearModelCache, coalesceRecording, codeModeWorkerPath, commandNameFromRelPath, compileRuleLists, compressionOptions, computeCost, computeCostMicros, computeExecHash, countRules, createAllowAllGate, createAllowAllImportGate, createAskQuestionTool, createCodeExecTool, createDelegateTool, createDenyAllGate, createDenyAllImportGate, createGoalTool, createImportGate, createMemoryTool, createPlanModeTools, createRoleFile, createRoleScope, createRunCodeTool, createScheduleDraftTool, createSessionMessagesReadTool, createSessionMessagesSearchTool, createSessionSearchTool, createSessionSearchTools, createSessionTraceTool, createSkillViewTool, createSkillWriteTools, createTodoTool, createToolRevealState, createToolScope, createToolSearchTool, createTrustGate, currentEpochVersion, decideImport, decideTrust, defaultConfig, defaultModelOf, describeArtifactRefusal, describeBackgroundTask, describeHeadlessPolicy, describeIsolation, describeJsonError, diagnoseSchedules, discoverMarkdown, discoverModels, discoverProject, displayCurrency, draftCommandLine, draftWidening, escapeRuleContent, estimateImageTokens, estimateRunTokens, estimateTokens, evaluateSelection, expandCommand, expandImports, explainSetting, extractArchive, findInstructionFiles, findProjectInstructions, findRole, formatBytes, formatSkillIndex, formatUsd, gateForTool, getCapability, getConfigIssues, getConfigOrigins, getImportGate, getTrustGate, hasDedicatedExecContent, hasExecTierContent, hasPromptCaching, hasProviderCredentials, hasReadTierContent, imageFromBase64, imageFromPath, imagePartTokens, importSkills, installPlugin, instructionDirs, instructionNotices, intervalSlots, inventoryProjectExtensions, inventoryTotal, isBlockCode, isCodeModeDeferred, isEmptyRules, isGoalPhase, isNonInteractive, isReadOnlySubCall, isSettingWriteLayer, isValidPluginName, isWithinWindow, isWritableSettingKey, labelSlug, layerRank, listSessionCandidates, listWorkspaceFiles, loadCommandDefinitions, loadCommandFile, loadCommands, loadConfig, loadHookSources, loadKeybindings, loadLexiconDir, loadLexiconFiles, loadPlugins, loadPolicyFiles, loadPolicyRules, loadRoleDefinitions, loadRoleDir, loadedImports, localDateString, managedSwitchNotes, mapClaudeToolName, mapEpochToolName, mapOperationType, matchPreauthorization, matchRuleLists, matchesHook, mentionsPluginRoot, mergeHeadlessPolicy, mergeRoles, mergeSchedulePatch, microsToUsd, modelListCandidates, needsAllowlist, nextFallbackModel, nextRunAt, noConfigOrigins, noManagedPolicy, noPlugins, openArtifact, originOf, packFileName, packPlugin, parseClaudeSettingsHooks, parseClock, parseDate, parseFrontmatter, parseHooksConfig, parseHooksConfigVerbose, parseImportLine, parseModelList, parseRoleDefinition, parseScheduleDraft, parseSkillFrontmatter, parseTrigger, pendingImageTokens, persistParts, persistToolResults, persistedUsage, planPack, previewSkillImport, pricingFor, projectEntryForDisplay, pruneArtifacts, pruneAttachments, pruneRecordings, pruneSchedules, readImageSize, readMarketplaces, readPluginManifest, readPluginRecords, readProviderKeyEnv, readRecording, readSessionSurface, reclaimFtsSpace, redactLine, refreshOpenRouterMetadata, removeMarketplace, 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, scanInstructions, scanPluginDir, scanSkillDirs, searchMarketplaces, setDisplayCurrency, setImportGate, setPluginEnabled, setTrustGate, settingValueChoices, settingValueKind, settingWriteApply, settingWriteLayers, settingWriteTargets, skillIndexDescription, skillIndexResidency, skillIndexStats, sniffMediaType, splitFrontmatter, staticToolProvider, stripArtifactData, substitutePluginRoot, suggestRuleFromApproval, systemOpenArgv, systemPromptSegments, toPosix, toolDefinitionTokens, toolMatches, toolTableTokens, totalTokens, traceSession, triggerPeriodMs, unescapeRuleContent, uninstallPlugin, unknownRoleSkills, unknownRoleTools, unloadedInstructionFiles, updateMarketplace, updatePlugin, usdToMicros, validateSchedule, validateTrigger, validateWindow, withGoalCompression, withGoalPrompt, workspaceDisplayPath, writeSettingValue };
|