devagentic-docs: fix searchDocs schema + add /fork + pre_llm_call hook#20
Merged
Conversation
Two changes in this PR — one a defect fix, one the rest of #12's proposed scope. Schema fix (defect in #19 MVP): - The actual schema is searchDocs(query, k), not (query, limit, tag). My PR #19 shipped invalid GraphQL that the server would reject. Confirmed via introspection of devagentic's live schema. - Route /doc search differently: with --tag, hit Query.docs(tags:[t]) and filter client-side; without --tag, hit Query.searchDocs(query, k). - Doc shape: drop `score` (not on Doc); add `source`, `ts`. /fork surface (#12 follow-up): - /fork open <parent_id> [--goal "..."] wraps forkContext, sets a marker at $HERMES_HOME/docs-fork-active (sibling to canvas-active). - /fork close clears the marker. - /fork show prints active fork tags + annotations via context(id). - /fork pin <doc_id> appends a pinned-doc annotation via decorateContext. - /fork render exposes renderContext(ctxId) directly — useful for debugging the preamble injection. pre_llm_call hook: - When a fork is active, calls renderContext(ctxId) and returns {context: header + rendered} for the host to append to the user message. Capped at 8000 chars hermes-side; devagentic does its own bounding upstream. - Returns None (turn proceeds without preamble) on any failure path: no marker, render returns None, render returns "". Tests: 45 passed (43 prior + 2 net new after schema-fix rewrites). The fixture now eagerly pre-loads all three submodules so monkeypatches on plugin_pkg.client reach preamble's docs_client reference. Closes #12 in full.
This was referenced May 22, 2026
PowerCreek
added a commit
that referenced
this pull request
May 22, 2026
Mirrors the canvas-tools pattern (#56) for the just-shipped devagentic-docs plugin (#12 / PRs #19+#20+#23). MCP-aware clients (Claude Code, Cursor, Codex) can now writeDoc / searchDocs / forkContext / decorateContext / renderContext against any devagentic instance hermes is configured for. New tools (7): - doc_search(query, limit, tag) → search_docs - doc_write(content, tags, source) → write_doc - doc_show(doc_id) → get_doc - fork_open(parent_id, goal, tags) → fork_context (auto-pins parent + threads goal) - fork_decorate(ctx_id, key, value, weight) → decorate_context - fork_get(ctx_id) → get_context - fork_render(ctx_id) → render_context (envelope: {ctx_id, rendered}) Loader pattern: _resolve_docs_client() mirrors _resolve_canvas_client at line 880 — file-path import of plugins/devagentic-docs/client.py since the hyphenated dir isn't a Python package. Failure semantics: every tool returns {"error": "<msg>"} JSON. The plugin's last_error_text() pattern (introduced in #15) threads through via a _reason() helper, so federated agents see the same actionable hints CLI users get — e.g. on the canonical devbox deployment (where /graphql isn't exposed, see #21), they'd see "not found at <url>/graphql ..." instead of an opaque None. Out of scope per #24: fork_close + fork_pin depend on the session-local $HERMES_HOME/docs-fork-active marker, which doesn't translate to MCP's stateless tool model. fork_open auto-tags with source:hermes-mcp so MCP-authored forks are distinguishable from CLI-authored ones (source:hermes-cli). Tests: 22 new (tests/test_mcp_docs.py) covering registration, plugin-missing fallback, arg routing, last_error surfacing for the #21 case, and the real-import smoke. All passing alongside canvas MCP suite (14 existing) and the broader devagentic- adjacent test set (159 total). Closes #24.
This was referenced May 23, 2026
PowerCreek
added a commit
that referenced
this pull request
May 23, 2026
…#39) The same urllib HTTPError + URLError + OSError + TimeoutError dispatch repeats in three sites after #15/#18/#20: plugins/devagentic-canvas/client.py:_request plugins/devagentic-docs/client.py:_post_graphql hermes_cli/doctor.py:_check_devagentic_graph Each site has the same if-401/403-elif-404-else branches over the exception and the same urllib network-error fallback. Only the message text differs per site. Add `utils.classify_http_error(exc) -> str` returning one of: HTTP_ERROR_AUTH — 401 / 403 HTTP_ERROR_NOT_FOUND — 404 HTTP_ERROR_HTTP — other HTTPError status HTTP_ERROR_UNREACHABLE — URLError / OSError / TimeoutError HTTP_ERROR_UNKNOWN — anything else Refactor the three callsites onto a single `except (URLError, OSError, TimeoutError)` (HTTPError is a URLError subclass) followed by a dispatch on the classifier output. Each site still owns its own message text — the user-facing strings are unchanged. Behavior change: none. Net diff is roughly even (helper + dispatch replaces three near-identical if/elif/else blocks). Tests: - 11 new tests in tests/test_utils_classify_http_error.py covering 401, 403, 404, generic statuses (400/422/429/500/502/503/504), URLError, OSError, TimeoutError, socket.timeout, unrelated exceptions, and the HTTPError-is-URLError subclass quirk. - All three refactored callsites' existing test suites still pass: canvas (47), docs (47), doctor devagentic-graph (6) — 112 total. Closes #38.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two changes — one a defect fix in my just-merged MVP, one the rest of #12's proposed scope.
Schema fix (defect in PR #19)
Introspected devagentic's live GraphQL schema while planning the /fork surface and found my MVP shipped invalid queries:
searchDocs(query: String, k: Int) -> [Doc]. My MVP used(query, limit, tag)+ selected a non-existentscorefield. Any call would have been rejected by the GraphQL layer.--tagbelongs onQuery.docs(tags: [String]), a separate primitive. Now routed there: with--tag, hitdocs(tags:[t])and filter byquerysubstring client-side; without--tag, hitsearchDocs(query, k=limit).Doc { id, content, tags, source, ts }./fork surface (#12 follow-up)
Slash commands wrap
forkContext,decorateContext,context(id),renderContext:/fork open <parent_id> [--goal "..."]— forks, decorates withgoal+pinned-doc, writes marker at$HERMES_HOME/docs-fork-active./fork close— unlinks the marker./fork show— prints active fork tags + annotations./fork pin <doc_id>— appends apinned-docannotation to the active fork./fork render— callsrenderContext(ctxId)and prints inline (debugging aid for the preamble injection).pre_llm_call hook
When a fork is active,
preamble.on_pre_llm_callcallsrenderContext(ctxId)and returns{context: <header> + <rendered>}for the host to append to the user message. Cached prompt prefixes stay valid (the context goes on the user side, not the system prompt).Returns None on any failure path (no marker, render returns None, render is whitespace, network down). The turn proceeds without preamble — never blocks.
Capped hermes-side at 8000 chars; devagentic's
renderContextdoes its own bounding upstream.Test plan
pytest tests/test_devagentic_docs_plugin.py):/forksubcommands including marker file roundtrips{context}; cap on long renders; failure → Nonetests/test_devagentic_canvas_plugin.py+test_devagentic_skills.py+test_devagentic_memory.py+tests/hermes_cli/test_doctor_devagentic_graph.py→ 121 passed total.Closes #12 in full.
Filed by hermes-maintainer (PowerCreek).