dsh-llm-omp-transports 0.2.4 → 0.2.6

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 (56) hide show
  1. package/README.md +160 -15
  2. package/bundle/cordis.patch.yml +1 -1
  3. package/lib/adapter.d.ts +133 -37
  4. package/lib/adapter.js +169 -87
  5. package/lib/adapter.js.map +1 -1
  6. package/lib/catalog/devin.d.ts +27 -0
  7. package/lib/catalog/devin.js +57 -0
  8. package/lib/catalog/devin.js.map +1 -0
  9. package/lib/catalog/google-antigravity.d.ts +27 -0
  10. package/lib/catalog/google-antigravity.js +1062 -0
  11. package/lib/catalog/google-antigravity.js.map +1 -0
  12. package/lib/catalog/google-gemini-cli.d.ts +28 -0
  13. package/lib/catalog/google-gemini-cli.js +330 -0
  14. package/lib/catalog/google-gemini-cli.js.map +1 -0
  15. package/lib/cursor/auth.js +3 -18
  16. package/lib/cursor/auth.js.map +1 -1
  17. package/lib/devin/auth.d.ts +97 -0
  18. package/lib/devin/auth.js +144 -0
  19. package/lib/devin/auth.js.map +1 -0
  20. package/lib/devin/credentials.d.ts +31 -0
  21. package/lib/devin/credentials.js +61 -0
  22. package/lib/devin/credentials.js.map +1 -0
  23. package/lib/devin/transport.d.ts +25 -0
  24. package/lib/devin/transport.js +26 -0
  25. package/lib/devin/transport.js.map +1 -0
  26. package/lib/google/auth.d.ts +130 -0
  27. package/lib/google/auth.js +590 -0
  28. package/lib/google/auth.js.map +1 -0
  29. package/lib/google/callback-listener.d.ts +67 -0
  30. package/lib/google/callback-listener.js +289 -0
  31. package/lib/google/callback-listener.js.map +1 -0
  32. package/lib/google/client-facts.generated.d.ts +13 -0
  33. package/lib/google/client-facts.generated.js +12 -0
  34. package/lib/google/client-facts.generated.js.map +1 -0
  35. package/lib/google/credentials.d.ts +49 -0
  36. package/lib/google/credentials.js +167 -0
  37. package/lib/google/credentials.js.map +1 -0
  38. package/lib/google/route.d.ts +54 -0
  39. package/lib/google/route.js +85 -0
  40. package/lib/google/route.js.map +1 -0
  41. package/lib/index.d.ts +322 -14
  42. package/lib/index.js +304 -20
  43. package/lib/index.js.map +1 -1
  44. package/lib/jwt.d.ts +36 -0
  45. package/lib/jwt.js +46 -0
  46. package/lib/jwt.js.map +1 -0
  47. package/lib/omp/devin.mjs +19952 -0
  48. package/lib/omp/google.mjs +20783 -0
  49. package/lib/omp.d.ts +165 -7
  50. package/lib/projection.d.ts +177 -6
  51. package/lib/projection.js +409 -101
  52. package/lib/projection.js.map +1 -1
  53. package/lib/transport/fetch.d.ts +9 -0
  54. package/lib/transport/fetch.js +41 -0
  55. package/lib/transport/fetch.js.map +1 -0
  56. package/package.json +8 -6
package/README.md CHANGED
@@ -11,16 +11,17 @@ and the plugin page lists both bundle components
11
11
  |---|---|
12
12
  | npm package | `dsh-llm-omp-transports` |
13
13
  | Plugin id | `llm-omp-transports` |
14
- | Route | `cursor` (first provider; the seam is provider-generic) |
15
- | Credential scope | `llm-omp-transports/<provider>`, today `llm-omp-transports/cursor` |
14
+ | Routes | `cursor`, `devin`, `google-gemini-cli`, `google-antigravity` (the seam is provider-generic) |
15
+ | Credential scope | `llm-omp-transports/<provider>`: `llm-omp-transports/cursor`, `llm-omp-transports/devin`, `llm-omp-transports/google-gemini-cli`, `llm-omp-transports/google-antigravity` |
16
16
  | Runtime | Node 24 (the bundle imports Node builtins only) |
17
17
  | License | MIT |
18
18
 
19
19
  The plugin registers its own route on the DSH `llm` seam, so it depends on no
20
20
  upstream DSH change. `@oh-my-pi/pi-ai` and `@oh-my-pi/pi-catalog` are used at
21
- **build time only**: the build inlines the pinned omp Cursor transport into one
22
- ESM artifact (`lib/omp/cursor.mjs`), and the published package imports nothing
23
- from `@oh-my-pi/*` or `bun:*` at runtime.
21
+ **build time only**: the build inlines the pinned omp transports into one ESM
22
+ artifact per route (`lib/omp/cursor.mjs`, `lib/omp/devin.mjs`), plus one shared
23
+ artifact for the two Google routes (`lib/omp/google.mjs`), and the published
24
+ package imports nothing from `@oh-my-pi/*` or `bun:*` at runtime.
24
25
 
25
26
  ## Cursor support status
26
27
 
@@ -47,6 +48,82 @@ from `@oh-my-pi/*` or `bun:*` at runtime.
47
48
  - **Images** — not yet. The route advertises text-only input and refuses image
48
49
  blocks with `CONTENT_UNSUPPORTED`; see [known limits](docs/known-limits.md).
49
50
 
51
+ ## Devin support status
52
+
53
+ - **Text streaming** — yes. Assistant text and reasoning are projected onto
54
+ DSH's `StreamChunk` stream, with the per-turn usage the chat frames report.
55
+ - **Reasoning streaming** — yes as content; no reasoning-effort selector. Both
56
+ pinned rows advertise no efforts, and a request that selects one is refused
57
+ with `UNSUPPORTED_REASONING_EFFORT`.
58
+ - **Tool-call handoff** — yes, native to DSH's tool loop. The transport emits
59
+ the call, finishes the turn `toolUse`, and DSH executes it; the result is
60
+ replayed from history on the next request. Unlike Cursor, no call is
61
+ transport-resolved, so nothing is filtered from the handoff.
62
+ - **Sign-in** — yes, by pasting the callback. The pinned omp login is a
63
+ declarative `oauth-code` rule whose loopback listener is Bun-only; this
64
+ package registers the `llm-omp-transports/devin` flow, opens the authorize
65
+ page, and asks for the address the browser landed on (or just the code).
66
+ There is **no refresh** (`refresh "none"`): an expired grant demands a new
67
+ sign-in.
68
+ - **Models** — from the pinned catalog: the Devin slice of
69
+ `@oh-my-pi/pi-catalog@18.12.3` (2 rows: `swe-1-6`, `swe-1-6-fast`) is
70
+ generated into `src/catalog/devin.ts` and served without a network call.
71
+ - **Route** — `devin`, declared configurable so the Models page has a
72
+ `providers.devin` profile with an allow-list.
73
+ - **Images** — not yet, same as Cursor: text-only input, image blocks refused
74
+ with `CONTENT_UNSUPPORTED`.
75
+
76
+ ## Google support status
77
+
78
+ Two routes share one artifact: `google-gemini-cli` (Google's Gemini CLI client)
79
+ and `google-antigravity` (the Antigravity hub client). The bundled
80
+ `streamGoogleGeminiCli` dispatches on `model.provider`, so the route is a data
81
+ difference — separate OAuth client, catalogs, hosts, scopes and credential
82
+ records — not a second code path.
83
+
84
+ - **Text streaming** — yes, including reasoning parts and usage.
85
+ - **Reasoning streaming** — yes, with each row's own effort ladder: the
86
+ budget-mode rows send `thinkingConfig.thinkingBudget`, the Gemini-3+ rows send
87
+ `thinkingLevel`. A row with `requiresEffort` refuses a turn that selects no
88
+ effort (`UNSUPPORTED_REASONING_EFFORT`), exactly as omp does.
89
+ - **Tool-call handoff** — yes, native to DSH's tool loop, like Devin: the
90
+ transport emits the call and finishes the turn `toolUse`. Antigravity's
91
+ default tool mode (`VALIDATED`) is sent on every request that declares tools.
92
+ - **Sign-in** — yes, with a real loopback listener on `127.0.0.1`:
93
+ `:8085/oauth2callback` for Gemini CLI and `:51121/oauth-callback` for
94
+ Antigravity, as the pinned rules declare. The browser redirect completes the
95
+ flow automatically; if the port is taken the listener falls back to an
96
+ ephemeral port and the authorize page names the port it actually bound. The
97
+ full address the browser landed on (or `code#state`) can also be pasted; a
98
+ pasted code without the state is refused, because that is exactly the shape a
99
+ forged callback would have. Anything the listener does not recognise — a
100
+ foreign `state`, an `error=`, a missing code — is answered `400` and dropped
101
+ without ending the attempt, so a stray request cannot kill the sign-in. The
102
+ listener closes on the matching callback, on an aborted attempt and **on a
103
+ timeout** (five minutes, `GoogleFlowOptions.waitMs` for tests): an expired wait
104
+ fails with `AUTH_FAILED` and commits nothing.
105
+ - **Refresh** — yes. The resolver refreshes once, under the credential store's
106
+ per-key lock, when `expires - 60 s <= now`, keeps the `projectId` and an
107
+ un-rotated `refresh_token`, and reports a dead sign-in as `REAUTH_REQUIRED`.
108
+ - **Credential record** — `llm-omp-transports/<route>` with
109
+ `{access, refresh, expires, projectId, email?}`. The adapter hands the
110
+ transport the structured JSON envelope (`token`, `projectId`, `refreshToken`,
111
+ `expiresAt`, `email`) that omp parses.
112
+ - **Project discovery** — sign-in finishes with the Cloud Code Assist project:
113
+ `loadCodeAssist` → (tier onboarding `onboardUser` + LRO poll, or the required
114
+ `GOOGLE_CLOUD_PROJECT` / `GOOGLE_CLOUD_PROJECT_ID` variable for a
115
+ `legacy-tier`/paid account). Antigravity additionally checks free-tier
116
+ eligibility and bounds onboarding at 30 s.
117
+ - **Models** — generated from the pinned `@oh-my-pi/pi-catalog@18.12.3`: 7 rows
118
+ for `google-gemini-cli`, 22 for `google-antigravity`, served without a network
119
+ call.
120
+ - **Routes** — both declared configurable, so the Models page has
121
+ `providers.google-gemini-cli` and `providers.google-antigravity` allow-lists.
122
+ - **Images** — not yet, same posture as the other routes: text-only input, image
123
+ blocks refused with `CONTENT_UNSUPPORTED`. omp's Antigravity image path
124
+ decodes through `Bun.Image`, which does not exist under Node, so that path is
125
+ dead here by construction; the projection never reaches it.
126
+
50
127
  ## Hard constraints
51
128
 
52
129
  - **Pinned, build-time-only omp.** `@oh-my-pi/pi-ai` and `@oh-my-pi/pi-catalog`
@@ -65,8 +142,9 @@ from `@oh-my-pi/*` or `bun:*` at runtime.
65
142
  committed manifest is unchanged after a build, so an omp bump that changes
66
143
  the contract shows up as a reviewable manifest diff before it can reach a
67
144
  request.
68
- - **Generated catalog.** The Cursor model table is generated from the pinned
69
- catalog and is not hand-edited. An omp or catalog bump requires
145
+ - **Generated catalogs.** The model tables (`cursor`, `devin`,
146
+ `google-gemini-cli`, `google-antigravity`) are generated from the pinned
147
+ catalog and are not hand-edited. An omp or catalog bump requires
70
148
  `pnpm -C packages/llm-omp run generate:catalog`.
71
149
 
72
150
  ## Limits and risks
@@ -95,14 +173,71 @@ from `@oh-my-pi/*` or `bun:*` at runtime.
95
173
  stops at the handoff; the result is only replayed on the follow-up request.
96
174
  Tool declarations travel as MCP definitions, and `toolHistory` is accepted
97
175
  but cannot be replayed (the active tool set is the projection).
98
- - **Only MCP calls are handed off.** Cursor-native exec frames (`read`, `shell`,
99
- `write`, `delete`, `grep`, `ls`, `diagnostics`, streamed edits) are answered
100
- by the transport with `Tool not available` and are **not** executed by DSH
101
- (live reachability unverified).
176
+ - **Colliding DSH tools are aliased, not dropped.** The transport keeps
177
+ Cursor's own `read`/`bash`/`write`/`delete`/`ls`/`grep`/`todo` names off the
178
+ MCP advertisement, so a DSH tool with one of those names is advertised as
179
+ `dsh_<name>`; the event stream restores the DSH name on the tool call, while
180
+ history replay keeps the advertised alias so the follow-up request stays
181
+ consistent. The seven `dsh_<native>` names are reserved: a DSH tool that
182
+ already carries one is refused with `TOOL_ALIAS_COLLISION`, which fails the
183
+ whole request and requires renaming the tool. Any other tool name travels
184
+ unchanged. Cursor-native exec frames (`read`, `shell`, `write`, `delete`,
185
+ `grep`, `ls`, `diagnostics`, streamed edits) are still answered by the
186
+ transport with `Tool not available` and are **not** executed by DSH (live
187
+ reachability unverified).
102
188
  - **Advisory request knobs are ignored.** Cursor's agent protocol has no field
103
189
  for an output cap, sampling temperature, stop sequences or an auxiliary-call
104
190
  purpose; DSH's `maxTokens`, `temperature`, `stop` and `purpose` never reach
105
191
  the wire, and Cursor applies the catalog output limit server-side.
192
+ - **Unofficial Devin client.** The transport presents the released Devin CLI
193
+ identity (`ideName: "devin-cli"`, `ideType: "chisel"`, `ideVersion:
194
+ "3000.11.3"`) and a `connect-go` client header the omp sources copy from the
195
+ CLI. Same posture as Cursor's S4: a first live turn rejected with `401`/`403`
196
+ stops the route until a product decision, never a retry under another
197
+ identity.
198
+ - **Attribution deviates on one call.** The Devin chat request must keep the
199
+ transport's own `connect-go` client header — the backend gates on it. The
200
+ header-less `GetUserJwt` handshake has no identity of its own, so the adapter
201
+ fills DSH's attribution `user-agent` only where a header is absent. Cursor's
202
+ requests keep full attribution.
203
+ - **Devin has no refresh.** The pinned rule declares `refresh "none"`, so the
204
+ record is a static bearer with a derived `expires` (JWT `exp` minus five
205
+ minutes, else one year). An expired or corrupt record is `REAUTH_REQUIRED`,
206
+ not renewed. Because the omp loopback listener is Bun-only and the browser
207
+ half is untestable offline, the flow is paste-only for now; a bare pasted
208
+ code skips the state check (the page is the only place the state could
209
+ travel).
210
+
211
+ - **Unofficial Google clients.** The Google routes reuse the OAuth clients and
212
+ client identities the pinned omp rules capture — Gemini CLI
213
+ (`GeminiCLI/0.46.0/...` plus `Client-Metadata`) and Antigravity
214
+ (`antigravity/hub/<version> ...`). Same posture as the Cursor and Devin
215
+ routes: the MIT license covers the code, not the service, and a first live
216
+ turn rejected with `401`/`403` on a valid token stops the route until a
217
+ product decision (stop condition **S4**) — never a retry under another
218
+ identity.
219
+ - **Antigravity version lookup.** Before the first Antigravity request the
220
+ artifact reads the client version from the public update manifest (D11),
221
+ because the backend gates newer models on that version. A failed lookup is
222
+ silent and falls back to the pinned `2.19.1` for ten minutes; an explicit
223
+ `PI_AI_ANTIGRAVITY_VERSION` skips the lookup. That is the only outbound
224
+ request the routes make besides the vendor API itself.
225
+ - **Google sign-in waits at most five minutes.** The loopback listener is
226
+ bounded by a wait budget (five minutes by default): a browser that never
227
+ returns fails the attempt with `AUTH_FAILED`, closes the socket and commits
228
+ nothing. An aborted attempt is reported as a cancellation, not a failure.
229
+ When the configured port is taken, the fallback is an ephemeral port; a host
230
+ that can bind neither fails the sign-in rather than silently dropping the
231
+ browser half (pasting still works only while the listener is up).
232
+ - **Google attribution deviates on both routes.** The Cloud Code Assist wire
233
+ sets a vendor `user-agent` that the backend gates on, so DSH's attribution
234
+ `user-agent` is filled only where a request left the header absent — the same
235
+ fill-absent wrapper the Devin handshake uses.
236
+ - **Real Google endpoints unverified.** The wire suite drives the bundled
237
+ transport end to end over a stubbed `fetch` (URL, envelope, headers, SSE,
238
+ in-band errors, Antigravity failover and the version manifest), but it never
239
+ calls Google. A first live sign-in and turn is a manual smoke check, not a
240
+ claim of server acceptance.
106
241
 
107
242
  ## Develop and test
108
243
 
@@ -113,9 +248,10 @@ pnpm -C packages/llm-omp test
113
248
  pnpm -C packages/llm-omp run generate:catalog
114
249
  ```
115
250
 
116
- `build` bundles the pinned omp graph from `scripts/omp-entry.ts` into
117
- `lib/omp/cursor.mjs` and rewrites `scripts/omp-manifest.json`; run it before
118
- `test` after a pin or shim change. CI runs the same sequence and then fails if
251
+ `build` bundles the pinned omp graphs from `scripts/omp-entry.ts`,
252
+ `scripts/omp-entry-devin.ts` and `scripts/omp-entry-google.ts` into
253
+ `lib/omp/cursor.mjs`, `lib/omp/devin.mjs` and `lib/omp/google.mjs` and rewrites
254
+ `scripts/omp-manifest.json`; run it before `test` after a pin or shim change. CI runs the same sequence and then fails if
119
255
  the committed manifest drifted.
120
256
 
121
257
  The install proof lives at the repository root and needs `pnpm` and `dsh` on
@@ -128,7 +264,7 @@ node scripts/verify-install.mjs
128
264
  It packs both packages, installs the root tarball into a fresh DSH profile,
129
265
  and asserts that the composed profile carries both loader rows
130
266
  (`dsh-keys-manager` and `llm-omp-transports`). It does not exercise the
131
- plugin-manager UI or any Cursor network behavior.
267
+ plugin-manager UI or any provider network behavior.
132
268
 
133
269
  ## Release
134
270
 
@@ -146,3 +282,12 @@ plugin surface.
146
282
  ## License
147
283
 
148
284
  Released under the [MIT License](../../LICENSE).
285
+
286
+ ## Deferred
287
+
288
+ `factory-droid` is **not** part of this component yet. Its omp graph pulls
289
+ `providers/register-builtins`, which statically imports every builtin provider,
290
+ measuring 327 modules / 16 991 893 B at the current pin — far past the plan's
291
+ stop rule — so the route waits for its own plan (tracked as issue `I-000253`,
292
+ with a build-substitution remedy as one candidate). Nothing in this package
293
+ reads or registers a `factory-droid` route.
@@ -1,5 +1,5 @@
1
1
  # Mounts the llm-omp-transports transport plugin when this package is installed on its
2
- # own. It owns the `cursor` (later `devin`, …) LLM routes and the
2
+ # own. It owns the `cursor` and `devin` LLM routes and the
3
3
  # `llm-omp-transports/<provider>` credential scope.
4
4
  - insert:
5
5
  - id: llm-omp-transports
package/lib/adapter.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  /**
2
- * Adapter for the omp-owned `cursor` route.
2
+ * Adapter for the omp-owned routes this plugin serves.
3
3
  *
4
- * The route speaks Cursor's own agent protocol (`agent.v1.AgentService/Run`
5
- * over HTTP/2) through the omp build artifact in `lib/omp/cursor.mjs`. The
4
+ * Two routes share one shape: the provider speaks its own agent protocol
5
+ * (Cursor's `agent.v1.AgentService/Run`, Devin's Connect-framed
6
+ * `GetChatMessage`) through an omp build artifact in `lib/omp/*.mjs`. The
6
7
  * transport is injected rather than imported so this module stays free of the
7
- * 14 MB build artifact and tests can replay recorded event scripts. The plugin
8
- * wires the bundled `streamCursor` at registration and the credential seam
9
- * provides {@link OmpCursorAdapterConfig.access}, which refreshes an expiring
10
- * grant under the store's lock before it answers.
8
+ * bundled artifacts and tests can replay recorded event scripts. A
9
+ * {@link TransportRoute} carries what differs per route: the catalog, the
10
+ * projection and the credential key; the base class carries the shared
11
+ * credential/turn ordering.
11
12
  *
12
- * The catalog is the generated `src/catalog/cursor.ts`, so `listModels` and
13
+ * The catalogs are the generated `src/catalog/*.ts`, so `listModels` and
13
14
  * `resolveModel` answer without a network call and carry the transport flags the
14
15
  * projection needs (effort routing, max mode, glyph tokenization).
15
16
  *
@@ -17,30 +18,95 @@
17
18
  */
18
19
  import { LlmAdapter } from '@deepseek-ai/dsh-llm';
19
20
  import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
20
- import type { OmpCursorTransport } from './omp.js';
21
- /** The provider route this adapter owns. */
21
+ import type { RouteProfile } from './projection.js';
22
+ import type { OmpAssistantMessageEvent, OmpContext } from './omp.js';
23
+ import type { CursorModelRow, DevinModelRow, GoogleModelRow, OmpCursorModel, OmpCursorOptions, OmpDevinModel, OmpDevinOptions, OmpGoogleModel, OmpGoogleOptions } from './omp.js';
24
+ /** The Cursor provider route this adapter owns. */
22
25
  export declare const CURSOR_ROUTE = "cursor";
26
+ /** The Devin provider route this adapter owns. */
27
+ export declare const DEVIN_ROUTE = "devin";
28
+ /** The Gemini CLI provider route this adapter owns. */
29
+ export declare const GOOGLE_GEMINI_CLI_ROUTE = "google-gemini-cli";
30
+ /** The Antigravity provider route this adapter owns. */
31
+ export declare const GOOGLE_ANTIGRAVITY_ROUTE = "google-antigravity";
23
32
  /** Machine code for a model id the generated catalog does not contain. */
24
33
  export declare const UNKNOWN_MODEL = "UNKNOWN_MODEL";
25
34
  /** Machine code for a provider route this adapter does not serve. */
26
35
  export declare const UNKNOWN_PROVIDER = "UNKNOWN_PROVIDER";
27
- /** What the adapter needs from its host plugin. */
28
- export interface OmpCursorAdapterConfig {
36
+ /** The catalog fields every route's row must carry. */
37
+ interface TransportRow {
38
+ readonly id: string;
39
+ readonly name: string;
40
+ readonly contextWindow: number;
41
+ }
42
+ /** The transport options both routes accept at their shared surface. */
43
+ interface TransportOptions {
44
+ readonly apiKey?: string;
45
+ readonly signal?: AbortSignal;
46
+ }
47
+ /** One omp transport function, narrowed to the plugin's event contract. */
48
+ export type OmpTransportOf<Model, Options> = (model: Model, context: OmpContext, options: Options) => AsyncIterable<OmpAssistantMessageEvent>;
49
+ /** The three positional transport arguments a projection produces. */
50
+ export interface ProjectedTransportRequest<Model, Options> {
51
+ readonly model: Model;
52
+ readonly context: OmpContext;
53
+ /** Transport options without the credential; the adapter injects `apiKey`. */
54
+ readonly options: Omit<Options, 'apiKey'> & {
55
+ readonly apiKey?: string;
56
+ };
57
+ }
58
+ /** What differs between the routes: identity, catalog, projection and credential record. */
59
+ export interface TransportRoute<Row extends TransportRow, Model, Options extends TransportOptions> {
60
+ /** Provider id; also the registered route set the projection's profile accepts. */
61
+ readonly id: 'cursor' | 'devin' | 'google-gemini-cli' | 'google-antigravity';
62
+ /** Models-page / provider-info display name. */
63
+ readonly displayName: string;
64
+ /** The `ctx.credentials` record this route reads. */
65
+ readonly credentialKey: string;
66
+ /** Projection facts: identity, fallback error code and transport-resolved marker. */
67
+ readonly profile: RouteProfile;
68
+ /** The generated catalog. */
69
+ readonly models: readonly Row[];
70
+ /** Project one DSH request onto this route's transport arguments. */
71
+ readonly project: (row: Row, options: GenerateOptions) => ProjectedTransportRequest<Model, Options>;
72
+ /**
73
+ * The row's advertised reasoning efforts.
74
+ *
75
+ * Cursor's rows carry `thinking.efforts`; Devin's rows advertise none (a
76
+ * selected effort is refused by its projection), so the route may omit this.
77
+ */
78
+ readonly efforts?: (row: Row) => readonly string[] | undefined;
79
+ }
80
+ /** The Cursor route's facts. */
81
+ export declare const CURSOR_TRANSPORT_ROUTE: TransportRoute<CursorModelRow, OmpCursorModel, OmpCursorOptions>;
82
+ /** The Devin route's facts. */
83
+ export declare const DEVIN_TRANSPORT_ROUTE: TransportRoute<DevinModelRow, OmpDevinModel, OmpDevinOptions>;
84
+ /**
85
+ * The two Google routes' facts.
86
+ *
87
+ * One artifact serves both: `streamGoogleGeminiCli` dispatches on
88
+ * `model.provider`, so only the profile, the catalog and the credential record
89
+ * differ. The credential key is the route id under the package namespace
90
+ * (`llm-omp-transports/<route>`), as it is for cursor and devin; the Google
91
+ * resolver reads and writes those records.
92
+ */
93
+ export declare const GOOGLE_GEMINI_CLI_TRANSPORT_ROUTE: TransportRoute<GoogleModelRow, OmpGoogleModel, OmpGoogleOptions>;
94
+ /** The Antigravity route's facts: the same provider over its own catalog and endpoint family. */
95
+ export declare const GOOGLE_ANTIGRAVITY_TRANSPORT_ROUTE: TransportRoute<GoogleModelRow, OmpGoogleModel, OmpGoogleOptions>;
96
+ /** What an adapter needs from its host plugin. */
97
+ export interface OmpAdapterOptions<Model, Options extends TransportOptions> {
29
98
  /**
30
- * Resolve the Cursor bearer token for one request.
99
+ * Resolve the route's bearer token for one request.
31
100
  *
32
101
  * @remarks
33
- * Asynchronous because it reads and refreshes the `llm-omp-transports/cursor`
102
+ * Asynchronous because it reads (and, for Cursor, refreshes) the route's
34
103
  * credential through the credentials seam. The request signal is forwarded
35
104
  * so an aborted turn can abandon a refresh instead of writing it late. Tests
36
105
  * inject a fake.
37
106
  */
38
107
  access: (signal?: AbortSignal) => Promise<string>;
39
- /**
40
- * The omp transport, normally the `streamCursor` export of
41
- * `lib/omp/cursor.mjs`. The seam tests drive it with recorded event scripts.
42
- */
43
- transport: OmpCursorTransport;
108
+ /** The omp transport, normally the artifact's stream export. Tests script it. */
109
+ transport: OmpTransportOf<Model, Options>;
44
110
  /**
45
111
  * Read the configured allow-list of catalog ids.
46
112
  *
@@ -48,32 +114,62 @@ export interface OmpCursorAdapterConfig {
48
114
  * A getter because the profile is a volatile setting: a save updates the
49
115
  * running config reference without re-running the plugin, so a captured
50
116
  * array would go stale. An absent or empty list advertises the full catalog,
51
- * so the schema default (`providers.cursor.models: []`) is today's behavior;
117
+ * so the schema default (`providers.<route>.models: []`) is today's behavior;
52
118
  * a non-empty list narrows the advertised models and the accepted ids.
53
119
  */
54
120
  models?: () => readonly string[] | undefined;
55
121
  }
56
- /** The DSH llm adapter for every route this plugin's omp transport serves. */
57
- export declare class OmpCursorAdapter extends LlmAdapter {
122
+ /** The adapter configuration for one concrete route. */
123
+ interface OmpRouteAdapterConfig<Row extends TransportRow, Model, Options extends TransportOptions> extends OmpAdapterOptions<Model, Options> {
124
+ readonly route: TransportRoute<Row, Model, Options>;
125
+ }
126
+ /**
127
+ * The DSH llm adapter for one omp-backed route.
128
+ *
129
+ * @remarks
130
+ * The per-turn order is fixed: refuse an already-aborted turn, resolve the row,
131
+ * project the request (refusals must not pay a credential read), read the
132
+ * credential, validate it, then stream. Cursor's grant can be refreshed under
133
+ * that read; Devin's resolver only reads.
134
+ */
135
+ declare abstract class OmpTransportAdapter<Row extends TransportRow, Model, Options extends TransportOptions> extends LlmAdapter {
58
136
  private readonly config;
59
- constructor(config: OmpCursorAdapterConfig);
60
- /**
61
- * Describe the route.
62
- *
63
- * @remarks
64
- * Cursor's agent protocol takes no client-side output cap, sampling
65
- * temperature, stop sequence or auxiliary-call purpose: the wire carries no
66
- * field for any of them, so the projection ignores those `GenerateOptions`
67
- * values instead of forwarding them. Cursor applies the catalog `maxTokens`
68
- * limit server-side.
69
- */
70
- providerInfo(provider: string): LlmProviderInfo;
71
- listModels(provider: string): Promise<readonly LlmModelInfo[]>;
72
- resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
73
- stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
137
+ private readonly rows;
138
+ protected constructor(config: OmpRouteAdapterConfig<Row, Model, Options>);
74
139
  /** The configured ids, or undefined when the route advertises the full catalog. */
75
140
  private allowed;
76
141
  /** Resolve one catalog row, refusing ids the configured allow-list excludes. */
77
142
  private rowFor;
143
+ providerInfo(provider: string): LlmProviderInfo;
144
+ listModels(provider: string): Promise<readonly LlmModelInfo[]>;
145
+ resolveModel(provider: string, model: string): Promise<LlmResolvedModelInfo>;
146
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
147
+ /** Refuse routes this adapter does not own instead of describing another provider's models. */
148
+ private assertRoute;
78
149
  private call;
150
+ /** Build the seam's exact-model metadata from one catalog row. */
151
+ private modelInfo;
152
+ }
153
+ /** The DSH llm adapter configuration for the Cursor route. */
154
+ export type OmpCursorAdapterConfig = OmpAdapterOptions<OmpCursorModel, OmpCursorOptions>;
155
+ /** The Cursor adapter: the bundled `streamCursor` over the generated Cursor catalog. */
156
+ export declare class OmpCursorAdapter extends OmpTransportAdapter<CursorModelRow, OmpCursorModel, OmpCursorOptions> {
157
+ constructor(options: OmpCursorAdapterConfig);
158
+ }
159
+ /** The DSH llm adapter configuration for the Devin route. */
160
+ export type OmpDevinAdapterConfig = OmpAdapterOptions<OmpDevinModel, OmpDevinOptions>;
161
+ /** The Devin adapter: the bundled `streamDevin` over the generated Devin catalog. */
162
+ export declare class OmpDevinAdapter extends OmpTransportAdapter<DevinModelRow, OmpDevinModel, OmpDevinOptions> {
163
+ constructor(options: OmpDevinAdapterConfig);
164
+ }
165
+ /** The DSH llm adapter configuration for a Google route. */
166
+ export type OmpGoogleAdapterConfig = OmpAdapterOptions<OmpGoogleModel, OmpGoogleOptions>;
167
+ /** The Gemini CLI adapter: the bundled `streamGoogleGeminiCli` over the Gemini CLI catalog. */
168
+ export declare class OmpGoogleGeminiCliAdapter extends OmpTransportAdapter<GoogleModelRow, OmpGoogleModel, OmpGoogleOptions> {
169
+ constructor(options: OmpGoogleAdapterConfig);
170
+ }
171
+ /** The Antigravity adapter: the same artifact and transport over the Antigravity catalog. */
172
+ export declare class OmpGoogleAntigravityAdapter extends OmpTransportAdapter<GoogleModelRow, OmpGoogleModel, OmpGoogleOptions> {
173
+ constructor(options: OmpGoogleAdapterConfig);
79
174
  }
175
+ export {};