# @dsh-yzj/tool-yzj Model-facing Yunzhijia tools over `ctx.yzjBridge`. This package owns tool schemas, digest rendering, budget caps, and the structured UI payload projection; the CLI channel stays in `@dsh-yzj/bridge`. ## Tools | Domain | Tools | | ------ | ----- | | contact | `yzj_whoami` (`yzj-cli whoami`), `yzj_contact_search`, `yzj_contact_get` | | doc | `yzj_doc_workspace_list/get/create`, `yzj_doc_list/get/recent/create/folder_create/rename/move/delete/import/download_url`, `yzj_doc_search/write/download`, `yzj_doc_block_list/insert/update/delete/replace` | | sheet | `yzj_sheet_create/get` (`get` accepts `lite`), `yzj_sheet_table_get/create/rename/delete`, `yzj_sheet_record_list/create/update/delete` | | calendar | `yzj_calendar_event_list/get/create/update/delete/participants`, `yzj_calendar_room_find` | | im | `yzj_im_message_send/recall/list/search`, `yzj_im_group_recent`, `yzj_im_group_search/create/rename/members_add/members_remove` | | file | `yzj_file_upload`, `yzj_file_download` | Every tool returns `{ content, truncated, data }`: - `content` — the model-facing digest capped at `maxRenderChars` (rendered through `output.render`). - `data` — the capped structured payload projected through `output.presentationMeta`. **Never model-visible**; persisted with the session log (`tool/result` meta) so the browser UI reproduces the card on live and replay paths alike. ## Home binding (`ctx.yzjHome`) Durable group-room table: one Yunzhijia conversation (group or DM) ↔ one DSH host session (`yzj-home-*`) plus 0..N topic sessions (`yzj-topic-*`). Shared by robot inbound `followup()` and the workbench pick-group path (`/yzj home-open`). Domain `yzj_home_bindings` (storage-domain); a second open is focus (`created: false`), never a parallel row. `TopicAnchorStore` keys `(conversation, rootMsgId)` and stores `lastActivity` / `status` (`running` | `confirm` | `done`). **Bound message log** (domain `yzj_home_logs`, keyed by `yzjConversationId`): inbound ① and DSH「发进群」② live here — never as harness `Session.append` events. Rows keep a clipped CLI `param` snapshot (`file_id` / `desc` / reply) so the group-room view can reuse the floating-panel renderer (avatars, emoticons, images). `formatSummonWindow` is the shared digest. The window is planted **once** as a plugin user message (`agent.inject` / `agent/pre-step`, `plugin: yzj-summon-window`) — it is not a `systemPrompt.context` snapshot section (pitfall-031). Topics prefer the reply chain around the anchor. Memory stays on the `yzj-memory` snapshot. File rows print `fileId=` (`param.file_id`, never msgId). The digest always pins `groupId` and per-line `msgId` (topic sessions also pin the anchor `msgId`) so the model can call `yzj_im_message_send` / `replyMsgId`. See `docs/spec/dsh-home-transcript.md` §5.2 and pitfall-027 / 029. ## Approval guard `tools/pre-execute` gates writes that must never run unconfirmed. Strong: `yzj_doc_delete`, `yzj_doc_block_delete`, `yzj_sheet_table_delete`, `yzj_sheet_record_delete`, `yzj_calendar_event_delete`, `yzj_im_group_members_remove` (CLI `--yes` after the card), `yzj_im_message_recall` (CLI has no `--yes`; the product card is the only gate). Standard: `yzj_im_message_send`, `yzj_file_upload`, `yzj_file_download`/`yzj_doc_download` with `overwrite: true`, `yzj_doc_move`/`workspace_create`/`create`/`folder_create`/`rename`/`import`/`write`/`block_insert`/`block_update`/`block_replace`, `yzj_im_group_create`/`rename`/`members_add`, `yzj_sheet_*` writes, `yzj_calendar_event_create`/`update`. The guard broadcasts `yzj/ask-pending` and waits on `yzj/confirm-request` (ui-yzj write-gate answers; `{ kind: 'allow' }` / `{ kind: 'deny' }`). It does **not** return harness `{ kind: 'ask' }` — GUI Full access sets `approval: never`, which would auto-reject an ask before the waterfall runs (pitfall-036). Headless overlays without write-gate fail closed (`unavailable` → deny). yzj-cli 0.1.6 high-risk commands without `--yes` exit **10** (`confirmation_required`); 0.1.4 used exit 3 for the same signal. Auth miss is still exit 3 (`credentials_missing`). Never bash-call the CLI for writes. ## Config | Field | Default | Meaning | | ----- | ------- | ------- | | `timeoutMs` | `60000` | Cooperative timeout per tool call. | | `maxRenderChars` | `30000` | Cap on model-facing digest characters. | | `maxMetaChars` | `50000` | Cap on the UI presentation payload characters (after clipping). | | `backfillLimit` | `50` | Recent Yunzhijia messages pulled when opening a bound session. | | `summonWindowMessages` | `20` | Max log rows in one summon window. | | `summonWindowChars` | `4000` | Summon-window character cap. | | `logRetention` | `500` | Per-conversation log retention (oldest dropped). | ## Model Experience Read tools return one digest line per record with stable formats (`- [类型] 标题 (id) · 更新时间`); write tools return the operation summary plus the doc link (`https://www.yunzhijia.com/knowledge/lingee/#/store/doc/`) per the yzj-cli contract. Bridge failures render as `yzj