@independo/capacitor-inderun 1.1.0-dev.3 → 1.1.0-dev.5

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.
@@ -142,6 +142,29 @@ class IndeRunSerializerTest {
142
142
 
143
143
  // --- encodeError ---
144
144
 
145
+ /**
146
+ * `systemModel` and `onnx` are web-only bootstrap keys, like
147
+ * `allowDirectOpenAIEndpoint`. Android registers its own on-device provider, so it must
148
+ * ignore them rather than fail on the options object that carries them.
149
+ */
150
+ @Test
151
+ fun `parseConfigureOptions ignores the web-only provider bootstrap keys`() {
152
+ val options = IndeRunSerializer.parseConfigureOptions(
153
+ JSONObject(
154
+ """
155
+ {
156
+ "openAI": { "model": "gpt-5.2", "auth": "none" },
157
+ "systemModel": { "id": "local.system-model.web", "timeoutMs": 30000 },
158
+ "onnx": { "modelPackage": { "id": "demo", "format": "onnx" } }
159
+ }
160
+ """.trimIndent()
161
+ )
162
+ )
163
+
164
+ assertEquals("gpt-5.2", options.openAI?.model)
165
+ assertEquals("none", options.openAI?.auth)
166
+ }
167
+
145
168
  @Test
146
169
  fun `encodeError produces correct shape with required fields only`() {
147
170
  val encoded = IndeRunSerializer.encodeError(
@@ -177,4 +200,60 @@ class IndeRunSerializerTest {
177
200
  assertEquals(2000L, encoded.getLong("retryAfterMs"))
178
201
  assertEquals("run_abc", encoded.getString("runId"))
179
202
  }
203
+
204
+ /**
205
+ * A routing refusal carries its plan diagnostics on the error's `details`, and since
206
+ * inderun 0.3.0 it does so on iOS and Android too, not just on the web SDK. The shape
207
+ * is nested — a `rejectedProviders` array of objects, each with its own `reasons`
208
+ * array — and `encodeError` hands the whole map to `JSONObject(Map)`, which deep-wraps
209
+ * via `wrap()`. Nothing asserted that before; this is the data a provider-refusal UI
210
+ * actually reads, so a regression here would be invisible until a demo showed an empty
211
+ * table.
212
+ */
213
+ @Test
214
+ fun `encodeError preserves nested route-plan diagnostics in details`() {
215
+ val encoded = IndeRunSerializer.encodeError(
216
+ IndeRunError(
217
+ errorClass = IndeRunErrorClass.CapabilityMismatch,
218
+ message = "No eligible provider can stream this request.",
219
+ details = mapOf(
220
+ "failureCode" to "CapabilityMismatch",
221
+ "rejectedProviders" to listOf(
222
+ mapOf(
223
+ "providerId" to "android.mlkit.genai",
224
+ "reasons" to listOf(
225
+ mapOf(
226
+ "code" to "streaming_not_supported",
227
+ "message" to "Provider does not declare streaming."
228
+ )
229
+ )
230
+ ),
231
+ mapOf(
232
+ "providerId" to "openai",
233
+ "reasons" to listOf(
234
+ mapOf("code" to "privacy_constraint", "message" to "local_required forbids cloud.")
235
+ )
236
+ )
237
+ )
238
+ )
239
+ )
240
+ )
241
+
242
+ val details = encoded.getJSONObject("details")
243
+ assertEquals("CapabilityMismatch", details.getString("failureCode"))
244
+
245
+ val rejected = details.getJSONArray("rejectedProviders")
246
+ assertEquals(2, rejected.length())
247
+ assertEquals("android.mlkit.genai", rejected.getJSONObject(0).getString("providerId"))
248
+ assertEquals(
249
+ "streaming_not_supported",
250
+ rejected.getJSONObject(0).getJSONArray("reasons").getJSONObject(0).getString("code")
251
+ )
252
+ assertEquals("openai", rejected.getJSONObject(1).getString("providerId"))
253
+ assertEquals(
254
+ "privacy_constraint",
255
+ rejected.getJSONObject(1).getJSONArray("reasons").getJSONObject(0).getString("code")
256
+ )
257
+ }
258
+
180
259
  }
@@ -1,5 +1,5 @@
1
1
  import type { PluginListenerHandle } from "@capacitor/core";
2
- import type { IndeRunError, StreamEvent, StreamRunHandle, TaskRequest, TaskResult } from "@independo/inderun-contracts";
2
+ import type { IndeRunError, ModelPackage, StreamEvent, StreamRunHandle, TaskRequest, TaskResult } from "@independo/inderun-contracts";
3
3
  export interface OpenAIProviderBootstrapOptions {
4
4
  model: string;
5
5
  endpointUrl?: string;
@@ -7,8 +7,50 @@ export interface OpenAIProviderBootstrapOptions {
7
7
  authContextRef?: string;
8
8
  timeoutMs?: number;
9
9
  }
10
+ /**
11
+ * Bootstrap options for the browser-managed on-device provider (Chrome's Prompt API).
12
+ *
13
+ * **Web only**, and ignored on iOS and Android, which register their own on-device
14
+ * providers — Apple Foundation Models and ML Kit GenAI — from `configure()` regardless.
15
+ *
16
+ * The browser owns model availability, download and execution, so there is nothing to
17
+ * configure: registering it is the whole point, and it is what makes
18
+ * `constraints.privacy = "local_required"` routable in a browser. Mode 1 only — this
19
+ * provider does not stream, so a `local_required` *stream* on the web is still refused at
20
+ * routing time.
21
+ *
22
+ * The web SDK's `runtime` injection seam is deliberately not exposed: it is a function,
23
+ * and `configure()` has to survive a JSON bridge hop on native.
24
+ */
25
+ export interface SystemModelProviderBootstrapOptions {
26
+ id?: string;
27
+ timeoutMs?: number;
28
+ }
29
+ /**
30
+ * Bootstrap options for the Web ONNX Runtime provider, for a developer-supplied local
31
+ * model.
32
+ *
33
+ * **Web only**, like `systemModel`, and Mode 1 only.
34
+ *
35
+ * Two caveats worth knowing before reaching for this. The consumer has to install the
36
+ * optional `@huggingface/transformers` peer dependency — this bridge does not declare it —
37
+ * and supply real model weights, because the web SDK's `runtime` seam is a function and so
38
+ * cannot cross the JSON bridge hop: only the default Transformers.js runtime is reachable
39
+ * from here, never the fixture runtime the upstream demos use offline. A registered
40
+ * provider that cannot load turns a clean routing refusal into a provider error, so
41
+ * register it only when the weights are actually there.
42
+ */
43
+ export interface OnnxProviderBootstrapOptions {
44
+ id?: string;
45
+ modelPackage: ModelPackage;
46
+ timeoutMs?: number;
47
+ }
10
48
  export interface ConfigureOptions {
11
49
  openAI?: OpenAIProviderBootstrapOptions;
50
+ /** Web only; native registers its own on-device provider. */
51
+ systemModel?: SystemModelProviderBootstrapOptions;
52
+ /** Web only; native registers its own on-device provider. */
53
+ onnx?: OnnxProviderBootstrapOptions;
12
54
  allowDirectOpenAIEndpoint?: boolean;
13
55
  }
14
56
  /**
@@ -53,9 +95,88 @@ export interface StreamRun {
53
95
  events: AsyncIterable<StreamEvent>;
54
96
  cancel(reason?: string): void;
55
97
  }
98
+ /**
99
+ * A provider's static capability declaration.
100
+ *
101
+ * Declared here rather than imported, because — unlike `TaskRequest`, `StreamEvent` and
102
+ * the rest — this shape is *not* a generated contract. There is no schema for it in
103
+ * `@independo/inderun-contracts` and no validator; each SDK declares it independently
104
+ * (`core/provider.d.ts` in `@independo/inderun-web`, `IndeRunCore/Provider.swift`,
105
+ * `core/Provider.kt`), and this is the fourth copy. Importing it from
106
+ * `@independo/inderun-web` is not an option either: that would make the native
107
+ * platforms' plugin contract depend on the web SDK.
108
+ *
109
+ * The drift guard is in `web.ts`, which returns the web SDK's value into this type
110
+ * uncast — so `tsc` proves the shapes still match on every build, the same way the
111
+ * `StreamRun` mirror below is checked. See the upstream follow-up asking for a schema.
112
+ */
113
+ export interface ProviderDescriptor {
114
+ id: string;
115
+ type: "local" | "edge" | "cloud";
116
+ transport: "in_process" | "system_service" | "http" | "sse" | "realtime";
117
+ streamingStyle?: "tokens" | "chunks" | "snapshots";
118
+ supports: {
119
+ run: boolean;
120
+ streaming: boolean;
121
+ realtime: boolean;
122
+ tools: boolean;
123
+ reasoningEvents: boolean;
124
+ structuredOutput: boolean;
125
+ multimodal: boolean;
126
+ };
127
+ cancel: "hard" | "soft" | "none";
128
+ tasks: string[];
129
+ limits?: {
130
+ maxInputTokens?: number;
131
+ maxOutputTokens?: number;
132
+ maxImageBytes?: number;
133
+ maxAudioSeconds?: number;
134
+ };
135
+ privacy?: {
136
+ dataLeavesDevice: boolean;
137
+ regions?: string[];
138
+ };
139
+ }
140
+ /**
141
+ * A provider's live availability, as of the moment `checkCapabilities()` was called.
142
+ *
143
+ * `streamingAvailable` and `cancellationAvailable` are **absent**, not `null`, when the
144
+ * runtime has nothing to say: absence means *inherit the static declaration*
145
+ * (`descriptor.supports.streaming`, and `descriptor.cancel !== "none"`). Both native
146
+ * encoders omit the key rather than emitting null for exactly that reason.
147
+ */
148
+ export interface ProviderDynamicCapabilities {
149
+ available: boolean;
150
+ reason?: string;
151
+ streamingAvailable?: boolean;
152
+ streamingUnavailableReason?: string;
153
+ cancellationAvailable?: boolean;
154
+ }
155
+ /** One registered provider's identity, static declaration, and live availability. */
156
+ export interface ProviderCapabilitySnapshot {
157
+ providerId: string;
158
+ descriptor: ProviderDescriptor;
159
+ capabilities: ProviderDynamicCapabilities;
160
+ }
161
+ /**
162
+ * Envelope for `checkCapabilities()`. The array is wrapped because a Capacitor plugin
163
+ * method must resolve an object on both native platforms — `PluginCall.resolve(JSObject)`
164
+ * and `call.resolve([String: Any])` cannot carry a top-level array. `IndeRunCapacitor`
165
+ * and `createIndeRunCapacitor()` unwrap it, so app code sees the same
166
+ * `ProviderCapabilitySnapshot[]` the three platform SDKs return.
167
+ */
168
+ export interface CheckCapabilitiesResult {
169
+ providers: ProviderCapabilitySnapshot[];
170
+ }
56
171
  export interface IndeRunCapacitorPlugin {
57
172
  configure(options?: ConfigureOptions): Promise<void>;
58
173
  run(request: TaskRequest): Promise<TaskResult>;
174
+ /**
175
+ * Live snapshot of every registered provider, without executing a task. Availability
176
+ * changes between calls — a local model can unload, cloud credentials can expire — so
177
+ * do not cache it across a `run()` or `stream()`.
178
+ */
179
+ checkCapabilities(): Promise<CheckCapabilitiesResult>;
59
180
  /**
60
181
  * Unlike `run(request)`, which passes the request at the options root, this nests it
61
182
  * under `request` so the envelope can also carry `streamId`. Both native decode sites
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACX,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,8BAA8B,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,6FAA6F;AAC7F,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACnC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,WAAW,CACT,SAAS,EAAE,oBAAoB,EAC/B,YAAY,EAAE,CAAC,YAAY,EAAE,uBAAuB,KAAK,IAAI,GAC5D,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC,WAAW,CACT,SAAS,EAAE,oBAAoB,EAC/B,YAAY,EAAE,CAAC,YAAY,EAAE,uBAAuB,KAAK,IAAI,GAC5D,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,20 +1,23 @@
1
1
  import type { TaskRequest, TaskResult } from "@independo/inderun-contracts";
2
- import type { CancelStreamOptions, ConfigureOptions, IndeRunCapacitorPlugin as IndeRunCapacitorPluginContract, OpenAIProviderBootstrapOptions, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun } from "./definitions.js";
2
+ import type { CancelStreamOptions, CheckCapabilitiesResult, ConfigureOptions, IndeRunCapacitorPlugin as IndeRunCapacitorPluginContract, OnnxProviderBootstrapOptions, OpenAIProviderBootstrapOptions, ProviderCapabilitySnapshot, ProviderDescriptor, ProviderDynamicCapabilities, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun, SystemModelProviderBootstrapOptions } from "./definitions.js";
3
3
  /**
4
4
  * The plugin contract plus the ergonomic Mode 2 entry point. `stream()` is not a
5
5
  * plugin method — it is `startStream`, the event listeners, and `cancelStream`
6
6
  * reassembled into the same shape the platform SDKs return from `stream()`.
7
7
  */
8
- export interface IndeRunCapacitorApi extends IndeRunCapacitorPluginContract {
8
+ export interface IndeRunCapacitorApi extends Omit<IndeRunCapacitorPluginContract, "checkCapabilities"> {
9
9
  stream(request: TaskRequest): Promise<StreamRun>;
10
+ /** The plugin's `{ providers }` envelope, unwrapped to match the platform SDKs. */
11
+ checkCapabilities(): Promise<ProviderCapabilitySnapshot[]>;
10
12
  }
11
13
  export declare const IndeRunCapacitor: IndeRunCapacitorApi;
12
14
  export interface IndeRunCapacitorInstance {
13
15
  run(request: TaskRequest): Promise<TaskResult>;
14
16
  stream(request: TaskRequest): Promise<StreamRun>;
17
+ checkCapabilities(): Promise<ProviderCapabilitySnapshot[]>;
15
18
  }
16
19
  export declare function createIndeRunCapacitor(options?: ConfigureOptions): IndeRunCapacitorInstance;
17
20
  export { STREAM_ERROR_NAME, STREAM_EVENT_NAME } from "./streaming.js";
18
- export type { CancelStreamOptions, ConfigureOptions, IndeRunCapacitorPluginContract as IndeRunCapacitorPlugin, OpenAIProviderBootstrapOptions, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun, TaskRequest, TaskResult };
21
+ export type { CancelStreamOptions, CheckCapabilitiesResult, ConfigureOptions, IndeRunCapacitorPluginContract as IndeRunCapacitorPlugin, OnnxProviderBootstrapOptions, OpenAIProviderBootstrapOptions, ProviderCapabilitySnapshot, ProviderDescriptor, ProviderDynamicCapabilities, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun, SystemModelProviderBootstrapOptions, TaskRequest, TaskResult };
19
22
  export type * from "@independo/inderun-contracts";
20
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE7F,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,IAAI,8BAA8B,EACxD,8BAA8B,EAC9B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,EACV,MAAM,kBAAkB,CAAC;AAQ1B;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,8BAA8B;IACzE,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CAClD;AAED,eAAO,MAAM,gBAAgB,EAAE,mBA4C9B,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CAClD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,wBAAwB,CAsB3F;AAED,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,8BAA8B,IAAI,sBAAsB,EACxD,8BAA8B,EAC9B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,EACT,WAAW,EACX,UAAU,EACX,CAAC;AAEF,mBAAmB,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE7F,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,IAAI,8BAA8B,EACxD,4BAA4B,EAC5B,8BAA8B,EAC9B,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,EACT,mCAAmC,EACpC,MAAM,kBAAkB,CAAC;AAQ1B;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,8BAA8B,EAAE,mBAAmB,CAAC;IACpG,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,mFAAmF;IACnF,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC;CAC5D;AAED,eAAO,MAAM,gBAAgB,EAAE,mBAqD9B,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC;CAC5D;AAED,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,wBAAwB,CA4B3F;AAED,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,8BAA8B,IAAI,sBAAsB,EACxD,4BAA4B,EAC5B,8BAA8B,EAC9B,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,EACT,mCAAmC,EACnC,WAAW,EACX,UAAU,EACX,CAAC;AAEF,mBAAmB,8BAA8B,CAAC"}
package/dist/index.js CHANGED
@@ -21,6 +21,15 @@ export const IndeRunCapacitor = {
21
21
  throw normalizePluginError(error);
22
22
  }
23
23
  },
24
+ async checkCapabilities() {
25
+ try {
26
+ const result = await IndeRunCapacitorNative.checkCapabilities();
27
+ return result.providers;
28
+ }
29
+ catch (error) {
30
+ throw normalizePluginError(error);
31
+ }
32
+ },
24
33
  async startStream(options) {
25
34
  try {
26
35
  return await IndeRunCapacitorNative.startStream(options);
@@ -62,6 +71,11 @@ export function createIndeRunCapacitor(options) {
62
71
  async stream(request) {
63
72
  await ensureConfigured();
64
73
  return IndeRunCapacitor.stream(request);
74
+ },
75
+ // Configures first: without a registry there are no providers to report on.
76
+ async checkCapabilities() {
77
+ await ensureConfigured();
78
+ return IndeRunCapacitor.checkCapabilities();
65
79
  }
66
80
  };
67
81
  }
package/dist/web.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { StreamRunHandle, TaskResult } from "@independo/inderun-contracts";
2
2
  import { WebPlugin } from "@capacitor/core";
3
- import type { CancelStreamOptions, ConfigureOptions, IndeRunCapacitorPlugin, StartStreamOptions } from "./definitions.js";
3
+ import type { CancelStreamOptions, CheckCapabilitiesResult, ConfigureOptions, IndeRunCapacitorPlugin, StartStreamOptions } from "./definitions.js";
4
4
  import type { TaskRequest } from "@independo/inderun-contracts";
5
5
  export declare class IndeRunWeb extends WebPlugin implements IndeRunCapacitorPlugin {
6
6
  private engine;
@@ -9,6 +9,7 @@ export declare class IndeRunWeb extends WebPlugin implements IndeRunCapacitorPlu
9
9
  private readonly pendingCancels;
10
10
  configure(options?: ConfigureOptions): Promise<void>;
11
11
  run(request: TaskRequest): Promise<TaskResult>;
12
+ checkCapabilities(): Promise<CheckCapabilitiesResult>;
12
13
  /**
13
14
  * The web path deliberately round-trips through `notifyListeners` rather than
14
15
  * handing the engine's `StreamRun` straight back.
package/dist/web.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAIhE,qBAAa,UAAW,SAAQ,SAAU,YAAW,sBAAsB;IACzE,OAAO,CAAC,MAAM,CAAwB;IAItC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyC;IAElE,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BzD;IAEK,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnD;IAED;;;;;;;;OAQG;IACG,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8BvE;IAEK,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9D;YAEa,IAAI;CAenB"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAIhE,qBAAa,UAAW,SAAQ,SAAU,YAAW,sBAAsB;IACzE,OAAO,CAAC,MAAM,CAAwB;IAItC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyC;IAElE,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzD;IAEK,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnD;IAEK,iBAAiB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAe1D;IAED;;;;;;;;OAQG;IACG,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8BvE;IAEK,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9D;YAEa,IAAI;CAenB"}
package/dist/web.js CHANGED
@@ -10,13 +10,27 @@ export class IndeRunWeb extends WebPlugin {
10
10
  startingStreams = new Set();
11
11
  pendingCancels = new Map();
12
12
  async configure(options) {
13
- if (!options?.openAI) {
14
- throw createUnavailable("Capacitor web execution requires OpenAI provider registration. Configure with openAI bootstrap options before calling run(request).").toContractError();
13
+ // The web SDK requires at least one provider, not specifically the cloud one. Held
14
+ // here as well as there so the failure is an `Unavailable` contract error rather than
15
+ // a raw SDK throw, which is what the facade's callers expect.
16
+ if (!options?.openAI && !options?.systemModel && !options?.onnx) {
17
+ throw createUnavailable("Capacitor web execution requires at least one provider registration. Configure with openAI, systemModel and/or onnx bootstrap options before calling run(request).").toContractError();
15
18
  }
16
19
  try {
17
- const webOptions = {
18
- openAI: compactOpenAIOptions(options)
19
- };
20
+ // The SDK's own option type, not a hand-written copy of it: an upstream rename
21
+ // then fails at the type level instead of silently dropping a field. This is
22
+ // deliberately the *outbound* shape only — `ConfigureOptions` stays a narrower,
23
+ // JSON-serializable subset, because it has to cross the native bridge hop.
24
+ const webOptions = {};
25
+ if (options.openAI !== undefined) {
26
+ webOptions.openAI = compactOpenAIOptions(options.openAI);
27
+ }
28
+ if (options.systemModel !== undefined) {
29
+ webOptions.systemModel = compactSystemModelOptions(options.systemModel);
30
+ }
31
+ if (options.onnx !== undefined) {
32
+ webOptions.onnx = compactOnnxOptions(options.onnx);
33
+ }
20
34
  if (options.allowDirectOpenAIEndpoint !== undefined) {
21
35
  webOptions.allowDirectOpenAIEndpoint = options.allowDirectOpenAIEndpoint;
22
36
  }
@@ -37,6 +51,20 @@ export class IndeRunWeb extends WebPlugin {
37
51
  throw toIndeRunException(error).toContractError();
38
52
  }
39
53
  }
54
+ async checkCapabilities() {
55
+ if (!this.engine) {
56
+ throw createUnavailable("Capacitor IndeRun has not been configured. Configure providers before calling checkCapabilities().").toContractError();
57
+ }
58
+ try {
59
+ // Deliberately uncast: the engine's snapshots are assigned straight into the
60
+ // bridge's own `ProviderCapabilitySnapshot`, so the two declarations staying
61
+ // identical is a compile error rather than a convention. See definitions.ts.
62
+ return { providers: await this.engine.checkCapabilities() };
63
+ }
64
+ catch (error) {
65
+ throw toIndeRunException(error).toContractError();
66
+ }
67
+ }
40
68
  /**
41
69
  * The web path deliberately round-trips through `notifyListeners` rather than
42
70
  * handing the engine's `StreamRun` straight back.
@@ -101,8 +129,17 @@ export class IndeRunWeb extends WebPlugin {
101
129
  }
102
130
  }
103
131
  }
104
- function compactOpenAIOptions(options) {
105
- const openAI = options.openAI;
132
+ /**
133
+ * Assigns only the fields the caller actually set. `exactOptionalPropertyTypes` makes
134
+ * this incremental style mandatory rather than cosmetic: assigning `undefined` to an
135
+ * optional property is an error, and an explicit `undefined` on the wire is not the same
136
+ * thing as an absent key to the provider that reads it.
137
+ *
138
+ * `id`, `healthCheckTimeoutMs` and `healthCheckCacheMs` are deliberately not bridged —
139
+ * all optional, and the bridge has no reason to expose provider-tuning knobs it cannot
140
+ * also offer on native.
141
+ */
142
+ function compactOpenAIOptions(openAI) {
106
143
  const result = {
107
144
  model: openAI.model
108
145
  };
@@ -120,3 +157,25 @@ function compactOpenAIOptions(options) {
120
157
  }
121
158
  return result;
122
159
  }
160
+ function compactSystemModelOptions(systemModel) {
161
+ const result = {};
162
+ if (systemModel.id !== undefined) {
163
+ result.id = systemModel.id;
164
+ }
165
+ if (systemModel.timeoutMs !== undefined) {
166
+ result.timeoutMs = systemModel.timeoutMs;
167
+ }
168
+ return result;
169
+ }
170
+ function compactOnnxOptions(onnx) {
171
+ const result = {
172
+ modelPackage: onnx.modelPackage
173
+ };
174
+ if (onnx.id !== undefined) {
175
+ result.id = onnx.id;
176
+ }
177
+ if (onnx.timeoutMs !== undefined) {
178
+ result.timeoutMs = onnx.timeoutMs;
179
+ }
180
+ return result;
181
+ }
@@ -49,6 +49,22 @@ struct CapacitorCancelStreamOptions: Codable {
49
49
  let reason: String?
50
50
  }
51
51
 
52
+ /// IndeRunCore's `ProviderCapabilitySnapshot` is `Sendable` but not `Codable`, even
53
+ /// though both of its members are. This mirror exists only to get it through
54
+ /// `JSONEncoder`; see the upstream follow-up asking for `Codable` (and a schema) on
55
+ /// the snapshot itself.
56
+ private struct EncodableCapabilitySnapshot: Encodable {
57
+ let providerId: String
58
+ let descriptor: ProviderDescriptor
59
+ let capabilities: ProviderDynamicCapabilities
60
+ }
61
+
62
+ /// A Capacitor plugin method must resolve an object, never a top-level array, so the
63
+ /// snapshots travel wrapped. `IndeRunCapacitor` unwraps them on the JS side.
64
+ private struct CapabilitiesEnvelope: Encodable {
65
+ let providers: [EncodableCapabilitySnapshot]
66
+ }
67
+
52
68
  /// Called with an already-encoded event/error for one run. The plugin turns these
53
69
  /// into `notifyListeners` calls; taking them as closures keeps the pump testable
54
70
  /// without Capacitor.
@@ -82,6 +98,16 @@ final class IndeRunCapacitorBridge {
82
98
  return try encode(result)
83
99
  }
84
100
 
101
+ func checkCapabilities() async throws -> JSObject {
102
+ guard let registry = configuredRegistry, let hostServices = configuredHostServices else {
103
+ throw createUnavailable(message: "Capacitor IndeRun has not been configured. Configure providers before calling checkCapabilities().")
104
+ }
105
+
106
+ // IndeRun is a stateless coordinator; new per call is intentional — registry is cached above.
107
+ let engine = IndeRun(registry: registry, hostServices: hostServices)
108
+ return try encode(capabilities: await engine.checkCapabilities())
109
+ }
110
+
85
111
  func startStream(
86
112
  options: JSObject,
87
113
  onEvent: @escaping StreamEventSink,
@@ -173,6 +199,24 @@ final class IndeRunCapacitorBridge {
173
199
  try encodeObject(handle)
174
200
  }
175
201
 
202
+ /// The descriptor's enums carry explicit raw values (`in_process`, not `inProcess`),
203
+ /// and JSONEncoder omits nil optionals — so an unset `streamingAvailable` arrives as
204
+ /// an absent key rather than a null, which is what lets the JS side read absence as
205
+ /// "inherit `descriptor.supports.streaming`".
206
+ func encode(capabilities: [ProviderCapabilitySnapshot]) throws -> JSObject {
207
+ try encodeObject(
208
+ CapabilitiesEnvelope(
209
+ providers: capabilities.map {
210
+ EncodableCapabilitySnapshot(
211
+ providerId: $0.providerId,
212
+ descriptor: $0.descriptor,
213
+ capabilities: $0.capabilities
214
+ )
215
+ }
216
+ )
217
+ )
218
+ }
219
+
176
220
  private func makeRegistry(openAI: OpenAIProviderBootstrapOptions?) throws -> ProviderRegistry {
177
221
  let registry = ProviderRegistry()
178
222
  try registry.register(AppleFoundationModelsProvider())
@@ -222,10 +266,26 @@ final class IndeRunCapacitorBridge {
222
266
  private func encodeObject<T: Encodable>(_ value: T) throws -> JSObject {
223
267
  let data = try JSONEncoder().encode(value)
224
268
  let object = try JSONSerialization.jsonObject(with: data, options: [])
269
+
270
+ #if canImport(Capacitor)
271
+ // Capacitor's JSObject is [String: any JSValue], and a plain `as?` cast cannot
272
+ // produce one: JSONSerialization hands back NSDictionary/NSArray values, which do
273
+ // not conform to JSValue, so anything with a nested object or array — a TaskResult's
274
+ // `output`, a stream event's `payload`, the providers array — failed the cast and
275
+ // surfaced as "Capacitor bridge failed to encode a JSON object". JSTypes coerces the
276
+ // tree recursively, which is what the cast was standing in for.
277
+ guard let dictionary = object as? [AnyHashable: Any],
278
+ let coerced = JSTypes.coerceDictionaryToJSObject(dictionary) else {
279
+ throw createInternal(message: "Capacitor bridge failed to encode a JSON object.")
280
+ }
281
+ return coerced
282
+ #else
283
+ // Standalone builds alias JSObject to [String: Any], where the cast is exact.
225
284
  guard let dictionary = object as? JSObject else {
226
285
  throw createInternal(message: "Capacitor bridge failed to encode a JSON object.")
227
286
  }
228
287
  return dictionary
288
+ #endif
229
289
  }
230
290
 
231
291
  func mapAuthMode(_ value: String?) -> OpenAIAuthMode {
@@ -10,6 +10,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
10
10
  public let pluginMethods: [CAPPluginMethod] = [
11
11
  CAPPluginMethod(name: "configure", returnType: CAPPluginReturnPromise),
12
12
  CAPPluginMethod(name: "run", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "checkCapabilities", returnType: CAPPluginReturnPromise),
13
14
  CAPPluginMethod(name: "startStream", returnType: CAPPluginReturnPromise),
14
15
  CAPPluginMethod(name: "cancelStream", returnType: CAPPluginReturnPromise)
15
16
  ]
@@ -25,7 +26,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
25
26
 
26
27
  @objc func configure(_ call: CAPPluginCall) {
27
28
  do {
28
- try implementation.configure(options: call.options)
29
+ try implementation.configure(options: call.jsObjectRepresentation)
29
30
  call.resolve()
30
31
  } catch let error as IndeRunException {
31
32
  let contractError = error.toContractError()
@@ -42,7 +43,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
42
43
  @objc func run(_ call: CAPPluginCall) {
43
44
  Task {
44
45
  do {
45
- let result = try await implementation.run(requestObject: call.options)
46
+ let result = try await implementation.run(requestObject: call.jsObjectRepresentation)
46
47
  call.resolve(result)
47
48
  } catch let error as IndeRunException {
48
49
  let contractError = error.toContractError()
@@ -57,6 +58,26 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
57
58
  }
58
59
  }
59
60
 
61
+ /// Reports every registered provider's static declaration and live availability
62
+ /// without executing a task. Availability changes between calls — a local model can
63
+ /// unload, cloud credentials can expire — so callers must not cache it across a run.
64
+ @objc func checkCapabilities(_ call: CAPPluginCall) {
65
+ Task {
66
+ do {
67
+ call.resolve(try await implementation.checkCapabilities())
68
+ } catch let error as IndeRunException {
69
+ let contractError = error.toContractError()
70
+ let details = try? implementation.encode(error: contractError)
71
+ call.reject(contractError.message, contractError.errorClass.rawValue, error, details)
72
+ } catch {
73
+ let normalized = toIndeRunException(error)
74
+ let contractError = normalized.toContractError()
75
+ let details = try? implementation.encode(error: contractError)
76
+ call.reject(contractError.message, contractError.errorClass.rawValue, normalized, details)
77
+ }
78
+ }
79
+ }
80
+
60
81
  /// Resolves with the run handle. Only validation and route-selection failures
61
82
  /// reject here; a provider failure, a cancellation, or completion all arrive as
62
83
  /// the single terminal event on `indeRunStreamEvent`.
@@ -69,7 +90,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
69
90
  guard let self else { return }
70
91
  do {
71
92
  let handle = try await self.implementation.startStream(
72
- options: call.options,
93
+ options: call.jsObjectRepresentation,
73
94
  onEvent: { [weak self] streamId, event in
74
95
  self?.notifyListeners(
75
96
  "indeRunStreamEvent",
@@ -103,7 +124,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
103
124
  /// is a no-op by contract, not an error.
104
125
  @objc func cancelStream(_ call: CAPPluginCall) {
105
126
  do {
106
- try implementation.cancelStream(options: call.options)
127
+ try implementation.cancelStream(options: call.jsObjectRepresentation)
107
128
  call.resolve()
108
129
  } catch let error as IndeRunException {
109
130
  let contractError = error.toContractError()