Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/config-management-detail-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,14 @@ custom provider 来自:
- 不在 `config` 中堆兼容旧字段的逻辑
- 不把选择修正混进快照校验
- 不把 provider/catalog/runtime 语义倒灌回 `config`

## custom provider `models` 校验约束

`~/.neocode/providers/<provider-name>/provider.yaml` 中允许通过 `models` 补齐模型元数据,用于 catalog/discovery 无法提供完整 `ContextWindow` 或 `MaxOutputTokens` 的场景。

该能力的约束是:

- `models[].id` 必须非空。
- `models[].context_window` 和 `models[].max_output_tokens` 如果显式提供,必须大于 `0`。
- 重复的模型 `id` 会在加载 custom provider 时直接失败,不保留 silently drop 的宽松行为。
- 这些元数据不会写回 `config.yaml`,只在 custom provider 文件中声明,并通过现有 catalog 合并链路参与运行时解析。
21 changes: 19 additions & 2 deletions docs/context-compact.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Context Compact

## Auto Compact Failure Fallback

- 当 `context.auto_compact.input_token_threshold <= 0` 时,系统会尝试基于当前模型的 `ContextWindow` 自动推导阈值。
- 若当前 provider 选择无效、catalog snapshot 查询失败,或模型窗口元数据缺失,系统会直接回退到 `fallback_input_token_threshold`。
- 自动推导失败不会静默关闭 auto compact;runtime 仍会拿到一个可用的保底阈值。

本文档说明 NeoCode 中 context compact 的配置、执行链路和摘要约定。

## 概览
Expand All @@ -23,7 +29,9 @@ context:
micro_compact_disabled: false
auto_compact:
enabled: false
input_token_threshold: 100000
input_token_threshold: 0
Comment thread
fennoai[bot] marked this conversation as resolved.
reserve_tokens: 13000
fallback_input_token_threshold: 100000
```

- `manual_strategy`
Expand All @@ -39,7 +47,7 @@ context:
- `auto_compact.enabled`
控制是否启用基于 token 阈值的自动压缩;默认关闭。
- `auto_compact.input_token_threshold`
当会话累计输入 token 数达到此阈值时触发自动压缩;默认 100000。
当会话累计输入 token 数达到此阈值时触发自动压缩;默认 `0`(自动推导),推导失败时回退到 `fallback_input_token_threshold`(默认 `100000`)

## 自动压缩

Expand Down Expand Up @@ -154,3 +162,12 @@ compact 相关 runtime 事件包括:
- `trigger_mode`
- `transcript_id`
- `transcript_path`

## Auto Compact 阈值解析

- `context.auto_compact.input_token_threshold > 0` 时,直接使用显式手动阈值。
- `context.auto_compact.input_token_threshold <= 0` 时,系统会对当前选中的 provider/model 做自动推导。
- 自动推导公式为 `resolved_threshold = context_window - reserve_tokens`。
- `reserve_tokens` 默认 `13000`,用于给输出、tool call 和 system prompt 预留缓冲。
- 如果当前模型没有可用的 `ContextWindow`,或窗口值小于等于 `reserve_tokens`,则回退到 `fallback_input_token_threshold`。
- `fallback_input_token_threshold` 默认 `100000`,用于保证主链路在缺少模型窗口元数据时仍可稳定运行。
31 changes: 31 additions & 0 deletions docs/guides/adding-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,34 @@ func DefaultProviders() []ProviderConfig {
```

所有内置 provider 都通过代码集中注册。模型选择器展示的候选模型由默认模型、动态发现结果和本地缓存共同组成。

## custom provider 模型元数据补齐

对于复用 `openaicompat` 驱动的 custom provider,如果上游 `GET /models` 不能返回可靠的上下文窗口信息,可以在:

```text
~/.neocode/providers/<provider-name>/provider.yaml
```

中显式声明 `models`:

```yaml
name: company-gateway
driver: openaicompat
api_key_env: COMPANY_GATEWAY_API_KEY
models:
- id: deepseek-coder
name: DeepSeek Coder
context_window: 131072
max_output_tokens: 8192
openai_compatible:
base_url: https://llm.example.com/v1
api_style: chat_completions
```

约束如下:

- `models[].id` 必须非空。
- `models[].context_window` 和 `models[].max_output_tokens` 如果显式配置,必须大于 `0`。
- 同一个 `provider.yaml` 中重复的模型 `id` 会在加载阶段直接报错。
- 这些元数据会进入统一的 model catalog 合并链路,优先级仍为“配置模型元数据优先于 discovery/default”。
36 changes: 35 additions & 1 deletion docs/guides/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ context:
micro_compact_disabled: false
Comment thread
fennoai[bot] marked this conversation as resolved.
auto_compact:
enabled: false
input_token_threshold: 100000
input_token_threshold: 0
reserve_tokens: 13000
fallback_input_token_threshold: 100000
```

### 基础字段
Expand All @@ -81,6 +83,8 @@ context:
| `context.compact.micro_compact_disabled` | 是否关闭默认启用的 micro compact |
| `context.auto_compact.enabled` | 是否启用自动压缩 |
| `context.auto_compact.input_token_threshold` | 自动压缩输入 token 阈值 |
| `context.auto_compact.reserve_tokens` | 自动阈值推导时预留 token 缓冲(`resolved_threshold = context_window - reserve_tokens`) |
| `context.auto_compact.fallback_input_token_threshold` | 自动推导失败时使用的保底阈值 |

### `runtime` 字段

Expand Down Expand Up @@ -142,6 +146,13 @@ openai_compatible:
api_style: chat_completions
```

## Auto Compact 失败与校验补充

- 当 `context.auto_compact.input_token_threshold <= 0` 时,如果当前 provider 选择无效、catalog snapshot 查询失败,或模型缺少可用的 `ContextWindow`,系统会回退到 `fallback_input_token_threshold`,不会静默关闭 auto compact。
- `~/.neocode/providers/<provider-name>/provider.yaml` 中的 `models[].id` 必须非空。
- `models[].context_window` 和 `models[].max_output_tokens` 如果显式配置,必须大于 `0`。
- `models` 中重复的模型 `id` 会在加载 `provider.yaml` 时直接报错。

文件路径:

```text
Expand Down Expand Up @@ -230,3 +241,26 @@ config: environment variable OPENAI_API_KEY is empty
- [添加 Provider](./adding-providers.md)
- [配置管理详细设计](../config-management-detail-design.md)
- [Context Compact](../context-compact.md)

## Auto Compact 补充说明

- `context.auto_compact.input_token_threshold > 0` 时,系统直接使用该显式阈值。
- `context.auto_compact.input_token_threshold <= 0` 时,系统会根据当前 `current_model` 对应的 `ContextWindow` 自动推导输入阈值。
- 推导公式为 `context_window - reserve_tokens`。
- `reserve_tokens` 默认 `13000`。
- 如果当前 provider/model 没有可用的 `ContextWindow` 元数据,则回退到 `fallback_input_token_threshold`。
- custom provider 可以在 `~/.neocode/providers/<provider-name>/provider.yaml` 中通过 `models` 字段补齐模型元数据,例如:

```yaml
name: company-gateway
driver: openaicompat
api_key_env: COMPANY_GATEWAY_API_KEY
models:
- id: deepseek-coder
name: DeepSeek Coder
context_window: 131072
max_output_tokens: 8192
openai_compatible:
base_url: https://llm.example.com/v1
api_style: chat_completions
```
15 changes: 15 additions & 0 deletions internal/app/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ func BuildRuntime(ctx context.Context, opts BootstrapOptions) (RuntimeBundle, er
contextBuilder,
)
runtimeSvc.SetSkillsRegistry(buildSkillsRegistry(ctx, loader.BaseDir()))
runtimeSvc.SetAutoCompactThresholdResolver(runtimeAutoCompactThresholdResolverFunc(
func(ctx context.Context, cfg config.Config) (int, error) {
resolution, err := configstate.ResolveAutoCompactThreshold(ctx, cfg, modelCatalogs)
if err != nil {
return 0, err
}
return resolution.Threshold, nil
},
))

// 注入记忆提取钩子:当 AutoExtract 启用且 memoSvc 可用时,ReAct 循环完成后异步提取记忆。
if memoSvc != nil && cfg.Memo.AutoExtract {
Expand Down Expand Up @@ -306,3 +315,9 @@ type textGenAdapter func(ctx context.Context, prompt string, msgs []providertype
func (f textGenAdapter) Generate(ctx context.Context, prompt string, msgs []providertypes.Message) (string, error) {
return f(ctx, prompt, msgs)
}

type runtimeAutoCompactThresholdResolverFunc func(ctx context.Context, cfg config.Config) (int, error)

func (f runtimeAutoCompactThresholdResolverFunc) ResolveAutoCompactThreshold(ctx context.Context, cfg config.Config) (int, error) {
return f(ctx, cfg)
}
Loading
Loading