Commit Graph

726 Commits

Author SHA1 Message Date
Acbox Liu 82c8d65a7d feat: add interactive web terminal for bot containers (#232)
* feat(terminal): add interactive web terminal for bot containers

Add WebSocket-based terminal endpoint (/container/terminal/ws) that
provides a full PTY shell session inside the bot's MCP container.
Extend the gRPC proto with pty and resize fields, implement PTY exec
on the container side using creack/pty, and add an xterm.js-based
terminal component in the frontend bot detail page.

* chore: add /mcp in .gitignore

* feat(terminal): add multi-tab support, localStorage cache, and reactivity fixes

- Support unlimited terminal tabs with add/close/switch
- Cache terminal content to localStorage via SerializeAddon for session persistence
- Use shallowReactive for tab objects to ensure status updates trigger UI reactivity
- Fix listener leak by tracking and disposing onData/onResize on reconnect
- Fix bottom clipping by using inset offsets instead of padding
2026-03-11 21:49:05 +08:00
Acbox fe04c5722b release: v0.4.3 2026-03-11 20:57:52 +08:00
Acbox 11b7fad30d Merge branch 'v0.4' 2026-03-11 20:55:35 +08:00
Ran 5cfb26b571 fix(memory): replace manifest.json with scan-based index
Remove the manifest.json dependency for memory file tracking. Instead,
build an index by scanning daily memory files on demand. This eliminates
a class of bugs where the manifest could drift out of sync with actual
files, and simplifies the code by removing Manifest/ManifestEntry types
and all read/write/path helpers.

Made-with: Cursor
2026-03-11 20:37:43 +08:00
Ran c9308e4ca5 Merge branch 'v0.4' 2026-03-11 19:10:26 +08:00
BBQ a1e58792c9 fix(mcp): recover data from orphaned snapshots on container rebuild (#228)
When a container is deleted but its snapshot survives (dev image rebuild,
containerd metadata loss, manual ctr deletion), the reconciliation path
previously created a fresh container and unconditionally destroyed the
old snapshot via prepareSnapshot, causing complete data loss.

Manager.Start now detects orphaned snapshots before EnsureBot runs,
exports /data to a backup archive, and restores it into the new
container's snapshot before the task starts.
2026-03-11 19:06:47 +08:00
Acbox bb26d18757 fix(command): add missing command handler wiring and lint fixes
Wire SetCommandHandler into ChannelInboundProcessor so slash commands
are intercepted before reaching the LLM. Also apply lint fixes across
command package (strconv.Itoa, comment formatting, unused code removal)
and remove obsolete tool-call-browser.vue component.
2026-03-11 19:05:55 +08:00
Acbox ab82a72639 feat(command): extend slash command system with new commands and UX improvements
Add 9 new command groups (/model, /memory, /search, /browser, /usage,
/email, /heartbeat, /skill, /fs) and improve existing commands by hiding
internal UUIDs, resolving IDs to human-readable names in /settings, and
switching /schedule to name-based references.
2026-03-11 18:57:08 +08:00
Acbox 0ec211f3d0 feat(web): add specialized UI for all built-in tool calls
Replace generic JSON display with dedicated components for search_memory,
search_inbox, web_fetch, send, react, get_contacts, email tools, browser
tools, subagent tools, and use_skill.
2026-03-11 17:59:58 +08:00
Acbox 1da251885d feat(agent): add extensible tag interception system and inline reactions
Refactor the attachment tag extraction into a generic TagResolver/StreamTagExtractor
system that supports multiple custom tags. Implement <reactions> tag allowing the
agent to embed emoji reactions directly in text responses, dispatched as side-effects
through the channel reactor interface.

- Add TagResolver interface and StreamTagExtractor streaming state machine
- Refactor AttachmentsStreamExtractor as backward-compatible wrapper
- Add reactionsResolver and ReactionDeltaAction stream event
- Wire reaction dispatch in Go channel inbound processor
- Fix .gitignore to scope compiled binary patterns to repo root
2026-03-11 17:43:30 +08:00
Acbox 05ed5a7adf feat(web): open container file attachments in file manager
Container file attachments (from agent <attachments> blocks) now render
as clickable buttons that open the right-side file manager preview.
Also broadens AttachmentItem type to cover both persisted media assets
and streaming container-file references.
2026-03-11 17:25:24 +08:00
Acbox ec4181d53a fix(web): allow Monaco editor to fill full container height
Change scrollBeyondLastLine from false to true so the editor background
extends beyond the last line of content, filling the entire container.
2026-03-11 17:25:09 +08:00
Acbox 14aadae3ca fix(web): prevent file manager from overlapping Sheet close button
Wrap the FileManager inside a relative container in the chat Sheet so
its absolute inset-0 positioning is scoped to the remaining space below
the SheetHeader, instead of covering the entire SheetContent.
2026-03-11 17:24:55 +08:00
Acbox 70252124ba fix(filemanager): return raw file content in FSRead to avoid embedded line numbers
The FSRead handler was using client.ReadFile() which formats each line
with a line number prefix (for MCP AI tools). Switch to client.ReadRaw()
so the file viewer gets unmodified content — fixes duplicate line numbers
in the Monaco editor.
2026-03-11 17:24:39 +08:00
Acbox 2debfb496c fix(channel): resolve attachment filename and prevent duplicate sends
- Derive attachment name from path basename when not explicitly set in
  parseAttachmentDelta, fixing the "file.bin" fallback on Telegram.
- Infer correct AttachmentType (image/audio/video) from MIME in
  applyAssetToAttachment instead of keeping the generic "file" type.
- Remove outboundAttachments re-attachment to final messages since
  attachments are already delivered during streaming via
  StreamEventAttachment, preventing duplicate file sends on platforms.
2026-03-11 17:00:07 +08:00
Acbox 30653fbdbf fix(agent): reject send tool when targeting the same conversation
Pass replyTarget through the full pipeline (ChatRequest → gateway
identity → agent headers → MCP session) so the send tool can detect
when the destination matches the current conversation and return an
error guiding the agent to reply directly instead.
2026-03-11 16:59:42 +08:00
Acbox a2e5c4f893 feat(channel): add quoted message context injection for Discord and Feishu
Prepend replied-to message text and attachments into the user query so
the LLM can see what is being replied to, matching the existing Telegram
behavior. Also set is_reply_to_bot metadata for Feishu reply-to-bot
detection in group chats.
2026-03-11 16:57:33 +08:00
Fodesu 93ddf3c6d4 feat(web): add incremental rendering for model list to avoid lag with large providers(openrouter) 2026-03-11 03:49:16 +08:00
Ran 3ddb4f361c fix(migrations): sync email oauth tokens with init schema 2026-03-11 02:46:08 +08:00
BBQ 599bfb5ca8 fix(wecom): pass lint and typo checks
Fix WeCom adapter typos and strict Go lint findings (gosec/bodyclose/errcheck/revive) while keeping runtime behavior unchanged.
2026-03-11 02:14:00 +08:00
BBQ bc47655309 fix(wecom): align adapter with channel stream behavior
Migrate the imported WeCom adapter to current channel interfaces and stabilize stream delivery by preventing heartbeat/reply ACK timeout regressions and post-final overwrite updates.
2026-03-11 02:14:00 +08:00
Acbox ef7ed961a9 fix(web): resolve chat image freeze and dynamic import failures
- attachment-block: use loading=eager with explicit dimensions to prevent Chromium lazy-load intervention from freezing the page
- router: add error handler for chunk load failures to auto-reload
- vite: pre-bundle route page dependencies to improve initial load speed
2026-03-10 00:19:14 +08:00
Yiming Qi a5c364911e feat(email/oauth): implement OAuth2 support for Gmail provider (#212) 2026-03-09 23:37:43 +08:00
Ringo.Typowriter f8bfd7c107 docs(channels): add QQ channel configuration guide (#219) 2026-03-09 23:37:28 +08:00
Fodesu a2cb5939d7 fix(discord): rm reason in final message (#220) 2026-03-09 23:34:34 +08:00
Acbox Liu 23d49a1c7b feat: message abort and web socket support (#222)
* feat: message abort and web socket support

* fix(web): chat end

* fix: lint

* fix: lint
2026-03-09 23:27:50 +08:00
Menci 36d50738b5 fix(channel): consistent markdown rendering across all Telegram paths (#210)
- Extract ContainsMarkdown to shared channel package
- Auto-detect markdown in normalizeOutboundMessage and MCP send tool
- Apply markdown-to-HTML conversion during streaming deltas, not just
  on the final message
- Remove resolveTelegramParseMode which incorrectly returned Telegram's
  native "Markdown" mode instead of converting to HTML
- Fix all 14 Telegram send/edit paths for consistent parse mode handling
- Reset parseMode for plain-text error messages to avoid HTML corruption
2026-03-09 13:06:44 +08:00
Menci c741f2410b fix(conversation): correct token trimming edge cases (#207)
- Treat maxTokens=0 as "unconfigured/unlimited" instead of disabling
  trimming for any non-positive value (which masked exhausted budgets)
- Set historyBudget=1 when maxTokens>0 but overhead exceeds the limit,
  ensuring aggressive trimming instead of no trimming
- Estimate token cost for messages without usage data (len/4 fallback)
  so user/tool messages are not free-passed during budget accounting
2026-03-09 13:06:19 +08:00
Ran 90104c49dc Merge branch 'fix/utf8-safe-truncation-main' 2026-03-09 12:46:52 +08:00
BBQ 3739def43f fix(text): avoid breaking UTF-8 during truncation
Use rune-aware truncation for user-facing text and log previews so multibyte content is not corrupted in memory context, Telegram messages, or diagnostics.
2026-03-09 12:43:57 +08:00
Menci 8ce5243eb3 fix(mcp): use dumb-init as PID 1 to reap zombie processes
MCP containers spawning child processes (npx, uvx, etc.) left zombies
because the Go binary running as PID 1 does not reap orphaned children.
Add dumb-init as the entrypoint init process.
2026-03-09 12:41:23 +08:00
BBQ 1bb90c70f4 fix(text): avoid breaking UTF-8 during truncation
Use rune-aware truncation for user-facing text and log previews so multibyte content is not corrupted in memory context, Telegram messages, or diagnostics.
2026-03-09 12:39:51 +08:00
Menci 71545dd606 fix(memory): use rune-based truncation for UTF-8 safety
truncateSnippet sliced bytes directly, which could split multi-byte
UTF-8 characters. Switch to []rune so truncation always respects
character boundaries.
2026-03-09 12:38:49 +08:00
Menci 7d10c3e180 fix(memory): add XML boundary markers to memory context
Wrap memory context with <memory-context> tags so the LLM can clearly
distinguish recalled memories from other system instructions.
2026-03-09 12:38:12 +08:00
Menci 09cdb8c87f refactor(telegram): reduce code duplication and improve readability
- Extract parseTelegramTarget helper to consolidate duplicated @username
  vs numeric chat ID parsing from 6+ locations (builder functions,
  sendTelegramTextReturnMessage, sendTelegramAttachmentImpl)
- Extract Config.baseURL() to eliminate duplicate base URL resolution
  between apiEndpoint() and fileEndpoint()
- Refactor stream.go Push method: extract resetStreamState(),
  deliverFinalText(), and per-event-type sub-methods (pushDelta,
  pushFinal, pushToolCallStart, pushAttachment, pushPhaseEnd,
  pushError), reducing the 200-line switch-case to a clean dispatcher
- Use pushFinal's existing getBot() instead of duplicating parseConfig +
  getOrCreateBot
- Replace sort.SliceStable with slices.SortStableFunc + cmp.Compare
- Replace strings.Index + manual slicing with strings.Cut in
  decodeDataURLBytes, ResolveAttachment, and parseTelegramUserInput
2026-03-09 10:03:12 +08:00
Ringo.Typowriter 32f42a201b feat(cmd/agent): add asset opener support to feishu adapter (#206) 2026-03-07 20:15:17 +08:00
Acbox de68022d3c script: remove cn mirror notice 2026-03-07 19:26:08 +08:00
Acbox 0ca3d35fa0 script: update version management 2026-03-07 19:18:13 +08:00
Acbox 99114d2521 Merge branch 'v0.4' 2026-03-07 18:26:46 +08:00
Acbox c70d452238 release: v0.4.2 v0.4.2 2026-03-07 18:20:46 +08:00
Acbox e554186ca9 Merge branch 'v0.4' 2026-03-07 18:19:51 +08:00
BBQ dae772f729 fix(containerd): backport network fallback fixes to v0.4 (#205)
* fix(containerd): prevent silent network failures from leaving containers unreachable (#202)

* fix(containerd): prevent silent network failures from leaving containers unreachable

Container network setup failures were silently swallowed at multiple
points in the call chain, leaving containers in a "running but
unreachable" ghost state. This patch closes every silent-failure path:

- setupCNINetwork: return error when CNI yields no usable IP
- Manager.Start: roll back container when IP is empty instead of
  returning success
- ensureContainerAndTask: extract setupNetworkOrFail with 1 retry,
  propagate error to callers
- ReconcileContainers: stop reporting "healthy" when network setup fails
- recoverContainerIP: retry up to 2 times with backoff for transient
  CNI failures (IPAM lock contention, etc.)
- gRPC Pool: evict connections stuck in Connecting state for >30s

* fix(containerd): clean stale cni0 bridge on startup to prevent MAC error

After a Docker container restart, the cni0 bridge interface can linger
with a zeroed MAC (00:00:00:00:00:00) and DOWN state. The CNI bridge
plugin then fails with "could not set bridge's mac: invalid argument",
making all MCP containers unreachable.

Two-layer fix:
- Entrypoint: delete cni0 and flush IPAM state before starting containerd
- Go: detect bridge MAC errors in setupCNINetwork and auto-delete cni0
  before retrying, as defense-in-depth for runtime recovery

* fix(containerd): use exec.CommandContext to satisfy noctx linter

* fix(mcp): propagate network errors from replaceContainerSnapshot

Network setup failure after snapshot replace (rollback/commit) was
silently swallowed — the container would start but remain unreachable
via gRPC. Return the error so callers (CreateSnapshot, RollbackVersion,
etc.) surface the failure instead of reporting success.
2026-03-07 18:13:06 +08:00
BBQ abbb14c59f fix(containerd): prevent silent network failures from leaving containers unreachable (#202)
* fix(containerd): prevent silent network failures from leaving containers unreachable

Container network setup failures were silently swallowed at multiple
points in the call chain, leaving containers in a "running but
unreachable" ghost state. This patch closes every silent-failure path:

- setupCNINetwork: return error when CNI yields no usable IP
- Manager.Start: roll back container when IP is empty instead of
  returning success
- ensureContainerAndTask: extract setupNetworkOrFail with 1 retry,
  propagate error to callers
- ReconcileContainers: stop reporting "healthy" when network setup fails
- recoverContainerIP: retry up to 2 times with backoff for transient
  CNI failures (IPAM lock contention, etc.)
- gRPC Pool: evict connections stuck in Connecting state for >30s

* fix(containerd): clean stale cni0 bridge on startup to prevent MAC error

After a Docker container restart, the cni0 bridge interface can linger
with a zeroed MAC (00:00:00:00:00:00) and DOWN state. The CNI bridge
plugin then fails with "could not set bridge's mac: invalid argument",
making all MCP containers unreachable.

Two-layer fix:
- Entrypoint: delete cni0 and flush IPAM state before starting containerd
- Go: detect bridge MAC errors in setupCNINetwork and auto-delete cni0
  before retrying, as defense-in-depth for runtime recovery

* fix(containerd): use exec.CommandContext to satisfy noctx linter
2026-03-07 17:50:01 +08:00
Ringo.Typowriter e6a6dbe3f6 feat(channel): add QQ channel support and image message pipeline (#199)
* feat(channel): add qq adapter and outbound delivery

* feat(channel): ingest inbound qq messages

* feat(web): expose qq channel in management ui

* feat(channel): support qq attachment ingestion

* fix(mcp): fail read raw immediately for missing files

* fix(agent): parse inline image data into native image parts

* test(agent): align read_media tool tests with SDK options

* fix(channel): harden qq image delivery and reconnect loop

Avoid data URLs for qq channel images, reset reconnect backoff after healthy sessions, and fall back gracefully for malformed public image URLs.

* fix(channel): restore qq media delivery and target resolution

* fix(qq,mcp,agent): fix message/qq regressions and pass go lint

* fix(qq,agent): validate inline base64 and sync heartbeat seq

* fix(qq): validate remote voice mime for upload checks

* fix(qq): fall back intents and restore adapter wiring

* fix(qq): prevent final text leakage and dedupe persisted inbound query
2026-03-07 17:12:06 +08:00
Acbox 05d2240c16 docs: update memory and browser 2026-03-07 16:58:56 +08:00
Acbox 7f3f8ce2e5 release: v0.4.1 v0.4.1 2026-03-07 16:02:53 +08:00
Acbox 635d2847be fix(docker): run browser gateway with bun 2026-03-07 15:49:27 +08:00
Acbox 3b2b821a41 fix(web): css path 2026-03-07 15:48:34 +08:00
Acbox d4749ab322 release: v0.4.0 v0.4.0 2026-03-07 15:33:43 +08:00
Acbox 356e867e8d docs: update README and AGENTS 2026-03-07 15:23:59 +08:00