[P1] Define dual synchronous/asynchronous API contract across RLM libraries #425

Closed
opened 2026-09-10 21:18:01 +00:00 by nsaspy · 1 comment
Owner

Goal

Make blocking-capable prolog-rlm library operations available through both synchronous and asynchronous APIs, following one asynchronous execution path plus a synchronous bridge for callers that want blocking behavior.

This is a cross-library contract, not an agentProlog/-only feature.

Current state — 2026-08-18

Canonical main inspected for this reconciliation: abfc30ebb9f335d5841c1f7910bd474da905ebcf.

The core migration is substantially complete:

  • PR #55 added the bounded reusable Future/task substrate.
  • PR #59 made completion/provider/chain execution canonical async-first.
  • PR #60 migrated tool invocation and MCP latency-bearing operations.
  • PR #61 migrated agent and graph latency-bearing operations.
  • PR #62 completed #53 host authority and the non-blocking pending-operation core without holding a scheduler worker while waiting for human approval.
  • PR #72 completed and closed #52, including first-class MCP configuration references and closed host-controlled installer/stdio execution policy.

The old status sentence saying “#52 remains open” and treating #53 as an unfinished dependency was stale. Both #52 and #53 are closed on canonical main.

This issue remains open for the parts of the cross-library contract that do not yet exist end to end: concrete process/test/network tool surfaces under #49/#50, equivalence coverage for those future blocking-capable surfaces, and downstream agentProlog/ approval/TUI responsiveness. The existence of non-blocking pending approval in core does not prove a TUI that has not been built.

Design principle

Do not build two independent implementations of every operation.

Prefer:

canonical execute operation
        |
        +--> async Future caller awaits/polls/composes it
        |
        +--> sync facade waits for the same Future

Code already running inside a bounded async worker calls the trusted execute ABI directly rather than nesting another Future wait.

Required task/future semantics

The reusable asynchronous result abstraction must support at least:

  • task/future creation;
  • completion with value;
  • completion with structured error;
  • non-blocking status inspection;
  • synchronous wait/resolve;
  • timeout-aware wait;
  • cancellation;
  • callback or continuation registration where useful;
  • composition of multiple tasks;
  • trace/session correlation;
  • deterministic cleanup.

Cross-library coverage

The dual API contract applies where blocking or latency is meaningful, including provider/model requests, streaming, retries, tool/process/network work, MCP lifecycle and invocation, supervised agent work, graph run/resume, approval resolution, and downstream interactive clients.

Immediate/pure operations do not need decorative async twins.

Sync/async equivalence

For the same operation and inputs:

  • sync and async surfaces must produce equivalent structured outcomes;
  • tracing and usage accounting must be equivalent;
  • authority/capability checks must be identical;
  • budgets/timeouts must be identical unless explicitly overridden;
  • cancellation must not leave duplicate or orphaned work;
  • retries must not execute twice merely because a sync wrapper is used.

Avoid nested blocking

The async implementation must never internally call the synchronous wrapper for an async operation. The sync wrapper may wait on the async implementation.

Streaming

Streaming model/tool operations should be naturally asynchronous, with a synchronous convenience consumer allowed to collect/iterate the same stream rather than creating a second provider implementation.

Acceptance criteria

  • Define one reusable task/future abstraction for the library family.
  • Define naming/convention for sync and async predicate pairs.
  • Sync wrappers use the same underlying execution path as async calls across all blocking-capable libraries.
  • Add async model/provider calls.
  • Add async tool invocation using the canonical async-first architecture.
  • Add async process/test/network tool support.
  • Add async MCP install/run/invoke lifecycle.
  • Add async agent request/result/cancellation support using the canonical async-first architecture.
  • Add async graph execution/resume where blocking applies using the canonical async-first architecture.
  • Approval/pending-diff workflows can be resolved without blocking the TUI.
  • agentProlog/ can remain interactive while one or more operations are active.
  • Multiple concurrent tasks can be supervised with bounded concurrency.
  • Sync/async outputs, accounting, traces, authority, and capability decisions are equivalent across all migrated blocking-capable libraries.
  • Timeouts and cancellation clean up Future workers/resources deterministically.
  • Tests cover concurrency, cancellation, timeout, failure propagation, sync/async equivalence, and no duplicate execution across the remaining library migrations.

Non-goals

  • Do not create separate sync and async business logic implementations.
  • Do not make the entire Prolog runtime globally asynchronous.
  • Do not require downstream libraries to expose async variants for operations that are inherently immediate/pure.
  • Do not let async execution bypass capability, authority, budget, trace, or confinement rules.

References

  • #49 / #50 external concrete tool work
  • completed #52 MCP lifecycle/config policy
  • completed #53 host authority and pending-operation core
  • #79 canonical effect-boundary adoption
  • docs/async-runtime.md
  • docs/authority-runtime.md
## Goal Make blocking-capable `prolog-rlm` library operations available through both synchronous and asynchronous APIs, following one asynchronous execution path plus a synchronous bridge for callers that want blocking behavior. This is a **cross-library contract**, not an `agentProlog/`-only feature. ## Current state — 2026-08-18 Canonical `main` inspected for this reconciliation: `abfc30ebb9f335d5841c1f7910bd474da905ebcf`. The core migration is substantially complete: - PR #55 added the bounded reusable Future/task substrate. - PR #59 made completion/provider/chain execution canonical async-first. - PR #60 migrated tool invocation and MCP latency-bearing operations. - PR #61 migrated agent and graph latency-bearing operations. - PR #62 completed #53 host authority and the non-blocking pending-operation core without holding a scheduler worker while waiting for human approval. - PR #72 completed and closed #52, including first-class MCP configuration references and closed host-controlled installer/stdio execution policy. The old status sentence saying “#52 remains open” and treating #53 as an unfinished dependency was stale. Both #52 and #53 are closed on canonical `main`. This issue remains open for the parts of the cross-library contract that do **not yet exist end to end**: concrete process/test/network tool surfaces under #49/#50, equivalence coverage for those future blocking-capable surfaces, and downstream `agentProlog/` approval/TUI responsiveness. The existence of non-blocking pending approval in core does not prove a TUI that has not been built. ## Design principle Do not build two independent implementations of every operation. Prefer: ```text canonical execute operation | +--> async Future caller awaits/polls/composes it | +--> sync facade waits for the same Future ``` Code already running inside a bounded async worker calls the trusted execute ABI directly rather than nesting another Future wait. ## Required task/future semantics The reusable asynchronous result abstraction must support at least: - task/future creation; - completion with value; - completion with structured error; - non-blocking status inspection; - synchronous wait/resolve; - timeout-aware wait; - cancellation; - callback or continuation registration where useful; - composition of multiple tasks; - trace/session correlation; - deterministic cleanup. ## Cross-library coverage The dual API contract applies where blocking or latency is meaningful, including provider/model requests, streaming, retries, tool/process/network work, MCP lifecycle and invocation, supervised agent work, graph run/resume, approval resolution, and downstream interactive clients. Immediate/pure operations do not need decorative async twins. ## Sync/async equivalence For the same operation and inputs: - sync and async surfaces must produce equivalent structured outcomes; - tracing and usage accounting must be equivalent; - authority/capability checks must be identical; - budgets/timeouts must be identical unless explicitly overridden; - cancellation must not leave duplicate or orphaned work; - retries must not execute twice merely because a sync wrapper is used. ## Avoid nested blocking The async implementation must never internally call the synchronous wrapper for an async operation. The sync wrapper may wait on the async implementation. ## Streaming Streaming model/tool operations should be naturally asynchronous, with a synchronous convenience consumer allowed to collect/iterate the same stream rather than creating a second provider implementation. ## Acceptance criteria - [x] Define one reusable task/future abstraction for the library family. - [x] Define naming/convention for sync and async predicate pairs. - [ ] Sync wrappers use the same underlying execution path as async calls across all blocking-capable libraries. - [x] Add async model/provider calls. - [x] Add async tool invocation using the canonical async-first architecture. - [ ] Add async process/test/network tool support. - [x] Add async MCP install/run/invoke lifecycle. - [x] Add async agent request/result/cancellation support using the canonical async-first architecture. - [x] Add async graph execution/resume where blocking applies using the canonical async-first architecture. - [ ] Approval/pending-diff workflows can be resolved without blocking the TUI. - [ ] `agentProlog/` can remain interactive while one or more operations are active. - [x] Multiple concurrent tasks can be supervised with bounded concurrency. - [ ] Sync/async outputs, accounting, traces, authority, and capability decisions are equivalent across all migrated blocking-capable libraries. - [x] Timeouts and cancellation clean up Future workers/resources deterministically. - [ ] Tests cover concurrency, cancellation, timeout, failure propagation, sync/async equivalence, and no duplicate execution across the remaining library migrations. ## Non-goals - Do not create separate sync and async business logic implementations. - Do not make the entire Prolog runtime globally asynchronous. - Do not require downstream libraries to expose async variants for operations that are inherently immediate/pure. - Do not let async execution bypass capability, authority, budget, trace, or confinement rules. ## References - #49 / #50 external concrete tool work - completed #52 MCP lifecycle/config policy - completed #53 host authority and pending-operation core - #79 canonical effect-boundary adoption - `docs/async-runtime.md` - `docs/authority-runtime.md`
Author
Owner

Duplicate of #54 (pre-existing Forgejo mirror with GitHub number parity). Closing this accidental duplicate created by today's open-state sync; #54 stays canonical on Forgejo.

Duplicate of #54 (pre-existing Forgejo mirror with GitHub number parity). Closing this accidental duplicate created by today's open-state sync; #54 stays canonical on Forgejo.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/prolog-rlm#425
No description provided.