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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## v1.0.5-beta.4 (2026-05-25)
- Added session tape memory to persist and compress agent conversation history more reliably
- Synced CUA driver to v0.2.0 with diagnostic tools and improved app launching
- Telegram replies now render Markdown as HTML for proper formatting
- Improved agent steer execution responsiveness
- Updated AI SDK packages and refreshed bundled provider registry data
- 新增 Session Tape Memory,更可靠地持久化和压缩 Agent 会话历史
- 同步 CUA driver 至 v0.2.0,新增诊断工具并改进应用启动能力
- Telegram 回复现在将 Markdown 渲染为 HTML,格式展示更准确
- 提升 Agent steer 执行的响应性
- 更新 AI SDK 依赖并刷新内置 Provider registry 数据

## v1.0.5-beta.3 (2026-05-22)
- Added encrypted SQLite database storage to strengthen local data protection
- Improved onboarding guide handoff by refreshing state after setup transitions
Expand Down
3 changes: 2 additions & 1 deletion README.jp.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,12 +481,13 @@ deepchatへの貢献をご検討いただきありがとうございます!貢

## 🙏🏻 謝辞

このプロジェクトは、以下の素晴らしいライブラリの支援により構築されています
このプロジェクトは、以下の素晴らしいライブラリとプロジェクトの支援により構築されています

- [Vue](https://vuejs.org/)
- [Electron](https://www.electronjs.org/)
- [Electron-Vite](https://electron-vite.org/)
- [oxlint](https://github.com/oxc-project/oxc)
- [Bub](https://github.com/bubbuild/bub)。その tape model は DeepChat の session tape 設計に着想を与えました。基盤となる tape アーキテクチャに関心がある方は [tape.systems](https://tape.systems/) をご覧ください。

## 📃 ライセンス

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,13 @@ Thank you for considering contributing to deepchat! The contribution guide can b

## 🙏🏻 Thanks

This project is built with the help of these awesome libraries:
This project is built with the help of these awesome libraries and projects:

- [Vue](https://vuejs.org/)
- [Electron](https://www.electronjs.org/)
- [Electron-Vite](https://electron-vite.org/)
- [oxlint](https://github.com/oxc-project/oxc)
- [Bub](https://github.com/bubbuild/bub), whose tape model inspired DeepChat's session tape design. For the underlying tape architecture, visit [tape.systems](https://tape.systems/).

## 📃 License

Expand Down
3 changes: 2 additions & 1 deletion README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,12 +482,13 @@ DeepChat是一个活跃的开源社区项目,我们欢迎各种形式的贡献

## 🙏🏻 致谢

本项目的构建得益于这些优秀的开源库
本项目的构建得益于这些优秀的开源库和项目

- [Vue](https://vuejs.org/)
- [Electron](https://www.electronjs.org/)
- [Electron-Vite](https://electron-vite.org/)
- [oxlint](https://github.com/oxc-project/oxc)
- [Bub](https://github.com/bubbuild/bub),其 tape model 启发了 DeepChat 的 session tape 设计。如果你对底层 tape 架构感兴趣,推荐访问 [tape.systems](https://tape.systems/)。

## 📃 许可证

Expand Down
39 changes: 39 additions & 0 deletions docs/issues/agent-loop-input-exec-responsiveness/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Agent Loop Input And Exec Responsiveness Plan

## Runtime Input Flow

- Keep `chat.steerActiveTurn` as the active-turn entry point.
- Remove hidden steer injection from provider request construction.
- Store active steer input as a priority pending row while the current loop turn continues, so steer
never aborts the in-flight provider request.
- At the process loop boundary after tool calls have returned, yield before continuing to the next
provider request when a pending steer exists; the outer runtime then drains steer through
`processMessage()` as a normal user message.
- Drain pending steer rows before pending queue rows by claiming the row and passing its payload to
`processMessage()` with visible user-message persistence.
- Keep steer rows locked and non-editable, but show not-yet-entered steer rows in the pending input
rail.

## Exec Isolation

- Keep the existing background exec core manager as the utility host implementation.
- Replace the exported singleton with a main-process RPC proxy that starts an Electron
`utilityProcess` from the existing main bundle using a dedicated host flag.
- Route `start`, `waitForCompletionOrYield`, `poll`, `log`, `write`, `kill`, `clear`, `remove`,
`cleanupConversation`, and `shutdown` through JSON-serializable messages.
- Track started sessions in the proxy so an unexpected utility exit can return diagnostic error
snapshots for affected sessions.

## Compatibility

- `PendingSessionInputMode` remains `queue | steer`.
- Existing `sessions.convertPendingInputToSteer` route remains available for stored and older UI
flows.
- `AgentBashHandler` keeps its current public return shape for completed and yielded commands.

## Validation

- Update agent runtime/session integration tests for visible steer turns.
- Update pending input rail tests to assert pending steer rows render as locked items.
- Preserve existing background exec core tests and add coverage around the utility proxy behavior
where practical.
30 changes: 30 additions & 0 deletions docs/issues/agent-loop-input-exec-responsiveness/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Agent Loop Input And Exec Responsiveness

## User Stories

- As a user steering an active agent turn, I want my steering input to appear as a normal user
message so the conversation transcript matches what the agent saw.
- As a user running long shell commands, I want `exec` to yield quickly and keep DeepChat's main
process responsive while the command continues in a managed background session.

## Acceptance Criteria

- Active steer does not interrupt the current provider request; it records a priority steer input,
lets the current loop iteration finish including tool results, then yields before the next
provider loop so the steer payload is inserted as a normal visible user turn.
- Pending rows with `mode: "steer"` remain readable for compatibility, but drain before ordinary
queued rows as visible user turns instead of hidden request injections.
- Pending input UI shows not-yet-entered steer rows in the waiting lane as locked items, and keeps
ordinary queued follow-ups editable.
- Foreground `exec` returns a normal result if it finishes inside `yieldMs`; otherwise it returns a
running `sessionId`.
- Shell process spawning, output decoding, output offload, timeout, and process-tree termination
run in an Electron utility process rather than the main event loop.
- If the utility process exits unexpectedly, affected sessions surface an error snapshot instead of
blocking the main process.

## Non-Goals

- Do not change the public `exec` tool schema or permission semantics.
- Do not add renderer settings for exec isolation.
- Do not refactor the full agent runtime or provider loop.
12 changes: 12 additions & 0 deletions docs/issues/agent-loop-input-exec-responsiveness/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Tasks

- [x] Add SDD artifacts for the combined responsiveness issue.
- [x] Queue active steer until the current loop iteration finishes without aborting the stream.
- [x] Yield the agent loop after completed tool calls when a pending steer should enter next.
- [x] Convert pending steer drain into visible user turns.
- [x] Remove hidden steer request injection.
- [x] Show not-yet-entered steer rows in the renderer pending rail.
- [x] Add utility-process RPC host for background exec.
- [x] Replace the production background exec singleton with a proxy.
- [x] Update and run targeted tests.
- [x] Run repository formatting, i18n, lint, and typecheck checks.
38 changes: 38 additions & 0 deletions docs/issues/cua-driver-v0-2-0-sync/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Plan

## Source Review

- Compare upstream `trycua/cua` tags `cua-driver-v0.1.5` and
`cua-driver-v0.2.0`.
- Apply the Swift driver delta with a three-way merge against DeepChat's
maintained fork.
- Keep upstream Rust driver changes out of this sync.

## Implementation

- Merge upstream Swift runtime changes into
`plugins/cua/vendor/cua-driver/source`.
- Adapt new upstream TCC, doctor, and MCP daemon-proxy text and commands to
`DeepChat Computer Use.app` and `com.wefonk.deepchat.computeruse`.
- Preserve DeepChat-only CLI behavior: `deepchat-permission-probe`, nonblocking
MCP startup, and DeepChat-managed `update`.
- Update `plugins/cua/vendor/cua-driver/upstream.json` to `cua-driver-v0.2.0`.
- Leave packaged skills unchanged unless validation shows upstream skill content
changed in the Swift release.

## Validation

- Run `swift build --package-path plugins/cua/vendor/cua-driver/source --product cua-driver`.
- Run `pnpm run format`.
- Run `pnpm run i18n`.
- Run `pnpm run lint`.
- Run `git diff --check`.
- Run `pnpm run plugin:cua:build:mac:arm64`.
- Run `pnpm run plugin:validate -- --name cua --platform darwin --arch arm64`.

## Risk

The vendored driver is a local fork with DeepChat-specific TCC and packaging
behavior. A direct replacement with upstream source would risk regressing the
helper identity, permission flow, and plugin-managed update path, so the sync is
kept as an explicit fork merge.
41 changes: 41 additions & 0 deletions docs/issues/cua-driver-v0-2-0-sync/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# CUA Driver v0.2.0 Sync

## Problem

The bundled DeepChat Computer Use helper is based on upstream
`cua-driver-v0.1.5`. Upstream Swift CUA driver `cua-driver-v0.2.0` contains
macOS reliability fixes for focus suppression, screenshot capture fallback,
hidden app handling, side-effect detection, and MCP daemon proxying.

## User Story

As a DeepChat user using the bundled CUA plugin, I need the macOS helper to
include current upstream Swift driver fixes while continuing to use DeepChat's
helper app, TCC permissions, MCP registration, and plugin packaging.

## Acceptance Criteria

- Vendored upstream metadata records `cua-driver-v0.2.0` and commit
`d3f3b9325f49aa5302c15fb03f6b66bd1e688e27`.
- The local fork includes the upstream Swift driver runtime improvements from
`v0.1.5` through `v0.2.0`.
- DeepChat-specific behavior remains intact: `DeepChat Computer Use.app`,
bundle id `com.wefonk.deepchat.computeruse`, `deepchat-permission-probe`,
DeepChat-managed updates, and MCP-first plugin skills.
- The Rust `cua-driver-rs` runtime is not introduced in this sync.
- Validation covers Swift build, formatting, i18n, lint, diff checks, CUA
runtime build, and plugin validation where practical.

## Non-goals

- No migration to `cua-driver-rs`.
- No changes to the CUA plugin manifest, settings UI, MCP server id, or tool
policy.
- No adoption of upstream standalone installer behavior for DeepChat updates.

## Constraints

- Preserve DeepChat's local helper app identity for TCC attribution.
- Keep packaged `plugins/cua/skills/cua-driver` guidance MCP-first.
- Treat upstream standalone scripts as reference material unless required by
the bundled helper build.
13 changes: 13 additions & 0 deletions docs/issues/cua-driver-v0-2-0-sync/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Tasks

- [x] Identify latest upstream Swift CUA driver release.
- [x] Confirm Rust `cua-driver-rs` remains out of scope.
- [x] Compare `cua-driver-v0.1.5` to `cua-driver-v0.2.0`.
- [x] Merge upstream Swift runtime changes into the DeepChat fork.
- [x] Preserve DeepChat helper app identity, permission probe, update policy,
and MCP-first behavior.
- [x] Update vendored upstream metadata.
- [x] Run Swift build validation.
- [x] Run formatting, i18n, lint, and diff checks.
- [x] Build the CUA plugin runtime.
- [x] Validate the CUA plugin package.
21 changes: 21 additions & 0 deletions docs/issues/telegram-message-markdown-render/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Telegram Message Markdown Render Plan

## Approach

- Add `src/main/presenter/remoteControlPresenter/telegram/telegramMarkdown.ts` exposing `convertMarkdownToTelegramHtml(text: string): string`, mirroring the Feishu-side `feishuMarkdown.ts` module location and shape.
- The converter:
- Escapes `&`, `<`, `>` first to make raw text safe for `parse_mode: 'HTML'`.
- Converts common GFM pipe tables into fenced fixed-width text before code-block extraction.
- Handles fenced code blocks (` ``` `) by emitting `<pre><code class="language-...">...</code></pre>` and protecting the body from further Markdown processing.
- Handles inline code (` `…` `), bold (`**`/`__`), italic (`*`/`_`), strikethrough (`~~`), links, headings (`#…######`), unordered/ordered lists, and blockquotes (`>`).
- Auto-closes a dangling fenced block when called on a chunk that ends mid-block, so each chunk produces valid HTML for Telegram.
- Extend `TelegramClient.sendMessage`, `editMessageText`, and `sendPhoto` with an optional `parseMode` ('HTML' | 'MarkdownV2'). Default remains undefined for backward compatibility.
- In `TelegramPoller`:
- Convert chunk text via `convertMarkdownToTelegramHtml` before `sendMessage`/`editMessageText` calls in `syncDeliverySegment`, `sendChunkedMessage`, `dispatchOutboundActions`, and `editMessageText`. Pass `parseMode: 'HTML'`.
- Apply conversion to the interaction prompt text as well so callback prompts render formatting consistently.
- Retry the original plain-text chunk when Telegram returns a 400 entity-parse error for converted HTML.

## Validation

- Run `pnpm test test/main/presenter/remoteControlPresenter/telegramClient.test.ts` (extended) and a new `telegramMarkdown.test.ts` covering core conversion rules, table fallback, and chunk-boundary behavior.
- Run `pnpm run typecheck:node` to confirm no signature break in callers (Poller, Adapter).
27 changes: 27 additions & 0 deletions docs/issues/telegram-message-markdown-render/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Telegram Message Markdown Render

## User Story

When DeepChat's Telegram remote control bot delivers AI replies, command output, and other generated text, users should see properly rendered formatting (bold, italic, inline code, fenced code blocks, links, lists, blockquotes) instead of raw Markdown symbols (`**bold**`, `# heading`, ` ``` `).

## Acceptance Criteria

- `telegramClient.sendMessage` and `telegramClient.editMessageText` call the Telegram Bot API with `parse_mode: 'HTML'` when the outbound text contains formatted content.
- AI answer / process delivery segments routed through `TelegramPoller.syncDeliverySegment` and outbound actions dispatched via `dispatchOutboundActions` go through a Markdown → Telegram-HTML converter that handles bold, italic, strikethrough, inline code, fenced code blocks, headings, links, ordered/unordered lists, blockquotes, and horizontal rules.
- Common GFM pipe tables render as fixed-width preformatted text because Telegram does not support native table entities.
- Plain text (system replies, error messages, command echoes) is HTML-escaped and accepted by Telegram without parse-mode errors.
- Chunked streaming (4096 char limit) keeps each chunk independently renderable — partial Markdown left at a chunk boundary (e.g. an unclosed code fence) renders as text or a safely balanced block instead of breaking the Telegram parse.
- If Telegram rejects converted HTML with an entity-parse error, DeepChat retries the same outbound chunk as plain text.
- Existing Telegram client tests pass; a new test covers the converter and parse-mode wiring.

## Constraints

- Keep behavior parity with the existing Feishu pattern: a dedicated `telegramMarkdown.ts` module living next to `telegramClient.ts`, surfaced through a single conversion entry point.
- No new runtime dependency; the conversion is implemented locally to keep the bundle lean and stay within Telegram's HTML subset.
- Do not change `chunkTelegramText` semantics or the streaming delivery state shape.

## Non-Goals

- No switch to Telegram MarkdownV2.
- No changes to attachment handling, photo captions beyond passing `parse_mode` when a caption is sent.
- No richer Telegram-only features (custom emojis, spoilers, MessageEntities).
9 changes: 9 additions & 0 deletions docs/issues/telegram-message-markdown-render/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Telegram Message Markdown Render Tasks

- [x] Capture the reproduction from issue #1665 and confirm `sendMessage`/`editMessageText` ship raw Markdown without `parse_mode`.
- [x] Draft SDD spec, plan, tasks documents.
- [x] Implement `telegram/telegramMarkdown.ts` with `convertMarkdownToTelegramHtml`.
- [x] Thread an optional `parseMode` through `TelegramClient.sendMessage`, `editMessageText`, and `sendPhoto`.
- [x] Update `TelegramPoller` to apply the converter and pass `parse_mode: 'HTML'` on all generated text paths.
- [x] Add focused tests for the converter, table fallback, parse-mode wiring, and plain-text retry.
- [ ] Run `pnpm run format`, `pnpm run lint`, `pnpm run typecheck:node`, and the focused test suites.
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "DeepChat",
"version": "1.0.5-beta.3",
"version": "1.0.5-beta.4",
"description": "DeepChat,一个简单易用的 Agent 客户端",
"main": "./out/main/index.js",
"author": "ThinkInAIXYZ",
Expand Down Expand Up @@ -75,13 +75,13 @@
},
"dependencies": {
"@agentclientprotocol/sdk": "^0.16.1",
"@ai-sdk/amazon-bedrock": "^4.0.107",
"@ai-sdk/anthropic": "^3.0.78",
"@ai-sdk/azure": "^3.0.65",
"@ai-sdk/google": "^3.0.75",
"@ai-sdk/google-vertex": "^4.0.131",
"@ai-sdk/openai": "^3.0.64",
"@ai-sdk/openai-compatible": "^2.0.47",
"@ai-sdk/amazon-bedrock": "^4.0.108",
"@ai-sdk/anthropic": "^3.0.79",
"@ai-sdk/azure": "^3.0.66",
"@ai-sdk/google": "^3.0.79",
"@ai-sdk/google-vertex": "^4.0.137",
"@ai-sdk/openai": "^3.0.65",
"@ai-sdk/openai-compatible": "^2.0.48",
"@ai-sdk/provider": "^3.0.10",
"@aws-sdk/client-bedrock": "^3.1049.0",
"@duckdb/node-api": "1.5.3-r.1",
Expand All @@ -91,7 +91,7 @@
"@jxa/run": "^1.4.0",
"@larksuiteoapi/node-sdk": "^1.64.0",
"@modelcontextprotocol/sdk": "^1.29.0",
"ai": "^6.0.185",
"ai": "^6.0.191",
"axios": "^1.16.1",
"better-sqlite3-multiple-ciphers": "12.9.0",
"cheerio": "^1.2.0",
Expand Down
2 changes: 1 addition & 1 deletion plugins/cua/vendor/cua-driver/source/.bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.1.5
current_version = 0.2.0
commit = True
tag = True
tag_name = cua-driver-v{new_version}
Expand Down
4 changes: 4 additions & 0 deletions plugins/cua/vendor/cua-driver/source/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@ let package = Package(
name: "ZoomMathTests",
dependencies: ["CuaDriverCore"]
),
.testTarget(
name: "FocusStealPreventerTests",
dependencies: ["CuaDriverCore"]
),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Darwin
import Foundation

/// Shared "is this binary running from inside an installed DeepChat Computer Use.app
/// bundle?" heuristic used by both `ServeCommand` (for the
/// auto-relaunch-via-`open` path) and `MCPCommand` (for the daemon proxy
/// path). Resolves `Bundle.main.executablePath` (falling back to
/// `CommandLine.arguments.first`) through any symlinks via `realpath` and
/// checks whether the resolved path lives inside some
/// `DeepChat Computer Use.app/Contents/MacOS/` directory.
///
/// That's the "installed via install-local.sh / install.sh" shape —
/// `/usr/local/bin/cua-driver` is a symlink into
/// `/Applications/DeepChat Computer Use.app`, and `realpath` walks into the
/// bundle. Returns `false` for `swift run` /
/// raw `.build/<config>/cua-driver` dev invocations, which have no installed
/// bundle to relaunch into.
///
/// Subcommands may wrap this with additional gating (env vars, flags,
/// parent-pid checks, etc.) when their relaunch heuristics diverge.
func isExecutableInsideCuaDriverApp() -> Bool {
// Prefer Foundation's executablePath (stable, absolute).
// Fall back to argv[0] when unset, which realpath() still
// resolves via $PATH lookup at the shell level — good enough
// for the cases we care about.
let candidate = Bundle.main.executablePath
?? CommandLine.arguments.first
?? ""
guard !candidate.isEmpty else { return false }

var buffer = [CChar](repeating: 0, count: Int(PATH_MAX))
guard realpath(candidate, &buffer) != nil else { return false }
let resolved = String(cString: buffer)
return resolved.contains("/DeepChat Computer Use.app/Contents/MacOS/")
}
Loading
Loading