feat(tools): use_oci + describe_oci — open-spec OCI control plane for agents#254
Merged
Conversation
…lane coverage Two built-ins that, together, expose every operation across the ~190 OCI Python SDK service modules to an agent without per-service plumbing: - describe_oci(service?, client?, operation?) — runtime introspection. Progressively zooms: list services, list clients in a service, list operations on a client (partitioned read-only vs mutating), or return the parameter schema for one operation (parsed from the OCI SDK :param: docstring + signature). - use_oci(service, client, operation, parameters, ...) — execute any operation. Builds the right oci.<service>.<Client> with the requested auth (api_key, security_token, instance_principal, resource_principal), invokes the method, and serialises the response (snake_case Python attrs -> camelCase wire names via attribute_map). Includes http_status + opc-request-id in the result for OCI-side traceability. Read-only by default. Operations whose names don't start with a read-only prefix (list_/get_/head_/summarize_/describe_/search_/ fetch_/compute_/preview_/validate_/test_) are refused unless either allow_mutations=True is passed or LOCUS_USE_OCI_ALLOW_MUTATIONS=1 is set. Enforced in code, not via an interactive prompt. The agent loop becomes: NL prompt -> describe_oci (verify shape) -> use_oci (execute) -> English summary. One execution path, one auth code-path, one serialiser, one mutation gate for all of OCI. Closes #253. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
- concepts/tools.md: new "Open-spec built-ins for the Oracle estate" section (placed after "Practical recipes", before "Common gotchas") that frames use_oci + describe_oci as the agentic-framework angle on cloud control planes — discover + execute, read-only by default — and cross-links to the Oracle 26ai RAG primitives (Notebook 06) for the data-plane half of the picture. - FEATURES.md: row in the existing Tools table for the new built-ins. Slotted next to the other tool features rather than the top banner. - mkdocs.yml: register notebook 70 under "Server & full pipelines". - examples/notebook_70_oci_tools.py: capitalise the docstring title so the auto-generated H1 reads cleanly. - docs/notebooks/notebook_70_oci_tools.md: rendered notebook page. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
This is an agentic framework, not a database product. The notebook nav read database-first because the Oracle 26ai cluster sat at slot 6-13 — right after "start here". Move that group below the Server & full pipelines block (and rename it "Oracle Database 26ai (optional persistence layer)") so Agent Foundations is what readers hit immediately after the OCI GenAI quickstart. Slot numbers stay 6-13 to avoid churn in the rendered notebook files. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
This is an agentic framework — the notebook nav now reflects that.
Renumber every notebook 6-54 so that the top-to-bottom order is
strictly sequential AND topically grouped:
1-5 OCI Generative AI (unchanged)
6-15 Agent Foundations (was 14-21; now includes Oracle agent
memory at 9 and Oracle store at 10, alongside Conversation
memory at 8)
16-23 Graphs & composition (was 22-29)
24-34 Multi-agent (was 30-40)
35-37 Reasoning & structured output (was 41-43)
38-44 RAG (was 44-46; now includes Oracle 26ai RAG at 41,
ADB document loader at 42, in-DB chunker at 43, in-DB
embeddings at 44)
45-49 Skills, playbooks & plugins (was 47-51)
50-57 Production (was 52-57; now includes Oracle 26ai
checkpointer at 53 and Oracle versioned checkpoint saver
at 54 alongside Checkpoint backends at 52)
58-62 Cognitive router & observability (unchanged)
63-67 Real-world workflows (unchanged)
68-70 Server & full pipelines (unchanged)
The Oracle 26ai notebooks now live in the agent sections where they
belong — RAG, Agent Foundations, Production — rather than in a
dedicated "database" section. Locus is an agentic framework; Oracle
26ai is the persistence layer when you want it.
Also:
- docs/workbench.md: lead the "Start with Oracle" demos with the
natural-language OCI driver (notebook 70 — use_oci + describe_oci)
before Oracle 26ai RAG, since it's the broadest agentic primitive.
- docs/concepts/tools.md: fix the cross-link from "Notebook 06" to
"Notebook 41" now that Oracle 26ai RAG sits in the RAG section.
Mechanically: 96 renames (.py + .md) executed in two phases through
a TMP namespace to avoid collisions, plus 376 cross-reference
rewrites across mkdocs.yml, README, CHANGELOG, every concept page,
every rendered notebook, and the workbench docs.
Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
CI on the PR flagged two issues on Python 3.14:
- `cast("type", client_cls)` triggered `[redundant-cast]` on mypy 3.14
(the isinstance narrowing one line above is enough). On mypy 3.12
the cast is still required to satisfy `[no-any-return]`. Suppress
both codes inline so the same source compiles cleanly under both
versions.
- `src/locus/tools/oci.py` had 14% coverage — under the per-file 90%
ratchet floor for new files. Add tests/unit/test_tools_oci.py
covering the pure-Python logic (docstring parser, mutation gate,
read-only classifier, OCI-model serialiser, auth-router branches,
client/operation resolution errors, plus a full success path
mocked through `_build_config_and_signer` and `_resolve_client_class`).
Coverage rises from 14% to 92%.
All 70 new tests pass; pre-commit (ruff, mypy 3.12, codespell)
clean.
Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
a193377 to
0d15447
Compare
…erence The arXiv citation `2604.23366` was inlined as a bare code span / plain link on five surfaces (concept page, capabilities page, FEATURES page, the rendered notebook page, and the source notebook docstring). The README already carries the full author line and a BibTeX block, so the canonical attribution exists — these five surfaces just didn't echo it. Update them all to render the citation as "Federico A. Kamelhar (2026), arXiv:2604.23366" with the arxiv.org/abs URL, so the author shows on every page that mentions the paper. No source code changes; mkdocs build --strict clean. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
5 tasks
fede-kamel
added a commit
that referenced
this pull request
May 23, 2026
#255) Bumps version 0.2.0b19 → 0.2.0b20 and rolls the [Unreleased] section into a dated [0.2.0b20] entry. Bundles: - PR #254 — feat(tools): use_oci + describe_oci open-spec OCI primitive (~190 services covered by one execution path, read-only by default), notebook 70 walkthrough, docs reorg. - PR #249 — feat(graph): LangGraph parity shims (sync invoke, mermaid/ascii renderers). - PR #247/#251 — fix(a2a): A2AClient httpx timeout configurable. - PR #245 — fix(telemetry): OTel trace context propagation through the agent run loop. - PR #246 — docs(readme): rebrand around the locus stack. - PR #248 — docs(site): canonical URL locusagents.oracle.com. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
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.
Closes #253.
Summary
Two built-in tools that, together, expose every operation in the OCI Python SDK to an agent through a single open-spec primitive — no per-service plumbing.
describe_oci(service?, client?, operation?)— runtime introspection. Progressively zooms into the SDK:oci.*(~190 of them)service→ list every*Clientclass in that moduleservice+client→ list operations, partitioned read-only vs mutatingservice+client+operation→ parameter schema parsed from the OCI SDK:param:docstring + signatureuse_oci(service, client, operation, parameters, ...)— execute any operation. Builds the rightoci.<service>.<Client>with the requested auth (api_key,security_token,instance_principal,resource_principal), invokes the method, and serialises the response (snake_case Python attrs → camelCase wire names viaattribute_map). Result includeshttp_status+opc-request-idfor OCI-side traceability.The agent loop becomes:
The model autonomously:
describe_oci(service=\"core\", client=\"ComputeClient\", operation=\"list_instances\")to learn the parameter shape.use_oci(...)three times — once per subscribed region.Adding a new OCI resource type to an agent no longer requires writing or registering any new code — one execution path, one auth code-path, one serialiser, one mutation gate for all of OCI.
Safety
use_ociis read-only by default. Operation names not starting withlist_/get_/head_/summarize_/describe_/search_/fetch_/compute_/preview_/validate_/test_are refused unless eitherallow_mutations=Trueis passed explicitly orLOCUS_USE_OCI_ALLOW_MUTATIONS=1is set. Enforced in code, not via interactive prompt (locus tools must be non-interactive).What's in the PR
src/locus/tools/oci.py— both tools, the docstring parser, the OCI-model serialiser, and the auth routersrc/locus/tools/builtins.py+src/locus/tools/__init__.py— re-exportsexamples/notebook_70_oci_tools.py— three-part walkthrough: introspection, direct dispatch, agent-driven NLTest plan
uv run pytest tests/unit/test_tools.py tests/unit/test_tools_schema.py tests/unit/test_idempotent_tools.py— 71/71 pass.identity.IdentityClient.list_compartments→http_status=200, returned the tenancy's compartments with realopc-request-id.object_storage.ObjectStorageClient.get_namespace(cross-region against us-chicago-1) →http_status=200, returned the real namespace.core.ComputeClient.list_instancesacross three subscribed regions → returned the running instance with its real OCID.delete_bucketwithoutallow_mutations→ refused with explanatory error.describe_oci()returns 189 service modules; the docstring parser correctly extractscompartment_id(required),compartment_id_in_subtree(optional bool),access_level(optional str), etc. fromlist_compartments.Narrative writeup
For a friendlier explanation of why this primitive matters — the design tradeoffs, the discover-then-execute pattern, a live trace against a real tenancy — see this gist:
https://gist.github.com/fede-kamel/d697e19290e94ecb00791e6dc1ff7d30