Skip to content

feat: initial public release of locus#2

Merged
fede-kamel merged 1 commit into
mainfrom
feat/initial-locus-public-release
Apr 28, 2026
Merged

feat: initial public release of locus#2
fede-kamel merged 1 commit into
mainfrom
feat/initial-locus-public-release

Conversation

@fede-kamel
Copy link
Copy Markdown
Contributor

First substantive push to oracle-samples/locus from the internal orahub repo. Squashed to a single initial-release commit because the OCA check has a 250-commit-per-PR cap and the internal history is well above that.

What's in here

  • src/locus/ — the Oracle agentic SDK. ReAct loop with a real Reflect node, idempotent tools, native checkpointer contract over nine backends, composable termination algebra, six in-process multi-agent patterns plus A2A.
  • docs/ — Material for MkDocs site. 22 concept pages grouped by capability, 7 multi-agent pattern pages, 6 how-tos including Quickstart and Deploy. Strict-mode build is clean.
  • examples/ — 37 progressive tutorials + 3 end-to-end demos (po_approval, oracle_26ai, trip_team).
  • tests/ — 2,987 unit tests + 330+ live integration tests.
  • .github/workflows/ — CI plus docs.yml that auto-deploys the docs site to GitHub Pages on push to main.

Scaffolding kept from upstream

LICENSE.txt (UPL-1.0 canonical wording), SECURITY.md (standard secalert_us@oracle.com), .github/pull_request_template.md (oracle-samples standard) — all taken directly from the existing scaffolding on main.

Privacy scrub before push

Every internal identifier scrubbed before the push:

  • Tenancy namespace replaced with <your-namespace> placeholder in the docs and source examples.
  • Internal profile names replaced with the DEFAULT placeholder.
  • One real production compartment OCID in a test fixture replaced with ..notfound.
  • docs/internal/ (threat model, security review, framework comparison, roadmap analysis) untracked entirely — those stay on the internal history.

Note on --no-verify in the squash commit

The underlying upstream commits passed the full pre-commit chain (ruff, mypy strict, markdownlint, secret-detection, large-file cap, commitizen) individually. The squashed commit was committed with --no-verify because re-running every hook on every file at once flags pre-existing tutorial patterns (e.g. /tmp/ paths in CLI tutorials) and intentional test fixtures (deliberately-fake API-key strings used to test the redaction logic). These are not new issues introduced by this commit.

Test plan

  • mkdocs build --strict — zero warnings.
  • pytest tests/unit -q — 2,987 tests pass.
  • All pre-commit hooks pass on the underlying upstream commits.
  • CI workflows pass on this PR.
  • Pages auto-deploys when the PR merges to main.

@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Apr 28, 2026
Locus — Oracle Generative AI · Multi-Agent · Reasoning · Orchestrator SDK.

The Oracle agentic SDK for Python. Turns a function into a tool, a
tool into an agent, agents into a team, and the team into a service
that survives restarts, double-fires, hung models, and human approvals.

Runtime
- ReAct loop with four explicit nodes: Think → Execute → Reflect →
  Terminate. Pure-function router; observable transitions.
- Idempotent tools — @tool(idempotent=True) deduplicates repeat tool
  calls inside the loop. Model can retry without double-charging.
- Reflexion as a real graph node — agent self-evaluates between
  Execute and the next Think.
- Termination algebra — composable & and | over typed conditions.
- Native checkpointer contract — nine backends (OCI Object Storage,
  Oracle 26ai, PostgreSQL, OpenSearch, Redis, SQLite, HTTP, file,
  in-memory) implementing one Protocol directly.
- Six in-process multi-agent patterns plus A2A — Composition,
  Orchestrator + Specialists, Swarm, Handoff, StateGraph, Functional,
  A2A across processes.
- Day-0 Oracle Generative AI — V1 OpenAI-compatible + OCI SDK
  transports, automatic transport selection, one auth surface for
  laptops, CI, and OCI workload identity.
- Reasoning add-ons — Reflexion, Grounding, Causal — first-class
  arguments on Agent(...).
- Tools — typed contracts auto-derived from Python signatures,
  parallel dispatch, idempotent dedup, MCP both directions.
- Memory — durable threads, LLMCompactor for long conversations,
  branching + vacuum native to every backend.
- RAG — seven vector stores, OCI Cohere + OpenAI embeddings,
  multimodal ingestion (PDF + OCR + audio).
- Hooks — Logging, StructuredLogging, Telemetry (OpenTelemetry),
  ModelRetry, Guardrails, Steering.
- Streaming + Server — typed write-protected events; SSE-streamed
  AgentServer (FastAPI) with X-Session-ID thread persistence.
- Skills + Playbooks — filesystem-first capability disclosure plus
  declarative step plans with PlaybookEnforcer.
- Evaluation — EvalCase / EvalRunner / EvalReport.

Documentation
- Material for MkDocs site under docs/ — 22 concept pages grouped
  by capability, 7 multi-agent pattern pages, 6 how-tos.
- docs/concepts/agent-loop.md is the architectural reference.
- .github/workflows/docs.yml deploys the site to GitHub Pages on
  every push to main.

Examples
- examples/ — 37 progressive tutorials, each a single runnable file.
- examples/demos/ — three end-to-end demos.

Quality
- 2,987 unit tests; 330+ live integration tests against real OCI
  Generative AI, Oracle 26ai, OCI Object Storage, OpenSearch, Redis,
  PostgreSQL on every commit. Not mocks.
- mypy strict, ruff clean, full pre-commit hook chain on every
  upstream commit (squash uses --no-verify because the same hooks
  flag pre-existing tutorial patterns when re-run on every file at
  once).

Licence: UPL-1.0.
@fede-kamel fede-kamel force-pushed the feat/initial-locus-public-release branch from 61dea17 to aed13ec Compare April 28, 2026 14:24
@fede-kamel fede-kamel merged commit 34324ec into main Apr 28, 2026
1 check passed
@fede-kamel fede-kamel deleted the feat/initial-locus-public-release branch April 28, 2026 14:26
fede-kamel added a commit that referenced this pull request May 4, 2026
Two threads in one commit (small enough to cohabitate):

1) Subtitle: drop "Orchestrator" everywhere — locus is the
   "Multi-Agent Reasoning SDK". Updated docs/img/logo.svg,
   docs/stylesheets/locus.css (CSS-injected docs header subtitle),
   sandbox/web/index.html brand-tag, and the playwright assertion
   in sandbox/e2e/tests/sandbox.spec.ts so the e2e test still passes.

2) Six things you can ship — swap two weak sections for two
   genuinely-shipped, peer-differentiated tutorials:

   - "Claims grounded …" (Reflexion+Grounding) → "Map-reduce a
     code-review crew" (tutorial 42). Send fan-out is shorter than
     LangGraph's routing function + targets dict; this is locus's
     most ergonomically-distinct primitive.
   - "Agent meshes across teams …" (A2A, niche audience) → "An
     incident runbook in one graph.execute()" (tutorial 46) — Send
     scatter to 3 investigators, severity gate, interrupt() for
     human approval, typed Postmortem.
   - "Day-one production deployment" (Agent Server) → "Voice in.
     Voice out." (tutorial 50) — multimodal gpt-audio in one
     chat-completions round-trip; net-new vs every peer SDK.

   Kept #2 idempotent tools, #3 handoff (now linking tutorial 45 too
   for the meatier HITL example), and #5 termination algebra
   verbatim — those three are the genuine differentiators the audit
   surfaced.

   The reflexion=True example was honest as code (the validator now
   coerces correctly post-d18d52f) but advertised result.grounding_score
   that the SDK doesn't surface that cleanly today; pulling it out of
   the marquee until the surface stabilises.

Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
fede-kamel added a commit that referenced this pull request May 6, 2026
)

The Anthropic sweep flaked on tutorials #1 and #2 because
configureAnthropic() only polled for Model A's option to appear in
the cfg-model dropdown — it then fired selectOption on cfg-model-b
immediately, racing the WebDriver layer's view of the populated
options. Playwright would retry for ~65s and eventually the test
timed out with "Target page, context or browser has been closed".

Mirror the existing A poll for B and C: wait for the desired option
text to be visible in the dropdown before calling selectOption. Same
15s budget, same toPass shape. Fixes the flake; the sweep ran
32/32 green in 9.5 min after this change.

Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
fede-kamel added a commit that referenced this pull request May 28, 2026
…278)

BREAKING: ``create_deepagent(max_tokens=...)`` is removed. Use
``total_token_budget=N`` for the run-level TokenLimit termination, or
``max_output_tokens=N`` for the per-completion output cap on each LLM
call.

Background — this is what was silently failing:

The old ``max_tokens`` parameter controlled the TOTAL-RUN token
budget (cumulative input+output across every iteration of one run),
wired into the typed-termination algebra as ``TokenLimit(max_tokens)``.
The name clashed with every LLM SDK on earth — OpenAI, Anthropic,
Google all use ``max_tokens`` for the per-completion output cap.

Callers reasonably passing ``max_tokens=65536`` expecting Gemini-
style "max 65K output tokens per call" got Locus's
``TokenLimit(65536)`` termination instead. On any agent with a long
system prompt (graph-grounded research, evaluator prompts, multi-
datastore RAG context), the input alone exceeded the cap on
iteration 1 → ``TokenLimit`` fired → run exited via
``TerminateEvent`` with empty output. No warning, no diagnostic.

The old 80_000 default was harmful — any agent with a ~50K-token
prompt was 1-2 iterations away from being silently killed. Cost
real debugging hours in the observai/optic AFS DeepAgent
integration before bisecting down to this.

What changes:

  - ``max_tokens=`` kwarg removed entirely (beta SDK, no migration
    needed). Rejected loud via TypeError with a message pointing
    to the new names + version so any straggler call sites fail at
    the bound boundary instead of silently mis-behaving.
  - ``total_token_budget: int | None = None`` is the new name for
    the run-level TokenLimit cap. ``None`` (default) means no
    TokenLimit term in the termination algebra — the run is bounded
    only by ToolCalled+Confidence or MaxIterations.
  - ``max_output_tokens: int | None = None`` stays — this is the
    per-completion cap forwarded to ``AgentConfig.max_tokens`` (and
    from there to the model provider's per-request max_tokens
    field). This is the knob callers usually meant when they
    passed the old name.
  - Docstring carries a loud "naming note" + "breaking change"
    block so anyone hitting the TypeError finds the migration path
    immediately.

Tests added:

  Unit (tests/unit/test_deepagent.py):
    - test_token_limit_omitted_when_budget_none — default doesn't
      add TokenLimit term (the foot-gun fix)
    - test_legacy_max_tokens_kwarg_rejected — TypeError with clear
      message; can't silently flow through to AgentConfig
    - test_max_output_tokens_propagated_independently_of_budget —
      per-completion cap lands on AgentConfig.max_tokens regardless
      of the run-budget setting
    - Updated test_typed_termination_attached to use the new name

  Integration stub (tests/integration/test_deepagent_token_budget.py):
    - 5 stub-mode tests covering bug shape + fix + loud rejection
    - No model calls; inspects termination tree directly

  Integration live (tests/integration/test_deepagent_token_budget_live.py):
    - Real OCI Gemini calls gated by RUN_LIVE_OCI=1
    - Reproduces the bug shape with explicit 80K opt-in (passes)
    - Verifies real-output happy path (xfailed pending Locus bug #2:
      runtime_loop drops final assistant message when agent
      terminates via MaxIterations without calling submit_tool —
      tracked in a follow-up issue)

Two related Locus bugs discovered during this work, NOT fixed here
(will be filed as separate issues):

  #2 — runtime_loop's final-message flush path is conditional on
       the submit_tool exit branch; agents that terminate via
       MaxIterations / TokenLimit return AgentResult.text='' even
       when the model emitted completion tokens. Live test marks
       this xfail.

  #3 — OCIModel + Gemini rejects Pydantic-derived structured-output
       schemas containing additionalProperties:false ("Unsupported
       JSON Schema feature for Gemini"). Vendor-aware schema
       munging needed in the OCI provider. Out of scope here;
       live tests omit output_schema to avoid hitting this.

Refs: #278 (this issue), observai/optic AFS DeepAgent integration
end-to-end testing surfaced all three bugs.

Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
fede-kamel added a commit that referenced this pull request May 28, 2026
…278) (#279)

BREAKING: ``create_deepagent(max_tokens=...)`` is removed. Use
``total_token_budget=N`` for the run-level TokenLimit termination, or
``max_output_tokens=N`` for the per-completion output cap on each LLM
call.

Background — this is what was silently failing:

The old ``max_tokens`` parameter controlled the TOTAL-RUN token
budget (cumulative input+output across every iteration of one run),
wired into the typed-termination algebra as ``TokenLimit(max_tokens)``.
The name clashed with every LLM SDK on earth — OpenAI, Anthropic,
Google all use ``max_tokens`` for the per-completion output cap.

Callers reasonably passing ``max_tokens=65536`` expecting Gemini-
style "max 65K output tokens per call" got Locus's
``TokenLimit(65536)`` termination instead. On any agent with a long
system prompt (graph-grounded research, evaluator prompts, multi-
datastore RAG context), the input alone exceeded the cap on
iteration 1 → ``TokenLimit`` fired → run exited via
``TerminateEvent`` with empty output. No warning, no diagnostic.

The old 80_000 default was harmful — any agent with a ~50K-token
prompt was 1-2 iterations away from being silently killed. Cost
real debugging hours in the observai/optic AFS DeepAgent
integration before bisecting down to this.

What changes:

  - ``max_tokens=`` kwarg removed entirely (beta SDK, no migration
    needed). Rejected loud via TypeError with a message pointing
    to the new names + version so any straggler call sites fail at
    the bound boundary instead of silently mis-behaving.
  - ``total_token_budget: int | None = None`` is the new name for
    the run-level TokenLimit cap. ``None`` (default) means no
    TokenLimit term in the termination algebra — the run is bounded
    only by ToolCalled+Confidence or MaxIterations.
  - ``max_output_tokens: int | None = None`` stays — this is the
    per-completion cap forwarded to ``AgentConfig.max_tokens`` (and
    from there to the model provider's per-request max_tokens
    field). This is the knob callers usually meant when they
    passed the old name.
  - Docstring carries a loud "naming note" + "breaking change"
    block so anyone hitting the TypeError finds the migration path
    immediately.

Tests added:

  Unit (tests/unit/test_deepagent.py):
    - test_token_limit_omitted_when_budget_none — default doesn't
      add TokenLimit term (the foot-gun fix)
    - test_legacy_max_tokens_kwarg_rejected — TypeError with clear
      message; can't silently flow through to AgentConfig
    - test_max_output_tokens_propagated_independently_of_budget —
      per-completion cap lands on AgentConfig.max_tokens regardless
      of the run-budget setting
    - Updated test_typed_termination_attached to use the new name

  Integration stub (tests/integration/test_deepagent_token_budget.py):
    - 5 stub-mode tests covering bug shape + fix + loud rejection
    - No model calls; inspects termination tree directly

  Integration live (tests/integration/test_deepagent_token_budget_live.py):
    - Real OCI Gemini calls gated by RUN_LIVE_OCI=1
    - Reproduces the bug shape with explicit 80K opt-in (passes)
    - Verifies real-output happy path (xfailed pending Locus bug #2:
      runtime_loop drops final assistant message when agent
      terminates via MaxIterations without calling submit_tool —
      tracked in a follow-up issue)

Two related Locus bugs discovered during this work, NOT fixed here
(will be filed as separate issues):

  #2 — runtime_loop's final-message flush path is conditional on
       the submit_tool exit branch; agents that terminate via
       MaxIterations / TokenLimit return AgentResult.text='' even
       when the model emitted completion tokens. Live test marks
       this xfail.

  #3 — OCIModel + Gemini rejects Pydantic-derived structured-output
       schemas containing additionalProperties:false ("Unsupported
       JSON Schema feature for Gemini"). Vendor-aware schema
       munging needed in the OCI provider. Out of scope here;
       live tests omit output_schema to avoid hitting this.

Refs: #278 (this issue), observai/optic AFS DeepAgent integration
end-to-end testing surfaced all three bugs.

Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant