Skip to content
Merged
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
19 changes: 16 additions & 3 deletions docs/daemon-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,16 @@ on demand, external-session polling uses `after`, and completion self-healing
reads only a bounded tail (plus one older page if the user-turn anchor is absent).
Full export, fork and explicit session references keep the legacy full read.

Conversation error messages (`role: "error"`) are persisted as transcript-only
records with `metadata.transcript_only: true`, a unique `uuid`, and a timestamp.
Their `id` is that UUID in both history and `message` events; original text and
`metadata.provider_error` details are preserved. Clients reconcile these errors
by ID, so history/event overlap produces one card while separate identical
failures remain separate cards. Legacy unmarked error events retain sequence
identity because their content-derived IDs can repeat. These records are visible
after switching sessions, refresh, and restart, but are excluded from provider
history and compaction input. Errors lost by older versions are not backfilled.

Visible system messages may include `metadata.system_notice` with
`{ "version": 1, "code": "goal_started", "params": { "goal": { ... } } }`.
The stable event code and structured parameters describe the notice; Web and
Expand Down Expand Up @@ -2903,11 +2913,12 @@ cannot be disabled and return `409 {"error":"HOOK_MANAGED"}`.
```

`api_protocol` 仅适用于 `provider:"openai"`,接受 `chat_completions` 或
`responses`;省略时继续使用 Chat Completions。模型设置的 **API 协议** 下拉框可
`responses`;省略时,目录身份 `models_dev_provider_id:"acemodel"` 使用 Responses,
其他 OpenAI 配置继续使用 Chat Completions。模型设置的 **API 协议** 下拉框可
选择 Responses,保存和连接检测使用同一协议。`base_url` 模式下 Responses 会向
基础地址追加 `/responses`;`full_url` 模式直接使用给定 URL。协议由该字段决定,
不会根据 URL 或模型名称自动推断。更新时省略该字段保留原值,传 `null` 清除并恢复
默认 Chat Completions;切换到其他 Provider 会清除该字段,其他 Provider 显式传入
该 Provider 的默认协议(ACEModel 为 Responses);切换到其他 Provider 会清除该字段,其他 Provider 显式传入
则返回 `UNSUPPORTED_MODEL_OPTION`,未知协议值返回 `INVALID_API_PROTOCOL`。

返回包含 `api_key` 原值的模型配置。校验错误使用 `BAD_JSON`、`BAD_REQUEST` 或
Expand Down Expand Up @@ -3093,7 +3104,9 @@ Errors include `COPILOT_AUTH_REQUIRED`, `GROK_AUTH_REQUIRED`,
`none` 或 `managed`。Custom OpenAI-compatible Provider 明确支持
`endpoint_modes:["base_url","full_url"]`,并要求 API Key 或兼容的
`credential_source_name`。一等自营 Provider `acemodel`(展示名 ACEModel)
使用与 OpenAI 相同的 OpenAI-compatible 字段,固定 Base URL 为
返回 `default_api_protocol:"responses"`,模型设置新增和批量新增时采用该默认值,
用户可在 **API 协议** 中修改;已有明确协议选择在加载及安装器升级时保持。
ACEModel 使用与 OpenAI 相同的 OpenAI-compatible 字段,固定 Base URL 为
`https://ge.bigjuan.xyz/aceapi/v1`,`group` 为 `custom`(Web 再按 id 提到「自营模型」),查询时返回内置
`starrylight`、`moonlight` 与 `aurora`,三者本地回退 `context_window` 均为 `250000`,且默认返回 `capabilities:["vision","tool_use"]`;模型探测得到的有效服务器值优先。Copilot 与 Grok Coding Plan 使用 `managed`,分别由
ACECode 的 GitHub/xAI 设备登录与固定受管端点负责认证。普通 `xai` Provider
Expand Down
7 changes: 7 additions & 0 deletions docs/releases/v1.0.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ACECode v1.0.3

- 修复模型服务报错后切换会话、刷新或重启导致红框提示丢失的问题。HTTP 451 额度用尽等错误现在会保存在会话记录中,保留原始详情;这些记录不会发送给模型或参与上下文压缩。同一次错误重放不会重复显示,不同回合的相同错误分别保留。
- ACEModel 默认采用 Responses 协议,模型设置中仍可切换为 Chat Completions。旧配置仅在未明确指定协议时采用新默认值,保留已有选择;安装器、模型目录和连接检测同步使用有效协议。
- 统一生成过程中的输入框主按钮:空草稿显示实心方块停止图标,有文字或附件时显示排队图标,回车或点击即可排队。按钮始终保持主题色背景,并保留停止在途、暂停队列和键盘操作反馈。

升级后请完整重启 ACECode;远端使用场景也需更新运行会话的服务器。旧版本未保存的错误提示无法补回。Agent Browser 集成于 Desktop,无需独立浏览器宿主或扩展。
4 changes: 4 additions & 0 deletions installer/windows/seed_acemodel.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function New-AceModelProfile([string]$name, [string]$key) {
$profile["api_key"] = $key
$profile["models_dev_provider_id"] = "acemodel"
$profile["endpoint_mode"] = "base_url"
$profile["api_protocol"] = "responses"
$profile["context_window"] = 250000
$profile["capabilities"] = @("vision", "tool_use")
$profile["capabilities_source"] = "catalog"
Expand All @@ -129,6 +130,9 @@ function Upsert-AceModel($models, [string]$name, [string]$key) {
$current["api_key"] = $key
$current["models_dev_provider_id"] = "acemodel"
$current["context_window"] = 250000
if (-not (Config-HasKey $current "api_protocol") -or [string]::IsNullOrWhiteSpace([string]$current["api_protocol"])) {
$current["api_protocol"] = "responses"
}
if (-not (Config-HasKey $current "endpoint_mode") -or [string]::IsNullOrWhiteSpace([string]$current["endpoint_mode"])) {
$current["endpoint_mode"] = "base_url"
}
Expand Down
17 changes: 17 additions & 0 deletions installer/windows/seed_acemodel.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ try {
"name": "starrylight",
"provider": "openai",
"model": "starrylight",
"api_protocol": "chat_completions",
"base_url": "https://old.example/v1",
"api_key": "old-key",
"capabilities": ["tool_use"],
Expand Down Expand Up @@ -75,13 +76,19 @@ try {
}
}
foreach ($profile in @($moon, $aurora)) {
if ($profile.api_protocol -ne "responses") {
throw "default Responses protocol was not set for $($profile.name)"
}
if ((@($profile.capabilities) -join ",") -ne "vision,tool_use" -or $profile.capabilities_source -ne "catalog") {
throw "default vision/tool capabilities were not set for $($profile.name)"
}
}
if ((@($star.capabilities) -join ",") -ne "tool_use" -or $star.capabilities_source -ne "manual") {
throw "manual ACEModel capabilities were overwritten"
}
if ($star.api_protocol -ne "chat_completions") {
throw "explicit Chat Completions selection was overwritten"
}
if ($config.default_model_name -ne "moonlight") {
throw "default model was not seeded"
}
Expand All @@ -99,6 +106,16 @@ try {
if (@($qwen.capabilities).Count -ne 1 -or @($qwen.capabilities)[0] -ne "tool_use") {
throw "existing qwen capabilities were damaged"
}
if ($qwen.PSObject.Properties.Name -contains "api_protocol") {
throw "unrelated qwen protocol was changed"
}
& powershell -NoProfile -ExecutionPolicy Bypass -File $seeder -KeyFile $keyFile -ConfigPath $configPath
if ($LASTEXITCODE -ne 0) { throw "second seeder run exited $LASTEXITCODE" }
$reseeded = Get-Content -LiteralPath $configPath -Raw | ConvertFrom-Json
foreach ($profile in $reseeded.saved_models | Where-Object { $_.PSObject.Properties.Name -contains "models_dev_provider_id" -and $_.models_dev_provider_id -eq "acemodel" }) {
$expected = if ($profile.name -eq "starrylight") { "chat_completions" } else { "responses" }
if ($profile.api_protocol -ne $expected) { throw "reseed changed explicit protocol for $($profile.name)" }
}
Write-Host "[pass] ACEModel seeder writes and upgrades all three profiles"
}
finally {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-09
26 changes: 26 additions & 0 deletions openspec/changes/default-acemodel-responses-protocol/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Context

See proposal.md. The existing ModelProfile.api_protocol field, Responses Provider, API protocol selector, mutation validation and fingerprinting already support explicit selection. Provider factory currently defaults every missing protocol to Chat Completions. ACEModel's catalog descriptor does not supply a default; the Windows seeder also omits it.

## Goals / Non-Goals

Goals: share protocol resolution across configuration, runtime and API defaults; retain explicit selections; use the existing accessible selector and settings styles.

Non-goals: infer identity from model names or URLs, modify credentials or capability metadata, implement another Responses transport, publish or restart the installed Desktop application.

## Decisions

1. Add a shared effective protocol helper in saved_models: an explicit value wins; an OpenAI profile with a case-insensitive ACEModel catalog identity defaults to Responses; other profiles default to Chat Completions. Using the capability-normalization predicate would incorrectly exclude manual capabilities and additional ACEModel model IDs.
2. Materialize missing ACEModel defaults when parsing saved configurations and report the effective default from model-list serialization. Keep the model editor's existing omitted/null semantics: null removes an override, then effective resolution uses the provider default. Factory uses the helper for ordinary calls, compaction and connection tests; protocol fingerprints already encode the effective request option.
3. Add optional default_api_protocol to the ACEModel catalog descriptor. Frontend normalization validates it; provider selection initializes the draft from that field and retains existing reset behavior for other providers. Every model in a batch inherits the selected protocol. Existing saved entries come from the daemon with the effective protocol.
4. Seeder writes Responses for new presets and only fills absent/empty protocol values on upgrade. Existing explicit Chat Completions remains a valid fallback.

## Risks / Trade-offs

- Missing-field ACEModel configurations change protocol at upgrade -> preserve explicit choices and expose Chat Completions in the existing selector.
- Default and display diverge for profiles created through TUI or direct API -> serialize effective ACEModel defaults and test in-memory profiles, parser and factory paths.
- A prior factory test assumes ACEModel always uses Chat Completions -> make that test explicitly select Chat Completions and add Responses factory coverage.

## Migration Plan

No direct edits to user configuration files. Load normalizes only missing ACEModel protocol values; subsequent ordinary saves persist them. Users can select Chat Completions to revert a profile. Validate targeted C++ HTTP/configuration/API tests, seeder regression, frontend tests/build, strict OpenSpec and diff checks. The current build/ Visual Studio Release directory is reusable; compile with --parallel 1.
24 changes: 24 additions & 0 deletions openspec/changes/default-acemodel-responses-protocol/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Why

ACECode 已支持 Responses,但 ACEModel 新建模型和未声明协议的旧配置仍默认使用 Chat Completions。用户希望 ACEModel 默认使用 Responses,并能在模型设置中修改协议。

## What Changes

- ACEModel 的 OpenAI 运行时配置在未声明协议时默认使用 Responses;明确选择的协议优先。
- 模型目录提供默认协议,新增及批量新增模型使用该默认值,编辑继续使用已有的 API 协议选择框。
- Windows 安装器新建及升级缺省 ACEModel 配置时写入 Responses,保留已有协议选择。
- 普通 OpenAI 兼容配置继续使用原默认值;默认协议依据目录身份,独立于模型名称、URL 及能力设置。

## Capabilities

### New Capabilities

无。

### Modified Capabilities

- `web-model-management`: ACEModel 默认协议、设置修改、旧配置及安装器的一致性。

## Impact

涉及保存模型配置解析、Provider 工厂、模型目录及列表 API、前端模型草稿、Windows seeder 和相关测试。复用现有 Responses 实现;不改变认证、能力及上下文信息。本变更针对 ACEModel 覆盖 `add-openai-responses-protocol` 的统一缺省 Chat Completions 约定。
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## ADDED Requirements

### Requirement: ACEModel configurable Responses default

ACECode SHALL default OpenAI runtime profiles identified by catalog provider `acemodel` to Responses when `api_protocol` is omitted. Explicit `chat_completions` or `responses` selections MUST take precedence. This default SHALL apply consistently to new profiles, loaded legacy profiles, runtime requests, connection tests and Windows installer presets, independently of model names, endpoint URLs and capability overrides. Other providers SHALL retain their existing default protocol.

#### Scenario: Create ACEModel profiles
- **WHEN** a user selects ACEModel and one or multiple models in model settings
- **THEN** the API protocol selector defaults to Responses and saving preserves that protocol on every created profile

#### Scenario: Load a legacy ACEModel profile
- **WHEN** an OpenAI profile with catalog identity `acemodel` has no explicit API protocol
- **THEN** the runtime and model settings use Responses, including profiles with manual capabilities or a proxy endpoint

#### Scenario: Change and retain a protocol selection
- **WHEN** the user selects Chat Completions or Responses in an ACEModel profile's API protocol selector and saves it
- **THEN** inference, connection tests and subsequent edits use the saved selection, and loading or installer upgrades preserve it

#### Scenario: Clear an override
- **WHEN** an API update clears an ACEModel profile's explicit protocol with `null`
- **THEN** its effective protocol returns to the ACEModel default of Responses

#### Scenario: Switch providers
- **WHEN** a user switches the model form between ACEModel and another provider
- **THEN** the new provider's default replaces the preceding protocol selection without carrying Responses into other providers implicitly

#### Scenario: Seed installer profiles
- **WHEN** the Windows installer creates ACEModel presets or upgrades presets without an explicit protocol
- **THEN** it writes Responses and leaves existing explicit protocol choices and unrelated profiles intact
13 changes: 13 additions & 0 deletions openspec/changes/default-acemodel-responses-protocol/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## 1. 默认协议与运行时

- [x] 1.1 实现共享 ACEModel 协议默认值、旧配置加载与模型列表/目录 API;通过配置及目录契约回归测试验证缺省、明确覆盖及其他 Provider 行为。
- [x] 1.2 Provider 工厂使用有效默认协议;通过本地 HTTP 测试验证 Responses 的流式/非流式请求、连接检测协议和明确切回 Chat Completions。

## 2. 设置与安装器

- [x] 2.1 前端采用目录默认协议并复用 API 协议选择框;通过草稿、批量保存、编辑、切换 Provider 的 JS 回归及界面检查验证。
- [x] 2.2 Windows seeder 写入缺省 Responses 并保留明确选择;运行 seed_acemodel.test.ps1 验证新建、升级与无关配置保留。

## 3. 集成验证

- [x] 3.1 更新 Daemon API 文档并完成定向 C++ 测试、pnpm test、pnpm build、严格 OpenSpec 校验及 git diff --check;记录验证结果及运行环境边界。
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 验证记录

日期:2026-10-09,当前 master 检出。

## 已完成

- `cmake --build build --config Release --target acecode_unit_tests --parallel 1`:在 `scripts/dev_windows_env.bat` 初始化的 MSVC 环境中构建成功。首次新增测试误用 `chat(..., true)`,修正为已有 `chat_for_compaction(..., nullptr)` 后增量重编成功。
- `build/tests/Release/acecode_unit_tests.exe --gtest_filter=SavedModelsTest.*:SavedModelsEditor*.*:ModelCatalogHandler.*:ModelsHandler.*:ModelProfileRuntimeOptions.*:OpenAiResponsesProviderTest.*:ModelConnectionTest.* --gtest_color=no`:7 个 suite、174 项全部通过。
- `node web/src/lib/modelSettings.test.js`:包含 ACEModel 目录默认值、批量保存、编辑及服务商切换的回归通过。
- `pnpm test`:3,080 项 Web 检查通过。
- `pnpm build`:Vite 构建和正则兼容检查通过。
- `powershell -NoProfile -ExecutionPolicy Bypass -File installer/windows/seed_acemodel.test.ps1`:新建、升级、重复运行保留明确协议、无关配置保留均通过。
- Headless Edge 使用真实 `ModelProfileDialog` 与当前 Vite 源码:4 项交互通过,覆盖默认 Responses 和三模型保存、编辑/检测/保存协议一致、明确 Chat Completions 回填后再切回 Responses、切换 Provider 恢复默认;无 pageerror。
- `python scripts/refactor/check_layer_libraries.py --build-dir build`:生产库分层检查通过。
- `openspec validate default-acemodel-responses-protocol --strict`:通过。
- `git diff --check`:通过。

## 验证边界

HTTP 回归使用本机 fixture,确认实际端点和请求体;浏览器检查使用 fixture API。未发送真实 ACEModel 付费请求。已验证源代码与 Web 构建,未更新当前运行的已安装 Desktop 软件。当前仓库规则忽略 `openspec/` 中新建文件,变更文档保存在本地既定目录中。

构建出现既有共享 Intermediate 目录警告;使用串行构建避免并发链接冲突。未提交或发布本次改动。
2 changes: 2 additions & 0 deletions openspec/changes/persist-session-error-notices/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-10
27 changes: 27 additions & 0 deletions openspec/changes/persist-session-error-notices/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Context

See proposal.md for the incident. Agent error messages use `TranscriptWriter::dispatch_message`, which emits callbacks and events without storing a ChatMessage. The Web reducer deliberately treats old error IDs as content-derived event identities. Durable transcript records already support `metadata.transcript_only`, and provider history filtering excludes these records and non-provider roles.

## Goals / Non-Goals

**Goals:** Persist every emitted red error message before publishing it; preserve diagnostics and independent occurrences; restore through ordinary transcript reads; keep current, resumed, and compacted model requests free of these records.

**Non-Goals:** Changing quota detection, retry policy, error-card design, or reconstructing errors never written by older versions. Transport connection errors and tool-result errors retain their existing semantics.

## Decisions

1. Inject the loop's nullable borrowed SessionManager into TranscriptWriter at construction. At the shared error dispatch boundary create a UUID, timestamp, and transcript-only metadata, append to history and session storage, then emit the existing callback/event. This covers all red error messages rather than only HTTP 451. A browser cache was rejected because it misses background failures and does not survive a daemon restart.
2. Use UUID identity for error records when available; retain existing content-derived IDs for legacy records and all other roles. A timestamp alone is insufficient for two equal failures within the same clock interval.
3. Distinguish durable errors by `role=error`, `metadata.transcript_only=true`, and a nonempty ID. Reconcile these by ID in both replay paths; bypass content-only deduplication for different error IDs. Unmarked legacy errors retain occurrence/sequence semantics.
4. Reuse the existing provider-history filter, and test both the actual next provider request and resumed history. No UI style changes or additional context protocol is required.

## Risks / Trade-offs

- [Duplicate live/history cards] -> Assert the persisted UUID equals the event/API ID and cover overlapping REST plus WebSocket replay.
- [Loss of equal errors] -> Separate UUIDs for each dispatch; test identical content in separate turns.
- [Accidental prompt contamination] -> Assert transcript-only markers and provider request exclusion before and after resume/compaction.
- [Existing dirty files] -> Restrict edits to this feature and preserve pre-existing daemon documentation changes.

## Migration Plan

Deploy backend and Web bundle together. Records are additive JSONL messages understood by existing storage; no migration is required. Old clients still display errors, but may duplicate overlapping replay until upgraded. Rollback leaves durable records safely excluded from model context.
Loading
Loading