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
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ VITE_AI_API_KEY=your-api-key-here
# OpenRouter free example:
# VITE_AI_API_URL=https://openrouter.ai/api/v1
# VITE_AI_MODEL=nvidia/nemotron-3-ultra-550b-a55b:free
VITE_AI_MODEL=your-model-name
VITE_AI_MODEL=nvidia/nemotron-3-ultra-550b-a55b:free

# Tavily Web Search API Key (for AI-powered web search)
# Get your key at: https://tavily.com
# Used by: web_search tool, sonar_search fallback, real-time information retrieval
# Used by: Scholar and explicit real-time information retrieval
VITE_TAVILY_API_KEY=tvly-xxxxxxxxxxxxxxxxxxxx
37 changes: 30 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

> Planned features not yet assigned to a specific version.

### Performance

- **One-model-request turn budget** (2026-08-13)
- Limited ordinary persona, Agent, and group turns to one configured text-model request; group chats now select one eligible responder instead of fanning out to every participant
- Removed automatic title generation, LLM memory extraction, recall rewrites, proactive images, background Moment generation, recursive model-backed tools, and automatic API retries
- Moved durable memory capture, titles, Moment templates, quizzes, idiom games, palettes, learning-state tools, and deterministic arithmetic to local code with zero text-model requests
- Preserved the latest user input and expanded working context to 48 recent messages / 100,000 characters; raised task-aware output ceilings to 1,600–6,144 tokens
- Kept ordinary turns at one model request while restoring a visible two-request native-tool path when the model must infer tool arguments and synthesize the verified result
- Rebuilt per-turn prompts from task-relevant sections so persona identity, memory, group context, freshness safeguards, and tool guidance are injected only when applicable
- Repaired the prompt regression benchmark against the current Scholar, Muse, and dynamic-turn owners; the measured specialist-prompt budget intentionally rises by about 146 estimated tokens (+11.5%) for stronger Coder/Sensei behavior, while request fan-out remains removed
- Added in-place streaming for task-Agent answers without adding requests; throttled UI updates and removed the redundant typing bubble once text is visible
- Corrected negated brevity requests such as “不要为了简短而省略” so they receive the long-form budget instead of an 800-token cap
- Disabled optional extended reasoning with OpenRouter `reasoning.effort: "none"` and excluded reasoning output after live testing exposed duplicated scratchpad content; normal inference and function calling remain enabled
- Strengthened post-tool synthesis so verified formulas and units remain authoritative, including area/circumference/volume distinctions; exact local math facts now replace unusable one-character provider synthesis without a third request
- Kept image generation and text-to-speech behind explicit user actions, with TTS caching for repeat playback
- **Fixed OpenRouter free model**
- Standardized the default and settings preset on `nvidia/nemotron-3-ultra-550b-a55b:free`; automatic fallback models and the random `openrouter/free` router remain disabled
- Added visible manual retry behavior for provider failures so a failed turn cannot silently spend additional requests

### Security

- **Deny-by-default agent tools and safe rich content** (2026-08-12)
Expand All @@ -117,19 +136,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- **Real OpenRouter Agent/persona validation** (2026-08-13)
- Added an OpenRouter quick-fill preset using `nvidia/nemotron-3-ultra-550b-a55b:free`
- **Real OpenRouter Agent/persona and request-budget validation** (2026-08-13)
- Validated the fixed Ultra route with one-request cross-topic persona recall, a generated TypeScript React Hook whose four tests passed in a temporary Vitest workspace, and a real two-request native math-tool flow
- Rejected Lightning and Super as the final default after executable code-quality checks; candidate comparison is test-only and is not runtime model routing
- Verified local math and trivia at zero provider requests, group chat at one responder/one model request, explicit Pixel image generation at one MiniMax request, and cached repeat TTS at zero additional requests
- Updated Scholar's official-source filter for the current OpenRouter free-router documentation URL while retaining one Tavily request
- Prevented question sentences from being stored as long-term facts and replaced base64 image source text in Agent topic previews with a localized photo label
- Preserved user-authored and model-generated bracket syntax such as `items[1]`, `items[0]`, citations, and tuple labels while continuing to remove explicit internal control tags
- Fixed mixed Chinese-plus-code language detection so identifiers no longer force an English system instruction
- Disabled reasoning for short OpenRouter title requests so reasoning-first models return a visible topic title within the token budget
- Switched MiniMax Moment images to the official durable `base64` response instead of expiring cross-origin URLs, and kept blob workers limited to the Vite development CSP
- Verified real Coder and Luna conversations through OpenRouter, then added bracket preservation to the Chrome E2E path
- Added request-budget, local-memory, local-game, context-window, and Scholar evidence regression coverage

- **Security, data-integrity, CI, and UX remediation** (2026-08-12)
- Prevented stale hydration from overwriting new messages and made ChatEngine snapshots immutable for React subscribers
- Recomputed message metadata after deletion, fixed poll memoization and Scholar tool schemas, and refreshed AI clients on config changes
- Added a real light theme, accessible accent contrast, semantic controls, dialog focus management, 44px touch targets, language metadata, and reduced-motion handling
- Added Playwright + Axe acceptance coverage: 19/19 Chromium tests and 8/8 mobile UX tests
- Added Playwright + Axe acceptance coverage: 21/21 Chromium tests and 10/10 mobile UX tests
- Replaced the missing notification audio asset with an on-demand Web Audio tone and prevented production Service Workers from controlling development sessions
- Replaced regex-only HTML filtering with DOMPurify, allowlisted avatar image sources, removed legacy persisted Moments image keys, and constrained persistent API configuration fields
- Declared read-only CI workflow permissions and removed 222 generated coverage artifacts from version control
Expand All @@ -140,8 +162,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added deterministic test coverage for the recall branch to stop intermittent test failures
- Hardened async memory extraction to avoid calling `.catch()` on non-Promise return values
- **Layered coverage gate** (`vitest.config.js`, `vitest.full-coverage.config.js`, `docs/TEST_COVERAGE_ANALYSIS.md`)
- Verified 407/407 tests and a 60% hard gate on regression-critical logic
- Current gated coverage is 85.04% statements, 77.83% branches, 84.91% functions, and 87.95% lines
- Verified 471/471 tests and a 60% hard gate on regression-critical logic
- Current gated coverage is 85.66% statements, 76.61% branches, 86.69% functions, and 88.86% lines
- Current whole-source observation is 27.61% statements, 25.00% branches, 21.31% functions, and 28.88% lines
- Kept an honest whole-repository observation command; UI behavior is gated separately by Playwright + Axe

### Added — UI Accessibility & Interaction Improvements (2026-03-08)
Expand Down
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
![Version](https://img.shields.io/badge/version-0.4.1-blue.svg)
![License](https://img.shields.io/badge/license-MIT-green.svg)
![React](https://img.shields.io/badge/React-19+-61DAFB.svg)
![Tests](https://img.shields.io/badge/tests-407%20passing-success.svg)
![Core Coverage](https://img.shields.io/badge/core%20lines-87.95%25-success.svg)
![Tests](https://img.shields.io/badge/tests-471%20passing-success.svg)
![Core Coverage](https://img.shields.io/badge/core%20lines-88.86%25-success.svg)

**AI Chat Companion**

Expand Down Expand Up @@ -132,9 +132,9 @@ npm run dev
|----------|----------|-------------|
| `VITE_AI_API_URL` | Yes | API Base URL (e.g., `https://api.deepseek.com`) |
| `VITE_AI_API_KEY` | Yes | Your API key for AI responses |
| `VITE_AI_MODEL` | Yes | Model name (e.g., `deepseek-chat`, `sonar`) |
| `VITE_AI_MODEL` | Yes | Model name (default: `nvidia/nemotron-3-ultra-550b-a55b:free`) |

> **Supported Providers**: OpenRouter, DeepSeek, Perplexity, OpenAI, and other OpenAI-compatible APIs. The API settings panel includes an OpenRouter preset for `nvidia/nemotron-3-ultra-550b-a55b:free`.
> **Provider setup**: the default preset uses OpenRouter with one fixed free model. Other OpenAI-compatible endpoints can be configured manually. Runtime keys entered in Settings live in `sessionStorage` only; build-time `VITE_*` secrets are still embedded in the client bundle, so production deployments should use a server-side proxy.

---

Expand All @@ -152,7 +152,20 @@ npm run dev
1. Type your message in the input field
2. Press Enter or click Send
3. AIs will respond based on their personality and context
4. In groups, AIs may also respond to each other
4. In a group, one eligible AI responds to each user turn to avoid model fan-out

### Request Budget

- A normal persona or Agent reply uses one request to the configured text model. There are no automatic model fallbacks or hidden retries.
- Explicit tools are precomputed when their arguments are unambiguous. If the model must infer tool arguments, the visible function-calling flow may use two text-model requests: choose the tool, then explain the verified result.
- Conversation titles, durable-memory capture, Moments background activity, quizzes, idiom games, palettes, and deterministic math run locally with zero model requests. Up to eight independently extracted durable facts are injected when relevant instead of replaying an extra model-generated summary.
- An explicit Scholar search uses one Tavily retrieval plus one text-model synthesis. Explicit image generation uses one MiniMax image request and no text-model request.
- Text-to-speech runs only after the user clicks Read Aloud; the generated audio is cached for repeat playback.
- Provider errors remain visible with a manual Retry action instead of spending another request automatically.
- Request efficiency never comes from discarding the user's task: the latest input is preserved, up to 48 recent messages / 100,000 characters are available, and output ceilings range from 1,600 to 6,144 tokens according to the task.
- `npm run prompt:bench` guards those capability contracts. The current specialist prompts intentionally use about 146 more estimated tokens (+11.5%) for stronger Coder/Sensei instructions; savings come from request fan-out and irrelevant per-turn sections, not from weakening the answer.
- Task Agents and personas stream answers into one in-place message. Requests to the fixed Nemotron model use OpenRouter `reasoning.effort: "none"` with reasoning excluded because live validation showed optional extended reasoning could consume the completion budget; normal inference and function calling remain enabled.
- If an upstream response reaches its length limit, the completed text stays visible with an explicit truncation notice. For math tools, the exact local result and symbolic form remain authoritative even when provider synthesis is unusable. The app never spends a hidden retry.

### Settings

Expand All @@ -172,7 +185,7 @@ npm run dev
- Frontend: React 19, Vite
- Styling: TailwindCSS
- State: Clean Architecture (ChatEngine + Context)
- AI: DeepSeek / Perplexity API
- AI: one configured OpenRouter/OpenAI-compatible text model; Tavily and MiniMax only for explicit search/media actions
- Storage: LocalStorage (settings) + IndexedDB (chats, documents, and media)

### Project Structure
Expand Down
25 changes: 19 additions & 6 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
![Version](https://img.shields.io/badge/version-0.4.1-blue.svg)
![License](https://img.shields.io/badge/license-MIT-green.svg)
![React](https://img.shields.io/badge/React-19-61DAFB.svg)
![Tests](https://img.shields.io/badge/tests-407%20passing-success.svg)
![核心覆盖率](https://img.shields.io/badge/core%20lines-87.95%25-success.svg)
![Tests](https://img.shields.io/badge/tests-471%20passing-success.svg)
![核心覆盖率](https://img.shields.io/badge/core%20lines-88.86%25-success.svg)

**AI 聊天伴侣**

Expand Down Expand Up @@ -177,9 +177,9 @@ npm run build
| ----------------- | ---- | ------------------------------------------- |
| `VITE_AI_API_URL` | 是 | API基础URL(如 `https://openrouter.ai/api/v1`) |
| `VITE_AI_API_KEY` | 是 | AI回复的API密钥 |
| `VITE_AI_MODEL` | 是 | 模型名称( `nvidia/nemotron-3-ultra-550b-a55b:free`) |
| `VITE_AI_MODEL` | 是 | 模型名称(默认 `nvidia/nemotron-3-ultra-550b-a55b:free`) |

> **支持的API提供商**:OpenRouter、DeepSeek、Perplexity、OpenAI及其他兼容OpenAI的API。设置面板已提供 OpenRouter 快速选项
> **Provider 配置**:默认快速选项为 OpenRouter,并固定使用一个免费模型;也可手动填写其他兼容 OpenAI 的端点。设置页输入的运行时密钥只存在 `sessionStorage`;构建期 `VITE_*` 变量仍会进入前端产物,生产环境应改用服务端代理

> **安全说明**:如果你在应用内设置面板中输入凭证,API 密钥只保存在当前浏览器会话中。保存的服务方案只保留地址和模型,不保存密钥。

Expand All @@ -199,7 +199,20 @@ npm run build
1. 在输入框中输入消息
2. 按回车或点击发送
3. AI会根据其性格和上下文回复
4. 在群聊中,AI之间也可能互相交流
4. 群聊每个用户回合只选择一位合适的 AI 回复,避免多角色并发消耗请求

### 请求预算

- 普通虚拟角色或 Agent 回复调用 1 次当前文本模型;不自动切换模型,也不做隐藏重试。
- 工具参数明确时由本地预执行;确实需要模型判断参数时,会显示“模型选择工具 → 执行 → 解释结果”的工具流程,并允许 2 次文本模型请求。
- 会话标题、长期记忆提取、朋友圈后台内容、知识竞答、成语游戏、配色和确定性数学均在本地完成,模型请求为 0;最多按需注入 8 条独立耐久事实,不再额外调用模型生成记忆摘要。
- 明确要求学者联网时使用 1 次 Tavily 检索 + 1 次文本模型综合;明确生成图片时只调用 1 次 MiniMax 图片接口,不调用文本模型。
- 朗读只在用户点击后调用,音频生成后会缓存,重复播放不再请求。
- Provider 失败会显示可见错误和手动“重试”,不会在后台继续花请求。
- 请求优化不会牺牲用户任务:当前输入完整保留,可使用最多 48 条近期消息 / 100,000 字符;输出上限按任务设为 1,600–6,144 tokens。
- `npm run prompt:bench` 会守住这些能力契约。当前专业角色提示词为了强化 Coder/Sensei 指令,估算 token 有意增加约 146(+11.5%);节省来自移除请求 fan-out 和每轮无关段落,而不是削弱回答。
- Agent 与虚拟角色都会流式更新同一条消息。固定 Nemotron 请求使用 OpenRouter `reasoning.effort: "none"` 并排除 reasoning;这是因为真实验收发现可选扩展推理可能耗尽回复预算,正常推理能力与函数调用仍保留。
- 上游回复若达到长度上限,已生成正文仍会保留并显示明确提示;数学工具的本地完整数值和符号形式始终优先,即使上游说明不可用也不会丢失。应用不会为此隐藏重试。

### 设置

Expand All @@ -220,7 +233,7 @@ npm run build
- 前端:React 19, Vite
- 样式:TailwindCSS
- 状态:Clean Architecture (ChatEngine + Context)
- AI:OpenRouter / DeepSeek / Perplexity / OpenAI 兼容 API
- AI:固定的 OpenRouter / OpenAI 兼容文本模型;Tavily 与 MiniMax 只用于用户明确触发的搜索和媒体操作
- 存储:LocalStorage(轻量设置)+ IndexedDB(聊天/文档主数据、媒体与背景资源)

### 项目结构
Expand Down
Loading