Skip to content

feat: multi-source docs plugin with Odoo integration best practices#162

Open
clemenshelm wants to merge 22 commits into
mainfrom
smarter-docs
Open

feat: multi-source docs plugin with Odoo integration best practices#162
clemenshelm wants to merge 22 commits into
mainfrom
smarter-docs

Conversation

@clemenshelm

Copy link
Copy Markdown
Contributor

Summary

  • Extends the pinchy-docs plugin from a single docs source to a multi-source architecture — each agent sees only the documentation relevant to its integrations (Pinchy docs for Smithers, Odoo accounting docs for Finance Controller, etc.)
  • Adds docs_list (grouped by source, source-scoped per agent) and docs_read (accepts sourceId/path format with per-agent access control) — agents can now look up integration best practices on demand instead of relying on hardcoded knowledge
  • Creates initial Odoo accounting docs (vat-booking.md, invoice-types.md, fiscal-positions.md) and wires them automatically to agents based on their accessible module categories (accounting/sales/inventory)
  • Slims down all 16 Odoo agent templates: removes hardcoded ## Available Data field lists and ## Typical Analysis Patterns query recipes (~386 lines), replaces with a docs_list/docs_read/odoo_schema instruction

Architecture

  • Plugin config: { sources: [{ id, label, path }], agents: { [agentId]: { sources: [] } } } — fully backwards-compatible with legacy docsPath format
  • openclaw-config.ts builds the config dynamically: personal agents → pinchy source, Odoo agents → Odoo doc sources matched by model category from MODEL_CATEGORIES
  • Fail-closed access control: undefined sources = no access (not all access)
  • Hierarchical retrieval: docs_list (~1k tokens) → docs_read (one doc at a time) — keeps context usage low since tool results stay permanently in OpenClaw session history
  • Docker volume: ./integration-docs:/integration-docs:ro mounted into Pinchy container

Test Plan

  • Plugin unit tests: 29 passing (packages/plugins/pinchy-docs)
  • Web tests: 2782 passing (packages/web)
  • docs_list returns sources grouped by source, filtered to agent's allowed sources
  • docs_read accepts sourceId/path.md format, enforces cross-source access control
  • Path traversal and symlink attacks blocked by resolveSafe() (existing protection preserved)
  • Agent with account.move permission → odoo-accounting source in config
  • Agent with mail.message permission only → no pinchy-docs config emitted
  • undefined agent sources → no access (fail-closed)
  • .md and .mdx files both discovered by docs_list
  • End-to-end: finance agent sees accounting only, cannot read sales docs

Clemens Helm added 22 commits April 19, 2026 08:58
…ds compat

Extends PluginConfig to support a sources[] array (DocSource with id/label/path)
alongside the legacy docsPath string. The register() method normalizes legacy
format to multi-source at runtime, so existing single-source configs continue to
work unchanged. Updates openclaw.plugin.json schema to allow either format, with
agents.sources[] for per-agent source scoping (used in Tasks 2-3).
docs_list now returns [{source, label, docs:[...]}] grouped by source,
filtered to only the sources the agent is configured to access.
Renames listMdxFiles → listDocs in preparation for Task 9 (.md support).
Switch from the old flat `docsPath` format to the new `sources` array
format so pinchy-docs can serve docs from multiple named sources. Personal
agents now get `sources: ["pinchy"]` rather than an empty `{}` object.
docs_list now mentions best practices, domain-specific how-tos, and
guides users to docs_read. docs_read label drops "Pinchy" prefix to
reflect its generic multi-source role.
…le category

Creates integration-docs/odoo/accounting/ with VAT booking, invoice types,
and fiscal positions guides. Wires pinchy-docs sources to Odoo agents based
on which MODEL_CATEGORIES have models in their permissions — agents with
account.* models get odoo-accounting, sales.* get odoo-sales, etc.

Moves the pinchy-docs block to after Odoo agent configs are built so the
wiring logic has access to odooAgentConfigs. Mounts integration-docs into
the pinchy container as read-only in docker-compose.yml.
listDocs() now picks up both .md and .mdx files so integration docs
created as plain Markdown (e.g. Odoo accounting guides from Task 6)
are visible to agents via docs_list and readable via docs_read.
…th docs_list/docs_read references

Remove ## Available Data (field lists) and ## Typical Analysis Patterns (query recipes)
from all 16 Odoo templates and replace with ODOO_DOCS_INSTRUCTION directing agents to
use docs_list/docs_read for domain knowledge and odoo_schema for field discovery.

Update existing tests that checked for model names in defaultAgentsMd to check
odooConfig.requiredModels instead (equal-strength: requiredModels is the actual
access-control source of truth, not the free-text prompt).
…tests

- pinchy-docs: invert undefined-sources semantics to fail-closed (undefined = no access)
- pinchy-docs: update all existing tests to use explicit sources arrays
- pinchy-docs: add test verifying undefined sources returns empty list
- openclaw-config: only push pinchy doc source when personal agents exist
- openclaw-config: add comment on ODOO_DOC_SOURCES placeholder directories
- openclaw-config.test.ts: merge duplicate Odoo doc source tests into one with enabled check
- Move ODOO_DOC_SOURCES constant to module level (was recreated on every config regen)
- Fix typo pincySource → pinchySource in openclaw-config.test.ts
- Remove leftover '// add this line' comment in pinchy-docs index.test.ts
- Update test mocks to use mockInnerJoin() for new .where() query chain from main merge
- Add docs section explaining on-demand domain knowledge in connect-odoo.mdx
Extends MODEL_CATEGORIES with 8 new categories (manufacturing, project,
expenses, recruitment, pos, marketing, fleet, website) so all Odoo template
agents get correct doc sources and sync-UI entries.

Extends ODOO_DOC_SOURCES with 11 new entries (crm, purchase, hr +
the 8 new categories) at module level for testability.

Adds 21 integration-docs files covering all functional areas:
accounting (payment reconciliation), sales (lifecycle, subscriptions,
pricing), inventory (stock levels, transfers), CRM (pipeline, activities),
purchase (lifecycle, supplier pricing), HR (leave, attendance/contracts),
manufacturing (production orders, BOM), project (tasks/timesheets),
expenses (expense reports), recruitment (applicant pipeline), POS
(sessions/reconciliation), marketing (campaigns), fleet (vehicles/services),
website (e-commerce orders).

Each doc focuses on business concepts, state machines, and cross-model
patterns — not field lists (agents use odoo_schema for those).
Generic for Odoo 16–19; only subscriptions.md notes v16/v17+ difference.

Adds 3 tests for new doc sources (manufacturing, fleet, website).
Wires EMAIL_DOC_SOURCE (/integration-docs/email) automatically for any
agent with email provider permissions (google/microsoft/imap), and
FILES_DOC_SOURCE (/integration-docs/files) for any agent with pinchy_ls
or pinchy_read in their allowedTools.

Adds 5 integration-docs files covering the key agent gotchas:
- email/gmail-folders-search.md — label names, search syntax
- email/composing-and-sending.md — draft vs send, threading, single recipient
- email/limitations.md — no CC/BCC/attachments, credential expiry, rate limits
- files/navigating-files.md — non-recursive ls, absolute paths, workflow
- files/reading-files.md — supported formats, PDF truncation, scanned PDFs

Adds 4 tests verifying the doc source wiring for both integrations.
The Odoo schema sync now probes ~76 curated models (up from ~28 after
adding manufacturing/project/expenses/recruitment/pos/marketing/fleet/
website categories). The two retry tests use a 500ms backoff per failed
model, so with concurrency=5 they each need ~7-8s end-to-end. Vitest's
default 5000ms timeout was tripping them.

Setting the per-test timeout to 20s gives plenty of headroom and also
prevents the cascade where a timed-out retry test leaks pending fields()
calls into the next test, breaking the concurrency assertion (10 instead
of <=5).
…okup

After merging main with the Web Search integration (PR #127),
regenerateOpenClawConfig() now calls
  db.select().from(integrationConnections).where(eq(...))
to find Brave Search credentials. The seven inline mock setups for the
new doc-source tests built their own from() mock without .where(),
breaking only when the merged code path runs.

Adds where: vi.fn().mockResolvedValue([]) to each, matching the shared
mockFrom() helper that already supports both .innerJoin().where() and
direct .where() chains.
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.

1 participant