@pasko70/pibo 1.16.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/agent-runtime/auth.js +28 -0
  2. package/dist/agent-runtime/capabilities.js +221 -0
  3. package/dist/agent-runtime/context-build.js +313 -0
  4. package/dist/agent-runtime/contract.js +45 -0
  5. package/dist/agent-runtime/errors.js +57 -0
  6. package/dist/agent-runtime/events.js +1 -0
  7. package/dist/agent-runtime/history.js +1 -0
  8. package/dist/agent-runtime/profile-validation.js +109 -0
  9. package/dist/agent-runtime/registry.js +608 -0
  10. package/dist/agent-runtime/resource-files.js +87 -0
  11. package/dist/agent-runtime/resource-service.js +635 -0
  12. package/dist/agent-runtime/resources.js +1 -0
  13. package/dist/agent-runtime/routed-session.js +931 -0
  14. package/dist/agent-runtime/testing/contract.js +51 -0
  15. package/dist/agent-runtime/testing/fake-adapter.js +192 -0
  16. package/dist/agent-runtime/types.js +3 -0
  17. package/dist/agent-runtimes/codex-native/adapter.js +905 -0
  18. package/dist/agent-runtimes/codex-native/auth.js +476 -0
  19. package/dist/agent-runtimes/codex-native/client.js +734 -0
  20. package/dist/agent-runtimes/codex-native/config.js +152 -0
  21. package/dist/agent-runtimes/codex-native/history.js +283 -0
  22. package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
  23. package/dist/agent-runtimes/codex-native/models.js +581 -0
  24. package/dist/agent-runtimes/codex-native/process.js +459 -0
  25. package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
  26. package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
  27. package/dist/agent-runtimes/codex-native/redaction.js +31 -0
  28. package/dist/agent-runtimes/codex-native/requests.js +378 -0
  29. package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
  30. package/dist/agent-runtimes/codex-native/thread.js +388 -0
  31. package/dist/agent-runtimes/codex-native/turn.js +849 -0
  32. package/dist/agent-runtimes/pi/adapter.js +653 -0
  33. package/dist/agent-runtimes/pi/auth.js +455 -0
  34. package/dist/agent-runtimes/pi/history.js +640 -0
  35. package/dist/agent-runtimes/pi/model-catalog.js +87 -0
  36. package/dist/agent-runtimes/pi/routed-session.js +1464 -0
  37. package/dist/agent-runtimes/pi/runtime.js +534 -0
  38. package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
  39. package/dist/apps/chat/agent-profiles.js +40 -23
  40. package/dist/apps/chat/agent-store.js +111 -64
  41. package/dist/apps/chat/chat-api-routes.js +1 -1
  42. package/dist/apps/chat/chat-request-normalizers.js +47 -0
  43. package/dist/apps/chat/data/chat-data-mappers.js +25 -9
  44. package/dist/apps/chat/data/history-query-service.js +108 -0
  45. package/dist/apps/chat/data/session-query-service.js +24 -3
  46. package/dist/apps/chat/data/timeline-query-service.js +3 -3
  47. package/dist/apps/chat/model-catalog.js +1 -55
  48. package/dist/apps/chat/provider-auth-actions.js +171 -23
  49. package/dist/apps/chat/stream.js +12 -0
  50. package/dist/apps/chat/trace-v2.js +1 -0
  51. package/dist/apps/chat/trace.js +126 -415
  52. package/dist/apps/chat/web-app.js +582 -157
  53. package/dist/apps/chat-ui/assets/{dist-QXwINWYY.js → dist-9v2ZXT6V.js} +1 -1
  54. package/dist/apps/chat-ui/assets/{dist-CvZNkkOi.js → dist-B1LVAytl.js} +1 -1
  55. package/dist/apps/chat-ui/assets/{dist-_SP-MjLq.js → dist-C6LPDFXU.js} +1 -1
  56. package/dist/apps/chat-ui/assets/{dist-Bad4Yz4P.js → dist-DVtXxfHc.js} +1 -1
  57. package/dist/apps/chat-ui/assets/{dist-xy-zomwl.js → dist-DW4Qrfbd.js} +1 -1
  58. package/dist/apps/chat-ui/assets/{dist-DI4i80O2.js → dist-DmbsHdMC.js} +1 -1
  59. package/dist/apps/chat-ui/assets/{dist-D17yAUqp.js → dist-DyvwuSFO.js} +1 -1
  60. package/dist/apps/chat-ui/assets/{dist-Bc3Vbgjh.js → dist-I26VB0QO.js} +1 -1
  61. package/dist/apps/chat-ui/assets/{dist-BzqH7w58.js → dist-RtHbJRPV.js} +1 -1
  62. package/dist/apps/chat-ui/assets/{dist-CMDJ-WZm.js → dist-sZgJkWZb.js} +1 -1
  63. package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
  64. package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
  65. package/dist/apps/chat-ui/index.html +2 -2
  66. package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
  67. package/dist/apps/chat-vscode-web/index.html +1 -1
  68. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  69. package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
  70. package/dist/auth/login-actions.js +5 -251
  71. package/dist/cli-session/localSessionSource.js +8 -1
  72. package/dist/core/context-build.js +124 -20
  73. package/dist/core/default-profile.js +8 -0
  74. package/dist/core/profiles.js +30 -3
  75. package/dist/core/routed-session.js +5 -1446
  76. package/dist/core/runtime.js +5 -561
  77. package/dist/core/session-router.js +637 -83
  78. package/dist/data/cli.js +20 -3
  79. package/dist/data/schema.js +104 -1
  80. package/dist/data/session-store.js +24 -1
  81. package/dist/debug/events.js +25 -10
  82. package/dist/debug/failures.js +23 -3
  83. package/dist/debug/index.js +24 -6
  84. package/dist/debug/messages.js +87 -7
  85. package/dist/debug/persisted-payloads.js +31 -0
  86. package/dist/debug/pty.js +7 -6
  87. package/dist/debug/runtime-binding.js +29 -0
  88. package/dist/debug/session.js +137 -0
  89. package/dist/debug/summary.js +12 -0
  90. package/dist/debug/telemetry.js +28 -0
  91. package/dist/debug/tools.js +12 -2
  92. package/dist/debug/trace.js +154 -76
  93. package/dist/gateway/server.js +87 -2
  94. package/dist/gateway/tool.js +5 -5
  95. package/dist/index.js +21 -2
  96. package/dist/loops/tools.js +13 -12
  97. package/dist/mcp/agent-context.js +13 -4
  98. package/dist/mcp/client.js +10 -6
  99. package/dist/mcp/config.js +5 -2
  100. package/dist/mcp/runtime-session.js +166 -0
  101. package/dist/plugins/builtin.js +191 -53
  102. package/dist/plugins/codex-native.js +29 -0
  103. package/dist/plugins/registry.js +66 -2
  104. package/dist/runs/tools.js +26 -25
  105. package/dist/session-ui/terminalRows.js +2 -2
  106. package/dist/sessions/pibo-data-store.js +125 -16
  107. package/dist/sessions/runtime-binding.js +107 -0
  108. package/dist/sessions/sqlite-store.js +239 -18
  109. package/dist/sessions/store.js +86 -7
  110. package/dist/shared/trace-engine.js +18 -9
  111. package/dist/shared/trace-event-projection.js +29 -11
  112. package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
  113. package/dist/shared/trace-order.js +9 -4
  114. package/dist/shared/trace-page-merge.js +1 -1
  115. package/dist/signals/projector.js +20 -2
  116. package/dist/signals/registry.js +11 -0
  117. package/dist/subagents/tool.js +8 -6
  118. package/dist/tools/codex-browser.js +20 -19
  119. package/dist/tools/codex-compat.js +10 -9
  120. package/dist/tools/codex-image-generation.js +8 -6
  121. package/dist/tools/contract.js +45 -0
  122. package/dist/tools/credential-registry.js +182 -0
  123. package/dist/tools/mcp-bridge.js +511 -0
  124. package/dist/tools/payload-writer.js +17 -0
  125. package/dist/tools/runtime/tool.js +10 -9
  126. package/dist/tools/schema.js +9 -0
  127. package/dist/tools/session-service.js +193 -0
  128. package/dist/tools/session-tool-set.js +85 -0
  129. package/dist/web-annotations/tools.js +17 -16
  130. package/docs/README.md +11 -0
  131. package/package.json +3 -2
  132. package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
  133. package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
  134. package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
  135. package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
  136. package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
  137. package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
  138. package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
  139. package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
  140. package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
  141. package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
  142. package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
  143. package/dist/apps/chat-ui/assets/index-C45B0rw7.js +0 -237
  144. package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
  145. package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
  146. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.16.5.vsix +0 -0
@@ -0,0 +1,608 @@
1
+ import { validateAgentRuntimeCapabilities } from "./capabilities.js";
2
+ import { assertAgentRuntimeSessionContract } from "./contract.js";
3
+ import { validateAgentRuntimeProfileCapabilities } from "./profile-validation.js";
4
+ import { AgentRuntimeAuthError, AgentRuntimeCapabilityUnavailableError, AgentRuntimeContractError, AgentRuntimeRegistrationError, AgentRuntimeUnavailableError, } from "./errors.js";
5
+ import { AGENT_RUNTIME_AUTH_COMPLETION_MODES, AGENT_RUNTIME_AUTH_METHOD_IDS, redactAgentRuntimeAuthText, } from "./auth.js";
6
+ const RUNTIME_ID_PATTERN = /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/;
7
+ const AUTH_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/;
8
+ const MAX_AUTH_API_KEY_LENGTH = 64 * 1_024;
9
+ const MAX_AUTH_COMPLETION_CODE_LENGTH = 16 * 1_024;
10
+ const MAX_AUTH_PROVIDERS = 256;
11
+ const AUTH_STATES = new Set([
12
+ "connected",
13
+ "disconnected",
14
+ "pending",
15
+ "partial",
16
+ "unsupported",
17
+ "failed",
18
+ ]);
19
+ function assertRuntimeId(value, label) {
20
+ if (!RUNTIME_ID_PATTERN.test(value)) {
21
+ throw new AgentRuntimeRegistrationError(`${label} "${value}" must match ${RUNTIME_ID_PATTERN}.`);
22
+ }
23
+ }
24
+ function cloneConfig(config) {
25
+ return structuredClone(config);
26
+ }
27
+ function assertAuthId(value, label, runtimeInstanceId = "auth") {
28
+ if (!AUTH_ID_PATTERN.test(value)) {
29
+ throw new AgentRuntimeContractError(runtimeInstanceId, `${label} must match ${AUTH_ID_PATTERN}.`);
30
+ }
31
+ }
32
+ function scopedAuthContractError(error, runtimeInstanceId) {
33
+ return error.runtimeInstanceId === runtimeInstanceId
34
+ ? error
35
+ : new AgentRuntimeContractError(runtimeInstanceId, error.message, { cause: error });
36
+ }
37
+ function boundedAuthText(value, label, maxLength) {
38
+ if (value === undefined)
39
+ return undefined;
40
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
41
+ throw new AgentRuntimeContractError("auth", `${label} must be a non-empty string no longer than ${maxLength} characters.`);
42
+ }
43
+ return redactAgentRuntimeAuthText(value, maxLength);
44
+ }
45
+ function safeAdapterAuthError(error, operation) {
46
+ if (error instanceof AgentRuntimeAuthError) {
47
+ const code = /^[a-z][a-z0-9._-]{0,63}$/.test(error.code) ? error.code : "runtime_auth_failed";
48
+ return new AgentRuntimeAuthError(code, redactAgentRuntimeAuthText(error.message), error.retryable === true);
49
+ }
50
+ return new AgentRuntimeAuthError("runtime_auth_failed", `Runtime provider authentication ${operation} failed safely.`, true);
51
+ }
52
+ function cloneAuthDetails(value) {
53
+ if (value === undefined)
54
+ return undefined;
55
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
56
+ throw new AgentRuntimeContractError("auth", "Auth details must be an object when provided.");
57
+ }
58
+ const details = {};
59
+ if (value.accountType !== undefined) {
60
+ if (!["api_key", "oauth", "chatgpt", "unknown"].includes(value.accountType)) {
61
+ throw new AgentRuntimeContractError("auth", "Auth details contain an invalid account type.");
62
+ }
63
+ details.accountType = value.accountType;
64
+ }
65
+ if (value.planType !== undefined) {
66
+ if (!/^[a-z0-9][a-z0-9._-]{0,63}$/i.test(value.planType)) {
67
+ throw new AgentRuntimeContractError("auth", "Auth details contain an invalid plan type.");
68
+ }
69
+ details.planType = value.planType;
70
+ }
71
+ return Object.keys(details).length > 0 ? details : undefined;
72
+ }
73
+ function declaredAuthMethod(methods, methodId) {
74
+ const method = methods.find((candidate) => candidate.id === methodId);
75
+ if (!method)
76
+ throw new AgentRuntimeContractError("auth", `Auth method "${methodId}" was not declared by the runtime adapter.`);
77
+ return method;
78
+ }
79
+ function cloneAuthFlow(value, methods) {
80
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
81
+ throw new AgentRuntimeContractError("auth", "Auth flow must be an object.");
82
+ }
83
+ assertAuthId(value.flowId, "Auth flow id");
84
+ if (!AGENT_RUNTIME_AUTH_METHOD_IDS.includes(value.method)) {
85
+ throw new AgentRuntimeContractError("auth", `Auth flow method "${String(value.method)}" is invalid.`);
86
+ }
87
+ if (!AGENT_RUNTIME_AUTH_COMPLETION_MODES.includes(value.completion)) {
88
+ throw new AgentRuntimeContractError("auth", `Auth flow completion mode "${String(value.completion)}" is invalid.`);
89
+ }
90
+ const declared = declaredAuthMethod(methods, value.method);
91
+ if (declared.completion !== value.completion) {
92
+ throw new AgentRuntimeContractError("auth", `Auth flow completion mode does not match declared method "${value.method}".`);
93
+ }
94
+ if (typeof value.startedAt !== "string" || !Number.isFinite(Date.parse(value.startedAt))) {
95
+ throw new AgentRuntimeContractError("auth", "Auth flow startedAt must be an ISO timestamp.");
96
+ }
97
+ if (value.expiresAt !== undefined
98
+ && (typeof value.expiresAt !== "string" || !Number.isFinite(Date.parse(value.expiresAt)))) {
99
+ throw new AgentRuntimeContractError("auth", "Auth flow expiresAt must be an ISO timestamp.");
100
+ }
101
+ const verificationUrl = boundedAuthText(value.verificationUrl, "Auth verification URL", 2_048);
102
+ if (verificationUrl) {
103
+ let parsed;
104
+ try {
105
+ parsed = new URL(verificationUrl);
106
+ }
107
+ catch {
108
+ throw new AgentRuntimeContractError("auth", "Auth verification URL is invalid.");
109
+ }
110
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
111
+ throw new AgentRuntimeContractError("auth", "Auth verification URL must use HTTP or HTTPS.");
112
+ }
113
+ }
114
+ return {
115
+ flowId: value.flowId,
116
+ method: value.method,
117
+ completion: value.completion,
118
+ startedAt: new Date(value.startedAt).toISOString(),
119
+ ...(value.expiresAt ? { expiresAt: new Date(value.expiresAt).toISOString() } : {}),
120
+ ...(verificationUrl ? { verificationUrl } : {}),
121
+ ...(value.userCode ? { userCode: boundedAuthText(value.userCode, "Auth user code", 128) } : {}),
122
+ ...(value.instructions ? { instructions: boundedAuthText(value.instructions, "Auth instructions", 1_000) } : {}),
123
+ };
124
+ }
125
+ function validateAuthConfiguredState(state, configured) {
126
+ if (state === "connected" && !configured) {
127
+ throw new AgentRuntimeContractError("auth", "Connected auth status must be configured.");
128
+ }
129
+ if ((state === "disconnected" || state === "unsupported") && configured) {
130
+ throw new AgentRuntimeContractError("auth", `${state} auth status cannot be configured.`);
131
+ }
132
+ }
133
+ function cloneAuthStatus(value, declaredMethods) {
134
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
135
+ throw new AgentRuntimeContractError("auth", "Auth provider status must be an object.");
136
+ }
137
+ assertAuthId(value.id, "Auth provider id");
138
+ if (!AUTH_STATES.has(value.state)) {
139
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" reported invalid state "${String(value.state)}".`);
140
+ }
141
+ if (typeof value.configured !== "boolean") {
142
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" must report configured as a boolean.`);
143
+ }
144
+ validateAuthConfiguredState(value.state, value.configured);
145
+ if (!Array.isArray(value.methods)) {
146
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" must report methods.`);
147
+ }
148
+ const seen = new Set();
149
+ const methods = value.methods.map((method) => {
150
+ if (!method || typeof method !== "object" || Array.isArray(method)) {
151
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" reported an invalid method.`);
152
+ }
153
+ if (seen.has(method.id))
154
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" repeats method "${method.id}".`);
155
+ seen.add(method.id);
156
+ const declared = declaredAuthMethod(declaredMethods, method.id);
157
+ if (declared.completion !== method.completion) {
158
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" method "${method.id}" has a mismatched completion mode.`);
159
+ }
160
+ return { ...declared };
161
+ });
162
+ if (value.state === "pending" && !value.pending) {
163
+ throw new AgentRuntimeContractError("auth", `Pending auth provider "${value.id}" must include a flow.`);
164
+ }
165
+ if (value.state !== "pending" && value.pending) {
166
+ throw new AgentRuntimeContractError("auth", `Auth provider "${value.id}" includes a flow while state is "${value.state}".`);
167
+ }
168
+ return {
169
+ id: value.id,
170
+ ...(value.displayName ? { displayName: boundedAuthText(value.displayName, "Auth provider display name", 160) } : {}),
171
+ state: value.state,
172
+ configured: value.configured,
173
+ methods,
174
+ ...(value.pending ? { pending: cloneAuthFlow(value.pending, declaredMethods) } : {}),
175
+ ...(value.message ? { message: boundedAuthText(value.message, "Auth status message", 1_000) } : {}),
176
+ ...(value.details ? { details: cloneAuthDetails(value.details) } : {}),
177
+ };
178
+ }
179
+ function cloneAuthOperationResult(value, inputProviderId, declaredMethods) {
180
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
181
+ throw new AgentRuntimeContractError("auth", "Auth operation result must be an object.");
182
+ }
183
+ assertAuthId(value.providerId, "Auth result provider id");
184
+ if (value.providerId !== inputProviderId) {
185
+ throw new AgentRuntimeContractError("auth", `Auth result provider "${value.providerId}" does not match requested provider "${inputProviderId}".`);
186
+ }
187
+ if (!AUTH_STATES.has(value.state)) {
188
+ throw new AgentRuntimeContractError("auth", `Auth result reported invalid state "${String(value.state)}".`);
189
+ }
190
+ if (typeof value.configured !== "boolean") {
191
+ throw new AgentRuntimeContractError("auth", "Auth result configured must be a boolean.");
192
+ }
193
+ validateAuthConfiguredState(value.state, value.configured);
194
+ if (value.state === "pending" && !value.flow) {
195
+ throw new AgentRuntimeContractError("auth", "Pending auth result must include a flow.");
196
+ }
197
+ if (value.state !== "pending" && value.flow) {
198
+ throw new AgentRuntimeContractError("auth", `Auth result includes a flow while state is "${value.state}".`);
199
+ }
200
+ return {
201
+ providerId: value.providerId,
202
+ state: value.state,
203
+ configured: value.configured,
204
+ ...(value.flow ? { flow: cloneAuthFlow(value.flow, declaredMethods) } : {}),
205
+ ...(value.message ? { message: boundedAuthText(value.message, "Auth result message", 1_000) } : {}),
206
+ ...(value.details ? { details: cloneAuthDetails(value.details) } : {}),
207
+ };
208
+ }
209
+ function assertAdapterAuthContract(adapter) {
210
+ const auth = adapter.descriptor.capabilities.auth;
211
+ if (auth.status !== Boolean(adapter.getAuthStatus)) {
212
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${adapter.instanceId}" auth.status must match getAuthStatus().`);
213
+ }
214
+ if ((auth.methods.length > 0) !== Boolean(adapter.startAuth)) {
215
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${adapter.instanceId}" declared auth methods must match startAuth().`);
216
+ }
217
+ const needsCompletion = auth.methods.some((method) => method.completion !== "immediate");
218
+ if (needsCompletion !== Boolean(adapter.completeAuth)) {
219
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${adapter.instanceId}" non-immediate auth methods must match completeAuth().`);
220
+ }
221
+ if (needsCompletion && !adapter.disposeAuth) {
222
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${adapter.instanceId}" non-immediate auth methods require disposeAuth().`);
223
+ }
224
+ if (auth.cancel !== Boolean(adapter.cancelAuth)) {
225
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${adapter.instanceId}" auth.cancel must match cancelAuth().`);
226
+ }
227
+ if (auth.logout !== Boolean(adapter.logoutAuth)) {
228
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${adapter.instanceId}" auth.logout must match logoutAuth().`);
229
+ }
230
+ }
231
+ export class AgentRuntimeAdapterRegistry {
232
+ drivers = new Map();
233
+ instances = new Map();
234
+ definitions = new Map();
235
+ registerDriver(driver) {
236
+ const descriptor = driver.descriptor;
237
+ assertRuntimeId(descriptor.id, "Agent runtime adapter id");
238
+ if (!descriptor.displayName.trim()) {
239
+ throw new AgentRuntimeRegistrationError(`Agent runtime adapter "${descriptor.id}" requires a display name.`);
240
+ }
241
+ if (this.drivers.has(descriptor.id)) {
242
+ throw new AgentRuntimeRegistrationError(`Agent runtime adapter "${descriptor.id}" is already registered.`);
243
+ }
244
+ if (!descriptor.configSchema || typeof descriptor.configSchema !== "object" || Array.isArray(descriptor.configSchema)) {
245
+ throw new AgentRuntimeRegistrationError(`Agent runtime adapter "${descriptor.id}" requires an object config schema.`);
246
+ }
247
+ const capabilityErrors = validateAgentRuntimeCapabilities(descriptor.capabilities);
248
+ if (capabilityErrors.length > 0) {
249
+ throw new AgentRuntimeRegistrationError(`Agent runtime adapter "${descriptor.id}" declares invalid capabilities: ${capabilityErrors.join("; ")}`);
250
+ }
251
+ this.drivers.set(descriptor.id, driver);
252
+ }
253
+ registerInstance(definition) {
254
+ assertRuntimeId(definition.id, "Agent runtime instance id");
255
+ assertRuntimeId(definition.adapterId, "Agent runtime adapter id");
256
+ if (this.instances.has(definition.id)) {
257
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${definition.id}" is already registered.`);
258
+ }
259
+ const driver = this.drivers.get(definition.adapterId);
260
+ if (!driver) {
261
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${definition.id}" references unknown adapter "${definition.adapterId}".`);
262
+ }
263
+ if (driver.descriptor.supportsMultipleInstances === false) {
264
+ const existing = [...this.definitions.values()].find((candidate) => candidate.adapterId === definition.adapterId);
265
+ if (existing) {
266
+ throw new AgentRuntimeRegistrationError(`Agent runtime adapter "${definition.adapterId}" does not support multiple instances (already configured as "${existing.id}").`);
267
+ }
268
+ }
269
+ const rawConfig = cloneConfig(definition.config ?? driver.defaultConfig());
270
+ let config;
271
+ try {
272
+ config = driver.parseConfig(rawConfig);
273
+ }
274
+ catch (error) {
275
+ throw new AgentRuntimeRegistrationError(`Invalid config for agent runtime instance "${definition.id}": ${error instanceof Error ? error.message : String(error)}`, { cause: error });
276
+ }
277
+ const adapter = driver.create({
278
+ instanceId: definition.id,
279
+ displayName: definition.displayName,
280
+ enabled: definition.enabled !== false,
281
+ config,
282
+ });
283
+ if (adapter.instanceId !== definition.id) {
284
+ throw new AgentRuntimeRegistrationError(`Agent runtime driver "${definition.adapterId}" created instance "${adapter.instanceId}" instead of "${definition.id}".`);
285
+ }
286
+ if (adapter.descriptor.id !== definition.adapterId) {
287
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${definition.id}" was created by adapter "${adapter.descriptor.id}" instead of "${definition.adapterId}".`);
288
+ }
289
+ const historyDeclared = adapter.descriptor.capabilities.maintenance.history;
290
+ if (historyDeclared && (!adapter.inspectHistory || !adapter.readHistory)) {
291
+ throw new AgentRuntimeRegistrationError(`Agent runtime instance "${definition.id}" declares maintenance.history but must implement inspectHistory() and readHistory().`);
292
+ }
293
+ assertAdapterAuthContract(adapter);
294
+ this.instances.set(definition.id, adapter);
295
+ this.definitions.set(definition.id, {
296
+ ...definition,
297
+ config: cloneConfig(rawConfig),
298
+ });
299
+ return adapter;
300
+ }
301
+ getDriver(adapterId) {
302
+ return this.drivers.get(adapterId);
303
+ }
304
+ getDescriptor(adapterId) {
305
+ return this.drivers.get(adapterId)?.descriptor;
306
+ }
307
+ getInstance(instanceId) {
308
+ return this.instances.get(instanceId);
309
+ }
310
+ async getAuthStatus(instanceId) {
311
+ const adapter = this.requireInstance(instanceId);
312
+ if (!adapter.descriptor.capabilities.auth.status || !adapter.getAuthStatus) {
313
+ throw new AgentRuntimeCapabilityUnavailableError("provider authentication status", instanceId);
314
+ }
315
+ let statuses;
316
+ try {
317
+ statuses = await adapter.getAuthStatus();
318
+ }
319
+ catch (error) {
320
+ throw safeAdapterAuthError(error, "status read");
321
+ }
322
+ if (!Array.isArray(statuses) || statuses.length > MAX_AUTH_PROVIDERS) {
323
+ throw new AgentRuntimeContractError(instanceId, `Runtime auth status must contain at most ${MAX_AUTH_PROVIDERS} providers.`);
324
+ }
325
+ const seen = new Set();
326
+ try {
327
+ return statuses.map((status) => {
328
+ const cloned = cloneAuthStatus(status, adapter.descriptor.capabilities.auth.methods);
329
+ if (seen.has(cloned.id)) {
330
+ throw new AgentRuntimeContractError(instanceId, `Runtime auth status repeats provider "${cloned.id}".`);
331
+ }
332
+ seen.add(cloned.id);
333
+ return cloned;
334
+ });
335
+ }
336
+ catch (error) {
337
+ if (error instanceof AgentRuntimeContractError)
338
+ throw scopedAuthContractError(error, instanceId);
339
+ throw error;
340
+ }
341
+ }
342
+ async startAuth(instanceId, input) {
343
+ const adapter = this.requireInstance(instanceId);
344
+ assertAuthId(input.providerId, "Auth provider id", instanceId);
345
+ if (adapter.descriptor.capabilities.auth.credentialScope === "adapter-shared") {
346
+ for (const candidate of this.authScopeAdapters(adapter)) {
347
+ if (candidate === adapter || !candidate.descriptor.capabilities.auth.status)
348
+ continue;
349
+ const pending = (await this.getAuthStatus(candidate.instanceId))
350
+ .some((status) => status.id === input.providerId && status.state === "pending");
351
+ if (pending) {
352
+ throw new AgentRuntimeAuthError("runtime_auth_pending", "A login flow is already pending for this adapter-shared provider credential.", true);
353
+ }
354
+ }
355
+ }
356
+ const method = adapter.descriptor.capabilities.auth.methods.find((candidate) => candidate.id === input.method);
357
+ if (!method || !adapter.startAuth) {
358
+ throw new AgentRuntimeCapabilityUnavailableError(`provider authentication method "${input.method}"`, instanceId);
359
+ }
360
+ if (input.method === "api_key"
361
+ && (input.apiKey.trim().length === 0 || input.apiKey.length > MAX_AUTH_API_KEY_LENGTH)) {
362
+ throw new AgentRuntimeContractError(instanceId, `API-key authentication requires a non-empty key no longer than ${MAX_AUTH_API_KEY_LENGTH} characters.`);
363
+ }
364
+ try {
365
+ return {
366
+ runtimeInstanceId: instanceId,
367
+ ...cloneAuthOperationResult(await adapter.startAuth(input), input.providerId, adapter.descriptor.capabilities.auth.methods),
368
+ };
369
+ }
370
+ catch (error) {
371
+ if (error instanceof AgentRuntimeContractError)
372
+ throw scopedAuthContractError(error, instanceId);
373
+ throw safeAdapterAuthError(error, "start");
374
+ }
375
+ }
376
+ async completeAuth(instanceId, input) {
377
+ const adapter = this.requireInstance(instanceId);
378
+ assertAuthId(input.providerId, "Auth provider id", instanceId);
379
+ assertAuthId(input.flowId, "Auth flow id", instanceId);
380
+ if (input.code !== undefined && (input.code.length === 0 || input.code.length > MAX_AUTH_COMPLETION_CODE_LENGTH)) {
381
+ throw new AgentRuntimeContractError(instanceId, `Authentication completion code must be non-empty and no longer than ${MAX_AUTH_COMPLETION_CODE_LENGTH} characters.`);
382
+ }
383
+ if (!adapter.completeAuth) {
384
+ throw new AgentRuntimeCapabilityUnavailableError("provider authentication completion", instanceId);
385
+ }
386
+ try {
387
+ return {
388
+ runtimeInstanceId: instanceId,
389
+ ...cloneAuthOperationResult(await adapter.completeAuth(input), input.providerId, adapter.descriptor.capabilities.auth.methods),
390
+ };
391
+ }
392
+ catch (error) {
393
+ if (error instanceof AgentRuntimeContractError)
394
+ throw scopedAuthContractError(error, instanceId);
395
+ throw safeAdapterAuthError(error, "completion");
396
+ }
397
+ }
398
+ async cancelAuth(instanceId, input) {
399
+ const adapter = this.requireInstance(instanceId);
400
+ assertAuthId(input.providerId, "Auth provider id", instanceId);
401
+ assertAuthId(input.flowId, "Auth flow id", instanceId);
402
+ if (!adapter.descriptor.capabilities.auth.cancel || !adapter.cancelAuth) {
403
+ throw new AgentRuntimeCapabilityUnavailableError("provider authentication cancellation", instanceId);
404
+ }
405
+ try {
406
+ return {
407
+ runtimeInstanceId: instanceId,
408
+ ...cloneAuthOperationResult(await adapter.cancelAuth(input), input.providerId, adapter.descriptor.capabilities.auth.methods),
409
+ };
410
+ }
411
+ catch (error) {
412
+ if (error instanceof AgentRuntimeContractError)
413
+ throw scopedAuthContractError(error, instanceId);
414
+ throw safeAdapterAuthError(error, "cancellation");
415
+ }
416
+ }
417
+ async logoutAuth(instanceId, input) {
418
+ const adapter = this.requireInstance(instanceId);
419
+ assertAuthId(input.providerId, "Auth provider id", instanceId);
420
+ if (!adapter.descriptor.capabilities.auth.logout || !adapter.logoutAuth) {
421
+ throw new AgentRuntimeCapabilityUnavailableError("provider authentication logout", instanceId);
422
+ }
423
+ try {
424
+ let selected;
425
+ for (const candidate of this.authScopeAdapters(adapter)) {
426
+ if (!candidate.descriptor.capabilities.auth.logout || !candidate.logoutAuth) {
427
+ throw new AgentRuntimeContractError(candidate.instanceId, "Adapter-shared auth logout is not implemented consistently.");
428
+ }
429
+ const result = cloneAuthOperationResult(await candidate.logoutAuth(input), input.providerId, candidate.descriptor.capabilities.auth.methods);
430
+ if (candidate === adapter)
431
+ selected = result;
432
+ }
433
+ if (!selected)
434
+ throw new AgentRuntimeContractError(instanceId, "Selected runtime auth target was not included in its credential scope.");
435
+ return { runtimeInstanceId: instanceId, ...selected };
436
+ }
437
+ catch (error) {
438
+ if (error instanceof AgentRuntimeContractError)
439
+ throw scopedAuthContractError(error, instanceId);
440
+ throw safeAdapterAuthError(error, "logout");
441
+ }
442
+ }
443
+ async disposeAuth() {
444
+ const results = await Promise.allSettled([...this.instances.values()].map(async (adapter) => await adapter.disposeAuth?.()));
445
+ const failures = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
446
+ if (failures.length > 0)
447
+ throw new AggregateError(failures, "Failed to dispose runtime authentication controllers.");
448
+ }
449
+ async openSession(instanceId, input) {
450
+ const adapter = this.requireInstance(instanceId);
451
+ const session = await adapter.openSession(input);
452
+ try {
453
+ assertAgentRuntimeSessionContract(session);
454
+ }
455
+ catch (error) {
456
+ await session.dispose().catch(() => { });
457
+ throw error;
458
+ }
459
+ return session;
460
+ }
461
+ requireInstance(instanceId) {
462
+ const adapter = this.instances.get(instanceId);
463
+ if (!adapter || !adapter.enabled) {
464
+ throw new AgentRuntimeUnavailableError(instanceId, adapter
465
+ ? `Agent runtime instance "${instanceId}" is disabled.`
466
+ : `Unknown agent runtime instance "${instanceId}". Available instances: ${this.getInstanceIds().join(", ") || "none"}.`);
467
+ }
468
+ return adapter;
469
+ }
470
+ getAdapterIds() {
471
+ return [...this.drivers.keys()];
472
+ }
473
+ getInstanceIds() {
474
+ return [...this.instances.keys()];
475
+ }
476
+ getInstanceInfos() {
477
+ return [...this.instances.values()].map((adapter) => this.instanceInfo(adapter));
478
+ }
479
+ async inspectInstances() {
480
+ return await Promise.all([...this.instances.values()].map(async (adapter) => {
481
+ const diagnostics = await this.diagnoseAdapter(adapter);
482
+ let models;
483
+ let auth;
484
+ if (!adapter.enabled) {
485
+ diagnostics.unshift({
486
+ severity: "error",
487
+ code: "runtime_instance_disabled",
488
+ message: `Agent runtime instance "${adapter.instanceId}" is disabled.`,
489
+ });
490
+ }
491
+ else {
492
+ if (adapter.descriptor.capabilities.models.catalog) {
493
+ if (!adapter.listModels) {
494
+ diagnostics.push({
495
+ severity: "error",
496
+ code: "runtime_model_catalog_contract_missing",
497
+ message: `Agent runtime instance "${adapter.instanceId}" declares a model catalog but does not implement listModels().`,
498
+ });
499
+ }
500
+ else {
501
+ try {
502
+ models = structuredClone(await adapter.listModels());
503
+ if (models.runtimeInstanceId !== adapter.instanceId) {
504
+ diagnostics.push({
505
+ severity: "error",
506
+ code: "runtime_model_catalog_instance_mismatch",
507
+ message: `Runtime model catalog reported instance "${models.runtimeInstanceId}" instead of "${adapter.instanceId}".`,
508
+ });
509
+ }
510
+ diagnostics.push(...(models.diagnostics ?? []));
511
+ }
512
+ catch (error) {
513
+ diagnostics.push({
514
+ severity: "error",
515
+ code: "runtime_model_catalog_failed",
516
+ message: error instanceof Error ? error.message : String(error),
517
+ });
518
+ }
519
+ }
520
+ }
521
+ if (adapter.descriptor.capabilities.auth.status) {
522
+ try {
523
+ auth = [...(await this.getAuthStatus(adapter.instanceId))];
524
+ }
525
+ catch {
526
+ diagnostics.push({
527
+ severity: "warning",
528
+ code: "runtime_auth_status_failed",
529
+ message: `Authentication status is unavailable for runtime instance "${adapter.instanceId}".`,
530
+ });
531
+ }
532
+ }
533
+ }
534
+ return {
535
+ ...this.instanceInfo(adapter),
536
+ available: adapter.enabled && !diagnostics.some((diagnostic) => diagnostic.severity === "error"),
537
+ diagnostics,
538
+ ...(models ? { models } : {}),
539
+ ...(auth ? { auth } : {}),
540
+ };
541
+ }));
542
+ }
543
+ async validateProfile(input) {
544
+ const adapter = this.instances.get(input.profile.runtimeInstanceId);
545
+ if (!adapter) {
546
+ return [{
547
+ severity: "error",
548
+ code: "runtime_instance_unknown",
549
+ message: `Profile "${input.profile.profileName}" selects unknown agent runtime instance "${input.profile.runtimeInstanceId}".`,
550
+ }];
551
+ }
552
+ const diagnostics = await this.diagnoseAdapter(adapter);
553
+ if (!adapter.enabled) {
554
+ diagnostics.unshift({
555
+ severity: "error",
556
+ code: "runtime_instance_disabled",
557
+ message: `Profile "${input.profile.profileName}" selects disabled agent runtime instance "${adapter.instanceId}".`,
558
+ });
559
+ }
560
+ diagnostics.push(...validateAgentRuntimeProfileCapabilities(input.profile, adapter.descriptor.capabilities));
561
+ try {
562
+ diagnostics.push(...adapter.validateProfile(input));
563
+ }
564
+ catch (error) {
565
+ diagnostics.push({
566
+ severity: "error",
567
+ code: "runtime_profile_validation_failed",
568
+ message: error instanceof Error ? error.message : String(error),
569
+ });
570
+ }
571
+ return diagnostics;
572
+ }
573
+ getInstanceDefinition(instanceId) {
574
+ const definition = this.definitions.get(instanceId);
575
+ return definition
576
+ ? { ...definition, ...(definition.config ? { config: cloneConfig(definition.config) } : {}) }
577
+ : undefined;
578
+ }
579
+ authScopeAdapters(adapter) {
580
+ if (adapter.descriptor.capabilities.auth.credentialScope === "runtime-instance")
581
+ return [adapter];
582
+ return [...this.instances.values()].filter((candidate) => candidate.enabled && candidate.descriptor.id === adapter.descriptor.id);
583
+ }
584
+ instanceInfo(adapter) {
585
+ return {
586
+ id: adapter.instanceId,
587
+ adapterId: adapter.descriptor.id,
588
+ displayName: adapter.displayName,
589
+ enabled: adapter.enabled,
590
+ transport: adapter.descriptor.transport,
591
+ capabilities: structuredClone(adapter.descriptor.capabilities),
592
+ configSchema: cloneConfig(adapter.descriptor.configSchema),
593
+ ...(adapter.descriptor.protocol ? { protocol: { ...adapter.descriptor.protocol } } : {}),
594
+ };
595
+ }
596
+ async diagnoseAdapter(adapter) {
597
+ try {
598
+ return structuredClone([...(await adapter.diagnose())]);
599
+ }
600
+ catch (error) {
601
+ return [{
602
+ severity: "error",
603
+ code: "runtime_diagnostics_failed",
604
+ message: error instanceof Error ? error.message : String(error),
605
+ }];
606
+ }
607
+ }
608
+ }