@xenosystem/agent-interface-host 0.1.7 → 0.1.8

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 (78) hide show
  1. package/dist/acp/AcpAgentTurnExecutionAdapter.d.ts.map +1 -1
  2. package/dist/acp/AcpAgentTurnExecutionAdapter.js +11 -0
  3. package/dist/acp/AcpAgentTurnExecutionAdapter.js.map +1 -1
  4. package/dist/acp/AcpNativeProviderLauncherResolver.d.ts +26 -0
  5. package/dist/acp/AcpNativeProviderLauncherResolver.d.ts.map +1 -0
  6. package/dist/acp/AcpNativeProviderLauncherResolver.js +145 -0
  7. package/dist/acp/AcpNativeProviderLauncherResolver.js.map +1 -0
  8. package/dist/acp/AcpProcessSupervisor.d.ts.map +1 -1
  9. package/dist/acp/AcpProcessSupervisor.js +4 -1
  10. package/dist/acp/AcpProcessSupervisor.js.map +1 -1
  11. package/dist/acp/AcpProviderModelService.d.ts +1 -0
  12. package/dist/acp/AcpProviderModelService.d.ts.map +1 -1
  13. package/dist/acp/AcpProviderModelService.js +2 -2
  14. package/dist/acp/AcpProviderModelService.js.map +1 -1
  15. package/dist/acp/AcpSessionService.d.ts.map +1 -1
  16. package/dist/acp/AcpSessionService.js +40 -2
  17. package/dist/acp/AcpSessionService.js.map +1 -1
  18. package/dist/acp/acpTypes.d.ts +3 -0
  19. package/dist/acp/acpTypes.d.ts.map +1 -1
  20. package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.d.ts.map +1 -1
  21. package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.js +4 -0
  22. package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.js.map +1 -1
  23. package/dist/index.d.ts +41 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +138 -10
  26. package/dist/index.js.map +1 -1
  27. package/dist/lease/ProcessLivenessProber.d.ts +30 -0
  28. package/dist/lease/ProcessLivenessProber.d.ts.map +1 -0
  29. package/dist/lease/ProcessLivenessProber.js +95 -0
  30. package/dist/lease/ProcessLivenessProber.js.map +1 -0
  31. package/dist/lease/ProviderWriterLeaseService.d.ts +43 -0
  32. package/dist/lease/ProviderWriterLeaseService.d.ts.map +1 -0
  33. package/dist/lease/ProviderWriterLeaseService.js +148 -0
  34. package/dist/lease/ProviderWriterLeaseService.js.map +1 -0
  35. package/dist/node.d.ts +8 -0
  36. package/dist/node.d.ts.map +1 -1
  37. package/dist/node.js +8 -0
  38. package/dist/node.js.map +1 -1
  39. package/dist/provider/ProviderLaneService.d.ts +71 -0
  40. package/dist/provider/ProviderLaneService.d.ts.map +1 -0
  41. package/dist/provider/ProviderLaneService.js +892 -0
  42. package/dist/provider/ProviderLaneService.js.map +1 -0
  43. package/dist/provider/ProviderTransitionOutboxDispatcher.d.ts +22 -0
  44. package/dist/provider/ProviderTransitionOutboxDispatcher.d.ts.map +1 -0
  45. package/dist/provider/ProviderTransitionOutboxDispatcher.js +60 -0
  46. package/dist/provider/ProviderTransitionOutboxDispatcher.js.map +1 -0
  47. package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.d.ts +4 -1
  48. package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.d.ts.map +1 -1
  49. package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.js +37 -1
  50. package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.js.map +1 -1
  51. package/dist/state/ProviderLaneSqliteStore.d.ts +64 -0
  52. package/dist/state/ProviderLaneSqliteStore.d.ts.map +1 -0
  53. package/dist/state/ProviderLaneSqliteStore.js +728 -0
  54. package/dist/state/ProviderLaneSqliteStore.js.map +1 -0
  55. package/dist/state/SqliteAgentStateRepository.d.ts +9 -0
  56. package/dist/state/SqliteAgentStateRepository.d.ts.map +1 -1
  57. package/dist/state/SqliteAgentStateRepository.js +171 -17
  58. package/dist/state/SqliteAgentStateRepository.js.map +1 -1
  59. package/dist/state/createAgentStateRepository.d.ts.map +1 -1
  60. package/dist/state/createAgentStateRepository.js +4 -2
  61. package/dist/state/createAgentStateRepository.js.map +1 -1
  62. package/dist/state/providerLaneSchema.d.ts +13 -0
  63. package/dist/state/providerLaneSchema.d.ts.map +1 -0
  64. package/dist/state/providerLaneSchema.js +129 -0
  65. package/dist/state/providerLaneSchema.js.map +1 -0
  66. package/dist/state/providerLaneTypes.d.ts +122 -0
  67. package/dist/state/providerLaneTypes.d.ts.map +1 -0
  68. package/dist/state/providerLaneTypes.js +28 -0
  69. package/dist/state/providerLaneTypes.js.map +1 -0
  70. package/dist/state/sdkProtectedStateCipher.d.ts +30 -0
  71. package/dist/state/sdkProtectedStateCipher.d.ts.map +1 -0
  72. package/dist/state/sdkProtectedStateCipher.js +50 -0
  73. package/dist/state/sdkProtectedStateCipher.js.map +1 -0
  74. package/dist/workspace/WorkspaceHostService.d.ts +31 -1
  75. package/dist/workspace/WorkspaceHostService.d.ts.map +1 -1
  76. package/dist/workspace/WorkspaceHostService.js +89 -12
  77. package/dist/workspace/WorkspaceHostService.js.map +1 -1
  78. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -86,6 +86,7 @@ export class AgentHostCoordinator {
86
86
  */
87
87
  subagentRuns;
88
88
  resolveRunId;
89
+ providerLaneService;
89
90
  connectedClients = new Map();
90
91
  /** What each connected client declared it can do, keyed the same way. */
91
92
  clientCapabilities = new Map();
@@ -130,7 +131,7 @@ export class AgentHostCoordinator {
130
131
  providerCatalogFingerprint = '';
131
132
  providerCatalogRefresh = null;
132
133
  constructor(options) {
133
- const { providers, providerCatalogLoader, runtimeEvents, runtimeEventRepository, stateRepository, workspaceService, interactionService, permissionPolicyService, interruptedTurnStore, turnAdmissionPolicy, turnAbandonGraceMs, sdkControlService, engineeringControlService, turnExecutionAdapters, coordinationService, runObservationService, runIsolationService, runObservationBinder, sessionService, nativeTuiLane, acpAgentRegistry, intakeService, knowledgeService, acpApprovalService, subagentRuns, resolveRunId, ...hostOptions } = options;
134
+ const { providers, providerCatalogLoader, runtimeEvents, runtimeEventRepository, stateRepository, workspaceService, interactionService, permissionPolicyService, interruptedTurnStore, turnAdmissionPolicy, turnAbandonGraceMs, sdkControlService, engineeringControlService, providerLaneService, turnExecutionAdapters, coordinationService, runObservationService, runIsolationService, runObservationBinder, sessionService, nativeTuiLane, acpAgentRegistry, intakeService, knowledgeService, acpApprovalService, subagentRuns, resolveRunId, ...hostOptions } = options;
134
135
  if (runtimeEventRepository && runtimeEvents && runtimeEvents.length > 0) {
135
136
  throw new Error('Seeded runtimeEvents cannot be combined with a durable runtimeEventRepository.');
136
137
  }
@@ -146,6 +147,9 @@ export class AgentHostCoordinator {
146
147
  this.turnAbandonGraceMs = turnAbandonGraceMs ?? DEFAULT_TURN_ABANDON_GRACE_MS;
147
148
  this.sdkControlService = sdkControlService;
148
149
  this.engineeringControlService = engineeringControlService;
150
+ this.providerLaneService = providerLaneService;
151
+ this.providerLaneService?.setEventSink?.((type, payload) => this.publish(type, payload));
152
+ this.providerLaneService?.start?.();
149
153
  this.coordinationService = coordinationService;
150
154
  // A turn's run identity, if the request carries one. `subagentRunId` first:
151
155
  // a subagent IS a distinct run with its own claims, so folding it into its
@@ -153,7 +157,11 @@ export class AgentHostCoordinator {
153
157
  // 🔴 `defaultRunIdOf`, not a hand-written `??` — a session filters runtime
154
158
  // EVENTS by the same rule, and the two must not drift. See its doc.
155
159
  this.resolveRunId = resolveRunId ?? ((request) => defaultRunIdOf(request));
156
- this.workspaceService?.setEventSink((type, payload) => this.publish(type, payload));
160
+ this.workspaceService?.setEventSink((type, payload) => {
161
+ if (type === 'workspace.pty.exit')
162
+ this.providerLaneService?.handleWorkspacePtyExit?.(payload);
163
+ this.publish(type, payload);
164
+ });
157
165
  // Coordination reaches surfaces through the event feed and nothing else.
158
166
  // Published as `redactionState: 'safe'` like every host event — which holds
159
167
  // because a coordination event carries ids, scopes and outcomes, never
@@ -1519,6 +1527,64 @@ export class AgentHostCoordinator {
1519
1527
  this.assertWorkspaceClient(input);
1520
1528
  return await this.requireWorkspaceService().stopPty(input);
1521
1529
  }
1530
+ if (method === 'conversation.open') {
1531
+ const request = input;
1532
+ this.assertConnectedClient(request.command.client, 'using provider conversations');
1533
+ return await this.requireProviderLaneService().openConversation(request);
1534
+ }
1535
+ if (method === 'conversation.resume') {
1536
+ const request = input;
1537
+ this.assertConnectedClient(request.command.client, 'using provider conversations');
1538
+ return await this.requireProviderLaneService().resumeConversation(request);
1539
+ }
1540
+ if (method === 'provider.lanes.list') {
1541
+ const request = input;
1542
+ this.assertConnectedClient(request.client, 'listing provider lanes');
1543
+ return await this.requireProviderLaneService().listLanes(request);
1544
+ }
1545
+ if (method === 'provider.lanes.get') {
1546
+ const request = input;
1547
+ this.assertConnectedClient(request.client, 'reading provider lanes');
1548
+ return await this.requireProviderLaneService().getLane(request);
1549
+ }
1550
+ if (method === 'provider.lanes.select') {
1551
+ const request = input;
1552
+ this.assertConnectedClient(request.command.client, 'selecting provider lanes');
1553
+ await this.refreshProviderCatalog();
1554
+ return await this.requireProviderLaneService().selectLane(request);
1555
+ }
1556
+ if (method === 'provider.native.attach') {
1557
+ const request = input;
1558
+ this.assertConnectedClient(request.command.client, 'attaching a native provider TUI');
1559
+ if ([...this.activeTurns.values()].some((active) => active.request.conversationId === request.conversationId)) {
1560
+ return {
1561
+ success: false,
1562
+ code: 'LANE_WRITER_ACTIVE',
1563
+ error: 'A structured provider turn is active for this conversation.',
1564
+ };
1565
+ }
1566
+ return await this.requireProviderLaneService().attachNative(request);
1567
+ }
1568
+ if (method === 'provider.native.detach') {
1569
+ const request = input;
1570
+ this.assertConnectedClient(request.command.client, 'detaching a native provider TUI');
1571
+ return await this.requireProviderLaneService().detachNative(request);
1572
+ }
1573
+ if (method === 'provider.native.reattach') {
1574
+ const request = input;
1575
+ this.assertConnectedClient(request.command.client, 'reattaching a native provider TUI');
1576
+ return await this.requireProviderLaneService().reattachNative(request);
1577
+ }
1578
+ if (method === 'provider.native.stop') {
1579
+ const request = input;
1580
+ this.assertConnectedClient(request.command.client, 'stopping a native provider TUI');
1581
+ return await this.requireProviderLaneService().stopNative(request);
1582
+ }
1583
+ if (method === 'provider.reconcile') {
1584
+ const request = input;
1585
+ this.assertConnectedClient(request.command.client, 'reconciling a provider lane');
1586
+ return await this.requireProviderLaneService().reconcile(request);
1587
+ }
1522
1588
  if (method === 'turn.start') {
1523
1589
  return await this.startTurn(input);
1524
1590
  }
@@ -1759,6 +1825,7 @@ export class AgentHostCoordinator {
1759
1825
  }));
1760
1826
  await this.sdkControlService?.close?.();
1761
1827
  await this.engineeringControlService?.close?.();
1828
+ await this.providerLaneService?.close?.();
1762
1829
  await this.workspaceService?.close?.();
1763
1830
  await this.stateRepository?.close?.();
1764
1831
  // Before the listeners go: each session's protocol channel is subscribed to
@@ -2008,13 +2075,26 @@ export class AgentHostCoordinator {
2008
2075
  this.trackTurnTimer(activeKey, timer);
2009
2076
  }
2010
2077
  async startTurn(input) {
2011
- const invalidReason = validateTurnStartRequest(input);
2078
+ let invalidReason = validateTurnStartRequest(input);
2012
2079
  if (invalidReason) {
2013
2080
  return turnStartFailure('invalid_request', invalidReason, input);
2014
2081
  }
2015
2082
  if (!this.isConnectedClient(input.command.client)) {
2016
2083
  return turnStartFailure('client_not_connected', 'The requesting surface must complete the host handshake before starting a turn.', input);
2017
2084
  }
2085
+ if (this.providerLaneService?.prepareTurn) {
2086
+ try {
2087
+ input = await this.providerLaneService.prepareTurn(structuredClone(input));
2088
+ }
2089
+ catch (error) {
2090
+ return turnStartFailure('invalid_request', error instanceof Error && error.message.trim()
2091
+ ? error.message.slice(0, 1_000)
2092
+ : 'The active provider lane rejected this turn.', input);
2093
+ }
2094
+ invalidReason = validateTurnStartRequest(input);
2095
+ if (invalidReason)
2096
+ return turnStartFailure('invalid_request', invalidReason, input);
2097
+ }
2018
2098
  const commandKey = this.commandKey('turn.start', input.command);
2019
2099
  const fingerprint = commandFingerprint(input);
2020
2100
  const prior = this.commandResults.get(commandKey);
@@ -2111,6 +2191,16 @@ export class AgentHostCoordinator {
2111
2191
  return turnStartFailure('concurrency_limit_reached', admission.safeError, input);
2112
2192
  }
2113
2193
  const request = structuredClone(input);
2194
+ if (this.providerLaneService?.beginStructuredTurn) {
2195
+ try {
2196
+ await this.providerLaneService.beginStructuredTurn(request);
2197
+ }
2198
+ catch (error) {
2199
+ return this.rememberTurnStartFailure(commandKey, fingerprint, turnStartFailure('request_already_active', error instanceof Error && error.message.trim()
2200
+ ? error.message.slice(0, 1_000)
2201
+ : 'The provider lane writer could not be acquired.', request));
2202
+ }
2203
+ }
2114
2204
  // Recorded BEFORE execution, so a coordination event arriving in the first
2115
2205
  // moments of a turn still finds its conversation.
2116
2206
  const contextRunId = this.resolveRunId(request);
@@ -2202,10 +2292,25 @@ export class AgentHostCoordinator {
2202
2292
  // §5.2b's `message` primitive is a PUSH, and this is the push. Without
2203
2293
  // it a run could send and no run could ever receive.
2204
2294
  .then(() => this.deliverCoordinationMessages(request))
2205
- .then(() => adapter.execute(request, provider, resolved.selection, {
2206
- signal: controller.signal,
2207
- publishPersistedRuntimeEvent: (event) => this.publishPersistedRuntimeEvent(event),
2208
- }))
2295
+ .then(async () => {
2296
+ const hostBinding = await this.providerLaneService?.getHostBinding?.(request.conversationId);
2297
+ return adapter.execute(request, provider, resolved.selection, {
2298
+ signal: controller.signal,
2299
+ ...(hostBinding ? { hostBinding: structuredClone(hostBinding) } : {}),
2300
+ publishPersistedRuntimeEvent: (event) => this.publishPersistedRuntimeEvent(event),
2301
+ commitProviderContinuation: async (continuation) => {
2302
+ if (!this.providerLaneService?.commitTurnContinuation)
2303
+ return;
2304
+ const result = await this.providerLaneService.commitTurnContinuation({
2305
+ conversationId: request.conversationId,
2306
+ requestId: request.requestId,
2307
+ continuation: structuredClone(continuation),
2308
+ });
2309
+ if (!result.success)
2310
+ throw new Error(result.error || 'Provider continuation could not be committed.');
2311
+ },
2312
+ });
2313
+ })
2209
2314
  .then(() => {
2210
2315
  // The turn ended WELL. Published here rather than inferred by each surface from
2211
2316
  // provider-specific runtime event strings — see the note on the event type itself.
@@ -2217,6 +2322,15 @@ export class AgentHostCoordinator {
2217
2322
  // what the host already told every surface. Late is not the same as successful.
2218
2323
  if (this.activeTurns.get(activeKey)?.controller !== controller)
2219
2324
  return;
2325
+ if (controller.signal.aborted) {
2326
+ this.publish('turn.execution.abandoned', {
2327
+ conversationId: request.conversationId,
2328
+ requestId: request.requestId,
2329
+ adapterId: adapter.id,
2330
+ reason: 'The turn was cancelled before completion.',
2331
+ });
2332
+ return;
2333
+ }
2220
2334
  this.publish('turn.execution.completed', {
2221
2335
  conversationId: request.conversationId,
2222
2336
  requestId: request.requestId,
@@ -2228,14 +2342,17 @@ export class AgentHostCoordinator {
2228
2342
  // second terminal event either.
2229
2343
  if (this.activeTurns.get(activeKey)?.controller !== controller)
2230
2344
  return;
2231
- this.publish('turn.execution.failed', {
2345
+ this.publish(controller.signal.aborted ? 'turn.execution.abandoned' : 'turn.execution.failed', {
2232
2346
  conversationId: request.conversationId,
2233
2347
  requestId: request.requestId,
2234
2348
  adapterId: adapter.id,
2235
- safeError: 'The selected runtime adapter failed to execute the turn.',
2349
+ ...(controller.signal.aborted
2350
+ ? { reason: 'The turn was cancelled before completion.' }
2351
+ : { safeError: 'The selected runtime adapter failed to execute the turn.' }),
2236
2352
  });
2237
2353
  })
2238
- .finally(() => {
2354
+ .finally(async () => {
2355
+ await this.providerLaneService?.finishStructuredTurn?.(request.conversationId, request.requestId);
2239
2356
  const active = this.activeTurns.get(activeKey);
2240
2357
  if (active?.controller === controller)
2241
2358
  this.activeTurns.delete(activeKey);
@@ -3034,6 +3151,17 @@ export class AgentHostCoordinator {
3034
3151
  }
3035
3152
  return this.engineeringControlService;
3036
3153
  }
3154
+ requireProviderLaneService() {
3155
+ if (!this.providerLaneService) {
3156
+ throw new AgentHostProtocolError('invalid_response', 'Host-owned provider lane services are unavailable.');
3157
+ }
3158
+ return this.providerLaneService;
3159
+ }
3160
+ assertConnectedClient(identity, operation) {
3161
+ if (!isAgentHostClientIdentity(identity) || !this.isConnectedClient(identity)) {
3162
+ throw new AgentHostProtocolError('invalid_response', `The requesting surface must complete the host handshake before ${operation}.`);
3163
+ }
3164
+ }
3037
3165
  assertWorkspaceClient(input) {
3038
3166
  if (!isRecord(input) || !isAgentHostClientIdentity(input.client) || !this.isConnectedClient(input.client)) {
3039
3167
  throw new AgentHostProtocolError('invalid_response', 'The requesting surface must complete the host handshake before using workspace services.');