69 Commits
Author SHA1 Message Date
zhayujieandcowagent 396d226180 fix: run chat skill commands on the current agent's own skills
Co-authored-by: cowagent <cow@cowagent.ai>
2026-10-14 20:10:37 +08:00
zhayujieandcowagent 395892b7ff feat: fall back to the default hub for unknown skills and keep display descriptions
- A skill the configured registry does not know is looked up on the default
  hub, without the registry's key
- Installers may record a display_description shown in place of SKILL.md's;
  the agent still reads SKILL.md
- New skills are stamped with installed_at

Co-authored-by: cowagent <cow@cowagent.ai>
2026-10-14 18:27:20 +08:00
zhayujieandcowagent f72fae3371 feat: let a configured skill registry serve installs by name
Add skill_hub_url and skill_hub_api_key. When set, bare-name installs,
skill search and the remote listing go to that registry, with the key
sent as a bearer token to it only; provider installs and the default
setup are unchanged. Display fields returned by the registry, or passed
as install meta from the console, are recorded in skills_config.json.
Sensitive values are masked when remote config is logged.

Co-authored-by: cowagent <cow@cowagent.ai>
2026-10-14 16:07:25 +08:00
zhayujieandcowagent 93d43e6b4b fix: apply context budget changes to live agents instead of clearing sessions
Saving agent_max_context_tokens / agent_max_steps used to evict every
cached agent, so the next turn rebuilt from the short restore window and
lost the working context and prompt cache. Update the limits in place
and let the regular trim enforce a smaller budget. /config set now
applies them immediately too.

Co-authored-by: cowagent <cow@cowagent.ai>
2026-10-10 16:04:18 +08:00
fly0sheep cb1a400580 fix: give hard-split line pieces a distinct chunk id
A line longer than the chunk budget is hard-split into several pieces that
all share (start_line, end_line). The chunk id is derived from the line range
alone, so every piece of that line gets the same id and
save_chunks_batch's "ON CONFLICT(id) DO UPDATE" keeps only the last one —
the rest silently leave the index. Measured with a 950-char line and a
200-char budget: 5 pieces stored as 1 row, 800 of 950 chars dropped.

Carry a `part` ordinal out of the chunker so the pieces get distinct ids.
part == 0 is used for every ordinary chunk, so its id is unchanged and no
needless re-sync is triggered.

CHUNKER_VERSION 2 -> 3: the boundaries are unchanged, but an index that
already dropped the colliding pieces must still be flagged stale. Chunked
files are only re-split when their content hash changes, so a chunker-only
change would otherwise never revisit them and the loss would stay forever.
The /memory status hint is reworded to stay accurate for a bump that does
not alter how text is split.
2026-10-07 18:05:09 +08:00
zhayujieandcowagent 677b01319e fix: trim batch-6 comments and tests, clean up kf voice segments
Co-authored-by: cowagent <cow@cowagent.ai>
2026-10-03 23:31:54 +08:00
zhayujie 1f4f91142a Merge pull request #3460 from aniruddhaadak80/fix/cow-cli-reject-skill-path-traversal
fix(cow_cli): reject traversal skill names in the chat uninstall path
2026-10-03 19:05:41 +08:00
HnBigVolibear 81f3bc5391 feat(cow_cli): add display loaded MCP servers (ready/total) in /status and cow status commands; and update status command description examples in 3 documentation locations 2026-10-02 22:31:26 +08:00
Aniruddha Adak 4cf42868a8 fix(cow_cli): reject traversal skill names in the chat uninstall path 2026-10-02 17:14:43 +05:30
zhayujie 44e2c0f898 Merge pull request #3349 from c020627/fix-web-logs-tail-bounded-read
refactor(logs): share one bounded tail reader across the log views
2026-10-01 18:44:47 +08:00
zhayujieandcowagent ca4ec00904 fix: keep the test suite out of the real home directory
- conftest points HOME at a temp dir before any test module is imported,
  so ~/.cow/.env and backup restore targets never touch real data
- merge common/docx_text.py and common/spreadsheet_text.py into common/office_text.py
- drop the repeated utf-8-sig comments

Co-authored-by: cowagent <cow@cowagent.ai>
2026-10-01 15:28:33 +08:00
c020627 e88c5a734a refactor(logs): share one bounded tail reader across the log views
Three places replayed a log tail with `readlines()` and then sliced the result:
the web logs view (last 200 lines), the chat `cow logs` command (up to 50) and
`cow logs` on the CLI (50). `run.log` is appended to for as long as CowAgent
runs and is never rotated, so all three read every line ever written to display
a handful of them -- and the chat command does it inside the bot process, where
a long-lived instance gets OOM-killed by its own help command.

Add `common.utils.tail_lines`, which walks the file backwards in 8 KiB blocks
and stops once enough lines have been collected, and use it from all three:

- `channel/web/api/logs.py` for the initial replay,
- `plugins/cow_cli/cow_cli.py` for `cow logs` in chat,
- `cli/commands/process.py::_print_last_lines`, imported on use like the CLI's
  other project imports (the CLI ships as its own package and only puts the
  project root on `sys.path` when it needs something from it).

Measured on a 20000-line / 1.0 MB run.log: the three views went from reading
100% of the file to 1.6%, 0.8% and 0.8%, with no `readlines()` call left.

Also drops the two pre-existing pyflakes findings in `cli/commands/process.py`,
since the CI lint gate requires the files a PR touches to be F-clean: the dead
`flag` assignment in `_kill_pid` (the `/F` flag is appended directly) and the
`f` prefix on a string with no placeholders.
2026-10-01 15:17:30 +08:00
zhayujieandcowagent 44e84d1ede fix: keep /skill hub commands in renamed builds, hide the hub URL there
Co-authored-by: cowagent <cow@cowagent.ai>
2026-09-29 19:36:24 +08:00
zhayujieandcowagent 9340abe57c refactor: share one atomic file write helper across stores
Replace the per-module sibling-file-and-rename copies with
common/atomic_write.py, which uses a unique dot-prefixed temp name,
fsyncs, and keeps the target's permissions.

Co-authored-by: cowagent <cow@cowagent.ai>
2026-09-29 14:51:02 +08:00
zhayujie 93c004542c Merge pull request #3281 from c020627/fix-cow-cli-config-atomic-write
# Conflicts:
#	plugins/cow_cli/cow_cli.py
2026-09-29 14:51:02 +08:00
zhayujieandcowagent 1f44b0507b feat: configurable app name and skill hub toggle for commands, align suggestion cards
Co-authored-by: cowagent <cow@cowagent.ai>
2026-09-29 13:06:23 +08:00
c020627 63fd00bc24 fix(cow_cli): write config files through a sibling file
The four in-place writers in this plugin truncated a live config file before
writing it, so a crash, a kill, or a full disk partway through left it
half-written. For config.json that is fatal on the next start: load_config
re-raises on a parse error unless the packaged desktop build is running, and
the desktop-only recovery path exists precisely because of "a bad write
during a previous update". For skills_config.json, uninstall swallowed the
exception and still reported success while every record was gone.

Serialise into a dot-prefixed sibling and os.replace it into place, matching
what agent/skills/manager.py and channel/web/core/_common.py already do for
these same two files.
2026-09-28 19:37:29 +08:00
zhayujieandcowagent a9dfc54c4e fix: tolerate UTF-8 BOM in config.json and stop pre-login 401 polling
Read config.json with utf-8-sig so a BOM (e.g. saved by Windows Notepad)
no longer breaks config/model updates from the web console; write-back
stays plain utf-8 to strip the BOM on next save.

Gate the /poll and /api/scheduler/runs background pollers behind auth so
a password-protected console no longer spams "401 Unauthorized" before
the user logs in.

Co-authored-by: cowagent <cow@cowagent.ai>
2026-09-11 10:41:18 +08:00
zhayujieandcowagent 87706beee7 refactor(scheduler): resolve live channel instance for delivery and use one global task store
Route scheduled delivery through the live ChannelManager instance (by instance_id, then the trusted recipient directory) instead of a bare create_channel() singleton, which fixed WeChat tasks stuck as "not ready" after restart in multi-agent mode (#3120). A shared common/channel_registry avoids the __main__-vs-app duplicate module hiding the manager from the scheduler.

Consolidate per-Agent tasks.json into a single global store; each task carries agent_id, and IM-task ownership is derived live from its delivery instance's binding (effective_task_agent_id) so re-binding a channel moves the task with no rewrite. Legacy per-Agent stores migrate once at startup; recipients.json moves under scheduler/.

Co-authored-by: cowagent <cow@cowagent.ai>
2026-09-07 18:20:41 +08:00
zhayujieandcowagent 6070603887 feat: keep agent_max_context_tokens as an optional budget override
On top of the merged #3087 + #3079, adjust the integration so the model-derived
context budget is the default while staying backward compatible.

- config.py / agent_initializer.py: agent_max_context_tokens is restored as an
  optional manual override (default 0 = derive from the model). Resolution
  order for the input budget is catalog context_window -> explicit
  agent_max_context_tokens (if > 0) -> name heuristics. This avoids the hard
  removal being a breaking change for existing configs and integrations.
- web_channel.py / cloud_client.py / cow_cli.py: re-expose the key in the
  config read/write/report paths.
- Desktop + web console: restore the "Max Context Tokens" field, relabelled as
  an optional override (empty/0 = auto), with zh / zh-Hant / en strings.
- agent.py get_context_usage(): note that the tools slice is an UPPER BOUND —
  with on-demand tool retrieval the live injected set can be smaller.
- .gitignore: ignore .obsidian/ to prevent re-committing the editor workspace.

Co-authored-by: cowagent <cow@cowagent.ai>
2026-09-06 17:07:03 +08:00
zhayujie 751b739ee8 Merge PR #3087: per-provider model catalogs and model-derived context budget
Merge chimyves:feat/model-catalog-v2 into the context-budget integration
branch. Conflicts (config.py, web_channel.py, and 3 desktop TS files) were
the "same region edited upstream" kind; resolved by keeping master's newer
logic (agent_bindings, optional custom-provider key, chat_fallback action,
key-dirty handling) and layering the catalog changes on top.

The optional-override treatment of agent_max_context_tokens is applied in a
follow-up commit.
2026-09-06 17:00:19 +08:00
alanyz106 e333cc9c6c feat(memory): track chunker version and suggest rebuild when stale
The heading-aware chunker (previous commit) only re-splits a file when its
content hash changes, so upgrading the chunker alone never refreshes old
chunk boundaries. There was also no on-disk record of which chunking strategy
built an index, so nothing could detect the staleness.

Add lightweight, opt-in version tracking (no schema migration):
- TextChunker.CHUNKER_VERSION: bumped when the chunking strategy changes.
- _meta KV helpers on MemoryStorage (get_meta/set_meta); _meta already exists
  (used for the trigram backfill flag), so no new table.
- MemoryManager.sync() stamps chunker_version when it (re)builds from an EMPTY
  index (fresh install, or right after rebuild-index clears it). A non-empty
  index may still hold chunks from an older algorithm, so it is left unstamped.
- detect_chunker_version(storage) in embedding/state.py mirrors
  detect_index_dim; returns None when an index predates version tracking
  (i.e. "old / unknown chunker").
- /memory status now shows a hint when the recorded version is missing or
  stale, suggesting `/memory rebuild-index`. This is only a hint — rebuilding
  re-embeds everything and is costly, so it stays the user's call.

Unstamped (legacy) and current indexes are indistinguishable from chunk data
alone, so the flag is the single source of truth: "no flag" == "built by an
older or unknown strategy".

Tests: tests/test_chunker_version.py (meta round-trip, detect on
stamped/unstamped, sync stamps only from an empty index).
2026-09-05 01:23:13 +00:00
zhayujieandcowagent b9de598026 feat(skills): scope /skill list to the Agent and prune uninstalled skills from team.json
Co-authored-by: cowagent <cowagent@163.com>
2026-08-31 17:15:55 +08:00
chim a153c2e238 feat(models): per-provider model catalogs and model-derived context budget 2026-08-30 02:46:33 +08:00
zhayujieandCursor b06954dedd Merge PR #2972: route channels to agent workspaces
Wires his router into the ambient identity: _identity_for now reads the
agent produce() already routed, instead of leaving agent_id unset. Without
that the bridge served the bound Agent while every workspace path still
resolved to the default one.

Routing an unavailable agent now raises instead of quietly substituting
the default, and IM replies that the assistant is disabled. Serving the
substitution would answer the user with another Agent's persona, memory
and workspace with nothing in the conversation revealing it, so his test
pinning the fallback is inverted rather than kept.

Steer keys were still unscoped while cancel keys were namespaced, so
/steer would have crossed agents sharing a session id. Both now go
through AgentBridge.scoped_session_key, including the session-delete and
cow_cli paths his branch predates.

Restores the agent_bindings config key and rebuilds the router when it
changes, matching the registry caching fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 15:43:54 +08:00
zhayujieandCursor 58f011fe6f Merge PR #2970: isolate runtime by agent workspace
Resolved against the ambient-identity foundation: initialize_agent now
takes agent_id as an override on top of the routed identity rather than
as the only way to select a workspace, and the .env refresh loop keeps
his per-agent walk but goes through state_dir for the path.

Cancel tokens are namespaced per agent; steer tokens are not yet, which
is the same bug and lands with the state isolation work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 15:24:25 +08:00
zhayujie cc92f76fb4 feat(agent): resolve workspace paths through one ambient identity
Every consumer read agent_workspace itself and joined its own subpaths,
so 42 call sites each hardcoded both where the workspace is and how it
is laid out. Adding a second agent, or a per-user layer under it, would
mean editing all of them.
2026-08-02 12:05:36 +08:00
zhayujie 084c129d6a feat(agent): add /compact command and unify /clear for context management 2026-07-25 22:04:33 +08:00
AaronZ345 41265897a1 feat(agent): isolate runtime by agent workspace 2026-07-19 14:16:38 +08:00
AaronZ345 64e8f56a7b feat: add cross-channel tasks command 2026-07-17 17:06:08 +08:00
zhayujie 5d55ec0f8c feat(browser): reuse system Chrome/Edge, bundle playwright for desktop 2026-07-14 18:02:27 +08:00
zhayujie ca404aeb24 fix(desktop): stop backend writing into the .app bundle 2026-07-08 01:59:08 +08:00
HnBigVolibear 8ddfcbb125 feat(web): add custom provider support for embedding & vision models, and fix memory_get Windows path bug!
1. Embedding model: support custom provider
   - Add "custom" entry to EMBEDDING_VENDORS with supports_dim_param=False
   - Parse custom:<id> credentials and model fallback in agent_initializer
   - Expand custom_providers as custom:<id> entries in Web UI dropdown

2. Vision model: support custom provider
   - Add custom:<id> routing in _route_by_provider_id
   - Add _build_custom_provider reading credentials from custom_providers
   - Expand custom_providers in Web UI dropdown, add validation in _set_vision

3. Fix memory_get Windows path validation bug!
   - str.startswith(path+'/') always False on Windows due to backslashes, So All Users can not use "memory_get" tool in Windows.
   - Use os.path.realpath + os.sep, consistent with MemoryService

4. Fix historical needsModel:false bug preventing embedding provider switch
   - Change embedding needsModel to true in console.js
   - Support custom:<id> resolution in cow_cli /memory status, also for adding custom provider support

Closes #2908, Closes #2880
2026-06-19 18:35:44 +08:00
zhayujie 2397ea019e feat: config cli support evolution 2026-06-15 17:57:10 +08:00
zhayujie 7fd30b608c fix(cow_cli): fix line breaks in CLI replies 2026-06-11 19:08:30 +08:00
zhayujie 1827a2a31c feat(i18n): bind web language switch to cow_lang config 2026-05-31 17:01:43 +08:00
zhayujie fcf4eb78dc feat(i18n): add global language resolution and localize user-facing text 2026-05-31 16:49:35 +08:00
lyteen 0994a3586d [feat] Fuzzy /command Resolution & Custom Aliases 2026-05-30 23:12:24 +08:00
zhayujie 8d67177a1b feat(agent): support user-initiated cancel for in-flight agent runs 2026-05-26 23:36:09 +08:00
zhayujie cc10d230b0 Merge pull request #2826 from zhayujie/feat-multi-model
feat: multi-provider model console
2026-05-22 11:08:13 +08:00
zhayujie a01423a196 fix: default agent mode to enabled when "agent" config is absent 2026-05-21 11:17:50 +08:00
zhayujie fff7326209 feat(memory): hot-swap embedding provider on rebuild-index
Switching embedding provider in the web console no longer requires a
restart and no longer drops the running conversation
2026-05-20 21:32:53 +08:00
zhayujie 3ffb563a44 feat(memory): support multi-vendor embedding fallback
Add embedding_provider config knob with native support for
openai / dashscope / doubao / zhipu / linkai, plus an in-chat
/memory status and /memory rebuild-index workflow for switching
vendors safely.
2026-05-20 11:00:53 +08:00
jimmyzhuu a4592ffdfe test: isolate cow cli plugin import 2026-04-29 16:08:40 +08:00
jimmyzhuu 7cd7bd1a48 fix: avoid cow cli import side effects 2026-04-29 16:04:48 +08:00
jimmyzhuu 9eeca70292 feat: register qianfan model provider 2026-04-29 15:52:32 +08:00
zhayujie f3c64ceea7 fix: refresh skill manager on /skill 2026-04-19 19:50:16 +08:00
zhayujie c82515a927 fix(agent): don't drop tool_calls from empty-response retry 2026-04-18 20:50:40 +08:00
zhayujie 26e630c2dd feat(cli): /config support set enable_thinking 2026-04-17 16:09:43 +08:00
zhayujie 9e86d46267 fix: sync env vars when updating config in docker env 2026-04-16 21:32:07 +08:00