Skip to content

Feat/meituan living assistant expert 内置美团生活助手专家 - #328

Merged
jubaoliang merged 4 commits into
TencentCloud:developfrom
miaowmint:feat/meituan-living-assistant-expert
Aug 19, 2026
Merged

Feat/meituan living assistant expert 内置美团生活助手专家#328
jubaoliang merged 4 commits into
TencentCloud:developfrom
miaowmint:feat/meituan-living-assistant-expert

Conversation

@miaowmint

@miaowmint miaowmint commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

内置「美团生活助手」专家模板(领券 / 搜索 / 下单全流程),并修复 Linux 部署下登录二维码缺失的问题。

Image_2026-08-18_20-59-20_pw2ls5dn 5lt Image_2026-08-18_20-59-54_jo4aswuy 3cr Image_2026-08-18_21-00-05_0ft2k4rk 5yj Image_2026-08-18_21-06-20_zgn2mosf cth Image_2026-08-18_21-08-49_z4dovwsm wfd Image_2026-08-18_21-09-02_4ek1v2qj p4n

Target branch

  • Base is develop (feature / fix — default)
  • Base is main (release/* or hotfix/* only)

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactor / chore
  • Release / hotfix

Test plan

  • make all passes locally
  • Added/updated tests

Checklist

  • Updated CHANGELOG.md (if user-facing)
  • README / docs updated (if needed)

新增专家模板 meituan-living-assistant(领券下单找我):
- manifest.json:双语元信息、美团黄主题色、4 个快捷指令
- SOUL.md:角色人格与触发范围
- skills/meituan-deals/SKILL.md:完整流程状态机
  (意图识别 → 扫码登录 → 领券/搜索/下单,含话术模板与错误码映射)
- scripts/:run.js 统一 CLI 入口(领券/搜索/下单/定位/认证)

Octop 适配改造:
- Token 存储支持 OCTOP_AUTH_DIR 环境变量注入,实现多 Agent 凭据隔离
  (run.js / auth.py / diag_*.py,未注入时回退原默认目录)
- Python 解析优先使用 Octop 自托管 venv
  (OCTOP_PYTHON > $OCTOP_HOME/venv > /app/.venv > PATH 兜底)
- npm bin 执行位自愈:专家模板经字节流播种后自动恢复 chmod +x
- 定时领券改用 Octop 定时任务体系,替代原 crontab + state.json
- dashboard iconForName 补充 utensils / bell 图标映射

来源:CodeBuddy 插件 meituan-living-assistant v1.0.2(美团官方)
Docker 镜像(python:3.12-slim)无 Node/npm,无法在 init 时安装
mtuser-pt-passport tgz。将预装好的 node_modules 产物随专家模板分发,
并精确反排除该子树(其余 node_modules 仍被忽略,不受影响)。
- run.js qrcode 命令:服务端接口失败时本地兜底(qrcode 库 PNG data URI
  → ASCII 字符画降级 → pip 自动安装重试),支付链接拦截保持不变
- 新增 qr_local.py:本地二维码生成(PNG/ASCII 双模式,JSON 输出)
- SKILL.md Step 1.2:取消 miniprogram 客户端不生成二维码的限制
  (Octop Web 控制台跑在 Linux 会被误判为 miniprogram,实际可扫码);
  登录消息模板增加裸链接行,方便复制
- run.js 帮助文本同步更新
- Optional[X] → X | None(UP045)、导入排序(I001)、移除未用导入(F401)
- try/except/pass → contextlib.suppress(SIM105)
- if/else → 三元表达式(SIM108)、歧义变量名 l → ln(E741)
- Qclaw_USER_ID 大小写为版本差异刻意保留,加 noqa(SIM112)
- ruff format 统一格式(含 qr_local.py)

make lint 本地全量通过:All checks passed
@jubaoliang
jubaoliang merged commit 37f612e into TencentCloud:develop Aug 19, 2026
3 checks passed
@miaowmint
miaowmint deleted the feat/meituan-living-assistant-expert branch August 20, 2026 11:27
jubaoliang added a commit that referenced this pull request Aug 21, 2026
* feat(skills): allow Unicode skill names with filesystem-safe validation

The create-form name pattern rejected CJK and other non-ASCII input,
while source mode (and the recording workflow, which derives names
from user titles) accepted them - the backend slug validator only
rejects path-hostile names. Octop targets non-technical users, so the
name field should not force ASCII slug conventions.

- Replace the ASCII whitelist with a blacklist: reject only
  filesystem-hostile characters (/ \ : * ? " < > |, control chars),
  a leading dot, empty names, and names over 64 chars
- Apply the same check to source-mode creation (frontmatter name),
  aligning both editor modes
- Skip the check on edit: updateSkill keeps the existing slug, so
  legacy skills with odd names stay editable
- Update zh/en namePattern copy and the placeholder examples

* fix(chat): strip media-offload placeholder text from image history

The MediaOffloadMiddleware writes a '[image offloaded: sha=… path=… size=…B
mime=…; use read_file to retrieve bytes]' placeholder text block into
LangGraph checkpoint state on every turn after the first one. That text is
meant for the LLM to read_file the bytes back, not for the dashboard UI —
after leaving and re-entering a chat, the user's image showed this internal
text underneath it.

On history serialization, strip the offload placeholder and the LLM-only
'User sent an image.' sentinel for user messages that carry an image in
octop_inbound_attachments (the original image is rendered from there). The
user's own caption is preserved. Pure-image user messages keep their entry
(with empty content) so the dashboard still renders the attachment.

* fix(dashboard): prevent AGENT_NOT_RUNNING race when saving page config (#293)

Editing an expert's 页面配置 (welcome message + quick-start cards) and
clicking 保存 surfaced "此专家未启用" (AGENT_NOT_RUNNING) on every save
after the first. Two failures combined to cause it:

1. PATCH /agents/{aid} schedules a background harness reload
   (arebuild_agent = aremove_agent + slow acreate_agent compile, often
   2-5s on Windows). During that window the agent is absent from the
   harness registry, but the DB row still says 'running'.
2. The manifest write was placed BEFORE the PATCH, so the first save
   landed before the reload started and worked. But every subsequent
   save (re-opening the drawer, expanding 页面配置, editing, saving
   again) hit the reload window from the previous PATCH — and
   require_running_workspace raised AGENT_NOT_RUNNING. The
   'manifest before PATCH' ordering alone only protects the within-save
   race, not the cross-save one.

Reproduction (live server, ENPKA2, 10 rapid saves with the WIP order):
2/10 manifest writes succeeded; 8/10 failed with AGENT_NOT_RUNNING.
First save after a 3s wait: 10/10 succeeded — confirms the reload
window is the cause.

Fix:
- Add writeManifestWithRetry (10 × 500ms = up to 5s, retries only on
  AGENT_NOT_RUNNING). Re-running for 5s is well within typical reload
  windows; the manifest is best-effort.
- Wrap the manifest write in its own try/catch. On failure show a
  warning toast (yellow, with i18n key experts.manifestWriteFailed) so
  the user knows, but never block the PATCH — the agent's main config
  must always save. The drawer still closes and the success toast still
  fires after the PATCH.

Scope of the change:
- New: WelcomeConfig.tsx (the 页面配置 editor, used by EditAgentDrawer).
- New: index.module.less styles for WelcomeConfig.
- Modified: EditAgentDrawer.tsx (render the new collapse section, save
  the manifest with retry, fall back to a warning).
- New i18n keys: experts.pageConfigTitle / welcomeMessageTitle /
  welcomeMessagePlaceholder / quickPromptsTitle / addQuickPrompt /
  quickPromptTitle(Placeholder) / quickPromptDescription(Placeholder) /
  quickPromptContent(Placeholder) / quickPromptColor / quickPromptIcon /
  quickPromptPreview / noQuickPrompts / noIcon / manifestWriteFailed
  in both zh.json and en.json; also backfilled experts.patchFailed in
  zh.json (was missing).

Out of scope (pre-existing, surfaced during review):
- WelcomeConfig's useImperativeHandle has no deps array — works
  correctly via closure but recreates the handle each render.
- loadConfig() runs on mount; a click on 保存 during the load would
  write the empty initial state to manifest.json. Not addressed here.

Verified: end-to-end against the live server, agent ENPKA2 and S35JZD,
after a 3s settle the 2nd save succeeds on retry attempt 2 (~25ms after
the first failed attempt), and 5 rapid back-to-back saves all land
without surfacing a red error to the user.

Co-authored-by: Georgyhongbo <georgyhongbo@users.noreply.github.com>

* fix(chat): stop message-list jitter while typing during streaming (#303)

adjustHeight() measured the live textarea by collapsing it to height:auto on
every keystroke. That transient shrink reflows the flex layout and grows the
message-list viewport (a sibling above the composer) for a moment; browsers
clamp the list scrollTop to the larger viewport and the clamp STICKS after the
height is restored. While a reply streams, the follow-to-bottom pin then snaps
the list back down — the per-keystroke up/down jitter.

Measure content height on a detached clone instead (cloneNode + position:fixed
off-screen), so the live layout is never disturbed. Skip the write when the
target height is unchanged (<0.5px). Verified with a frame-by-frame harness:
typing-while-streaming bottom gap dropped from avg 8.6px/max 14px to 0.0/0.0.

Co-authored-by: jubaoliang <jubaoliang@gmail.com>

* fix(plugins): sanitize non-ASCII tool names for strict LLM tool-name APIs (#308)

Plugin tools registered with Chinese names passed straight into the
function-calling schema and failed on APIs that require
^[a-zA-Z0-9_-]{1,64}$. Rewrite illegal names to legal pinyin
transliterations (underscore fallback when pypinyin is unavailable),
dedupe collisions with _2/_3 suffixes, and keep the original name in a
[原名: ...] description prefix. Config keys and plugin-side closures
still use the original names, so routing and per-agent tool config are
unaffected.

Co-authored-by: jubaoliang <jubaoliang@gmail.com>

* Feat/自定义主题色 (#334)

* feat(dashboard): custom brand color palette with color picker

Extend the 8 curated brand palettes with a 9th "custom" entry driven by
a user-chosen hex color:

- PaletteSwitcher gains a custom swatch plus a native color input
  (round swatch); picking a color switches the theme to "custom"
- The full Ant Design brand token set and all brand-tinted CSS
  variables (~30 tokens incl. bubble gradient, sidebar, row-selected,
  shadows) are derived from the single hex at runtime:
  - solid states are darkened until white text reaches WCAG AA (4.5:1)
  - dark-mode text/links are lightened until readable on #0f1117
- customColor is persisted alongside preference/palette in the shared
  `theme` localStorage key (normalized to lowercase #rrggbb; invalid
  values fall back to the default #4B74FA)
- ThemeContext injects the derived CSS block via a reusable
  <style id="octop-custom-palette"> element, refreshed on
  color/mode change; curated palettes are unchanged
- charts (TokenUsage, Memory overview) resolve the custom brand via
  brandPrimary(palette, isDark, customColor)

* fix(dashboard): unify custom color into one swatch and extend to expert colors

Address three usability issues from the first custom-color iteration:

1. Single control instead of two: the theme palette row now shows ONE
   custom swatch (rainbow conic-gradient hint). Clicking it opens the
   Ant Design ColorPicker — pick from the palette or type a hex code;
   the chosen color fills the swatch and activates the custom palette.
   The separate "custom swatch + native color input" pair is gone.

2. Smooth picker: replaced the laggy native <input type="color"> with
   antd 5 ColorPicker (palette + gradient + hex input, dark-mode aware).

3. Expert colors get the same feature: ExpertColorPicker (create/edit
   expert, subagent form) now accepts a hex value and exposes the same
   custom swatch; callers hold palette-key-or-hex strings and persist
   custom hex directly to agent config / subagent frontmatter. A small
   hex readout shows the active custom color.

Also raise workbox maximumFileSizeToCacheInBytes to 3 MiB — the antd
ColorPicker color engine pushed vendor-antd past the 2 MiB default,
which silently dropped it from the PWA precache and failed the build.

* fix(experts): keep custom expert color selected when reopening settings

The edit drawer reloaded agent details after mount and mapped the stored
color with resolveExpertPalette(), which snaps any hex to the nearest
curated swatch — so a saved custom color displayed as the closest preset
instead of the custom swatch.

Add parseStoredColor(): exact-match a curated swatch hex back to its
palette key, keep any other valid hex as-is (custom), return null for
invalid values. Both drawers and the initial state now round-trip
custom hex without snapping.

* fix(voice): MiMo TTS low-latency streaming, voice preset fix, TTS auto-activate (#331)

1. TTS providers now auto-activate after configuration when the active
   TTS is still "browser", mirroring the existing STT behavior.

2. Remove the invalid "mimo_default" voice option (not a valid MiMo
   preset voice ID). The UI defaults to 冰糖; the backend maps legacy
   "mimo_default" configs to 冰糖 so existing setups keep working.

3. MiMo TTS low-latency streaming end to end:
   - Backend: request pcm16 + stream, parse SSE audio chunks and wrap
     them in a live WAV container (24kHz PCM16LE mono)
   - Router: return audio/wav for mimo, audio/mpeg otherwise
   - Frontend: stream the response via requestStream and play chunks
     incrementally with WebAudio (WavStreamPlayer), falling back to the
     buffered blob path for non-WAV providers

* Feat/meituan living assistant expert 内置美团生活助手专家 (#328)

* feat(experts): 内置美团生活助手专家

新增专家模板 meituan-living-assistant(领券下单找我):
- manifest.json:双语元信息、美团黄主题色、4 个快捷指令
- SOUL.md:角色人格与触发范围
- skills/meituan-deals/SKILL.md:完整流程状态机
  (意图识别 → 扫码登录 → 领券/搜索/下单,含话术模板与错误码映射)
- scripts/:run.js 统一 CLI 入口(领券/搜索/下单/定位/认证)

Octop 适配改造:
- Token 存储支持 OCTOP_AUTH_DIR 环境变量注入,实现多 Agent 凭据隔离
  (run.js / auth.py / diag_*.py,未注入时回退原默认目录)
- Python 解析优先使用 Octop 自托管 venv
  (OCTOP_PYTHON > $OCTOP_HOME/venv > /app/.venv > PATH 兜底)
- npm bin 执行位自愈:专家模板经字节流播种后自动恢复 chmod +x
- 定时领券改用 Octop 定时任务体系,替代原 crontab + state.json
- dashboard iconForName 补充 utensils / bell 图标映射

来源:CodeBuddy 插件 meituan-living-assistant v1.0.2(美团官方)

* fix(experts): gitignore 放行美团专家随包的 pt-passport 运行时

Docker 镜像(python:3.12-slim)无 Node/npm,无法在 init 时安装
mtuser-pt-passport tgz。将预装好的 node_modules 产物随专家模板分发,
并精确反排除该子树(其余 node_modules 仍被忽略,不受影响)。

* fix(experts): 美团专家登录二维码三级兜底与可复制裸链接

- run.js qrcode 命令:服务端接口失败时本地兜底(qrcode 库 PNG data URI
  → ASCII 字符画降级 → pip 自动安装重试),支付链接拦截保持不变
- 新增 qr_local.py:本地二维码生成(PNG/ASCII 双模式,JSON 输出)
- SKILL.md Step 1.2:取消 miniprogram 客户端不生成二维码的限制
  (Octop Web 控制台跑在 Linux 会被误判为 miniprogram,实际可扫码);
  登录消息模板增加裸链接行,方便复制
- run.js 帮助文本同步更新

* style(experts): 修复美团专家脚本 ruff lint 错误

- Optional[X] → X | None(UP045)、导入排序(I001)、移除未用导入(F401)
- try/except/pass → contextlib.suppress(SIM105)
- if/else → 三元表达式(SIM108)、歧义变量名 l → ln(E741)
- Qclaw_USER_ID 大小写为版本差异刻意保留,加 noqa(SIM112)
- ruff format 统一格式(含 qr_local.py)

make lint 本地全量通过:All checks passed

* fix(dashboard): adjust CronJobs table layout for better content display (#326)

- Set max-width for promptCell to 280px to prevent long instructions from stretching rows.
- Change table scroll behavior to 'max-content' for improved responsiveness.
- Update task type rendering to ensure consistent display with nowrap styling.

These changes enhance the user interface by maintaining a clean layout and improving readability of task types.

* fix(dashboard): move update progress/result prompts above release notes (#332)

The upgrade progress bar and the "upgrade complete / restart required"
prompts rendered below the (default-expanded) release notes collapse,
pushing them out of the viewport with no visible cue — easy to miss.

Reorder the panel: progress / result prompts now render directly under
the action buttons (check / restart / upgrade), above the release notes.
No logic changes; the two blocks are independent (both use margin-top).

* feat: show memory slimming progress on chat and agent status (#321)

* feat: show memory slimming progress on chat and agent status

Expose memory_maintenance from the agent status API and pause send
while this agent's SQLite is being compacted.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(deps): 刷新 uv.lock —— harness 升级 + 补齐 pyproject 已声明但未锁的依赖

diff 有 5300 余行,但实质内容变更仅 5 条,其余全部是 uv 0.8.20 的锁格式重写
(revision 1 -> 3,为每条 sdist/wheel 记录追加 upload-time 字段,约 2600 条)。
schema 的 version 字段保持为 1 未变,按 uv 文档 revision 属向后兼容变更,
旧版本 uv 读取不会报错。

实质变更:
- orcakit-harness-agent  0.9.20 -> 0.9.21
- harness-memory         0.9.5  -> 0.9.6
- harness-browser        0.7.4  -> 0.7.5   (pyproject 已要求 >=0.7.5)
- octop                  0.9.23 -> 0.9.24  (版本号跟进)
- 新增 pypinyin 依赖声明                    (pyproject 已声明 >=0.53)

后三条是在修既有问题:此前 pyproject 加入 harness-browser>=0.7.5 与 pypinyin
后未重新锁定,HEAD 上的 uv.lock 执行 uv lock --check 会失败。CI 的 make install
走 uv sync 且未加 --locked/--frozen,会在 runner 内自行重新解析,因此锁文件失配
不会让 CI 变红——这也意味着 CI 当前并未验证锁定的版本组合。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* typecheck

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* fix(chat): hide stale scroll-to-bottom button after dock close (#304)

A layout clamp (dock open/close, content shrink) can rewrite scrollTop to
the bottom without a user gesture. Previously this could leave free mode
active with a stale jump-to-bottom control while the user is pinned to the
bottom, or surface the control after the dock interaction with no correction.

- Pass gapToBottom + atBottomBandPx to shouldEnterFreeModeOnScrollUp so a
  scroll-up whose resulting position stays inside the bottom band is treated
  as a layout clamp, not user intent.
- Re-check position on scroll-up and after resize in free mode: landing
  inside the bottom band resumes follow mode and hides the control.

* feat(experts): allow custom agent id when creating experts (#333)

Users could not choose the agent id when creating an expert (bundled,
published, or SkillHub market) — a random 6-char id was always
generated, making workspaces under ~/.octop/agents/ hard to identify.

Backend:
- Expose optional `agent_id` on all three creation endpoints
  (POST /agents/from-expert/{id}, POST /experts/hub/{slug}/install,
  POST /experts/published/{id}/install) and thread it through
  SkillHubMarketAgentCreateOptions / PublishedExpertInstallOptions.
- Add validate_custom_agent_id(): 3-64 chars of [a-zA-Z0-9_-], must
  start/end with a letter or digit; reserved words (api/admin/agents/
  experts) rejected — the id becomes a workspace directory name, so
  separators/dots/unicode are refused to keep every downstream path
  and URL usage safe.
- New ErrorCodes AGENT_ID_INVALID (400) / AGENT_ID_TAKEN (409) with
  zh/en messages, replacing the generic AGENT_BUSY on duplicates.

Dashboard:
- "Custom ID (optional)" input on the create-expert drawer (shared by
  all three sources) with live format + reserved-word validation and
  a hint that it cannot be changed after creation.

Omitting the field keeps the previous auto-generated short id.

* fix(channels): add missing internal scroll to channels panel in fill layout (#340)

The Personalization channels tab clips overflowing cards when the page is
zoomed: the fill layout's fillChild is overflow:hidden and ChannelsPanel
had no flex:1 nor a scroll container between the toolbar and the card
grid, so cards pushed below the viewport could never be reached.

Mirror the Skills tabbedBody pattern: pin the toolbar, wrap the grid (and
the loading skeleton) in a scrollable body (flex:1, min-height:0,
overflow:auto, 8px top padding so card hover lift stays inside the
scrollport). Mobile keeps page-level scrolling via a max-width:767px
override, matching fillChild. The Experts ChannelCatalogDrawer embed is
unaffected (block wrapper makes flex:1 inert; auto-height overflow does
not scroll).

* feat(expert): extend meituan-living-assistant to 6 quick prompts (#344)

Add two more quick start prompts to the built-in meituan-living-assistant
expert (drinks search and group-buy ordering), plus the coffee and
shopping-bag icons in the dashboard icon map.

* fix: inject Admin env into running agents and sum turn token usage (#345)

Running shells and Docker sandboxes now pick up ~/.octop/env (and workspace .env) without a full reload; MCP stdio no longer inherits the entire host environment. Usage accounting adds every model call in the turn, and workspace I/O survives the harness rebuild window.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dashboard): hide cron session routing when using a fresh thread (#347)

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix/agent env usage workspace (#351)

* fix: inject Admin env into running agents and sum turn token usage

Running shells and Docker sandboxes now pick up ~/.octop/env (and workspace .env) without a full reload; MCP stdio no longer inherits the entire host environment. Usage accounting adds every model call in the turn, and workspace I/O survives the harness rebuild window.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: schema v7 identity, expert profiles, chat artifacts, and KB citations (#346)

* feat: schema v7 identity, expert profiles, chat artifacts, and KB citations

Fold integer PKs plus public string ids, document folders, agent profile columns, and thread artifacts into v7 SQL (not only Python helpers). Experts get workspace avatars and a single welcome_message; chat keeps file changes across sessions, shows knowledge citations, and can drag workspace files.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: drop cron JobDrawer UX from the schema v7 PR

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: prefer tool-arg paths when recording chat artifacts

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(gateway): upgrade to 0.9.3 (#353)

Co-authored-by: leoxyang <leoxyang@tencent.com>

* fix(usage): add cache-aware token accounting (#352)

Co-authored-by: leoxyang <leoxyang@tencent.com>

* fix(cli): force utf-8 stdio so octop init does not crash on GBK consoles (#348)

Chinese Windows (GBK/cp936) encode piped/redirected CLI stdout with the
ANSI code page, so the checkmark success message in `octop init` raised
UnicodeEncodeError after the DB and admin user were already created.
Re-encode stdout/stderr to utf-8 at the CLI entry to cover the whole bug
class (init, stub, QR art, future emoji).

Add 3 unit tests (tests/unit/cli/test_main_encoding.py): two for the
guard helper and an end-to-end `octop init` run under
PYTHONIOENCODING=gbk. pytest -m "not live" passes locally; the 12
failures are pre-existing Windows/db-migration environment issues,
unchanged by this patch.

* 修复onnx向量模型调用 (#360)

Co-authored-by: jubaoliang <jubaoliang@gmail.com>

* fix(skills): keep sibling files when editing a skill's SKILL.md (#365)

PUT /agents/{aid}/skills/{name} deleted the whole skills/<slug>/
directory before writing back the request payload. The dashboard
editor sends only the SKILL.md content, so saving an edit on an
imported multi-file skill (ZIP / SkillHub) wiped README.md,
references/, workflows/ and every other sibling, leaving a lone
SKILL.md behind.

A content-only update now rewrites just the manifest in place. A
full files payload still replaces the directory wholesale,
matching create-with-overwrite / re-import semantics (and the
truthiness check mirrors _files_from_skill_body so an empty
files list falls back to the content path on both sides).

* Feat/tencentcloud api expert (#370)

* feat(experts): add tencentcloud-api built-in expert

Port the standalone tencentcloud-api expert package into the Octop
bundled expert library:

- manifest.json: id/label/description/welcome/icon/color, prompt_files
  (SOUL.md) and five quick prompts (list CVM, launch pay-as-you-go CVM,
  security group, all-region scan, error diagnosis)
- SOUL.md: persona covering intent -> API-doc retrieval -> tccli command
  construction, safety guardrails (confirm-before-change, cost alerts,
  irreversible-delete warnings), disambiguation rules, identity
  confirmation (GetCallerIdentity) and output conventions
- skills/tcapi/: full SKILL.md workflow (env probe, doc retrieval via
  cloudcache, credential dual-path, call & JSON-safe parsing, error table,
  python fallback) plus references/ (auth/install/refs)

The catalog discovers it automatically at server start via
ExpertCatalog.refresh() scanning library/<id>/manifest.json.

* feat(experts): prefer Octop venv tccli, add 6th quick prompt, automate OAuth

Three improvements to the tencentcloud-api expert:

1. venv-first tccli resolution (SKILL.md Step 0 / Step 5,
   references/install.md): locate the Octop virtualenv via the running
   octop process (/proc/<pid>/cwd), probe venv tccli -> PATH ->
   auto-install into the venv with uv. Fallback python invocation in
   Step 5 now prefers the venv interpreter over system-wide probing.

2. Fully automated OAuth flow (SKILL.md Step 2): run
   'BROWSER=echo tccli auth login' in the background so headless
   environments don't abort, extract the authorize URL from the log,
   surface it to the user, poll until the browser callback completes,
   then verify credentials and echo identity via GetCallerIdentity.
   Legacy tccli without 'auth login' is auto-upgraded in the venv
   before retrying. Error table updated accordingly. SOUL.md synced.

3. Sixth quick prompt '账号登录授权' in manifest.json for one-click
   sign-in with identity echo.

* fix(experts): use credential-file mtime as OAuth success signal, never block-poll

Real-world test feedback: the user completed browser authorization
successfully, but the agent misjudged it as 'timed out because the user
hasn't completed authorization' and re-issued a fresh login link (which
invalidated the completed one).

Root cause: the SKILL's wait loop (300 x 1s kill -0 polling) holds the
tool call open until the agent's per-call execution timeout kills it.
A tool timeout is NOT a login failure, but the agent conflated the two.
Meanwhile the backgrounded 'tccli auth login' kept running: the OAuth
callback landed and the credential was written to
~/.tccli/default.credential (verified: file existed, type=oauth,
GetCallerIdentity returned the account).

Changes (SKILL.md Step 2.2, error table, SOUL.md, references/auth.md):

- Success criterion is the credential file mtime, not process exit:
  record a baseline before handing the link out, then compare after the
  user reports back. Log line '登录成功, 密钥凭证已被写入' is an
  equivalent signal.
- Forbid long blocking polls: hand the link to the user, keep probing
  windows short (<=30s), return control to the conversation, and confirm
  via file mtime + GetCallerIdentity on the next turn.
- Never re-run 'auth login' when the credential file already updated:
  a new login invalidates the previous (already authorized) link and
  forces the user to click again.
- On TokenFailure/RefreshTokenError, check the credential file first
  before declaring it invalid (the previous attempt may have succeeded
  and been misjudged).
- Document the remote/callback caveat: OAuth redirects to
  localhost:9000-9100 on the tccli host; when the user's browser is not
  on the same machine (server deployments), the callback cannot reach
  tccli — fall back to copying the oauth credential file or manual
  'tccli configure'.

* chore(experts): move sign-in quick prompt to first position

Put '账号登录授权' (fully automated OAuth sign-in with identity echo)
at the top of the quick prompts so new users authorize first, then
explore the resource-management prompts.

* feat(experts): actively listen for OAuth callback instead of waiting for user reply

Previously after handing out the authorize link the agent ended its
turn and only verified on the user's next message. Now the agent keeps
bounded listening windows on the credential file so the moment the user
clicks 'authorize' in the browser, the flow continues automatically —
zero user replies needed.

Listening protocol (SKILL.md Step 2.2 / SOUL.md / references/auth.md):

- One listening window: compare mtime of
  ~/.tccli/<profile>.credential against /tmp/tccli_auth.log every 3s,
  up to 60s per window (must stay below the tool execution timeout).
  Credential newer than log -> AUTH_DONE, verify immediately.
- Window expiry is NOT failure: never re-issue the link (that would
  invalidate the user's in-flight authorization), just open another
  window (3-5 windows ≈ 3-5 min total), then optionally return control
  to the conversation and confirm via the verification script later.
- Verification scheme unchanged (authoritative): credential mtime >
  login-log mtime, then 'tccli sts GetCallerIdentity' identity echo.
- Baseline uses the login log's mtime instead of a shell variable
  because shell state does not survive across tool calls.
- Tool timeout of a listening window still != login failure: run the
  standalone verification script afterwards, judge by the credential
  file only.

Dry-run validated: link extraction, silent window expiry with no
credential, and both verification branches behave as specified.

* feat(experts): add clinical learning subscription assistant (#369)

* feat(experts): add clinical learning subscription assistant

基层医生学习小助手专家包(26 个文件):
- 通用助手 + 医学学习安全域作用域隔离,通用能力不被医学规则误伤
- 8 个 skills:指南学习/章节展开/学习路径图/备考选材/医保回顾/学习诊断/更新提醒/来源核验/登记
- 输出校验器按模块作用域生效;反绕过规则(创作包装不改变内容性质)
- 自包含:脚本仅标准库依赖,可整包迁移

附专家包模板测试。

* feat(experts): progressive disclosure + registration-first bootstrap + py3.9 compat

- SOUL 瘦身(14.7kB→12kB):能力细则下沉回各 skill,保留身份/禁令/安全域/分流
- SOUL 新增新用户识别:主动引导登记,个性化功能先登记
- BOOTSTRAP 重写为登记优先短流程(含首条回复示例),用户可拒绝不纠缠
- AGENTS 新增医学输出四条硬格式(模板头/来源行含正例/边界声明/禁编造)
- 子代理定义补格式要求;审校员必查项加格式合规
- clinical_profile.py 兼容 Python 3.9(datetime.UTC→timezone.utc)
- 三处统一:脚本失败只报告,禁止手改 USER.md/state.json

* feat(experts): enable daily guideline learning via weak-dedup cron protocol

- clinical_profile.py 新增 delivery-check/delivery-record:按逻辑日期幂等去重,
  记录后自动推进单元;兼容 Python 3.9(_UTC 运行时解析)
- cron-presets.json 每日学习预设从 blocked 改为 enabled_weak_delivery,
  prompt 内嵌防重规程(查重→校验→记账→输出)
- SOUL/AGENTS/guideline-learning/doctor-registration 解锁通用 cron 投递,
  统一弱投递口径:账本只防重复、不是送达回执、不宣称已确认送达
- 订阅任务创建默认微信通道,创建后核对绑定并如实告知
- 新增弱投递账本测试(幂等+推进)

* feat(experts): expand evidence whitelist with official and semi-official sources

Add verified domains per source-tier rules (V2.0 doc section 9.2):
- S-tier official: cde.org.cn (CDE), cdr-adr.org.cn (ADR monitoring)
- A-tier societies: cmda.net (CMDA), cpma.org.cn (CPMA)
- Semi-official: cha.org.cn, csco.org.cn, cnsoc.org, pmph.com

* fix(experts): drop wechat-only gate for clinical subscription cron

平台 cronjob_create 自动绑定当前会话通道(微信/QQ/dashboard/CLI),
无需微信绑定门禁。移除 cron-presets.json 的 :weixin:/allow_dashboard
门禁、AGENTS.md §4.7 与 doctor-registration 流程的微信绑定要求,回执
统一为已启用并推送至当前会话通道。clinical_profile 默认值改为未创建并
对历史 state 兼容;simulate_weixin_flow 改为任意会话均可创建。每日指南
学习用通用 cron + 弱投递防重,选定指南轨道前不推送。新增 TEST_CASES.md。

* refactor(experts): progressive disclosure + skill routing + i18n + source policy

- 顶层精简去重:SOUL/AGENTS/BOOTSTRAP 互不重复,细则下沉 skill/reference
- 新增 skill:intent-routing(意图路由)、output-format(医学输出校验)、subscription-setup(订阅创建,从 doctor-registration 拆出)
- guideline-learning 改为流程约束,操作细则下沉 references/learning-operations.md
- BOOTSTRAP 渐进式入口(7-20骨架+当前需求),安全底线自含(首次SOUL不加载)
- 中文化:validate_output errors 改中文,manifest 删 en 只留 zh
- cron prompt 加输出约束(简体中文+静默执行+不输出思考),三 task 补 prompt
- 信源白名单 A/B/C/D 四级:新增 ndcpa/natcm/std.samr(B)、guidelines-registry(C)
- 删除 TEST_CASES.md

* fix(manifest): 恢复 en 字段(19 quick_prompts+welcome); fix(bootstrap): 首次开场话术改介绍+5项+隐私+征求同意

* fix(experts): tighten clinical source verification

* docs(experts): refine clinical assistant description

* fix(experts): improve clinical learning cycle completion

* perf(experts): speed up verified clinical guidance

* fix(experts): suppress preview validation preamble

* fix(experts): limit browser automation usage

* fix(experts): suppress validation status preambles

* feat(experts): add controlled secondary source fallback

---------

Co-authored-by: leoxyang <leoxyang@tencent.com>

* feat: workspace backend sandboxing, execute-env injection, and ephemeral image refs (#376)

* feat: workspace backend sandboxing, execute-env injection, and ephemeral image refs

Workspace file-I/O hardening across backend and dashboard:
- Host directory sandboxing via root_dir allow-list and denied prefixes
- Execute-environment defaults injected into harness backend specs
- Ephemeral workspace image rematerialization for model calls
- Attachment hint expansion and inbound store improvements
- Portable memory backend and skill workspace catalog updates
- Dashboard UI for agent backend fields and root-dir selection
- Bump harness-agent 0.9.23 / harness-memory 0.9.7; docs + install notes

* feat: add user invitation codes with admin management and redeem flow

- Add user_invites table (migration 009) plus SQLite/Postgres reconcile paths
- Add InviteRepo and InviteService for create/revoke/list/redeem
- Expose public validate/redeem endpoints and admin create/revoke/list routers
- Extract default-agent bootstrap into octop.infra.agents.default_agent
- Add invite error codes and en/zh i18n strings
- Dashboard: invite drawer, login redeem UI, users list, and locales

* fix: add Windows cross-platform guards for pre-existing sandbox/rootfs tests

- Guard POSIX/container-only tests (rootfs-absolute /.octop/... workspace
  paths) with posix_only in test_thread_artifacts.py and test_agent_manager.py
- Normalize the rendered workspace path assertion in test_octop_builtin_skills.py
  (forward slashes on Windows, not str(tmp_path) backslashes)
- Canonicalize ws_dir before the prefix check in attachment hint/path tests
  (tempfile may yield an 8.3 short path on Windows while the resolved
  attachment path uses the long form)

These failures predate the user-invites commit and are unrelated to it; the
product path logic is correct.

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>

* chore: release 0.9.25

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: chujieHong <2280628443@qq.com>
Co-authored-by: chujieHong <31946519+chujieHong@users.noreply.github.com>
Co-authored-by: Georgyhongbo <georgyhongbo@users.noreply.github.com>
Co-authored-by: 猫猫摸大鱼 <58991169+miaowmint@users.noreply.github.com>
Co-authored-by: liukewia <liukewia@gmail.com>
Co-authored-by: 薄生 <67680641+Bosheng0422@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Panda <163635413+Pandakingxbc@users.noreply.github.com>
Co-authored-by: leoxyang <leoxyang@tencent.com>
Co-authored-by: XiaoChen <1326713348@qq.com>
@jubaoliang jubaoliang mentioned this pull request Aug 22, 2026
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants