Add an AI connection
A connection extension has a game-side declaration and a backend running in the external Bridge JVM. The game root owns local settings and declares the embedded backend; ProviderFactory creates the selected backend owner. Do not put Minecraft classes in the backend.
Declare and package
Register ConnectionDefinition and ConnectionOptions with ExtensionRegistrar.connection. Use the supported API_VERSION. The backend factory ID must match <your_mod_id>:<connection_name> exactly. Its classpath lists embedded JAR resources and their hashes through BackendResource.
Compile the backend against agent-bridge-provider-api and its diagnostic dependency. Do not embed host APIs. Isolate private implementation/dependency packages, and include the factory's fully qualified name in META-INF/services/dev.miyomiyo.agentbridge.provider.ProviderFactory.
Discovery, constructors and create are passive. create returns a fresh owner; connect starts its connection without sending model input. Repeated connection observations share the same attempt. The host supplies world/player identity, conversation storage, display metadata, tools, options and shutdown budget through ProviderConfiguration.
Use host services
Use ProviderHost.executor() for state changes and ordered events. Move blocking I/O to its worker facility. Commit state before publish: a notification can reenter your provider. Never stop the host executor.
Obtain current tool definitions from host.tools(). Do not hard-code Reports or Navigation, and do not cache definitions across model requests. A missing extension should require no provider-specific branch.
Keep different facts separate
| Fact | Contract |
|---|---|
| Can an input start/join now? | InputOpportunity |
| Was this exact input accepted? | InputResult |
| Has a run finished? | ExecutionEvent |
| Was interruption requested? | Interruption |
| Is the harness waiting for a person? | approvals/questions and HostWait |
| Has shutdown actually completed? | the result of close |
A run-start event does not prove that a particular input was accepted. Use Unconfirmed for ambiguous outcomes, not Rejected; the host must not resend such an input blindly. Cancelling an observer future must not cancel an accepted command or cleanup. Interrupt only the run ID requested by the host.
The host retains input identities and receipts for the connection. It does not resend pending, accepted or unconfirmed identities to the provider. Definitely rejected input may be explicitly retried. Providers do not need a second connection-wide receipt history; native persistence and reconciliation across reconnects remain their responsibility.
Use structured provider events for activity, compaction and completion. Do not infer lifecycle from model prose or localized errors. Return unavailable values for unsupported features; optional capabilities are represented by the public contracts rather than provider-name checks.
On close, seal admission first, then drain owned connection attempts, runs, writes and processes. A timeout is not successful cleanup. Authentication and spending checks remain the provider's responsibility; installing an extension does not authorize paid fallback.