Skip to content

feat(integrations): expose OKF v0.2 bundles through a progressive-disclosure toolset - #7796

Open
ALDRIN121 wants to merge 1 commit into
google:mainfrom
ALDRIN121:feat/okf-toolset
Open

ALDRIN121 wants to merge 1 commit into
google:mainfrom
ALDRIN121:feat/okf-toolset

Conversation

@ALDRIN121

Copy link
Copy Markdown
Contributor

Problem

ADK has first-class support for procedural knowledge (SKILL.md trees) but no way to consume a local directory of declarative knowledge: markdown concepts with YAML frontmatter carrying type, tags, sources, verification events, status, and stale_after. An agent grounded in such a corpus has to either load all of it into context or grow a bespoke retrieval layer that discards the structure the corpus already carries.

Solution

google.adk.integrations.okf.OkfToolset reads an OKF v0.2 bundle as progressive, filterable context:

tool level returns
okf_index L1 one frontmatter row per matching concept — never a body
okf_read L2 one concept's frontmatter and markdown body
okf_resource L3 a file attached to a concept, capped at 64 KiB
okf_search — deterministic substring/regex matches
from google.adk.integrations.okf import OkfToolset

agent = LlmAgent(
    name="knowledge_agent",
    instruction="Answer from the knowledge bundle and cite concept paths.",
    tools=[OkfToolset(bundle="./knowledge", tool_name_prefix="okf")],
)

It lives under integrations/ because that is what the directory's README describes: a self-contained sub-package that manages its own internal structure and keeps optional third-party dependencies out of core. This one needs none — it reads frontmatter with pyyaml, which is already a core dependency, so no extra and no lazy third-party import are involved.

Design points worth reviewing:

  • One filter predicate, shared by okf_index and okf_search (directory, type, tags, trust_tier, include_deprecated, include_stale), so the two tools cannot disagree about which concepts exist.
  • Derived, never stored. Trust tier, lifecycle, and staleness are recomputed from frontmatter per read. Absent or unknown status reads as stable — OKF §11 forbids rejecting a concept for an unrecognised value — and a stale_after without a timezone is treated as absent rather than guessed.
  • Paths. A leading / is bundle-relative, never host-absolute. .. traversal and symlinks escaping the bundle root are refused by one guard used by every path argument, at eager load as well as at call time.
  • Failures are results. No tool raises: not_found, unsafe_path, invalid_argument, unreadable, invalid_regex, internal_error come back as structured dicts, and a malformed bundle is reported as a violations list rather than aborting the load.

Security

A bundle is untrusted input, written by whoever produced the corpus rather than by the agent's operator.

  • Concept bodies and resource text are data, never instructions: every tool description says so, and both reading tools mark their payload with content_is_untrusted_data: true.
  • Trust tiers are advisory (OKF §5.3). They filter discovery; they never authorise an action, and no code path gates on them.
  • The toolset is read-only: it executes nothing from the bundle — no scripts, no attested computations, no network — and a test asserts its source references no write, spawn, or network primitive.

Testing Plan

Unit tests — new directory, no existing test changed:

$ PYTHONPATH=. python -m pytest tests/unittests/integrations/okf -q
107 passed
  • Adversarial suite: frontmatter-programmed traversal, symlink escape on read and on eager load, prompt-injection labelling, and the "trust cannot authorise" property above.
  • Golden tests over the four published OKF sample bundles (vendored offline, provenance in fixtures/bundles/PROVENANCE.md): §11 rules 1–3, exact concept counts, derived trust tiers, and tolerance of a producer-extension key that the spec forbids rejecting.

Manual E2E — test_agent_smoke.py runs an Agent with MockModel through InMemoryRunner: the model calls okf_read, the tool result carries the concept's frontmatter and body, and the run completes. This needs no network and no model credentials, so it can be read as the end-to-end evidence for the tool wiring:

$ PYTHONPATH=. python -m pytest tests/unittests/integrations/okf/test_agent_smoke.py -q
1 passed

Repo gates — pre-commit run --files <changed> passes every hook on this diff: ruff, isort, pyink, addlicense, check-new-py-prefix (private modules with exported symbols), the unit-guide check, compliance, check-docs, and codespell.

Checklist

  • Unit tests added for the change, and passing locally
  • Unit guide at docs/guides/integrations/okf/toolset/index.md, listed in docs/guides/README.md
  • Integration README at src/google/adk/integrations/okf/README.md
  • CI (fork run awaits maintainer approval)

Expose a directory of typed markdown knowledge (Open Knowledge Format v0.2) to
an agent progressively: frontmatter index (L1), one concept body (L2), its
attached resources (L3), and a deterministic offline search. Trust tier,
lifecycle, and staleness are derived from frontmatter on every read and used
only to filter discovery.

A bundle is untrusted input. Concept bodies and resource text are labelled as
data, never instructions; every path argument resolves through one bundle-root
guard that refuses `..` traversal and symlink escape at load time as well as at
call time; and no tool raises, so a hostile or broken bundle reaches the model
as a structured error dict instead of an opaque failure.

107 tests, including an adversarial suite and golden tests over the four
published OKF sample bundles.
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.

Feature request: OKF (Open Knowledge Format) bundle support for ADK

2 participants