Skip to content

v1.4.14

Latest

Choose a tag to compare

@shibing624 shibing624 released this 25 Aug 14:52
· 13 commits to main since this release

Agentica v1.4.14

权限档对齐 Codex(ask 不再藏写工具,增加「拒绝类似」);Web/桌面真正多账号;文件工具收成 apply_patch + write_file;Worktree 默认进仓库内;系统 skill 包内加载;桌面版首次打开自动装 Python runtime。

安装: pip install -U agentica==1.4.14(网页/桌面:pip install -U "agentica[gateway]"

下载桌面版

系统 安装包
macOS 11+ Apple 芯片(arm64) · Intel(x64)
Windows 10+ x64 安装程序(NSIS)
Linux x64 AppImage · deb

桌面版是个壳,服务端仍是 Python gateway:装应用之前先 pip install -U "agentica[gateway]"。安装包未签名,首次启动被系统拦下时按 README 里对应系统的一步操作解除。

完整对比: v1.4.13...v1.4.14


[1.4.14] - 2026-08-25

breaking

  • agentica.subagent / agentica.subagent_loader 挪到 agentica.subagents:内置定义从 agentica/agents/*.md 改到 agentica/subagents/bundled/*.md(和 skills/bundled 同结构)。运行时 from agentica.subagents import SubagentRegistry;加载器是 agentica.subagents.loader。不留旧模块。用户/项目目录 .agentica/agents/$AGENTICA_HOME/agents//agents 斜杠命令不变。
  • SkillRegistry.get_skill_instruction() / generate_skills_prompt() 删除:生产 catalog 一直是 SkillTool.get_system_prompt()(自进化 spawn 也是写盘后再走这条)。两条是死 API,catalog 预算改挂在活路径上,不再维护第二套按注册序截断的 XML 列表。
  • GET /api/memory 不再返回用户级 AGENTS.md:payload 改为 {auto_extract, index_path, entries}(MEMORY.md 索引)。常驻规则改走 GET/PUT /api/user_agents_mdPUT /api/memory 删除(405),避免旧前端把 AGENTS.md 正文写进记忆结构。
  • 权限档 ask 改为 Codex「Ask for approval」:以前 ask 会从 schema 里藏掉写工具(write_file / execute / apply_patch 等,模型看到 Function not found);现在三个档工具都在,差别只在真正 execute 之前要不要停车等人。ask(含工作区外;文件工具 + 只读 shell,含 cd && git diff | head 包装)自动放行;write_file / apply_patch,含工作区内)、会改状态的 executeweb_search / fetch_url、硬不安全路径/命令停车。auto:再放行工作区内写、普通 execute 和网络。allow-all 不询问、不拒绝(含硬不安全;项目「拒绝类似」只约束 ask/auto)。删掉模型可见的 request_path_access,改由公开 grant_path_access 写入沙箱白名单。默认不变:CLI / SDK 仍是 allow-all,Web 仍是 auto。无人值守(无 LiveTurn:IM / cron / 非流式 POST /chat / --print)立即把工具结果写成 Tool call denied by user.,不 500、不 sibling-abort。
  • 审批增加 deny 路由和「拒绝类似」classify 返回 allow | ask | deny。三档权限嵌套:autoaskallow-all 是 root。askweb_search / fetch_url 和工作区内写文件弹卡;auto 放行网络和工作区内写,硬不安全仍弹卡。新增 deny_prefix(CLI x / 4,Web 拒绝按钮下拉「拒绝类似」),写入 project.json approvals.deny_command_prefixes 等,下次同类在 ask/auto 下不弹卡直接拒。allow-all 忽略项目拒绝,只 warning + 记 approval_decisionallow_all_ignore_deny / allow_all_hard_unsafe),命令照跑;进程用当前 OS 用户的权限,能 sudo 就能 sudo。用户在 ask/auto 点允许之后,执行时的 check_command_safety block / sandbox blocked_commands 不再跟卡打架。
  • 系统 skill 不再拷贝到 $AGENTICA_HOME/skills/.system/,改为包内原位加载:CLI / gateway 的 load_system_skills() 把搜索路径末尾直接指向包内 agentica/skills/bundled/ensure_system_skills()skills/.system、内容哈希指纹同步整套删除(同仓库 subagents/bundled 一直是这个模型)。拷贝本来就不是正确性前提(复制失败时回退的就是包路径),却让每次产品启动都扫树做 sha256、只读 home / 容器 / CI 走 OSError 降级、.systembundled/ 双源难查、模型看到的 Path: 在 home 里像用户资产其实升级即被覆盖;SDK 侧「不捡到 CLI 残留」的隔离测试面也随之消失(.system 点开头,目录发现本来就不扫)。覆盖方式不变:~/.agentica/skills/<name>/ 同名 user skill 优先级更高;Web 插件 API 的 editable = (location == "user") 不受影响,bundled 依旧不可编辑。

fixes

  • 权限档文案与 classify() 对齐ask 的读(含工作区外)与 auto 相同,只拦写、会改状态的 shell 和联网。CLI --permissions / /permissions、Web Permission 提示不再写成「只有工作区内读才自动」或「ask 只有只读工具」。
  • execute 超大输出改为落盘预览,不再静默丢掉中间段:原先 max_output_length(默认 20k)先做 40/60 头尾截断,中间直接丢;max_result_size_chars=50k 的 Layer 0 落盘永远触发不了。现在超过 20k 写入会话 tool-results/,上下文只留路径 + 行数 + 头尾预览,后续用 read_file/grep 查。成功与非零退出(失败命令的巨型 traceback)都走这条路——Layer 0 钩子挪到结果内容组装之后(错误文本先脱敏再落盘,spill 文件不碰密钥),原先挂在「仅成功」分支上,报错路径仍然丢中间。
  • SDK print_response_stream 不再把工具事件漏进回答show_tool_calls=False 时原先不跳过 ToolCallStarted / ToolCallCompletedRunning tool: read_file 会被当成正文打印。现在走和 CLI / Web 同一套 classify_run_response,工具事件无论显不显示都不会进答案。
  • CLI 审批卡裁掉「拒绝」、两项时跳号rm /path 这类不能「允许类似」的命令本来就只有允许/拒绝,但 TUI 把整段卡当成一行再多塞一个换行,高度少算一行,拒绝被裁掉,屏幕上只剩 1. Yes, proceed (y)。同时拒绝还写死成 3.2 仍绑「允许类似」。现在按可见选项连续编号(两项就是 1 允许 / 2 拒绝;四项仍是允许、允许类似、拒绝、拒绝类似),数字键跟着走;长命令按终端宽度预留折行高度,不再把选项挤出屏幕。SDK / Web 同一套 options,没有类似可批时本来就不渲染那两个按钮。
  • CLI 拒绝文案不再催用户写原因,审批后命令留在 transcript:拒绝从 No, and tell the agent what to do differently (esc) 改成 No, deny (esc/n)esc / n 都是直接拒,不追问理由)。审批卡画在输入区 layout 里,决定后整段卸掉,$ rm … 会跟着消失。现在卸卡之后把命令和 ✓ allowed / ✗ denied 打进 scrollback。
  • Web 审批卡按 Enter 会整轮「已中止」:卡上「允许一次」标了 ⏎,但焦点在输入框时 Enter 被当成「空输入为停止」。有未决审批时输入框禁用(附件 / slash / 粘贴也停),只留停止;Enter 允许一次、Esc 拒绝。残留草稿不再插入当前轮。
  • Web 侧栏会话状态与对话页被误删deny_prefix 那次提交冲掉了 sessions.tslastTs / unread / syncSessionStatus,以及 ChatPage 的左侧 query 导航(ChatNav)、settleWork、已读 markSessionRead、以及 running 清位。已从上一版补回,审批卡仍带 deny_prefix

features

  • 工具说明去掉二进制黑名单,改为正面能力描述execute docstring、tools.mdShellTool 不再写「not cat / not find / not sed -i / MUST avoid find」式禁令——实测这类禁令把强模型推向更差的绕行路径,且多处文案互相矛盾。管线(pytest | rg '^FAILED' | sortrg … | headfind … -mtime -3 | xargs ls -lt)与文件工具各自正面展示。grep content 模式的 limit 是全局条数上限:stdout 读满 limit 行即杀掉 rg(不再用每文件 --max-count,也不再 communicate() 整棵树再切片)。read_file 支持 tail 和负 offsetoffset=-50 即最后 50 行,配 limit 取窗口内最旧的若干行);tail/负 offset 不再被 256KB 守卫拦住(守卫只拦从头分页;报错只建议 tail,正 offset/limit 过不了守卫)。从尾扫描超过 20 秒超时。

  • SDK print_response / print_response_stream 默认展示工具,调用行跟 CLI 同一套文案:默认 show_tool_calls=True(仍可关掉)。工具行用 format_tool_displayread_file foo.py (L1-80),不再打原始 dict);read_file / glob / grep 成功时只留调用行,和 Web 一致。思考在工具之后再出现会再打一次 💭 THINKING,时间线是思考 → 工具 → 思考 → 回答。

  • Skills catalog 按模型上下文窗口的 2% 做 token 预算(无窗口时退回 8000 字符)。单条 description 硬帽 1024 字符(从前截)。超预算先从列表尾部丢掉 description(保留名字),仍超才 omit 并注明条数。卫生规则写进 prompt:匹配才用、当轮读完 get_skill_info、不跨轮携带、不深追 references。freeze_session_guidance() 仍然冻住整块,不每轮重排。

  • 粘贴/输入里的非法 UTF-8 不再打崩 CLI、Web、SDK:孤立 surrogate(例如 U+DCE5)以前在 .encode("utf-8") 上炸掉 Enter 写历史、agent 落盘和 Langfuse OTLP。CLI 入口、Agent.run / steer、Web ChatRequest / SteerRequest / GoalRequest 都换成 U+FFFD,相邻汉字不动。

  • Web 侧栏会话时间改为「多久没发起 query」:原先 agoStr 用的是 first_timestamp(会话第一次请求),所以一直聊的对话也会显示 7h。现在用 last_timestamp,有本地 transcript 时再取最后一条非 steer 用户消息;文案按界面语言粗粒度显示(刚刚 / 5 分钟一档 / x 小时前 / x 天前,英文 just now / 5 min ago / x hours ago / x days ago)。选中行的时间不再叠一层 background(原先 --bg2 盖在 --accent-soft 上会变成一块深色芯片)。组内会话按最近一次 query 排序;项目组顺序仍按该目录第一次对话。

  • Web 侧栏会话状态:回复中转圈 / 未读绿点 / 空闲时间:发完 query 切到别的会话时,原会话 title 右侧不再显示「刚刚」,AI 思考、tool call、压缩期间是转圈;回复结束后如果没打开过就是绿点,点进去看过才回到时间标签。last_read_at 写在 session sidecar,GET /api/sessionsunread / running,打开会话会 POST /api/sessions/{id}/read。旧会话没有 last_read_at 不当未读。

  • Web 对话左侧 query 导航条对齐 Codex minimap 设计:左侧留白区域默认只展示极窄短横刻度,鼠标悬浮短横时在右侧弹出不透明浮窗(圆角、边框),展示截断 query(前 50 字、最多两行);点击平滑直达对应问答轮次并带微光闪烁反馈;当浏览器宽度收窄(≤ 1024px)时自动隐藏,不侵占主对话区域。

  • 自动抽取的记忆带上会话证据,search_memory 回读 provenancewrite_memory_entry(evidence_refs=) 原先只在手动写入时用得上,抽取结果没有来源。现在 MemoryExtractHooks 把抽取窗口归档后写入 evidence_refssearch_memory 每条结果带 title / memory_type / memory_source / evidence_refs。评测脚本在 evaluation/reconcile_mem/

  • auto 只拦工作区外的文件写:读(含工作区外的 skill/SKILL.md)、工作区内写、全部 execute、网络、以及 self_manage / cronjob / skill 等内置工具(不看 action)一律过。ask 的读与 auto 对齐(含工作区外);拦写文件(含工作区内)、会改状态的 shell、以及 web_search / fetch_url。记忆、task / delegate、skill 和其它内置工具直接过。self_manage show 不再把 compact_token_limit 当成 secret;api_key 只藏中间(含 fallback_models / auxiliary_model 里的 key)。

  • 轨迹 approval_decision 带上审批卡和用户决定:停车才写。事件里有工具名、入参、question/preview、可选「允许类似」标签、档位、等待秒数(wait_s,两位小数)、以及用户点的 allow / allow_prefix / deny。选了允许类似时把写入 project.json 的 grant(命令类 / 路径前缀)记在同一条上,不再只剩 decision + tool_call_id

  • 工具审批停车(CLI / Gateway / Web 同一套 ApproveFn:Runner 在 fc.execute() 之前、wait_for 120s 超时之外调用 Agent.approve。Gateway 的 ApprovalRegistry 只住在 LiveTurn(不是 Agent 缓存);SSE tool_calltool_call_id,新事件 approval_request(刷新按 seq 回放并重推未决项,不看当时有没有 SSE 订阅者);POST /api/sessions/{session_id}/approvals/{tool_call_id} 提交 {decision: allow|allow_prefix|deny|deny_prefix}(按账号鉴权,未知 id 404)。取消或结束 deny_all;有未决审批的 Agent 不被 LRU 清掉。CLI 对齐 Codex 选项(y / p / esc / x),并行 tool_call 串行弹卡,Ctrl+C 拒绝全部。Web 底部固定一张卡(拒绝 Esc + 下拉「拒绝类似」/ 允许一次 Enter / 下拉「允许类似 rm -f 命令」),刷新按 tool_call_id 挂回工具行。allow_prefix / deny_prefix 批的是命令rm -f,不含文件名),写入该项目 project.jsonapprovals(与 work_dir / active_profile 同文件),重启 CLI / gateway 仍生效;「允许/拒绝一次」不落盘。复合命令不能「允许/拒绝类似」。/permissions 改为三档说明。

  • Web 对话 run 与 SSE 连接拆开:刷新 / 断网只断开订阅,后端继续跑。POST /api/chat/runs 立刻返回 run_idGET /api/chat/runs/{id}/events?after= 按序号重连去重;GET /api/chat/runs/active 找回当前 session 的 run;POST /api/chat/runs/{id}/cancel 显式取消并等到 session lock 释放(已结束则幂等返回终态)。Stop 在 lock 释放前不允许发下一轮(新输入排队)。发送后立刻出现 WorkGroup「正在思考」转圈(有附件时是「正在准备附件」),不再空白等到首字。live_turn / Agent 缓存 / session lock / work_dir / 审批档都按 (账号, session_id) 分区,session_id 是客户端可控字段,不能让 B 账号的 409 或删除碰到 A 的 run。list_sessions 会并上该账号尚未落盘的 live run,刷新不会让刚发出的新对话从侧栏消失。

  • Web 工具调用入参跟 CLI 同一套展示:对话里不再 json.dumps 原始参数。read_file / glob / grep 一行路径;write_file / apply_patch 文件名或文件数(结果仍是 diff);execute 命令;write_todos 清单;web_search / fetch_url 查询或 URL;task / delegate / send_message 全文;list_agents 只显示名字;其余 key=value 摘要。轨迹页仍是原始 JSON。

  • Worktree 默认短命、落在仓库内:默认路径改为 <repo>/.agentica/worktrees/<任务>(不再是兄弟目录 ../<repo>-<任务>settings.worktree.root: sibling 可回到旧布局)。worktree(action="merge") 合入本地 base 后删除 checkout 和 wt/<任务> 分支,会话回到主目录;进行中的同名 use 仍复用。新增 remove。会话绑定期间 git worktree lockagentica pid=<pid>),活着的别人的锁和用户手加的锁都不抢;pid 已死才偷锁。删除前的安全标准是「agentica 的 wt/ 分支 + 没有独有工作」(干净且不 ahead 本地 main),不是「是否已 push」;detached / 手建 / Claude Code 的树一律不删。退出 CLI 时,没有独有工作的 wt/ worktree 自动清掉,有独有工作的保持 lock。.env 仍是 symlink。use 发现别人持锁时会点名 pid。工具 remove 先校验再搬家。

  • web_search 默认引擎从 baidu 换成 exa:走 Exa 公开 MCP(https://mcp.exa.ai/mcp),不设 EXA_API_KEY 用共享免费池(有限流),设了走自己的额度。和 OpenCode 同一条免费接入;AGENTICA_WEB_SEARCH=baiduprovider="baidu" 仍可选。环境变量配了需要 key 却没给 key 时,降级目标也跟着改成 Exa。

  • Web 对话回答列对齐 980px、正文 14px:原先 .msg-stack 再套一层 min(760px, 88%),宽窗口两侧留白,开着工作区面板时表格还被压到约 600px。现在 assistant 列跟 .msgs 同宽,用户气泡仍是聊天宽度;输入框 max-width:980px 与对话列对齐。段距 / 列表 / 表格 / 标题一起从 compact 终端密度调到网页可读。

  • glob / grep 硬超时从 3s 调到 20s_GLOB_TIMEOUT / _GREP_TIMEOUT):3s 会误杀本地大仓、冷盘和没有 rg 时的 Python fallback;仍不暴露给模型。对齐 kimi-cli / Claude Code 的 ripgrep 20s 上限。glob 继续留超时:当前实现是 pathlib.glob 整树走完才返回,结果上限挡不住 NFS hang。

  • 设置 › 模型配置顶部只留 config.yaml 路径:去掉当前 profile / 模型 / effort / context / compact 那一行摘要,列表里本身就能看到谁在用。

  • compact_token_limit:压缩工作阈值,不改模型 context_window。1M 窗口可以配 300000,Layer 2 在 min(该值, 窗口×0.95) 触发摘要;Layer 1 的 0.8/0.5 相对 min(该值, 窗口)。不配则和现在一样(约 95% 窗口才摘要)。写在 config.yaml 的 profile 上,也可写 settings.compact_token_limit 做全局默认。CLI:/config set compact_token_limit 300000--compact-token-limit。Web 模型配置有填才显示。SDK:ToolConfig(compact_token_limit=300000)

  • 设置 › 记忆拆成两层:上半编辑用户级 AGENTS.md(常驻规则,进 system prompt);下半「生成对话记忆」开关仍接 auto_extract_memory,列出的是 MEMORY.md 索引条目,不再把 AGENTS.md 预览假装成抽取结果。CLI / SDK / Gateway 同一套注入:会话开头把 MEMORY.md 索引(标题+hook+相对路径,最多 60 行 / 4KB)冻进 prompt 并点名绝对路径,memory/*.md 正文按需 search_memory / read_file。抽取仍大约每 10 轮。已知限制:write_user_agents_md 会清掉共享 Workspace 上的 _context_snapshot,Gateway 下一轮所有会话会重建 AGENTS.md 前缀(快照应按会话持有,v1 不改)。

  • 「Profile」中文改叫「模型配置」

  • 个人助理的 Web 地址可点:和 config.yaml 一样走 POST /api/open,用系统默认浏览器打开 http://127.0.0.1:8881/chat

  • 个人微信默认就能扫码WECHAT_TOKEN_FILE 默认 ~/.agentica/cache/wxbot_token.jsonWECHAT_ALLOWED_USERS 默认空。gateway 启动不再弹码;网页点「配置」才生成二维码(过期约 120 秒)。没扫或过期显示「失败」;离开再进个人助理页,码是空的,要再点配置。

  • 微信 / 网页 / 桌面是同一个人:点「配置」扫码时登录的账号就是机主。IM 不再用微信 openid 另开 users/<openid>/ 分区;会话、记忆、AGENTS.md 都进这个账号。已连上的再点一次「配置」也会绑到当前登录账号。

  • 设置 › 个人助理:设置弹窗第二个 tab(常规旁边),展示本机 Web 地址和微信 / 企微 / QQ / 飞书等 IM 的接入状态与连接方法。账号菜单同一项打开这个 tab。/assistant 仍是同一套内容的独立页。GET /api/channels 增加 catalog / web_url / listen

  • 桌面版第一次打开会自己装 Python runtime:安装包仍然不含解释器(壳最难更新)。找不到 agentica-gateway 时用 uv 在 Application Support 装 CPython 3.12 + agentica[gateway],不进 ~/.agentica;已经 pip 过的继续用原来的。AGENTICA_GATEWAY_BIN / AGENTICA_DESKTOP_NO_BOOTSTRAP 可跳过。

  • CLI 运行中输入提示改直白:Enter 插话显示 Steered the current query. Tip: Tab or /queue queues a request.;Tab 排队显示 Queued the next request. Enter steers the current query.。原先 Guidance added to the current task 没说清 steer 的是当前这一问,也没点出 /queue

  • CLI 回答按 Markdown 块增量落屏:原先 stream_response 把整段缓冲到 finalize 才一次性 print(Markdown),长回答只能盯着 answering…。现在围栏感知的空行一旦闭合一块(标题/列表/代码/表格)就立刻渲进 scrollback,未完成的尾部仍等结束;不用 Rich Live,避免和 prompt_toolkit 抢光标。cli_markdown=off 仍整段纯文本。

  • 设置 › Profile 顶部是本地 config.yaml:原先「当前配置」和预览弹窗在常规页。现在这块在 Profile 最上面,路径是可点链接,走已有的 POST /api/open 用系统默认编辑器打开(本机 gateway / 桌面版);打不开就 toast。预览弹窗去掉。GET /api/config/file 仍给别的调用方打码读文件。

  • Web 思考与工具按真实调用顺序穿插:思考是组里一行(11px、和工具同行高),正在流式的那段默认展开、正文随页面贴底,不再用 max-height 把最新思考裁在卡片里。工具同样一行一卡。正文仍会打断分组,所以时间线是思考 → 工具 → 回答 → 思考 → 工具 → 回答。流式光标只留在最下面那一个气泡。

  • Web /goal 过程流式:原先 POST /api/goal 只推 status 条,正文等整轮 done 才一次性出现。现在每轮走 run_stream,和普通对话同一套 thinking / tool_call / tool_result / content SSE,工具组和吐字穿插出现;顶栏 tokens 进度仍用 status。停止按钮、插话 chip 也挂到这一轮 live 消息上。

  • Web /goal 只限 tokens,默认不限:原先网关硬编码 turns 15 / tokens 80,000 / wall 300s,状态条三项一起显示。现在对齐 CLI 主闸:只传 token_budgetGoalRequest.token_budget-1 = 不限,网页默认)。输入 /goal 进入目标模式:先填 token 预算(空=不限,支持 k/m),再写目标。运行中状态条只显示 tokens usedtokens used/budget。CLI --turns / --wall 不动。

  • Web 流式吐字贴底跟滚:回答过程中每条 token 不再立刻重跑 Markdown / KaTeX / 高亮(那会把主线程卡住,看起来像输出冻住);按动画帧合并绘制,流式时用轻量渲染。用户没上翻时始终跟到底;程序化滚动不再被误判成「用户离开底部」。

  • Web 插话(steer):输入栏只有一个按钮。空内容是停止;有内容则发送(纯文本走 CLI 同一条 agent.steer())。要排到下一轮/queue <prompt>/q 同义),和 CLI 一样;附件和其它斜杠命令仍排队。插话气泡带图标、虚线框。来不及送达的插话在本轮结束后自动改排队。API:POST /api/chat/steerPOST /api/chat/steer/take

  • glob / grep 不再把 timeout 暴露给模型grep 同时去掉 multiline):内部硬超时,不给模型覆盖。此前无上限的 timeout 让模型随手填 60 就能拆掉 fail-fast;跨行正则 fallback 又不支持,有 rg 和没 rg 会搜出两套结果。超时错误改为让模型收窄 path / include,不要原样重试或改走 executecontext_lines > 0 时忽略 before_context / after_context(与 rg -C 一致),写进 docstring。execute / waittimeout 不动。

  • 文件工具去掉 ls / edit_file / undo_edit:编辑只留 apply_patch + write_fileread_file / glob / grep 仍在),方法本身也删了,schema 里不再出现。列目录改用 glob(pattern="*")——它本来就返回子目录,工具 docstring 和 tools.md 里点明了这一点,免得模型退回 execute("ls")。Web 默认审批档是 autoChatRequest.approval_mode),不是 asktaskweb_search、memory、list_agents / send_message 仍常驻。CLI / Gateway 不再保留对 ls / edit_file / undo_edit / multi_edit_file 的历史日志渲染分支。越权路径不再走模型可见的 request_path_access(已删除),改为审批卡停车后 grant_path_access

  • 权限档以 Agent 为准,工具自己那份只在脱离 Agent 单用时生效Agent 在接线工具时(_wire_tools_to_self)把 tool_config.permission_mode 灌给它持有的每个 BuiltinFileToolget_builtin_tools() 因此不再有 permission_mode 参数——同一个决定不留两个入口。工作区外写入走审批卡 + grant_path_access,不再挂模型可见的 request_path_access

  • Web / 桌面版变成真正的多账号产品,seed 的账号从 admin 改名 default:账号名同时是数据分区名(它命名 users/<id>/,也就是会话与记忆的落盘位置),叫 admin 就意味着首启动会凭空造出一个 users/admin/ 分区,而这台机器上已有的对话全在 users/default/ 下——同一个人换个入口进来看到的是空列表。现在默认账号名直接取 settings.default_user_id(即 default),并对已装过上一版的机器做一次性迁移:auth.json 里那条 admin 记录连密码带会话一起改名成 default,所以旧密码继续能登、开着的浏览器不掉线。左下角的账号入口显示用户名 + 角色(原先显示的是当前 profile 名——profile 是模型配置,和「我是谁」无关)。账号名会先规范化再当目录名(清理后 2–32 位、字母开头、仅字母数字下划线)。

  • 每个账号有自己独立的会话、归档与定时任务AgentService 的每条入口(chat / chat_stream / run_goal、会话列删改归档、trace 读取)多一个 owner 参数,由服务端从会话 cookie 解析,agent 实例的缓存键也带上它。相应地 ChatRequest / GoalRequest / MemoryRequest / CronJobCreateRequest 删掉了 user_id 字段——请求体里的身份是客户端说了算的,等于任何登录用户都能把别人的 user_id 填进来。网页侧边栏只展示服务端返回的会话(不再把同一个浏览器里上一个账号的 localStorage 合并进来,那会让 kk 登录后看见 default 的对话)。定时任务按账号切开:/api/scheduler/jobs 只列出当前账号的任务,创建时把 cookie 里的账号名写进 CronJob.user_id,别人的任务 id 一律 404;调度器仍会执行所有到期任务,跑的时候用任务上的 user_id 作为数据分区。归档是会话上的标记,跟着会话走。「用户管理」是唯一的管理员专属功能/api/auth/users* 非管理员一律 403):模型 profile、工作目录、技能、MCP 仍是这台机器的配置,任何账号都能改。删账号只吊销登录,users/<id>/ 的数据留在盘上。端到端验证 tmp/multi_account_smoke.py(真 gateway、真流式对话,两个账号互不可见、非管理员 403、管理员改密、删号后数据仍在)。

  • 用户管理从设置弹窗里拆成右侧独立页 /users,新增 / 改密改成完整表单:原先塞在设置 tab 里的一行输入框既看不清也做不全。现在主侧栏不变、右侧是账号表;新增用户是二级窗口:用户名会先规范化再当目录名(小写、空格/连字符变下划线、其它非法字符丢掉、数字开头加 u_、超长截断;清理后须 2–32 位且字母开头),初始密码(管理员自己填,至少 6 位)。规范化后与已有账号撞名则拒绝。用户名合法时提示将创建默认 Project <id>(不再带 -default_project 后缀,目录就是账号名)。只能新增用户角色——第二名管理员会把「谁能改谁的密码」搅成一团,seed 的那一个就是唯一管理员。去掉重置密码:改自己(内置管理员)要填当前管理员密码(提示写明初始密码打印在首次启动的终端里,形如 abcd-1234),改普通用户只填新密码 + 确认。改密只在用户管理页(以及设置 › 访问);左下角账号菜单改为 退出登录,方便切账号。

  • 网页去掉「让模型输出推理过程」开关,thinking 默认一直开:这不是给用户选的产品能力——支持 thinking 的模型本来就该把推理过程流出来,关掉只是让界面少一块;不支持的模型会忽略。删除 /api/config/thinking 与设置里的勾选,Gateway 构建主模型时固定传 thinking="enabled"

  • 轨迹是会话的附属,不再是独立 tab:主侧栏去掉「轨迹」按钮,中间那列会话列表也去掉。唯一入口是对话标题右边的「查看轨迹」;轨迹页左上角「返回对话」回到该会话。直接打开 /traces(不带 sessionId)会回到聊天。

  • 对话页右侧「打开工作区」:顶栏去掉「目录: …」那一行,改成打开当前会话工作目录的文件面板(Web / Desktop 同一套 SPA)。面板标题是「文件」,工具条是「根目录」加详情 / 刷新 / 上传;点进文件可预览(文本 / Markdown 渲染与源码 / 图片 / PDF / HTML 沙箱),超过 256 KiB 截断并提示下载(源码高亮到 64 KiB 为止,更大的 Markdown 默认开源码视图以免卡主线程),预览页可返回、可下载。对话里提到的路径(行内代码、read_file/write_file/apply_patch 参数、上传附件)会聚成文件卡片,点「预览」打开同一块面板。路径必须落在工作目录内(.. 与 symlink 逃逸拒绝)。API:GET /api/workspace/files/contentPOST /stat/upload

  • 对话输入框右下角的上下文占用改成 CLI /usage 同款会话级拆分:鼠标悬停看到 Context Window(已用 / 窗口)、消息数、API 调用、费用、本会话输入/缓存命中/输出,以及 system prompt / 规则与工作区 / 技能 / 工具说明 / 工具定义 / 对话各自占用的 token。各行是并列拆分(加起来等于下一轮请求),不是父子:System prompt 是整段 system message 扣掉已归因块后的剩余,工具定义是 API schema、不在那段字符串里。分段只报 token 数,不再配百分比、进度条和缩进;/usage 同样去掉 % full, estimated 和 ▓ 条。数字来自同一条 measure_context 路径。API:GET /api/sessions/{id}/usage;流式 done 事件也带上这份快照,圆环百分比跟占用走。

  • 侧栏每个 Project 行右侧「+」在该项目下新建对话;不再显示 project 路径(工作区已经有路径)。工作区 Details 点外面或 Esc 关掉。Markdown 预览支持 HTML 标签(如 <p align="center">)和 LaTeX;源码 / 纯文本预览右上角可复制可见文本。每轮结束后,鼠标悬停答案显示日期、↑输入 / ↓输出 tokens、input cache tokens 与 cache hit(与 CLI footer 同一口径)、tok/s、费用、耗时和复制;footer 每一项都有 tooltip(费用是「成本(USD)」)。用户消息悬停只显示简写日期时间和复制。新建对话可在输入栏选择/更换 work dir(浏览上级目录、改用临时工作区)。输入 / 可触发 /goal/compact 和已安装 skill。可粘贴/预览图片:底模能看图则直接附上,否则由 settings.media_model 配置的模型描述后转交(未配置时提示如何在 config.yaml 里写 media_model)。流式输出贴底滚动,上滑后页面中间出现下拉箭头可跳回最新。输入框随内容长高。

  • Web 读图提示不再写死 Gemini:底模不能看图时,tip 显示 settings.media_model 里实际配置的 model_name;未配置则说明在 config.yaml 里怎么写该块(需要 model_name,以及 model_providerbase_url)。GET /api/status 增加 media_model。IM 渠道未配置时的回复同样不再写「指向 Gemini」。

  • Web 输入栏、footer、/goal 与新建会话目录:去掉输入框上方的 Enter to send · … tip(换行/粘贴写进 placeholder)。每轮 footer 的 cache 改成数据库图标,夹在输入 tokens 和输出 tokens 中间。/goal 运行时输入框上方显示 CLI 同款状态(Goal [active]: … + tokens/turns),期间再发的消息进入队列而不是 409「already has an active run」。新建会话选目录时可直接输入绝对路径;路径不存在或无法访问时提示「目录不存在或无法访问,已回退」,仍停留在旧目录上可继续改。

  • 设置 › 默认工作目录:历史条目可单条删除;已不存在的路径(包括 pytest 留下的临时目录)打开设置时自动丢掉。输入绝对路径点应用 / 回车,非法路径同样提示「目录不存在或无法访问,已回退」。DELETE /api/config/dir_history?path=

  • Web 偏好落盘到 gateway,localStorage 只做首屏缓存:主题、语言、审批档、上次打开的会话写入 $AGENTICA_HOME/gateway/prefs/<账号>.jsonGET/PUT /api/prefs)。清浏览器缓存或换浏览器后仍能从本机读回;第一帧仍读 localStorage,登录后再对账。会话正文仍是 SessionLog,没有另起一份 SQLite。

  • 输入框 Skills / Permission 对齐可发现性:Skills 按钮(打开的书 + 下箭头)弹出带搜索的列表,展示技能名和描述,悬停 tip 是完整 desc。Permission 三档跟 agentica.agent.permissions 一致,不是 Codex 截图里的「每次询问」:ask 是征求批准(读含工作区外、只读 shell 自动;写文件 / 改状态的 shell / 联网停车)、auto 是代为批准、allow-all 是完全访问。图标按 Codex 习惯:眼睛 / 闪电 / 三角感叹号;按钮带下箭头,括号里跟英文 id。/ 斜杠菜单过长时列表可滚、键盘选中项滚进视口,技能行也用打开的书。

  • 源码预览按语言语法高亮:工作区打开 .md / .py / .yaml / .toml / .java 等文本文件(Markdown、HTML 切到「源码」也一样),以及对话里的围栏代码块,都画成带语言标签和复制按钮的代码卡片,用 highlight.js 着色(标题蓝、引用绿、跟常见 GitHub 主题同一套 token)。Markdown 渲染视图不变。源码卡片自己管横竖滚动(不再把纵向甩给外层、横向甩给 <pre>):两条都是 8px 细条、始终可见、可拖滑块,点轨道跳到对应位置。

  • 工作区预览上限从 12000 字符改成 256 KiB:原先一个普通源码文件就会被截成「请下载」。GET /api/workspace/content?preview=1 现在只读文件头 TEXT_PREVIEW_BYTES(256 KiB),不再整文件进内存再切;超过 64 KiB 关掉语法高亮,更大的 Markdown 默认开源码视图,避免卡主线程。

  • 查看轨迹后侧栏丢掉刚建的对话:进 /traces 会拆掉整棵 AppShellGET /api/sessions 覆盖列表;而这个接口只列默认工作目录下的 session,刚在别的 project 里问完的对话(轨迹能打开,因为它按 session id 找)就不在列表里,覆盖时连 localStorage 一起冲掉。现在 chat/traces/users 共用一个 layout,切轨迹不再重拉列表;list_sessions 列出该账号下每一个 project,并带上 work_dir

  • gateway 重启后「查看轨迹」提示盘上没有 jsonl_session_work_dirs 是进程内存,重启后空了就去 settings.base_dir 找;对话其实写在另一个 project 下。session_log_for / 删改归档现在用 SessionLog.find_sessions 在该账号所有 project 里按 session id 定位。轨迹页 cache 改成与对话 footer 同一套数据库图标 + tip。

  • 轨迹时间线此前是一根实心条,现在是真的分段thinking / text / tool_call 三种事件是在一次请求结束后才一并落盘的,时间戳几乎相同,于是分析出来的模型泳道要么只有一段、要么后面几段宽度为零——时间线看着像没坏,但它讲的不是这一轮实际发生的事。现在流式循环在推理段和正文段真正结束的那一刻记下 time.time()SessionLog.append_event() 接受显式 timestamp,落盘前按发生顺序排序,所以「思考 2.3s、回复 36ms」这种分布才画得出来。

  • 工具泳道按工具名合并,图例五项:原先每个工具调用各占一条泳道,一轮里调 20 次 read_file 就是 20 条几乎一样的线;现在同名工具收进一条泳道(并发调用才在道内错开分层,道尾标调用次数),并且图例五个阶段常驻(思考 / 模型回复 / 工具参数生成 / 审批等待 / 工具执行)——只画本轮出现过的颜色,会让两轮之间的同一个颜色对应不同阶段。不再画「其它」:那是墙钟减去各段之后的残差,时间线上本来就没有对应的条。

  • Web 工作组在回答结束后不再显示「运行中」:思考切片的 ms 没冻住时,组头和「正在思考」按墙钟一直加,隔天变成 45h。现在所有未收口的思考都冻住(中间段用下一段工具/t0,不要用现在的墙钟);回合结束走 settleWork;已经不在流式的卡片即使旧数据缺 ms 也不再转圈。

  • 沙箱 blocked_commands 不再把 rm -rf / 当成所有绝对路径删除的前缀:以前只卡左侧边界,rm -rf /Users/.../__pycache__rm -rf /tmp/x 都被当成删根目录拦掉(测试还把这个漏洞写成预期)。现在按操作数匹配:/ 是完整路径,后面不能再接 Usersrm -rf /rm -rf /*echo x; rm -rf / 仍拦。对齐 Codex / OpenCode / Penguin:工作区内删除走审批或 OS 围栏,不用字符串前缀当禁令。

  • 工具审批分类器与「允许类似」is_destructive 第三方工具(如 cronjob)在 ask 下停车,不再误落到兜底 allowauto 下放行(只拦工作区外文件写)。命令「允许类似」按命令类(rm -f,不含路径/文件名),rm -f a 批过之后 rm -f b 不再问、git add 不会放行 git push;类短于 2 个 token 时不提供「允许类似」(bash deploy.sh 不能永久放行任意 bash -c);echo hi && rm 这类复合命令不能用首段越权,只提供允许一次。已写入 project.json 的单 token 前缀(["bash"])读取时忽略。ask 下工作区 write_file / apply_patch 也会弹卡。todo / memory / skills / ask_user_question 不弹卡。Web 输入框 Enter 不再误批。tool_result SSE 带 tool_call_id。真正停过车才写 approval_decision

  • 输入栏弹出层点外面或 Esc 就关掉:模型 profile、权限档、Skills 打开后只能再点一次按钮才关。现在点对话区、输入框或其它按钮会立刻收起,Esc 也先关菜单(有菜单开着时不拿去停止生成)。

  • Web 生成中空 Enter 会停止,Stop 按钮一直在:placeholder 写着「空输入为停止」,但空 Enter 直接 return;输入框有草稿时按钮还会变成发送。busy 期间按钮恒为 Stop,空 Enter / Esc 都停止。

  • 创建 run 途中点 Stop 不再留下孤儿任务POST /api/chat/runs 返回后若用户已停止,立刻 cancelRunApi,避免 UI 已 aborted、后端仍占 session lock。

  • SSE 空闲 15s 发 keepalive;干净 EOF 且未见 done/error/aborted 则按断线重连:前置代理闲置掐流不会再被当成回合完成。

  • 已结束的 live_turn 10 分钟后从注册表丢掉:完成/取消后仍可重连回放,超时释放事件缓冲,删会话立刻清掉。

  • live_turn 事件缓冲和订阅队列有上限:运行中不再按 token 数无限 append;连续 content/thinking delta 在缓冲里合并;慢订阅者队列满则断开,让客户端按 after=seq 重连,避免长 /goal + 多标签页把网关打到 OOM。

  • Steer 打断思考时上一张思考卡片停止计时:插话把思考切到下一张卡,但上一张 ms 没冻住,墙钟还在涨。现在插入 steer 或开新思考切片都会 finishThink

  • Web 侧栏按会话创建时间排序:jsonl 首行 first_timestamp 是第一次请求。GET /api/sessions 和侧栏都按它倒序(新在上),发消息不再把老会话顶上去;「3d」小字也是创建时间,不是最后活动。Project 分组按该目录第一次出现会话的时间排,给旧项目加 New Chat 不会把它顶到最上面。CLI /resume 仍按 mtime 倒序。

  • Web 对话不再狂打 /api/workspace/stat:消息底部的文件卡片原先跟着流式正文每一帧重抽路径,数组换了引用就 POST 一次,长回答会打满日志。现在流式期间不查;路径集合没变也不查;同一帧里多条消息合并成一次请求。

  • Web 工具调用一开始就上屏:思考是流式的,但 execute 这类要跑一会儿的工具要等完成才出现——flushStream() 以前只在有挂起的 rAF 时才 bump(),思考停了之后那条 tool_call SSE 改了数据却不重绘。现在结构事件立刻绘制。

  • Web 回答过程闪屏:每 token 整段 Markdown 重挂载(components={{}} 每次新对象)、.bub pre{transition:all .2s} 让代码块从 0 高度动画出来。改成 120ms 节流、冻结的 ChatMarkdown(流式跳过高亮/KaTeX,结束后高亮一次)、光标改成独立 caret,去掉 pre 的全属性 transition。

  • Web 工作组耗时按思考 + 工具切片求和:组头原先用「第一刀到现在」的墙钟,思考 step 又不冻 ms,最后一轮在回答已经结束后仍因 isLast 每秒刷新,总时长跟着墙上的钟涨。现在每段思考结束就记下切片,组头 = 各思考耗时 + 各工具耗时;思考行也显示这段时长。回答生成时间不再算进运行过程。

  • Web tool result 不再 500 字截断:网关原先一律截成 500 字,前端再 slice(0, 8000) 且完成后默认折叠,所以 execute 的 stdout 看起来像没了。只有 read_file / glob / grep 成功时不展开结果(本地读文件,调用行够了);write_file / apply_patch / write_todos / web_search / fetch_url / save_memory / search_memory / execute / task 等展开时同时展示完整入参和结果(write_file / apply_patch 不再只送行数摘要),默认展开,只有超过 10 万字才截。task 不再收成只有 tool_count_task_meta JSON,展开子 agent 的逐步调用和完整回答。出错的结果一律展示。

  • 没有 rggrep 的 context 不再静默失效:纯 Python fallback 原先丢掉 context_lines / before_context / after_context,模型传了 -C 3 却只拿到匹配行。现在按 rg 同样的优先级切片(context_lines > 0 忽略 before/after,重叠窗口合并,组间 --)。

  • Web /compact 发出后立刻显示用户那一行,压缩完成前不能再发:以前要等压缩 API 回来才把 /compact 写进对话,期间发送按钮也不算 busy,于是用户以为没发出去再敲一次,第二条撞上 session 锁变成「already has an active run」。现在用户气泡马上出现;压缩期间 Enter / 发送键挡住(不是发出去再 409)。普通对话和 /skill 本来发出去就上屏,这条没改。

  • 对话 footer 和轨迹同一轮的 tok/s、耗时对不上:footer 用整段 chat_stream 墙钟(含建 agent)当分母,10 token / 3.6s 显示成 2.8 tok/s、耗时再四舍五入成 4s;轨迹用 jsonl 里 request 的 LLM 时间,同一轮是 5.3 tok/s / 1.90s。现在 done 带上 last_completed_roundduration_ms / llm_ms / tps(跟 View trace 同一套分析),footer 用 LLM 时间算 tok/s、用 round 墙钟显示耗时。两边共用 fmtDurationMs(不到 10s 两位小数)和 fmtTps(一位小数)。

  • 轨迹页顶栏的 git 分支和工作目录是会话自己的,不是 gateway 进程的:jsonl 原先每条都盖 os.getcwd() 和进程里的 git branch,网页会话于是一律显示 git:main…/Codes/agentica。现在按会话 work_dir 打戳、在那个目录探分支;没有 git 就不显示 git:。已写出的旧记录打开轨迹时也用会话目录覆盖。