@grackle-ai/adapter-sdk 0.132.2 → 0.133.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.
package/dist/adapter.d.ts CHANGED
@@ -1,21 +1,25 @@
1
- import type { Client } from "@connectrpc/connect";
2
- import type { powerline } from "@grackle-ai/common";
3
1
  import type { AdapterLogger } from "./logger.js";
4
2
  import type { IHostTransport } from "./host-transport.js";
5
- /** Type-safe ConnectRPC client for the PowerLine gRPC service. */
6
- export type PowerLineClient = Client<typeof powerline.GracklePowerLine>;
7
- /** An active connection to a PowerLine, including the gRPC client and port info. */
3
+ /** An active connection to a PowerLine. */
8
4
  export interface PowerLineConnection {
9
- client: PowerLineClient;
10
5
  environmentId: string;
11
6
  port: number;
12
7
  /**
13
- * Transport-agnostic host interface (AHP HR8c). One instance per connection,
14
- * constructed when the connection is established. Consumers use this
15
- * instead of touching `client` directly so the HR8d wire-flip is a
16
- * swap of one `IHostTransport` impl for another.
8
+ * Transport-agnostic host interface. Constructed when the connection is
9
+ * established and used for all session-level operations.
17
10
  */
18
11
  transport: IHostTransport;
12
+ /**
13
+ * Send a liveness probe to the PowerLine. Resolves on success; rejects on
14
+ * any transport-layer error.
15
+ */
16
+ ping(): Promise<void>;
17
+ /**
18
+ * Tear down the underlying transport (WebSocket + pending RPCs). Idempotent.
19
+ * Adapters MUST call this from `disconnect()` to avoid socket leaks —
20
+ * under HR8d the AHP transport is persistent and only closes here.
21
+ */
22
+ close(): Promise<void>;
19
23
  }
20
24
  /** Progress event emitted during environment provisioning. */
21
25
  export interface ProvisionEvent {
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAExE,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,SAAS,EAAE,cAAc,CAAC;CAC3B;AAED,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IAEb,0DAA0D;IAC1D,SAAS,CACP,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,GACrB,cAAc,CAAC,cAAc,CAAC,CAAC;IAClC,+EAA+E;IAC/E,OAAO,CACL,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChC,uFAAuF;IACvF,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,gFAAgF;IAChF,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,gEAAgE;IAChE,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,0DAA0D;IAC1D,WAAW,CAAC,UAAU,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,gGAAgG;IAChG,SAAS,CAAC,CACR,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,GACrB,cAAc,CAAC,cAAc,CAAC,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAuB,oBAAoB,CACzC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,OAAO,EACrB,KAAK,GAAE,OAAe,EACtB,MAAM,GAAE,aAA6B,GACpC,cAAc,CAAC,cAAc,CAAC,CAgBhC"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,EAAE,cAAc,CAAC;IAC1B;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6DAA6D;AAC7D,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IAEb,0DAA0D;IAC1D,SAAS,CACP,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,GACrB,cAAc,CAAC,cAAc,CAAC,CAAC;IAClC,+EAA+E;IAC/E,OAAO,CACL,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChC,uFAAuF;IACvF,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,gFAAgF;IAChF,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,gEAAgE;IAChE,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,0DAA0D;IAC1D,WAAW,CAAC,UAAU,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,gGAAgG;IAChG,SAAS,CAAC,CACR,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,GACrB,cAAc,CAAC,cAAc,CAAC,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAuB,oBAAoB,CACzC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,OAAO,EACrB,KAAK,GAAE,OAAe,EACtB,MAAM,GAAE,aAA6B,GACpC,cAAc,CAAC,cAAc,CAAC,CAgBhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAmErD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,oBAAoB,CACzC,aAAqB,EACrB,OAA2B,EAC3B,MAA+B,EAC/B,cAAsB,EACtB,YAAqB,EACrB,QAAiB,KAAK,EACtB,SAAwB,aAAa;IAErC,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC,KAAK,IAAI,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;YAChE,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;gBACrC,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,kDAAkD,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IACD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAwErD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,oBAAoB,CACzC,aAAqB,EACrB,OAA2B,EAC3B,MAA+B,EAC/B,cAAsB,EACtB,YAAqB,EACrB,QAAiB,KAAK,EACtB,SAAwB,aAAa;IAErC,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC,KAAK,IAAI,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAChD,IAAI,CAAC;YACH,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;YAChE,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;gBACrC,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,kDAAkD,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IACD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * AHP-backed implementation of {@link IHostTransport} (AHP HR8d / #1336).
3
+ *
4
+ * Owns one `AhpClientSocket` per `PowerLineConnection` and routes
5
+ * inbound `action` notifications to per-session queues via the
6
+ * {@link reverseMapAction} reverse mapper. Downstream consumers in
7
+ * `@grackle-ai/core` continue to read `envelope.event` (the synthesized
8
+ * AgentEventFields), so no consumer code changes — only the wire format does.
9
+ *
10
+ * Wire-protocol summary (per #1336):
11
+ *
12
+ * - `createSession` (spawn) → AHP `createSession` + `subscribe`
13
+ * - `createSession` (reanimate) → same, with `config.resumeFromRuntimeSessionId`
14
+ * - `dispatchInput` → AHP `dispatchAction` notification with `SessionTurnStartedAction`
15
+ * - `dispose` (kill) → AHP `disposeSession`
16
+ * - `listSessions` → AHP `listSessions`
17
+ * - `authenticate` → AHP `authenticate`
18
+ *
19
+ * Drain semantics (Option E): PowerLine replays parked events as `action`
20
+ * notifications immediately after the `subscribe` response, so the consumer
21
+ * receives them via the same stream — no separate `drainBuffered` RPC.
22
+ *
23
+ * @module ahp-host-transport
24
+ */
25
+ import type { AhpNotification } from "@grackle-ai/ahp";
26
+ import { AhpClientSocket } from "@grackle-ai/ahp-transport";
27
+ import type { AuthenticateParams, CreateSessionParams, CreateSessionResult, HostSessionInfo, IHostTransport, ReanimateParams, ServerActionEnvelope } from "./host-transport.js";
28
+ /**
29
+ * AHP-backed {@link IHostTransport} for a single environment.
30
+ *
31
+ * Lifecycle: one instance per `PowerLineConnection`. Owns one
32
+ * `AhpClientSocket`; multiplexes session subscriptions over it.
33
+ *
34
+ * Construct via {@link createAhpHostTransport} (in `./connect.ts`) which
35
+ * handles the `socket.open()` handshake. Tests can construct directly with
36
+ * a pre-opened socket.
37
+ */
38
+ export declare class AhpHostTransport implements IHostTransport {
39
+ private readonly socket;
40
+ private readonly sessions;
41
+ private nextClientSeq;
42
+ /**
43
+ * Construct an AhpHostTransport over a pre-opened `AhpClientSocket`.
44
+ * The socket MUST already have completed its `initialize` handshake.
45
+ *
46
+ * @param socket - The AHP client socket, opened and connected.
47
+ */
48
+ constructor(socket: AhpClientSocket);
49
+ /**
50
+ * Notification handler that must be supplied to `AhpClientSocket` at
51
+ * construction time (the socket's `onNotification` option). This is a
52
+ * static-bound method so it can be passed to the socket constructor.
53
+ *
54
+ * Routes inbound `action` notifications to the appropriate per-session
55
+ * queue, running the reverse mapper to synthesize `AgentEventFields` and
56
+ * wrapping each into a `ServerActionEnvelope`. Other notification methods
57
+ * are ignored (no consumers in the wire-only scope of HR8d).
58
+ *
59
+ * @param notif - The AHP notification from the wire.
60
+ */
61
+ handleNotification(notif: AhpNotification): void;
62
+ /**
63
+ * Create a new session via AHP `createSession` + `subscribe`.
64
+ *
65
+ * Returns synchronously with the session URI and the live envelope stream.
66
+ * The actual AHP requests fire in the background; failures push an error
67
+ * sentinel into the stream and close it (mirroring how gRPC stream errors
68
+ * surface during iteration).
69
+ */
70
+ createSession(params: CreateSessionParams): CreateSessionResult;
71
+ /**
72
+ * Reanimate a suspended session. Maps to AHP `createSession` with a
73
+ * `config.resumeFromRuntimeSessionId` hint that PowerLine interprets as
74
+ * "spawn a continuation runtime from this prior runtime session."
75
+ */
76
+ reanimate(params: ReanimateParams): AsyncIterable<ServerActionEnvelope>;
77
+ /** Send input text by dispatching a `SessionTurnStartedAction`. */
78
+ dispatchInput(sessionUri: string, text: string): Promise<void>;
79
+ /**
80
+ * Deliver runtime credentials.
81
+ *
82
+ * AHP `authenticate` is OAuth-shaped (single `{ resource, token }`) and
83
+ * Grackle's HR6 authenticate delivers multiple typed tokens (env-var or
84
+ * file-backed) for one provider. HR8d preserves the AHP-spec wire method
85
+ * by fanning Grackle's tokens out into N `authenticate` calls. Each call:
86
+ *
87
+ * - `resource`: `grackle://provider/{provider}/{name}` — encodes the
88
+ * Grackle-side identity. PowerLine recognizes the `grackle://` scheme
89
+ * and decodes it.
90
+ * - `token`: JSON-encoded `{ type, envVar?, filePath?, value }` — carries
91
+ * the delivery instructions inside the AHP token field.
92
+ *
93
+ * On-spec method, abused field semantics. The contortion is documented in
94
+ * #1336 and bounded to this single command.
95
+ */
96
+ authenticate(params: AuthenticateParams): Promise<void>;
97
+ /**
98
+ * Dispose a session via AHP `disposeSession`.
99
+ *
100
+ * AHP's `DisposeSessionParams` doesn't carry a `reason` field; the optional
101
+ * `reason` argument is logged client-side but not delivered to PowerLine.
102
+ * Acceptable for HR8d — `reason` was informational in the gRPC path too.
103
+ */
104
+ dispose(sessionUri: string, _reason?: string): Promise<void>;
105
+ /** List active sessions via AHP `listSessions`. */
106
+ listSessions(): Promise<HostSessionInfo[]>;
107
+ private getOrCreateSession;
108
+ private closeSession;
109
+ private runSpawnFlow;
110
+ private surfaceErrorAndClose;
111
+ }
112
+ /**
113
+ * Helper to wire {@link AhpHostTransport}'s notification handler into an
114
+ * `AhpClientSocket` at construction time. The transport's
115
+ * {@link AhpHostTransport.handleNotification} method must be bound to the
116
+ * socket BEFORE `socket.open()` so the first inbound `action` notifications
117
+ * are routed correctly.
118
+ *
119
+ * @param transport - The transport whose handler should be bound.
120
+ * @returns A function suitable for passing as `onNotification` to
121
+ * `AhpClientSocket`'s constructor options.
122
+ */
123
+ export declare function bindNotificationHandler(transport: AhpHostTransport): (n: AhpNotification) => void;
124
+ //# sourceMappingURL=ahp-host-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ahp-host-transport.d.ts","sourceRoot":"","sources":["../src/ahp-host-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAMV,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,eAAe,EACf,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AA+F7B;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,YAAW,cAAc;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,OAAO,CAAC,aAAa,CAAa;IAElC;;;;;OAKG;gBACgB,MAAM,EAAE,eAAe;IAI1C;;;;;;;;;;;OAWG;IACI,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAiBvD;;;;;;;OAOG;IACI,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB;IAStE;;;;OAIG;IACI,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,CAAC,oBAAoB,CAAC;IA2B9E,mEAAmE;IACtD,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc3E;;;;;;;;;;;;;;;;OAgBG;IACU,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBpE;;;;;;OAMG;IACU,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzE,mDAAmD;IACtC,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAevD,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,YAAY;YASN,YAAY;IAmD1B,OAAO,CAAC,oBAAoB;CAS7B;AAsDD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,gBAAgB,GAAG,CAAC,CAAC,EAAE,eAAe,KAAK,IAAI,CAEjG"}
@@ -0,0 +1,413 @@
1
+ /**
2
+ * AHP-backed implementation of {@link IHostTransport} (AHP HR8d / #1336).
3
+ *
4
+ * Owns one `AhpClientSocket` per `PowerLineConnection` and routes
5
+ * inbound `action` notifications to per-session queues via the
6
+ * {@link reverseMapAction} reverse mapper. Downstream consumers in
7
+ * `@grackle-ai/core` continue to read `envelope.event` (the synthesized
8
+ * AgentEventFields), so no consumer code changes — only the wire format does.
9
+ *
10
+ * Wire-protocol summary (per #1336):
11
+ *
12
+ * - `createSession` (spawn) → AHP `createSession` + `subscribe`
13
+ * - `createSession` (reanimate) → same, with `config.resumeFromRuntimeSessionId`
14
+ * - `dispatchInput` → AHP `dispatchAction` notification with `SessionTurnStartedAction`
15
+ * - `dispose` (kill) → AHP `disposeSession`
16
+ * - `listSessions` → AHP `listSessions`
17
+ * - `authenticate` → AHP `authenticate`
18
+ *
19
+ * Drain semantics (Option E): PowerLine replays parked events as `action`
20
+ * notifications immediately after the `subscribe` response, so the consumer
21
+ * receives them via the same stream — no separate `drainBuffered` RPC.
22
+ *
23
+ * @module ahp-host-transport
24
+ */
25
+ import { ActionType } from "@grackle-ai/ahp";
26
+ import { newReverseMapperContext, reverseMapAction, } from "@grackle-ai/common";
27
+ const ROOT_CHANNEL = "ahp-root://";
28
+ const SESSION_CHANNEL_PREFIX = "ahp-session:/";
29
+ /** Build the AHP session channel URI for a Grackle session id. */
30
+ function sessionChannel(sessionId) {
31
+ return `${SESSION_CHANNEL_PREFIX}${sessionId}`;
32
+ }
33
+ /**
34
+ * Accept either a plain Grackle session id (e.g. `"sess-1"`) or an
35
+ * already-formed AHP session URI (`"ahp-session:/sess-1"`) and return the
36
+ * URI form. `IHostTransport`'s `dispatchInput` / `dispose` historically
37
+ * pass a session id; this helper keeps the boundary forgiving.
38
+ */
39
+ function toSessionChannel(sessionIdOrUri) {
40
+ return sessionIdOrUri.startsWith(SESSION_CHANNEL_PREFIX)
41
+ ? sessionIdOrUri
42
+ : sessionChannel(sessionIdOrUri);
43
+ }
44
+ /**
45
+ * Minimal push/pull queue specialized for per-session envelope streaming.
46
+ * Mirrors `packages/runtime-sdk/src/async-queue.ts:1-48`; inlined here to
47
+ * avoid a new dep edge on runtime-sdk.
48
+ *
49
+ * @internal
50
+ */
51
+ class EnvelopeQueue {
52
+ buffer = [];
53
+ waiters = [];
54
+ closedFlag = false;
55
+ push(item) {
56
+ if (this.closedFlag) {
57
+ return;
58
+ }
59
+ const waiter = this.waiters.shift();
60
+ if (waiter !== undefined) {
61
+ waiter(item);
62
+ return;
63
+ }
64
+ this.buffer.push(item);
65
+ }
66
+ async shift() {
67
+ const buffered = this.buffer.shift();
68
+ if (buffered !== undefined) {
69
+ return buffered;
70
+ }
71
+ if (this.closedFlag) {
72
+ return undefined;
73
+ }
74
+ return new Promise((resolve) => {
75
+ this.waiters.push(resolve);
76
+ });
77
+ }
78
+ close() {
79
+ if (this.closedFlag) {
80
+ return;
81
+ }
82
+ this.closedFlag = true;
83
+ for (const waiter of this.waiters) {
84
+ waiter(undefined);
85
+ }
86
+ this.waiters.length = 0;
87
+ }
88
+ get closed() {
89
+ return this.closedFlag;
90
+ }
91
+ async *[Symbol.asyncIterator]() {
92
+ while (true) {
93
+ const item = await this.shift();
94
+ if (item === undefined) {
95
+ return;
96
+ }
97
+ yield item;
98
+ }
99
+ }
100
+ }
101
+ /**
102
+ * AHP-backed {@link IHostTransport} for a single environment.
103
+ *
104
+ * Lifecycle: one instance per `PowerLineConnection`. Owns one
105
+ * `AhpClientSocket`; multiplexes session subscriptions over it.
106
+ *
107
+ * Construct via {@link createAhpHostTransport} (in `./connect.ts`) which
108
+ * handles the `socket.open()` handshake. Tests can construct directly with
109
+ * a pre-opened socket.
110
+ */
111
+ export class AhpHostTransport {
112
+ socket;
113
+ sessions = new Map();
114
+ nextClientSeq = 0;
115
+ /**
116
+ * Construct an AhpHostTransport over a pre-opened `AhpClientSocket`.
117
+ * The socket MUST already have completed its `initialize` handshake.
118
+ *
119
+ * @param socket - The AHP client socket, opened and connected.
120
+ */
121
+ constructor(socket) {
122
+ this.socket = socket;
123
+ }
124
+ /**
125
+ * Notification handler that must be supplied to `AhpClientSocket` at
126
+ * construction time (the socket's `onNotification` option). This is a
127
+ * static-bound method so it can be passed to the socket constructor.
128
+ *
129
+ * Routes inbound `action` notifications to the appropriate per-session
130
+ * queue, running the reverse mapper to synthesize `AgentEventFields` and
131
+ * wrapping each into a `ServerActionEnvelope`. Other notification methods
132
+ * are ignored (no consumers in the wire-only scope of HR8d).
133
+ *
134
+ * @param notif - The AHP notification from the wire.
135
+ */
136
+ handleNotification(notif) {
137
+ if (notif.method !== "action") {
138
+ // Other notifications (root/sessionAdded, auth/required, otlp/*, etc.)
139
+ // are not consumed by Grackle's downstream pipeline; drop silently.
140
+ return;
141
+ }
142
+ const envelope = notif.params;
143
+ const session = this.sessions.get(envelope.channel);
144
+ if (session === undefined) {
145
+ return;
146
+ }
147
+ const result = reverseMapAction(envelope, session.context);
148
+ for (const event of result.events) {
149
+ session.queue.push({ event, actions: [envelope.action] });
150
+ }
151
+ }
152
+ /**
153
+ * Create a new session via AHP `createSession` + `subscribe`.
154
+ *
155
+ * Returns synchronously with the session URI and the live envelope stream.
156
+ * The actual AHP requests fire in the background; failures push an error
157
+ * sentinel into the stream and close it (mirroring how gRPC stream errors
158
+ * surface during iteration).
159
+ */
160
+ createSession(params) {
161
+ const channel = sessionChannel(params.sessionId);
162
+ const session = this.getOrCreateSession(channel);
163
+ void this.runSpawnFlow(channel, params, undefined).catch((err) => {
164
+ this.surfaceErrorAndClose(session, channel, err);
165
+ });
166
+ return { sessionUri: channel, stream: session.queue };
167
+ }
168
+ /**
169
+ * Reanimate a suspended session. Maps to AHP `createSession` with a
170
+ * `config.resumeFromRuntimeSessionId` hint that PowerLine interprets as
171
+ * "spawn a continuation runtime from this prior runtime session."
172
+ */
173
+ reanimate(params) {
174
+ const channel = sessionChannel(params.sessionId);
175
+ const session = this.getOrCreateSession(channel);
176
+ const reanimateConfig = {
177
+ sessionId: params.sessionId,
178
+ runtime: params.runtime,
179
+ // Reanimate doesn't have prompt/model/etc.; use empty defaults — the
180
+ // PowerLine handler ignores them when resumeFromRuntimeSessionId is set.
181
+ prompt: "",
182
+ model: "",
183
+ maxTurns: 0,
184
+ branch: "",
185
+ workingDirectory: "",
186
+ systemContext: "",
187
+ taskId: "",
188
+ mcpServersJson: "",
189
+ mcpUrl: "",
190
+ mcpToken: "",
191
+ };
192
+ void this.runSpawnFlow(channel, reanimateConfig, params.runtimeSessionId).catch((err) => {
193
+ this.surfaceErrorAndClose(session, channel, err);
194
+ });
195
+ return session.queue;
196
+ }
197
+ /** Send input text by dispatching a `SessionTurnStartedAction`. */
198
+ async dispatchInput(sessionUri, text) {
199
+ this.nextClientSeq += 1;
200
+ const action = {
201
+ type: ActionType.SessionTurnStarted,
202
+ turnId: `turn-input-${String(this.nextClientSeq)}`,
203
+ userMessage: { text },
204
+ };
205
+ this.socket.notify("dispatchAction", {
206
+ channel: toSessionChannel(sessionUri),
207
+ clientSeq: this.nextClientSeq,
208
+ action,
209
+ });
210
+ }
211
+ /**
212
+ * Deliver runtime credentials.
213
+ *
214
+ * AHP `authenticate` is OAuth-shaped (single `{ resource, token }`) and
215
+ * Grackle's HR6 authenticate delivers multiple typed tokens (env-var or
216
+ * file-backed) for one provider. HR8d preserves the AHP-spec wire method
217
+ * by fanning Grackle's tokens out into N `authenticate` calls. Each call:
218
+ *
219
+ * - `resource`: `grackle://provider/{provider}/{name}` — encodes the
220
+ * Grackle-side identity. PowerLine recognizes the `grackle://` scheme
221
+ * and decodes it.
222
+ * - `token`: JSON-encoded `{ type, envVar?, filePath?, value }` — carries
223
+ * the delivery instructions inside the AHP token field.
224
+ *
225
+ * On-spec method, abused field semantics. The contortion is documented in
226
+ * #1336 and bounded to this single command.
227
+ */
228
+ async authenticate(params) {
229
+ const settlements = await Promise.allSettled(params.tokens.map((t) => this.socket.request("authenticate", {
230
+ channel: ROOT_CHANNEL,
231
+ resource: `grackle://provider/${params.provider}/${t.name}`,
232
+ token: JSON.stringify({
233
+ type: t.type,
234
+ envVar: t.envVar,
235
+ filePath: t.filePath,
236
+ value: t.value,
237
+ }),
238
+ })));
239
+ // Surface the first failure (if any) so the caller can log it — matches
240
+ // the prior gRPC-path "best-effort, log and continue" semantics.
241
+ const rejection = settlements.find((s) => s.status === "rejected");
242
+ if (rejection !== undefined && rejection.status === "rejected") {
243
+ throw rejection.reason;
244
+ }
245
+ }
246
+ /**
247
+ * Dispose a session via AHP `disposeSession`.
248
+ *
249
+ * AHP's `DisposeSessionParams` doesn't carry a `reason` field; the optional
250
+ * `reason` argument is logged client-side but not delivered to PowerLine.
251
+ * Acceptable for HR8d — `reason` was informational in the gRPC path too.
252
+ */
253
+ async dispose(sessionUri, _reason) {
254
+ const channel = toSessionChannel(sessionUri);
255
+ try {
256
+ await this.socket.request("disposeSession", { channel });
257
+ }
258
+ finally {
259
+ this.closeSession(channel);
260
+ }
261
+ }
262
+ /** List active sessions via AHP `listSessions`. */
263
+ async listSessions() {
264
+ const result = (await this.socket.request("listSessions", {
265
+ channel: ROOT_CHANNEL,
266
+ }));
267
+ return result.items.map((s) => ({
268
+ sessionId: s.resource.replace(/^ahp-session:\//, ""),
269
+ runtime: s.provider,
270
+ // SessionStatus is a bitset enum; preserve the numeric value as string
271
+ // so existing consumers (which treat status as opaque) still work.
272
+ status: String(s.status),
273
+ }));
274
+ }
275
+ // ─── Internals ────────────────────────────────────────────────────
276
+ getOrCreateSession(channel) {
277
+ let session = this.sessions.get(channel);
278
+ if (session === undefined) {
279
+ session = { queue: new EnvelopeQueue(), context: newReverseMapperContext() };
280
+ this.sessions.set(channel, session);
281
+ }
282
+ return session;
283
+ }
284
+ closeSession(channel) {
285
+ const session = this.sessions.get(channel);
286
+ if (session === undefined) {
287
+ return;
288
+ }
289
+ session.queue.close();
290
+ this.sessions.delete(channel);
291
+ }
292
+ async runSpawnFlow(channel, params, resumeFromRuntimeSessionId) {
293
+ const config = {
294
+ // Grackle-specific session config — PowerLine handler validates this shape.
295
+ prompt: params.prompt,
296
+ model: params.model,
297
+ maxTurns: params.maxTurns,
298
+ branch: params.branch,
299
+ workingDirectory: params.workingDirectory,
300
+ systemContext: params.systemContext,
301
+ taskId: params.taskId,
302
+ mcpServersJson: params.mcpServersJson,
303
+ mcpUrl: params.mcpUrl,
304
+ mcpToken: params.mcpToken,
305
+ ...(params.workspaceId !== undefined ? { workspaceId: params.workspaceId } : {}),
306
+ ...(params.useWorktrees !== undefined ? { useWorktrees: params.useWorktrees } : {}),
307
+ ...(params.pipe !== undefined && params.pipe !== "" ? { pipe: params.pipe } : {}),
308
+ ...(params.scriptContent !== undefined && params.scriptContent !== ""
309
+ ? { scriptContent: params.scriptContent }
310
+ : {}),
311
+ ...(resumeFromRuntimeSessionId !== undefined ? { resumeFromRuntimeSessionId } : {}),
312
+ };
313
+ const ahpParams = {
314
+ channel,
315
+ provider: params.runtime,
316
+ config,
317
+ };
318
+ const isReanimate = resumeFromRuntimeSessionId !== undefined;
319
+ try {
320
+ await this.socket.request("createSession", ahpParams);
321
+ }
322
+ catch (err) {
323
+ // Reanimate path: if the channel is already live on PowerLine (env was
324
+ // never actually torn down — happens with the local adapter whose
325
+ // `stop()` is a no-op), the server returns "Session already active".
326
+ // For reanimate that's success: the underlying runtime never died, we
327
+ // just need to re-subscribe to its action stream.
328
+ if (isReanimate && isSessionAlreadyActiveError(err)) {
329
+ // intentional fall-through to subscribe()
330
+ }
331
+ else {
332
+ throw err;
333
+ }
334
+ }
335
+ await this.socket.request("subscribe", { channel });
336
+ // After subscribe resolves, PowerLine starts firing action notifications
337
+ // (including any replayed parked events) — the handleNotification handler
338
+ // routes them to the session's queue.
339
+ }
340
+ surfaceErrorAndClose(session, channel, err) {
341
+ // Synthesize an error event so the downstream pipeline sees the failure
342
+ // through the same channel it sees normal events.
343
+ const message = formatTransportError(err);
344
+ const errorEvent = { type: "error", content: message };
345
+ session.queue.push({ event: errorEvent, actions: [] });
346
+ session.queue.push({ event: { type: "status", content: "failed" }, actions: [] });
347
+ this.closeSession(channel);
348
+ }
349
+ }
350
+ /**
351
+ * True if `err` is the JSON-RPC "Session already active" error PowerLine
352
+ * returns when `createSession` targets a channel whose underlying session
353
+ * is still live in the registry. Tested with both message-prefix and
354
+ * code+message-shape since the error can arrive as a rejected
355
+ * `TransportError` or a raw JSON-RPC error object depending on the
356
+ * `request()` path.
357
+ */
358
+ function isSessionAlreadyActiveError(err) {
359
+ const message = err instanceof Error
360
+ ? err.message
361
+ : err !== null &&
362
+ typeof err === "object" &&
363
+ typeof err.message === "string"
364
+ ? err.message
365
+ : "";
366
+ return message.startsWith("Session already active");
367
+ }
368
+ /**
369
+ * Stringify an unknown error into a readable message for the synthesized
370
+ * `type: "error"` event surfaced into the downstream pipeline.
371
+ *
372
+ * Handles four shapes:
373
+ * - `Error` (and subclasses, including `TransportError` from
374
+ * `@grackle-ai/ahp-transport`): use `.message`.
375
+ * - JSON-RPC error object `{ code, message }` (what `request()` rejects with
376
+ * on a server-returned error): use `.message`, prefix with code if present.
377
+ * Without this branch, `String(err)` returns `"[object Object]"` and the
378
+ * UI renders an opaque "Error: [object Object]" with no diagnostic value.
379
+ * - String: pass through.
380
+ * - Anything else: best-effort `String(err)`.
381
+ */
382
+ function formatTransportError(err) {
383
+ if (err instanceof Error) {
384
+ return err.message;
385
+ }
386
+ if (typeof err === "string") {
387
+ return err;
388
+ }
389
+ if (err !== null && typeof err === "object") {
390
+ const obj = err;
391
+ if (typeof obj.message === "string" && obj.message.length > 0) {
392
+ return typeof obj.code === "number" || typeof obj.code === "string"
393
+ ? `JSON-RPC error ${String(obj.code)}: ${obj.message}`
394
+ : obj.message;
395
+ }
396
+ }
397
+ return String(err);
398
+ }
399
+ /**
400
+ * Helper to wire {@link AhpHostTransport}'s notification handler into an
401
+ * `AhpClientSocket` at construction time. The transport's
402
+ * {@link AhpHostTransport.handleNotification} method must be bound to the
403
+ * socket BEFORE `socket.open()` so the first inbound `action` notifications
404
+ * are routed correctly.
405
+ *
406
+ * @param transport - The transport whose handler should be bound.
407
+ * @returns A function suitable for passing as `onNotification` to
408
+ * `AhpClientSocket`'s constructor options.
409
+ */
410
+ export function bindNotificationHandler(transport) {
411
+ return (n) => transport.handleNotification(n);
412
+ }
413
+ //# sourceMappingURL=ahp-host-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ahp-host-transport.js","sourceRoot":"","sources":["../src/ahp-host-transport.ts"],"names":[],"mappings":"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"}
package/dist/connect.d.ts CHANGED
@@ -1,16 +1,42 @@
1
- import type { PowerLineClient, PowerLineConnection } from "./adapter.js";
1
+ import { AhpClientSocket } from "@grackle-ai/ahp-transport";
2
+ import type { PowerLineConnection } from "./adapter.js";
3
+ import { AhpHostTransport } from "./ahp-host-transport.js";
2
4
  import type { AdapterLogger } from "./logger.js";
3
5
  /**
4
- * Create an authenticated gRPC client for a PowerLine.
5
- * The PowerLine token is sent as a Bearer token on every request.
6
- * When `traceId` is provided, it is forwarded as the `x-trace-id` header for request correlation.
6
+ * Construct an opened {@link AhpHostTransport} for a single PowerLine.
7
+ *
8
+ * Opens an `AhpClientSocket` to `${baseUrl}/ahp`, awaits the AHP
9
+ * `initialize` handshake, and returns the transport ready for use.
10
+ *
11
+ * `InMemoryClientIdStore` is used by default — Grackle's adapter
12
+ * connections are ephemeral (one per provision; reconnect creates a fresh
13
+ * one). Persistent `clientId` across server restarts is not required for
14
+ * HR8d. A future optimization (HR8a-followup #1344) would persist for
15
+ * reconnect-RPC replay efficiency.
16
+ *
17
+ * @param baseUrl - Origin URL of the PowerLine (e.g. `ws://127.0.0.1:7433`).
18
+ * The helper appends `/ahp` to form the WebSocket URL.
19
+ * @param powerlineToken - Bearer token sent on the HTTP upgrade.
20
+ * @param environmentId - Used as the `clientIdKey` to namespace the
21
+ * persisted clientId within the store.
22
+ * @param logger - Optional logger for state transitions.
23
+ * @returns The opened transport.
7
24
  */
8
- export declare function createPowerLineClient(baseUrl: string, powerlineToken: string, traceId?: string): PowerLineClient;
25
+ export declare function createAhpHostTransport(baseUrl: string, powerlineToken: string, environmentId: string, logger?: AdapterLogger): Promise<{
26
+ transport: AhpHostTransport;
27
+ socket: AhpClientSocket;
28
+ }>;
9
29
  /**
10
- * Connect to a PowerLine through a local tunnel port, retrying until the gRPC
11
- * service responds to a ping.
30
+ * Connect to a PowerLine through a local tunnel port, retrying until the AHP
31
+ * `ping` succeeds.
32
+ *
33
+ * @param environmentId - Stable identifier for the environment.
34
+ * @param localPort - Local TCP port the tunnel forwards to the PowerLine.
35
+ * @param powerlineToken - Bearer token for the PowerLine.
36
+ * @param logger - Optional logger.
37
+ * @returns A {@link PowerLineConnection} ready for session operations.
12
38
  */
13
- export declare function connectThroughTunnel(environmentId: string, localPort: number, powerlineToken: string, logger?: AdapterLogger, traceId?: string): Promise<PowerLineConnection>;
39
+ export declare function connectThroughTunnel(environmentId: string, localPort: number, powerlineToken: string, logger?: AdapterLogger): Promise<PowerLineConnection>;
14
40
  /** Single-shot TCP port prober used by {@link waitForLocalPort}. */
15
41
  export interface PortProber {
16
42
  /** Attempt a single TCP connection to `host:port`, returning `true` if it succeeds. */