Skip to content

feat(tools): add knowledge_search over the shared knowledge base - #488

Open
limin1975 wants to merge 6 commits into
vxcontrol:mainfrom
limin1975:main
Open

limin1975 wants to merge 6 commits into
vxcontrol:mainfrom
limin1975:main

Conversation

@limin1975

Copy link
Copy Markdown

Summary

Adds a knowledge_search tool that lets the assistant query the shared/manual
knowledge base
(documents flagged Manual=true) via natural language. This
complements the per-agent RAG retriever (which now excludes Manual docs), so
operators can publish curated knowledge that is only reachable through an
explicit tool call instead of being silently mixed into every agent turn.

Changes

  • pkg/tools/knowledge_search.go: new tool calling KnowledgeStore.SearchDocuments, scoped to Manual=true.
  • pkg/tools/search.go: exclude Manual=true docs from the generic retriever.
  • pkg/tools/registry.go + tools.go: register the tool (only when everyService=true).
  • pkg/templates/... + providers/assistant.go: forced-retrieval rule + tool-name rendering.
  • pkg/providers/performer.go: callWithRetries accepts extraOpts ...llms.CallOption; keeps CallWithTools on the default path and switches to CallWithExtraOptions only when extra options (e.g. a forced named tool_choice) are present.
  • pkg/database/knowledge/knowledge.go: define KnowledgePublisher locally to break the tools → knowledge → subscriptions → tools import cycle.
  • Env gate PENTAGI_ASSISTANT_FORCE_KBSEARCH (default off) forces the first assistant call to a named tool_choice for deterministic retrieval; verified disabled in production.
  • docker-compose.yml + Dockerfile.ollama + .gitignore: optional local Ollama service for RAG embeddings.
  • push_to_fork.sh: one-shot helper to push to the fork over SSH port 443.

Why

Shared knowledge (deployment briefs, access keys, runbooks) should be explicitly
retrievable and auditable, not injected into every agent context.

Testing

  • End-to-end: a running flow autonomously invoked knowledge_search and returned the correct curated document (relevance 0.8655).
  • pkg/tools/... and pkg/providers/... tests pass (two pre-existing upstream README/Graphiti baseline failures are unrelated).
  • Container rebuilt with CGO_ENABLED=0; API login returns 200.

Notes

The forced-tool_choice path is env-gated and disabled by default; production behavior is unchanged unless explicitly enabled.

@limin1975
limin1975 force-pushed the main branch 3 times, most recently from b69a64e to afbd65a Compare November 8, 2026 08:06
limin added 6 commits November 8, 2026 16:19
The agent could only reach its own long-term memory (search_answer /
search_guide / search_code / search_in_memory). Documents the user
explicitly uploaded into the shared knowledge base were unreachable.

Add a dedicated knowledge_search tool that queries the KnowledgeStore
where Manual=true, and keep the two surfaces disjoint:

- knowledge_search.go: new tool over KnowledgeStore.SearchDocuments,
  scoped to Manual=true via the existing KnowledgeFilter.
- search.go: excludeManualKnowledgeDocs drops Manual=true documents from
  the agent's own memory search, so user-curated documents are reachable
  only through knowledge_search.
- registry.go: tool name, type mapping, definition, and message type.
  The search_* definitions now state that they cover only agent-authored
  content and point at knowledge_search for user-uploaded documents.
- tools.go: assemble the tool for both the agent-orchestrated and the
  direct (useAgents=false) assistant paths.
- assistant.tmpl / templates.go / assistant.go: render the tool name and
  state the mandatory routing rule (FIRST retrieval action for a task that
  depends on user-provided documents).

The knowledge package no longer imports graph/subscriptions: the publisher
surface it needs is declared locally as knowledge.KnowledgePublisher, which
breaks the tools -> knowledge -> subscriptions -> converter -> tester ->
tools import cycle. router.go adapts the subscriptions publisher to it.

Verified end to end: the agent calls knowledge_search and returns the
document content from the knowledge base.
The agent picks its own tool on the first assistant iteration, so the
retrieval path a task takes depends on the model's judgement. To make
that routing reproducible — for verification, and for any task that must
start from a specific tool — allow an extra llms.CallOption to reach the
provider.

- performer.go: callWithRetries takes extraOpts and forwards them via
  CallWithExtraOptions instead of CallWithTools. On the assistant path,
  when PENTAGI_ASSISTANT_FORCE_KBSEARCH=1, the first iteration requests
  tool_choice = {"type":"function","function":{"name":"knowledge_search"}}.
  The object form is required: OpenAI-compatible endpoints reject a bare
  tool name.
- docker-compose.yml: pass the flag through. It is empty by default, so
  the production behaviour is unchanged unless it is explicitly set.
- performer_test.go: cover both states — the flag forces the named
  tool_choice, and without it no tool_choice is set.

Used to verify the knowledge_search path deterministically; the flag is
off by default.
Run the embedding model locally instead of reaching a cloud endpoint.

- Dockerfile.ollama: build Ollama from alpine 3.23 with the community
  apk mirror, since the official ollama/ollama image layer kept getting
  reset mid-pull.
- docker-compose.yml: add the ollama-server service on the pentagi
  network, reached by the service name, with models kept in the
  pentagi-ollama volume.
The custom binary and its image build context are ~100MB each and are
rebuilt locally, so they must not be staged. Also ignore the local
provider config, the installer-generated example link stubs, and the
local verification scripts and their logs.
Routing every assistant call through CallWithExtraOptions broke providers
whose two entry points behave differently: the mock provider resolves its
canned responses in CallWithTools, so the tool-free-agent and optional
refiner tests failed and the package panicked.

Only take the CallWithExtraOptions path when there are options to pass.
With the flag off the assistant call is byte-for-byte the old
CallWithTools call again.
@limin1975

Copy link
Copy Markdown
Author

Hi maintainers, thanks for taking a look at this PR!

Since it's opened from a fork, the CI workflows are currently awaiting approval (2 workflows). Could you please approve the workflows so they can run, and review the changes when you get a chance?

Quick recap:​ this adds a knowledge_search tool over the shared/manual knowledge base, plus an env-gated forced tool_choice path that is disabled by default (production behavior unchanged). All 6 commits are signed and show as Verified.

Happy to address any feedback — thanks!

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