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
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Bumping the version requires editing `releaseVersionName` and `defaultConfig.ver
- `ANTHROPIC_MESSAGES` → `AnthropicMessagesProtocol`
- `LOCAL_GGUF` → `LocalGgufProtocol`

Messages flow via `cn.lineai.ai.message.*` (`SystemModelMessage`, `UserModelMessage`, `AssistantModelMessage`, `ToolModelMessage`). `ModelClient` is the high-level entry point used by `MainCoordinator`. Tool-call text inside a stream is parsed by `ToolCallTextParser`; reasoning by `ThinkTagParser`. System prompts are assembled by `cn.lineai.ai.prompt.SystemPromptProvider` from `app/src/main/assets/prompts/*.txt` templates (`system-prompt-template.txt`, tone variants, `context-compaction-template.txt`, `memory-extraction-template.txt`, `skill-extraction-template.txt`, `work-directory-template.txt`, `learning-context-template.txt`, `model-identity-template.txt`) — modify templates there, not by hardcoding in Java. `SystemPromptProvider.build(..., ModelConfig model)` renders the model identity block (modelId / name / provider / protocol) from the currently selected model and injects it as `{{MODEL_IDENTITY}}` so the assistant can answer capability questions against the actual model id.
Messages flow via `cn.lineai.ai.message.*` (`SystemModelMessage`, `UserModelMessage`, `AssistantModelMessage`, `ToolModelMessage`). `ModelClient` is the high-level entry point used by `MainCoordinator`. Tool-call text inside a stream is parsed by `ToolCallTextParser`; reasoning by `ThinkTagParser`. System prompts are assembled by `cn.lineai.ai.prompt.SystemPromptProvider` from `app/src/main/assets/prompts/*.txt` templates (`system-prompt-template.txt`, tone variants, `context-compaction-template.txt`, `work-directory-template.txt`, `learning-context-template.txt`, `model-identity-template.txt`) — modify templates there, not by hardcoding in Java. `SystemPromptProvider.build(..., ModelConfig model)` renders the model identity block (modelId / name / provider / protocol) from the currently selected model and injects it as `{{MODEL_IDENTITY}}` so the assistant can answer capability questions against the actual model id.

### Model config & context size
`ModelConfig` (`:core-model`) carries `contextSize` (tokens) as a first-class field, parsed by `ContextSizeParser` from user input like `128K`, `1m`, `128000`. UI uses a plain text field (`R.string.model_field_context_size`); the legacy `{id}[{size}]` suffix in `modelId` is still tolerated for old DB rows via `ModelContextParser.parse(ModelConfig)` / `apiModelId(ModelConfig)`. Protocols must call `apiModelId(ModelConfig)` rather than reading `modelId` directly, so the `[size]` suffix is stripped when needed. The `model_configs` SQLite table has a `context_size` column; `ModelRepository.ensureModelConfigColumns` auto-`ALTER`s old databases.
Expand All @@ -68,7 +68,7 @@ Messages flow via `cn.lineai.ai.message.*` (`SystemModelMessage`, `UserModelMess
- Compaction calls are dedicated model requests using the codex-style handoff-summary template (`assets/prompts/context-compaction-template.txt` + `context-compaction-summary-prefix.txt`), with retry + backoff (`MAX_COMPACT_RETRIES`) and usage recorded into `TokenUsageTracker` so the post-compact context becomes the new baseline.
- Transcript is built segment-by-segment (`List<String>`, each ≤ `TRANSCRIPT_SEGMENT_MAX_CHARS = 256KB`) to avoid single-`StringBuilder` OOM. **Do not reintroduce per-message or total-length truncation** — earlier `MAX_MESSAGE_CONTENT_CHARS` / `MAX_TRANSCRIPT_CHARS` limits were removed as harmful. `ContextCompactionController.startSoftContextCompaction` / `finishSoftContextCompaction` drive the soft flow; `ChatInteractionController` checks the soft trigger before each request when the hard trigger has not fired and the switch is enabled. `OutOfMemoryError` is caught in both the service and the controller as a last-resort fallback. `TokenUsageTracker` is reset on conversation switch (`ContextCompactionController.onConversationChanged`).
- `AndroidManifest.xml` sets `android:largeHeap="true"` to support large transcripts.
- `MemoryExtractionService` and `LearningContextRepository` feed durable knowledge back into the system prompt.
- Durable knowledge (memories saved via the `memory_update` tool or the memory management screen, plus conversation/skill indexes) is reinjected into the system prompt by `LearningContextRepository` / `LearningContextService` when Learning Mode is enabled.

### Image attachments in chat
`ComposerView` exposes a dedicated image button (right of the attach `+`) that opens the system image picker (`ACTION_OPEN_DOCUMENT`, `image/*`). Selected images are compressed (long edge ≤ 1568px, JPEG q=85, >3.5MB further downgraded) and base64-encoded. Send path goes through `ChatInteractionController.sendMessageWithImage` → `ImageInputPayload.rawInputJson(prompt, mimeType, base64)` → `ChatMessage.responseInputItemJson`. Protocols detect `ImageInputPayload.KIND` in `message.getRawInputJson()` and emit the correct shape per provider (OpenAI `image_url`, Anthropic `image.source.base64`, Codex `input_image`). No protocol changes are needed when adding new image entry points — reuse `ImageInputPayload`.
Expand Down Expand Up @@ -144,7 +144,7 @@ The chat list renders Markdown through `:markdown` (`cn.lineai.ui.markdown.*`),
- 所有用户可见字符串必须使用 R.string.* 资源,禁止在 Java 代码中硬编码中文或英文字符串
- 英文资源在 values/strings.xml,中文资源在 values-zh/strings.xml,俄文资源在 values-ru/strings.xml
- 警惕 \uXXXX 转义的中文字符,这些绕过 grep 搜索但不违反规则
- AI 提示词中的中文关键词(如 MemoryExtractionService 的记忆匹配词、SkillFileManager 的 Skill 模板)不属于用户可见字符串,不需要 i18n
- AI 提示词中的中文关键词(如 SkillFileManager 的 Skill 模板)不属于用户可见字符串,不需要 i18n
- Repository 层通过 ResourceProvider.getString() 获取字符串资源,不直接使用 Context
- Agent 提示词 fallback 通过 Context.getString() 读取资源,无 Context 时回退到硬编码英文

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ The application id is `cn.lineai` and the project is a multi-module Gradle proje
- Streaming chat with **multiple model protocols** in the same UI: OpenAI-compatible HTTP APIs, Anthropic Messages, OpenAI Codex Responses, and a local GGUF runtime.
- Reasoning blocks (`<think>…</think>`) are extracted and rendered separately from the final answer.
- Tool-call text inside a stream is parsed and dispatched by `ToolCallTextParser`; everything the model asks to do is shown to you before it runs.
- System prompts are assembled from `feature-model/src/main/assets/prompts/*.txt` — tone variants (chat / coding), context-compaction, memory-extraction, skill-extraction, work-directory, learning-context, and model-identity templates. You can override the tone, the work directory, the identity block, and the prompt template from settings.
- Long conversations are summarised in the background by `ContextCompactionService` with **dynamic compaction** (50% soft trigger + 80% hard trigger) using the active model itself; durable knowledge is extracted by `MemoryExtractionService` and reinjected next session by `LearningContextRepository`.
- System prompts are assembled from `feature-model/src/main/assets/prompts/*.txt` — tone variants (chat / coding), context-compaction, work-directory, learning-context, and model-identity templates. You can override the tone, the work directory, the identity block, and the prompt template from settings.
- Long conversations are summarised in the background by `ContextCompactionService` with **dynamic compaction** (50% soft trigger + 80% hard trigger) using the active model itself; durable knowledge saved via the `memory_update` tool or the memory screen is reinjected next session by `LearningContextRepository`.
- **Image attachments** — pick an image from the system picker; it is compressed, base64-encoded, and sent in the protocol-specific format (OpenAI `image_url`, Anthropic `image.source.base64`, Codex `input_image`).

### Tool execution
Expand Down
4 changes: 2 additions & 2 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ LineCode 不是一个轻量聊天客户端,它是一个**完整的编程工作
- 同一个聊天界面下支持**多种模型协议**:OpenAI 兼容 HTTP API、Anthropic Messages、OpenAI Codex Responses、本地 GGUF 推理。
- 推理块(`<think>…</think>`)会被 `ThinkTagParser` 单独抽出来,和最终回答分块渲染。
- 流中的工具调用文本由 `ToolCallTextParser` 解析并派发;模型请求做的每件事,在真正执行前都会先展示给你看。
- 系统提示由 `feature-model/src/main/assets/prompts/*.txt` 中的模板拼装:语气(聊天 / 编程)变体、上下文压缩、记忆抽取、技能抽取、工作目录、学习上下文、模型身份。你可以在设置里覆盖语气、工作目录、身份块、提示模板。
- 长对话由 `ContextCompactionService` 后台用**当前模型本身**做**动态压缩**(50% 软触发 + 80% 硬触发);`MemoryExtractionService` 抽取长期知识,`LearningContextRepository` 在下一次会话中喂回上下文。
- 系统提示由 `feature-model/src/main/assets/prompts/*.txt` 中的模板拼装:语气(聊天 / 编程)变体、上下文压缩、工作目录、学习上下文、模型身份。你可以在设置里覆盖语气、工作目录、身份块、提示模板。
- 长对话由 `ContextCompactionService` 后台用**当前模型本身**做**动态压缩**(50% 软触发 + 80% 硬触发);通过 `memory_update` 工具或记忆管理界面保存的长期知识,由 `LearningContextRepository` 在下一次会话中喂回上下文。
- **图片附件** - 在输入框右侧点图片按钮打开系统选择器;选中的图片经压缩后 base64 编码,按协议格式输出(OpenAI `image_url`、Anthropic `image.source.base64`、Codex `input_image`)。

### 工具执行
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
alias(libs.plugins.android.application)
}

val releaseVersionName = "1.2.6-rc.2"
val releaseVersionName = "1.2.6"
val releaseApkName = "LineCode Pro $releaseVersionName.APK"
val releaseIdsigName = "$releaseApkName.idsig"
val releaseSigningProperties = Properties()
Expand Down Expand Up @@ -103,7 +103,7 @@ android {
applicationId = "cn.lineai"
minSdk = 26
targetSdk = 37
versionCode = 30
versionCode = 31
versionName = releaseVersionName
}

Expand Down
Loading
Loading