From e5f26a5540a40a68dc7e1b643767104df7f3af8d Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 7 Jul 2026 16:05:16 +0000 Subject: [PATCH] feat(query): document hybrid business wiki answers Teach wiki-query to split entity overview questions into an ordinary wiki context track and a read-only business facts track, then fuse the results. Update the MCP query prompt to explicitly allow read-only hybrid subagents while preserving public-only and mutating-command restrictions. Add a skill instruction regression test and update docs. Validation: python3 -m unittest tests/test_wiki_skills.py -v; python3 -m unittest tests/test_mcp_query.py -v; python3 -m unittest tests/test_business_facts.py -v; python3 -m unittest discover -v; python3 -m compileall obsidian_wiki tests scripts; git diff --check --- .skills/wiki-query/SKILL.md | 19 +++++++++++++++++++ README.md | 4 ++-- docs/business-facts.md | 2 +- obsidian_wiki/mcp_query.py | 1 + tests/test_mcp_query.py | 2 ++ tests/test_wiki_skills.py | 20 ++++++++++++++++++++ 6 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 tests/test_wiki_skills.py diff --git a/.skills/wiki-query/SKILL.md b/.skills/wiki-query/SKILL.md index 94d3bd1..2dbb78b 100644 --- a/.skills/wiki-query/SKILL.md +++ b/.skills/wiki-query/SKILL.md @@ -76,6 +76,25 @@ If it is a business facts query: 4. If the template or guarded SQL returns an answer, answer from that JSON result as structured business facts. Do not cite wiki pages unless you also used wiki pages for business context. Mention stale sync warnings when `is_stale` is true. 5. If the CLI/database is unavailable or the question is not a business facts query, continue with the normal wiki retrieval protocol below. +### Step 1b: Hybrid Business + Wiki Route (subagent split) + +Do not use hybrid mode when filtered mode is active. In filtered mode, skip business facts entirely and continue with ordinary filtered wiki-query retrieval. + +Use hybrid mode when the user asks for an entity overview, situation, background, profile, current status, or "大体情况" where both wiki context and business facts would materially improve the answer. Common examples: customer overview with recent orders, customer relationship status, product situation with order signals, salesperson activity with related customers/projects, or "告诉我一下某某客户的大体情况". + +For a hybrid query, spawn two subagents when the platform supports subagents: + +1. **ordinary wiki-query subagent** — run the normal wiki-query retrieval path only. Do not use business facts. Return concise narrative context with wiki citations: customer/project background, relationships, email-derived signals, risks, open questions, and pages consulted. +2. **business facts query subagent** — run only the business facts route. Load `obsidian-wiki business schema --json`, prefer templates such as `customer_summary`, `customer_order_list`, `breakdown_by_product` with `--customer`, `order_trend`/`sales_trend` with customer filters, or guarded `business sql` when no template fits. Return structured metrics, rows, `last_sync`, and `is_stale`. + +The main agent must wait for both tracks, then fuse the two results into one answer: + +- Lead with the business snapshot when available: recent order count, sales amount, main products, latest orders, trend, and data freshness. +- Then add wiki context: who the customer is, related projects/products, important relationship history, risks, and citations. +- Keep business numbers separate from narrative claims; cite wiki pages only for wiki-derived statements. +- If one track fails or has no data, still answer from the other track and state that gap. +- If subagents are not available, run the same two tracks sequentially and mention only material limitations, not internal tooling details. + ### Step 2: Index Pass (cheap) Build a candidate set *without opening any page bodies*: diff --git a/README.md b/README.md index bbc63d6..2376bb0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ obsidian-wiki setup --project . # also drop project-local skills + AGENTS.md int obsidian-wiki setup --copy # copy skill files instead of symlinking ``` -For operational questions such as "2026 年 6 月接了多少单", ask your agent with `wiki-query`. The `wiki-query` skill decides whether the question needs structured business facts, then uses the business template catalog or guarded read-only SQL before falling back to normal wiki retrieval. +For operational questions such as "2026 年 6 月接了多少单", ask your agent with `wiki-query`. The `wiki-query` skill decides whether the question needs structured business facts, then uses the business template catalog or guarded read-only SQL before falling back to normal wiki retrieval. For hybrid questions such as "某客户的大体情况", it splits the work into a normal wiki context track and a business facts track, then fuses the narrative context with recent order/customer metrics. When working from a cloned repo, `scripts/obsidian-wiki-ops.py` is the single repo-local operations entrypoint. It wraps common `obsidian-wiki` commands, Kingdee business sync/templates, the business sync timer, daily update, and the managed MCP service: @@ -327,7 +327,7 @@ Staging is for upload/intake only. The normal ingest flow should still classify ### Optional: Business Fact Queries -Operational counts and amounts belong in a structured fact database, not in markdown pages. The `business` CLI stores Kingdee sales orders in `/_meta/business-facts.sqlite`. Normal users should ask through `wiki-query`; the skill decides when to use structured business facts, prefers templates, and only falls back to guarded read-only SQL when no template fits. +Operational counts and amounts belong in a structured fact database, not in markdown pages. The `business` CLI stores Kingdee sales orders in `/_meta/business-facts.sqlite`. Normal users should ask through `wiki-query`; the skill decides when to use structured business facts, prefers templates, and only falls back to guarded read-only SQL when no template fits. For customer/product/person overview questions, `wiki-query` runs a hybrid path: one track gathers wiki context and citations, another gathers read-only business metrics, and the final answer keeps the two sources clearly separated. ```bash # Sync from an exported or API-fetched Kingdee JSON payload. diff --git a/docs/business-facts.md b/docs/business-facts.md index efeb654..c233ac7 100644 --- a/docs/business-facts.md +++ b/docs/business-facts.md @@ -95,7 +95,7 @@ Order upsert key: `order_id`, falling back to `order_no` when no explicit ID is ## Query Flow And Counting Basis -`wiki-query` decides semantically whether a user question needs business facts. When it does, it loads `obsidian-wiki business schema --json`, chooses a template if one fits, and only then uses guarded SQL for gaps. +`wiki-query` decides semantically whether a user question needs business facts. When it does, it loads `obsidian-wiki business schema --json`, chooses a template if one fits, and only then uses guarded SQL for gaps. For hybrid overview questions such as "某客户的大体情况", it runs two tracks: ordinary wiki retrieval for context/citations and business facts retrieval for customer/order metrics, then fuses the results in one answer. Template families include: diff --git a/obsidian_wiki/mcp_query.py b/obsidian_wiki/mcp_query.py index 273bbe2..99f2172 100644 --- a/obsidian_wiki/mcp_query.py +++ b/obsidian_wiki/mcp_query.py @@ -266,6 +266,7 @@ class QueryManager: "Do not run arbitrary shell commands or commands outside this prompt's allowlist.", "Do not write files, run source-file ingest workflows, wiki-ingest, wiki-update, wiki-rebuild, Kingdee sync/config/timer commands, or any other mutating operation.", "For business facts questions only, the wiki-query skill may run these read-only business facts commands: `obsidian-wiki business schema --json`, `obsidian-wiki business template ... --vault \"$OBSIDIAN_VAULT_PATH\" ... --json`, and `obsidian-wiki business sql --vault \"$OBSIDIAN_VAULT_PATH\" \"