Negotiated remote tool outcomes
Available in oneringai@2.0.0-beta.1 as opt-in C7. Publication does not
automatically upgrade consumers or negotiate a remote protocol.
The old AgentPackageToolServer, transport, DTOs, classification and literal
AGENT_PACKAGE_PROTOCOL_VERSION = 2 remain unchanged.
Use AgentPackageOutcomeServer(sourceAgent, legacyPackage, { storage, authorize })
and server.package() to create a separate OutcomeAgentPackage envelope with
protocol oneringai.tool-outcomes/1. Call hydrateAgentPackageWithOutcomes with
ordinary trusted hydration options, an enabled evidence plugin and authenticated
RemoteOutcomeTransport; it returns { agent, session }. Old loaders reject the
new envelope. Negotiation failure never falls back to old execution.
The host implements five transport methods by adapting its authenticated channel:
negotiate, execute, getReceipt, cancel, readEvidence. The server requires
trusted host context separately on every method, rechecks authorization for cached
results and each chunk, and derives effects and executable contracts from actual
source registrations. A package, request ID, fingerprint or reference grants no
authority. Do not pass model-selected tenant identity as trusted host context.
Keep the server alive until source work settles; await server.close() waits for
raw work and completes the ordinary external Agent lifecycle. It does not destroy
the borrowed source Agent, transport, storage or ModelTask.
If completion hooks/listeners fail, close() preserves that error and still releases
the settled composition lease, so the borrowed Agent can be reused. Repeated close
calls share the same completion/error.
For C6 or tools-first construction, await createAgentPackageOutcomeTools(envelope, { transport, storage }). Put its tools and the same storage object in the
ordinary Agent/factory configuration with evidence enabled. A session owns one
manager. Create a fresh toolset for another Agent or scoped child. Use
session.checkpoint(agent) in this path; the hydration convenience also permits
session.checkpoint().
agent.tools is still agent.context.tools. Actual proxy and server outcomes stay
separate in session.inspect(): IDs, timing, cancellation and local completion are
not rewritten. Business success: false remains data. C1 owning operational failures
remain failures. The ordinary result normalizer still handles null/undefined tool
returns; a null JSON field and wire result-presence flag remain lossless.
Before action submission, an acknowledged admission record binds the actual proxy
invocation to the request/session and canonical argument fingerprint. Full local
observations are stored as oneringai.remote-observation/1 in existing
EvidenceRecord.result, with the admission reference, actual proxy outcome,
validated remote receipt and complete payload. Server source records use
oneringai.remote-source/1. Backend schemas and old session/event shapes do not
change. Host redaction must preserve required correlation fields; otherwise the
source remains unacknowledged. Raw tool returns/events retain their normal shape.
An unknown remote write/unknown effect blocks further managed model/action dispatch,
even without loop-policy configuration. Reconcile with
await session.getReceipt(operationId), which retrieves full acknowledged source,
stores a local observation and acknowledges matching retained context evidence.
It never resubmits the action.
Unchanged receipt lookups reuse a validated local observation instead of consuming
another evidence record or re-fetching the full remote source. Concurrent lookups
serialize reconciliation for that invocation and each still uses the authenticated
receipt transport. A missing/expired local observation can be repaired without
resubmission; a failed repair keeps the action barrier in place.
Legacy ToolManager.execute overrides that bypass outcome instrumentation remain
supported on their original path. On this negotiated path, missing authoritative
metadata after execution handoff means unknown, even when the override returns
or throws. It cannot establish non-admission, success or a safe retry. Use an
instrumented source pipeline for reconcilable server observations.
A transport abort does not prove server cancellation;
session.cancel(id) requests per-invocation cancellation. Late results retain the
original identity. Cancelling one source call does not cancel siblings or a borrowed
task. session.close() closes local admission without claiming remote rollback.
Inline results default to 64 KiB, configurable through maxInlineBytes (zero forces
references, maximum 1 MB). Evidence is read in exact bounded chunks with a separate
content digest: a backend reference hashes its storage blob, which may include
scope/encoding overhead. Configure maxReadChars no larger than the selected
backend's read limit. Source/backend and local serialization quotas still apply.
If source storage fails, the server retains the exact record and rejects new
admissions. Host-only readRetainedSource(id) and acknowledgeSource(id, ref) repair
it after storage succeeds; the action is not repeated. Oversized non-JSON sources
require host repair and remain explicit failures, never prefix-truncated results.
Process-local request deduplication keeps identities through settlement; capacity
(default/maximum 1000 distinct requests) rejects new admissions instead of evicting
active authority. session.inspect(id?) is detached, bounded metadata and performs
no IO. Observers are isolated. Accounting is explicitly external_unknown; no
remote live task/budget is serialized or silently charged as local model usage.
Checkpoints store references and metadata, not credentials, callbacks, workflow
cursors or task authority. Loading verifies admission/full-observation proof against
the owning scoped backend. A restarted source can return unknown for an old epoch;
that does not authorize replay. Use FileEvidenceStorage for actual restart
recovery; an in-memory backend is process-local. The host must reauthorize recovery.
Run npm run example:remote-outcomes for the offline authenticated transport demo
(read, declined business data, uncertain synthetic write, exact recovery, one
submission). RUN_REMOTE_OUTCOMES_LIVE=1 npx vitest run tests/integration/text/RemoteOutcomes.live.integration.test.ts opts into billable
OpenAI/Anthropic/Google run/stream checks using .env.
Runtime H1 integrations must resolve C7 proxies with their original manager/Agent owner and exact evidence storage handle. Native materialization cannot clone a borrowed external manager. The existing source guard/reconciliation remains authoritative; no new runtime outcome wire format is introduced.
Runtime H3 uses the existing ToolExecutionReport in a trusted original-receipt reconcile callback. It does not define another outcome wire protocol, clone C7 managers, or treat a missing report as not-started. Saved provider payloads may be redelivered; unresolved original effects require source/receipt reconciliation. Native routine authority remains outside control checkpoints.
Managed runtime resume can reconcile retained outbox effects even after the native turn stopped requesting a result. The admission record retains the original name/arguments/call/run IDs; the trusted resolver reads the original source receipt and returns the existing ToolExecutionReport. It never allocates a replacement action. Unknown effects prevent deletion of their control record.