@oh-my-pi/pi-ai 17.2.5 → 17.2.7

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/CHANGELOG.md +21 -0
  2. package/dist/types/auth-broker/client.d.ts +7 -0
  3. package/dist/types/auth-broker/server.d.ts +11 -0
  4. package/dist/types/auth-broker/wire-schema-resource.d.ts +1 -1
  5. package/dist/types/auth-broker/wire-schemas.d.ts +4 -2
  6. package/dist/types/dialect/examples.d.ts +8 -0
  7. package/dist/types/error/aws.d.ts +5 -1
  8. package/dist/types/index.d.ts +1 -1
  9. package/dist/types/providers/anthropic-messages-server-schema.d.ts +695 -255
  10. package/dist/types/providers/aws-credentials.d.ts +5 -10
  11. package/dist/types/providers/bedrock-mantle.d.ts +13 -0
  12. package/dist/types/providers/openai-chat-server-schema.d.ts +909 -293
  13. package/dist/types/providers/openai-responses-server-schema.d.ts +980 -353
  14. package/dist/types/registry/amazon-bedrock.d.ts +7 -1
  15. package/dist/types/registry/aws.d.ts +13 -0
  16. package/dist/types/registry/bedrock-mantle.d.ts +22 -0
  17. package/dist/types/registry/registry.d.ts +25 -1
  18. package/dist/types/registry/types.d.ts +24 -0
  19. package/dist/types/types.d.ts +13 -5
  20. package/dist/types/usage.d.ts +152 -46
  21. package/dist/types/utils/aws-profile.d.ts +17 -0
  22. package/dist/types/utils/schema/wire.d.ts +1 -1
  23. package/dist/types/utils/validation.d.ts +24 -0
  24. package/package.json +5 -5
  25. package/src/auth-broker/client.ts +2 -1
  26. package/src/auth-broker/server.ts +2 -1
  27. package/src/auth-broker/wire-schema-resource.ts +1 -1
  28. package/src/dialect/examples.ts +34 -8
  29. package/src/dialect/inventory.ts +2 -2
  30. package/src/error/aws.ts +5 -1
  31. package/src/index.ts +1 -1
  32. package/src/providers/amazon-bedrock.ts +5 -5
  33. package/src/providers/anthropic-messages-server-schema.ts +1 -1
  34. package/src/providers/anthropic-messages-server.ts +1 -1
  35. package/src/providers/aws-credentials.ts +262 -76
  36. package/src/providers/bedrock-mantle.ts +110 -0
  37. package/src/providers/cursor.ts +31 -3
  38. package/src/providers/google-gemini-cli.ts +1 -1
  39. package/src/providers/ollama.ts +27 -1
  40. package/src/providers/openai-chat-server-schema.ts +1 -1
  41. package/src/providers/openai-chat-server.ts +1 -1
  42. package/src/providers/openai-codex-responses.ts +1 -1
  43. package/src/providers/openai-responses-server-schema.ts +1 -1
  44. package/src/providers/openai-responses-server.ts +1 -1
  45. package/src/registry/amazon-bedrock.ts +9 -14
  46. package/src/registry/aws.ts +57 -0
  47. package/src/registry/bedrock-mantle.ts +34 -0
  48. package/src/registry/google-vertex.ts +2 -2
  49. package/src/registry/registry.ts +2 -0
  50. package/src/registry/types.ts +30 -0
  51. package/src/stream.ts +46 -30
  52. package/src/types.ts +14 -6
  53. package/src/usage.ts +1 -1
  54. package/src/utils/aws-profile.ts +88 -0
  55. package/src/utils/schema/wire.ts +1 -1
  56. package/src/utils/validation.ts +2 -1
@@ -1,5 +1,11 @@
1
+ import { resolveAwsRegistryApiKey } from "./aws.js";
1
2
  export declare const amazonBedrockProvider: {
2
3
  readonly id: "amazon-bedrock";
3
4
  readonly name: "Amazon Bedrock";
4
- readonly envKeys: () => "<authenticated>" | undefined;
5
+ readonly envKeys: typeof resolveAwsRegistryApiKey;
6
+ readonly mapSimpleOptions: (options: import("../index.js").SimpleStreamOptions) => {
7
+ region: string | undefined;
8
+ profile: string | undefined;
9
+ bearerToken: string | undefined;
10
+ };
5
11
  };
@@ -0,0 +1,13 @@
1
+ export interface AwsBedrockProviderOptions extends Readonly<Record<string, unknown>> {
2
+ /** AWS region used in the service endpoint and SigV4 credential scope. */
3
+ region?: string;
4
+ /** Named AWS shared-credentials/config profile. */
5
+ profile?: string;
6
+ /** Amazon Bedrock API key sent as a bearer token, ahead of SigV4 credential resolution. */
7
+ bearerToken?: string;
8
+ }
9
+ export declare function hasAwsCredentialSource(): boolean;
10
+ /** Registry key marker for AWS transports that resolve their own bearer/IAM credentials. */
11
+ export declare function resolveAwsRegistryApiKey(): string | undefined;
12
+ /** Resolve a real AWS bearer token while filtering the registry's auth marker. */
13
+ export declare function resolveAwsBearerToken(apiKey?: string, bearerToken?: string): string | undefined;
@@ -0,0 +1,22 @@
1
+ import type { Model } from "../types.js";
2
+ import { resolveAwsRegistryApiKey } from "./aws.js";
3
+ export declare const bedrockMantleProvider: {
4
+ readonly id: "bedrock-mantle";
5
+ readonly name: "Amazon Bedrock Mantle";
6
+ readonly envKeys: typeof resolveAwsRegistryApiKey;
7
+ readonly allowsMissingApiKey: true;
8
+ readonly prepareRequest: (model: Model<import("@oh-my-pi/pi-catalog").Api>, options: import("../index.js").StreamOptions) => import("../providers/bedrock-mantle.js").PreparedBedrockMantleRequest;
9
+ readonly mapSimpleOptions: (options: import("../index.js").SimpleStreamOptions) => {
10
+ providerOptions: Readonly<Record<string, unknown>> | undefined;
11
+ };
12
+ readonly prepareModelDiscovery: (config: import("./types.js").ProviderModelDiscoveryConfig) => {
13
+ baseUrl?: string;
14
+ fetch?: import("@oh-my-pi/pi-utils").FetchImpl;
15
+ apiKey: undefined;
16
+ authenticated: false;
17
+ } | {
18
+ authenticated: true;
19
+ baseUrl: string;
20
+ fetch: import("@oh-my-pi/pi-utils").FetchImpl;
21
+ };
22
+ };
@@ -25,7 +25,12 @@ declare const ALL: ({
25
25
  } | {
26
26
  readonly id: "amazon-bedrock";
27
27
  readonly name: "Amazon Bedrock";
28
- readonly envKeys: () => "<authenticated>" | undefined;
28
+ readonly envKeys: typeof import("./aws.js").resolveAwsRegistryApiKey;
29
+ readonly mapSimpleOptions: (options: import("../index.js").SimpleStreamOptions) => {
30
+ region: string | undefined;
31
+ profile: string | undefined;
32
+ bearerToken: string | undefined;
33
+ };
29
34
  } | {
30
35
  readonly id: "anthropic";
31
36
  readonly name: "Anthropic (Claude Pro/Max)";
@@ -41,6 +46,25 @@ declare const ALL: ({
41
46
  readonly id: "baseten";
42
47
  readonly name: "Baseten";
43
48
  readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
49
+ } | {
50
+ readonly id: "bedrock-mantle";
51
+ readonly name: "Amazon Bedrock Mantle";
52
+ readonly envKeys: typeof import("./aws.js").resolveAwsRegistryApiKey;
53
+ readonly allowsMissingApiKey: true;
54
+ readonly prepareRequest: (model: import("@oh-my-pi/pi-catalog").Model<import("@oh-my-pi/pi-catalog").Api>, options: import("../index.js").StreamOptions) => import("../providers/bedrock-mantle.js").PreparedBedrockMantleRequest;
55
+ readonly mapSimpleOptions: (options: import("../index.js").SimpleStreamOptions) => {
56
+ providerOptions: Readonly<Record<string, unknown>> | undefined;
57
+ };
58
+ readonly prepareModelDiscovery: (config: import("./types.js").ProviderModelDiscoveryConfig) => {
59
+ baseUrl?: string;
60
+ fetch?: import("@oh-my-pi/pi-utils").FetchImpl;
61
+ apiKey: undefined;
62
+ authenticated: false;
63
+ } | {
64
+ authenticated: true;
65
+ baseUrl: string;
66
+ fetch: import("@oh-my-pi/pi-utils").FetchImpl;
67
+ };
44
68
  } | {
45
69
  readonly id: "cerebras";
46
70
  readonly name: "Cerebras";
@@ -9,6 +9,7 @@
9
9
  * (default model, model-manager factory, catalog discovery) lives in
10
10
  * `@oh-my-pi/pi-catalog`'s descriptor table.
11
11
  */
12
+ import type { Api, FetchImpl, Model, SimpleStreamOptions, StreamOptions } from "../types.js";
12
13
  import type { OAuthCredentials, OAuthLoginCallbacks } from "./oauth/types.js";
13
14
  /**
14
15
  * API-key environment fallback: either a single env var name (e.g.
@@ -16,6 +17,21 @@ import type { OAuthCredentials, OAuthLoginCallbacks } from "./oauth/types.js";
16
17
  * the host (Vertex ADC, Bedrock credential chains, …).
17
18
  */
18
19
  export type KeyResolver = string | (() => string | undefined);
20
+ /** Credentials are resolved by the provider transport rather than used as a bearer string. */
21
+ export declare const AUTHENTICATED_SENTINEL = "<authenticated>";
22
+ export interface PreparedProviderRequest {
23
+ readonly model: Model<Api>;
24
+ readonly options: StreamOptions;
25
+ }
26
+ export type ProviderRequestPreparer = (model: Model<Api>, options: StreamOptions) => PreparedProviderRequest;
27
+ export type ProviderSimpleOptionsMapper = (options: SimpleStreamOptions) => Readonly<Record<string, unknown>>;
28
+ export interface ProviderModelDiscoveryConfig {
29
+ readonly apiKey?: string;
30
+ readonly baseUrl?: string;
31
+ readonly fetch?: FetchImpl;
32
+ readonly authenticated?: boolean;
33
+ }
34
+ export type ProviderModelDiscoveryPreparer = (config: ProviderModelDiscoveryConfig) => ProviderModelDiscoveryConfig;
19
35
  /**
20
36
  * Declarative description of a single provider's auth/login wiring. All
21
37
  * fields are optional except `id`/`name`; presence of a field opts the
@@ -39,6 +55,14 @@ export interface ProviderDefinition {
39
55
  /** Whether to surface in the interactive login list. Defaults to true when `login` is present. */
40
56
  readonly showInLoginList?: boolean;
41
57
  readonly envKeys?: KeyResolver;
58
+ /** Provider transport can authenticate without a resolved API-key string. */
59
+ readonly allowsMissingApiKey?: boolean;
60
+ /** Provider-owned request shaping applied before generic API dispatch. */
61
+ readonly prepareRequest?: ProviderRequestPreparer;
62
+ /** Provider-owned projection from the generic simple-stream option bag. */
63
+ readonly mapSimpleOptions?: ProviderSimpleOptionsMapper;
64
+ /** Provider-owned authentication and endpoint setup for model discovery. */
65
+ readonly prepareModelDiscovery?: ProviderModelDiscoveryPreparer;
42
66
  readonly login?: (callbacks: OAuthLoginCallbacks) => Promise<OAuthCredentials | string>;
43
67
  readonly refreshToken?: (credentials: OAuthCredentials) => Promise<OAuthCredentials>;
44
68
  readonly getApiKey?: (credentials: OAuthCredentials) => string;
@@ -1,9 +1,9 @@
1
1
  export * from "@oh-my-pi/pi-catalog/effort";
2
2
  export * from "@oh-my-pi/pi-catalog/types";
3
+ import type { Type } from "@oh-my-pi/omptype";
3
4
  import type { DeleteArgs, DeleteResult, DiagnosticsArgs, DiagnosticsResult, GrepArgs, GrepResult, LsArgs, LsResult, McpResult, PiBashExecArgs, PiBashExecResult, PiEditExecArgs, PiEditExecResult, PiFindExecArgs, PiFindExecResult, PiGrepExecArgs, PiGrepExecResult, PiLsExecArgs, PiLsExecResult, PiReadExecArgs, PiReadExecResult, PiWriteExecArgs, PiWriteExecResult, ReadArgs, ReadResult, ShellArgs, ShellResult, WriteArgs, WriteResult } from "@oh-my-pi/pi-catalog/discovery/cursor-gen/agent_pb";
4
5
  import type { Effort } from "@oh-my-pi/pi-catalog/effort";
5
6
  import type { Api, FetchImpl, Model, Provider, ThinkingBudgets, Usage } from "@oh-my-pi/pi-catalog/types";
6
- import type { Type } from "arktype";
7
7
  import type { ZodType, z } from "zod/v4";
8
8
  import type { ApiKey } from "./auth-retry.js";
9
9
  import type { BedrockOptions } from "./providers/amazon-bedrock.js";
@@ -124,10 +124,13 @@ export declare function serviceTierFamily(model: ServiceTierModel): ServiceTierF
124
124
  export declare function resolveModelServiceTier(tiers: ServiceTierByFamily | null | undefined, model: Pick<Model, "provider" | "api" | "id">): ServiceTier | undefined;
125
125
  /**
126
126
  * True when the tier should be sent on the wire as the provider's service-tier
127
- * request field. OpenAI / OpenAI-Codex accept every {@link ServiceTier};
128
- * Google (Gemini API + Vertex) and OpenRouter accept `flex`/`priority`;
129
- * Fireworks Serverless realizes only its Priority serving path. Anthropic is
130
- * absent because it realizes `priority` via `speed: "fast"`.
127
+ * request field. `auto` is never forwarded — it is OpenAI's implicit default, so
128
+ * omitting `service_tier` is identical to requesting `auto`, and the Codex
129
+ * (ChatGPT OAuth) endpoint rejects an explicit `auto` outright. OpenAI /
130
+ * OpenAI-Codex accept every other {@link ServiceTier}; Google (Gemini API +
131
+ * Vertex) and OpenRouter accept `flex`/`priority`; Fireworks Serverless
132
+ * realizes only its Priority serving path. Anthropic is absent because it
133
+ * realizes `priority` via `speed: "fast"`.
131
134
  */
132
135
  export declare function shouldSendServiceTier(serviceTier: ServiceTier | null | undefined, target: Provider | ServiceTierModel | undefined): boolean;
133
136
  /**
@@ -249,6 +252,11 @@ export interface StreamOptions {
249
252
  * For example, Anthropic uses `user_id` for abuse tracking and rate limiting.
250
253
  */
251
254
  metadata?: Record<string, unknown>;
255
+ /**
256
+ * Provider-owned request configuration. Provider hooks interpret this bag;
257
+ * generic API transports do not forward its fields onto the wire.
258
+ */
259
+ providerOptions?: Readonly<Record<string, unknown>>;
252
260
  /** OpenAI Responses/Codex response fields to include verbatim. */
253
261
  include?: OpenAIResponseInclude[];
254
262
  /**
@@ -206,125 +206,231 @@ export interface ClientUsageClientSummary {
206
206
  export interface ClientUsageSummary {
207
207
  clients: ClientUsageClientSummary[];
208
208
  }
209
- export declare const usageUnitSchema: import("arktype/internal/variants/string.ts").StringType<"bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd", {}>;
210
- export declare const usageStatusSchema: import("arktype/internal/variants/string.ts").StringType<"exhausted" | "ok" | "unknown" | "warning", {}>;
211
- export declare const usageWindowSchema: import("arktype/internal/variants/object.ts").ObjectType<{
209
+ export declare const usageUnitSchema: import("@oh-my-pi/omptype").FluentType<"bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd", "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd">;
210
+ export declare const usageStatusSchema: import("@oh-my-pi/omptype").FluentType<"exhausted" | "ok" | "unknown" | "warning", "exhausted" | "ok" | "unknown" | "warning">;
211
+ export declare const usageWindowSchema: import("@oh-my-pi/omptype").FluentType<{
212
+ durationMs?: number | undefined;
212
213
  id: string;
213
214
  label: string;
214
- durationMs?: number | undefined;
215
+ resetLabel?: string | undefined;
215
216
  resetsAt?: number | undefined;
217
+ }, {
218
+ durationMs?: number | undefined;
219
+ id: string;
220
+ label: string;
216
221
  resetLabel?: string | undefined;
217
- }, {}>;
218
- export declare const usageAmountSchema: import("arktype/internal/variants/object.ts").ObjectType<{
219
- used?: number | undefined;
222
+ resetsAt?: number | undefined;
223
+ }>;
224
+ export declare const usageAmountSchema: import("@oh-my-pi/omptype").FluentType<{
220
225
  limit?: number | undefined;
221
226
  remaining?: number | undefined;
227
+ remainingFraction?: number | undefined;
228
+ unit: "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd";
229
+ used?: number | undefined;
222
230
  usedFraction?: number | undefined;
231
+ }, {
232
+ limit?: number | undefined;
233
+ remaining?: number | undefined;
223
234
  remainingFraction?: number | undefined;
224
235
  unit: "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd";
225
- }, {}>;
226
- export declare const usageScopeSchema: import("arktype/internal/variants/object.ts").ObjectType<{
227
- provider: string;
236
+ used?: number | undefined;
237
+ usedFraction?: number | undefined;
238
+ }>;
239
+ export declare const usageScopeSchema: import("@oh-my-pi/omptype").FluentType<{
228
240
  accountId?: string | undefined;
229
- projectId?: string | undefined;
230
- orgId?: string | undefined;
231
241
  modelId?: string | undefined;
242
+ orgId?: string | undefined;
243
+ projectId?: string | undefined;
244
+ provider: string;
245
+ shared?: boolean | undefined;
232
246
  tier?: string | undefined;
233
247
  windowId?: string | undefined;
248
+ }, {
249
+ accountId?: string | undefined;
250
+ modelId?: string | undefined;
251
+ orgId?: string | undefined;
252
+ projectId?: string | undefined;
253
+ provider: string;
234
254
  shared?: boolean | undefined;
235
- }, {}>;
236
- export declare const usageLimitSchema: import("arktype/internal/variants/object.ts").ObjectType<{
255
+ tier?: string | undefined;
256
+ windowId?: string | undefined;
257
+ }>;
258
+ export declare const usageLimitSchema: import("@oh-my-pi/omptype").FluentType<{
259
+ amount: {
260
+ limit?: number | undefined;
261
+ remaining?: number | undefined;
262
+ remainingFraction?: number | undefined;
263
+ unit: "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd";
264
+ used?: number | undefined;
265
+ usedFraction?: number | undefined;
266
+ };
237
267
  id: string;
238
268
  label: string;
269
+ notes?: string[] | undefined;
239
270
  scope: {
240
- provider: string;
241
271
  accountId?: string | undefined;
242
- projectId?: string | undefined;
243
- orgId?: string | undefined;
244
272
  modelId?: string | undefined;
273
+ orgId?: string | undefined;
274
+ projectId?: string | undefined;
275
+ provider: string;
276
+ shared?: boolean | undefined;
245
277
  tier?: string | undefined;
246
278
  windowId?: string | undefined;
247
- shared?: boolean | undefined;
248
279
  };
280
+ status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
249
281
  window?: {
282
+ durationMs?: number | undefined;
250
283
  id: string;
251
284
  label: string;
252
- durationMs?: number | undefined;
253
- resetsAt?: number | undefined;
254
285
  resetLabel?: string | undefined;
286
+ resetsAt?: number | undefined;
255
287
  } | undefined;
288
+ }, {
256
289
  amount: {
257
- used?: number | undefined;
258
290
  limit?: number | undefined;
259
291
  remaining?: number | undefined;
260
- usedFraction?: number | undefined;
261
292
  remainingFraction?: number | undefined;
262
293
  unit: "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd";
294
+ used?: number | undefined;
295
+ usedFraction?: number | undefined;
263
296
  };
264
- status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
297
+ id: string;
298
+ label: string;
265
299
  notes?: string[] | undefined;
266
- }, {}>;
267
- export declare const usageResetCreditDetailSchema: import("arktype/internal/variants/object.ts").ObjectType<{
300
+ scope: {
301
+ accountId?: string | undefined;
302
+ modelId?: string | undefined;
303
+ orgId?: string | undefined;
304
+ projectId?: string | undefined;
305
+ provider: string;
306
+ shared?: boolean | undefined;
307
+ tier?: string | undefined;
308
+ windowId?: string | undefined;
309
+ };
310
+ status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
311
+ window?: {
312
+ durationMs?: number | undefined;
313
+ id: string;
314
+ label: string;
315
+ resetLabel?: string | undefined;
316
+ resetsAt?: number | undefined;
317
+ } | undefined;
318
+ }>;
319
+ export declare const usageResetCreditDetailSchema: import("@oh-my-pi/omptype").FluentType<{
320
+ expiresAt?: string | undefined;
268
321
  grantedAt?: string | undefined;
322
+ status?: string | undefined;
323
+ }, {
269
324
  expiresAt?: string | undefined;
325
+ grantedAt?: string | undefined;
270
326
  status?: string | undefined;
271
- }, {}>;
272
- export declare const usageResetCreditsSchema: import("arktype/internal/variants/object.ts").ObjectType<{
327
+ }>;
328
+ export declare const usageResetCreditsSchema: import("@oh-my-pi/omptype").FluentType<{
273
329
  availableCount: number;
274
330
  credits?: {
331
+ expiresAt?: string | undefined;
275
332
  grantedAt?: string | undefined;
333
+ status?: string | undefined;
334
+ }[] | undefined;
335
+ }, {
336
+ availableCount: number;
337
+ credits?: {
276
338
  expiresAt?: string | undefined;
339
+ grantedAt?: string | undefined;
277
340
  status?: string | undefined;
278
341
  }[] | undefined;
279
- }, {}>;
280
- export declare const usageReportSchema: import("arktype/internal/variants/object.ts").ObjectType<{
281
- provider: string;
342
+ }>;
343
+ export declare const usageReportSchema: import("@oh-my-pi/omptype").FluentType<{
282
344
  fetchedAt: number;
283
345
  limits: {
346
+ amount: {
347
+ limit?: number | undefined;
348
+ remaining?: number | undefined;
349
+ remainingFraction?: number | undefined;
350
+ unit: "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd";
351
+ used?: number | undefined;
352
+ usedFraction?: number | undefined;
353
+ };
284
354
  id: string;
285
355
  label: string;
356
+ notes?: string[] | undefined;
286
357
  scope: {
287
- provider: string;
288
358
  accountId?: string | undefined;
289
- projectId?: string | undefined;
290
- orgId?: string | undefined;
291
359
  modelId?: string | undefined;
360
+ orgId?: string | undefined;
361
+ projectId?: string | undefined;
362
+ provider: string;
363
+ shared?: boolean | undefined;
292
364
  tier?: string | undefined;
293
365
  windowId?: string | undefined;
294
- shared?: boolean | undefined;
295
366
  };
367
+ status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
296
368
  window?: {
369
+ durationMs?: number | undefined;
297
370
  id: string;
298
371
  label: string;
299
- durationMs?: number | undefined;
300
- resetsAt?: number | undefined;
301
372
  resetLabel?: string | undefined;
373
+ resetsAt?: number | undefined;
302
374
  } | undefined;
375
+ }[];
376
+ metadata?: Record<string, unknown> | undefined;
377
+ notes?: string[] | undefined;
378
+ provider: string;
379
+ raw?: unknown;
380
+ resetCredits?: {
381
+ availableCount: number;
382
+ credits?: {
383
+ expiresAt?: string | undefined;
384
+ grantedAt?: string | undefined;
385
+ status?: string | undefined;
386
+ }[] | undefined;
387
+ } | undefined;
388
+ }, {
389
+ fetchedAt: number;
390
+ limits: {
303
391
  amount: {
304
- used?: number | undefined;
305
392
  limit?: number | undefined;
306
393
  remaining?: number | undefined;
307
- usedFraction?: number | undefined;
308
394
  remainingFraction?: number | undefined;
309
395
  unit: "bytes" | "minutes" | "percent" | "requests" | "tokens" | "unknown" | "usd";
396
+ used?: number | undefined;
397
+ usedFraction?: number | undefined;
310
398
  };
311
- status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
399
+ id: string;
400
+ label: string;
312
401
  notes?: string[] | undefined;
402
+ scope: {
403
+ accountId?: string | undefined;
404
+ modelId?: string | undefined;
405
+ orgId?: string | undefined;
406
+ projectId?: string | undefined;
407
+ provider: string;
408
+ shared?: boolean | undefined;
409
+ tier?: string | undefined;
410
+ windowId?: string | undefined;
411
+ };
412
+ status?: "exhausted" | "ok" | "unknown" | "warning" | undefined;
413
+ window?: {
414
+ durationMs?: number | undefined;
415
+ id: string;
416
+ label: string;
417
+ resetLabel?: string | undefined;
418
+ resetsAt?: number | undefined;
419
+ } | undefined;
313
420
  }[];
421
+ metadata?: Record<string, unknown> | undefined;
422
+ notes?: string[] | undefined;
423
+ provider: string;
424
+ raw?: unknown;
314
425
  resetCredits?: {
315
426
  availableCount: number;
316
427
  credits?: {
317
- grantedAt?: string | undefined;
318
428
  expiresAt?: string | undefined;
429
+ grantedAt?: string | undefined;
319
430
  status?: string | undefined;
320
431
  }[] | undefined;
321
432
  } | undefined;
322
- notes?: string[] | undefined;
323
- metadata?: {
324
- [x: string]: unknown;
325
- } | undefined;
326
- raw?: unknown;
327
- }, {}>;
433
+ }>;
328
434
  /** Optional logger for usage fetchers. */
329
435
  export interface UsageLogger {
330
436
  debug(message: string, meta?: Record<string, unknown>): void;
@@ -0,0 +1,17 @@
1
+ /** INI sections with `profile ` / `sso-session ` prefixes normalized. */
2
+ export type AwsIniFile = Record<string, Record<string, string>>;
3
+ export declare function parseAwsIni(text: string): AwsIniFile;
4
+ /** Resolve the selected shared-credentials profile. */
5
+ export declare function resolveAwsProfile(profile?: string): string;
6
+ /**
7
+ * Whether the shared config file participates in profile/region resolution.
8
+ * Explicit profile selection enables it; the implicit default profile follows
9
+ * the AWS SDK's `AWS_SDK_LOAD_CONFIG` opt-in.
10
+ */
11
+ export declare function shouldLoadAwsSharedConfig(profile?: string): boolean;
12
+ export declare function resolveAwsProfileRegion(profile?: string): string | undefined;
13
+ /** Region selected by the environment or active shared-config profile. */
14
+ export declare function resolveAwsAmbientRegion(profile?: string): string | undefined;
15
+ /** Resolve the region precedence shared by AWS transports and credential exchanges. */
16
+ export declare function resolveAwsRegion(explicitRegion?: string, profile?: string): string;
17
+ export declare function hasConfiguredAwsProfile(profile?: string): boolean;
@@ -10,7 +10,7 @@
10
10
  * All three are normalized at the boundary so providers and validators see the same
11
11
  * JSON Schema dialect.
12
12
  */
13
- import type { Type } from "arktype";
13
+ import type { Type } from "@oh-my-pi/omptype";
14
14
  import { type ZodType } from "zod/v4";
15
15
  import type { Tool } from "../../types.js";
16
16
  /**
@@ -1,3 +1,27 @@
1
+ /**
2
+ * Tool-call argument validation pipeline.
3
+ *
4
+ * Tools may declare their parameters as either Zod schemas (canonical) or
5
+ * plain JSON Schema (legacy / extensions). This module is the single
6
+ * entrypoint the agent calls before dispatching a tool — it:
7
+ *
8
+ * 1. Builds (or fetches from cache) a `ValidationContext` for the tool —
9
+ * the Zod schema if available plus the equivalent wire JSON Schema, or
10
+ * just the JSON Schema for non-Zod tools.
11
+ * 2. Normalizes LLM quirks (null / "null" → omit-or-default substitution)
12
+ * against the JSON Schema before validation.
13
+ * 3. Validates with the Zod or JSON-Schema validator.
14
+ * 4. On failure, walks the resulting issues and coerces common LLM type
15
+ * drift (JSON-stringified values, boolean/number/string scalar drift),
16
+ * drops unrecognized keys, and retries up to `MAX_COERCION_PASSES` times.
17
+ * 5. Throws a formatted error if reconciliation fails; otherwise returns
18
+ * the parsed arguments with original unknown root fields preserved (so
19
+ * hallucinated top-level keys still surface to the caller).
20
+ *
21
+ * The goal is to be conservative: every coercion is a structural rewrite that
22
+ * keeps the schema in charge of acceptance — we never invent values, only
23
+ * massage shapes the LLM almost got right.
24
+ */
1
25
  import type { Tool, ToolCall } from "../types.js";
2
26
  /**
3
27
  * Finds a tool by name and validates the tool call arguments against its schema.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "17.2.5",
4
+ "version": "17.2.7",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -38,10 +38,10 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@bufbuild/protobuf": "^2.12.1",
41
- "@oh-my-pi/pi-catalog": "17.2.5",
42
- "@oh-my-pi/pi-utils": "17.2.5",
43
- "@oh-my-pi/pi-wire": "17.2.5",
44
- "arktype": "2.2.3",
41
+ "@oh-my-pi/omptype": "17.2.7",
42
+ "@oh-my-pi/pi-catalog": "17.2.7",
43
+ "@oh-my-pi/pi-utils": "17.2.7",
44
+ "@oh-my-pi/pi-wire": "17.2.7",
45
45
  "zod": "^4"
46
46
  },
47
47
  "devDependencies": {
@@ -5,8 +5,9 @@
5
5
  * `omp auth-broker status` (liveness checks). All endpoints except
6
6
  * `/v1/healthz` require a bearer token.
7
7
  */
8
+
9
+ import { type } from "@oh-my-pi/omptype";
8
10
  import { readSseEvents } from "@oh-my-pi/pi-utils";
9
- import { type } from "arktype";
10
11
  import type { AuthCredential, DisabledCredentialSummary } from "../auth-storage";
11
12
  import type {
12
13
  ClientUsageReportRequest,
@@ -9,8 +9,9 @@
9
9
  * Transport security is delegated to the operator (Tailscale / Wireguard);
10
10
  * the server only checks a bearer token against an allow-list per request.
11
11
  */
12
+
13
+ import { type Type, type } from "@oh-my-pi/omptype";
12
14
  import { logger } from "@oh-my-pi/pi-utils";
13
- import { type Type, type } from "arktype";
14
15
  import type { AuthStorage, StoredCredentialBlock } from "../auth-storage";
15
16
  import { parseBind } from "../utils/parse-bind";
16
17
  import { AuthBrokerRefresher, type AuthBrokerRefresherSchedule } from "./refresher";
@@ -12,7 +12,7 @@
12
12
  * exception (standard type keeps extra keys): it preserves provider-specific extension fields so
13
13
  * they round-trip through the broker instead of being dropped (see below).
14
14
  */
15
- import { type Type, type } from "arktype";
15
+ import { type Type, type } from "@oh-my-pi/omptype";
16
16
  import {
17
17
  type ApiKeyCredential,
18
18
  type AuthCredential,
@@ -15,17 +15,12 @@ export function renderToolExamples(tool: InbandTool, intentField?: string): stri
15
15
  const examples = tool.examples;
16
16
  if (!examples?.length) return "";
17
17
  const renderCall = (args: Record<string, unknown>): string => {
18
- let soleKey: string | undefined;
19
- let argCount = 0;
20
- for (const key in args) {
21
- argCount++;
22
- soleKey = key;
23
- }
24
- if (argCount === 1 && soleKey !== undefined && typeof args[soleKey] === "string") {
18
+ const bare = bareStringArg(args);
19
+ if (bare !== undefined) {
25
20
  // Bare payload. The intent placeholder still rides on the envelope so
26
21
  // intent-traced schemas (where `i` is required) keep teaching it.
27
22
  const intentAttr = intentField ? ` ${intentField}="${INTENT_PLACEHOLDER}"` : "";
28
- return `<example${intentAttr}>\n${args[soleKey]}\n</example>`;
23
+ return `<example${intentAttr}>\n${bare}\n</example>`;
29
24
  }
30
25
  // When intent tracing injects `i` into the schema, examples must show a
31
26
  // placeholder so the model learns to emit it. Keep it first, matching the
@@ -43,3 +38,34 @@ export function renderToolExamples(tool: InbandTool, intentField?: string): stri
43
38
  });
44
39
  return `<examples>\n${parts.join("\n")}\n</examples>`;
45
40
  }
41
+
42
+ /**
43
+ * Render a tool's examples as JSDoc-style `@example` lines for comment-gutter
44
+ * contexts (the Harmony `namespace functions` inventory): `@example "caption"`
45
+ * followed by the call in the same Python kwargs syntax as the wire block. The
46
+ * tag line delimits each example, so no XML envelope is needed — which is why
47
+ * the inventory uses this instead of `//`-prefixing the `<examples>` block.
48
+ */
49
+ export function renderToolExamplesJsdoc(tool: InbandTool): string {
50
+ const examples = tool.examples;
51
+ if (!examples?.length) return "";
52
+ const renderCall = (args: Record<string, unknown>): string => bareStringArg(args) ?? pyCall(tool.name, args);
53
+ const parts = examples.map(ex => {
54
+ const head = ex.caption ? `@example ${JSON.stringify(ex.caption)}` : "@example";
55
+ if ("call" in ex) return `${head}\n${renderCall(ex.call)}`;
56
+ if ("good" in ex) return `${head}\nWRONG:\n${renderCall(ex.bad)}\nRIGHT:\n${renderCall(ex.good)}`;
57
+ return ex.note ? `${head}\n${ex.note}` : head;
58
+ });
59
+ return parts.join("\n");
60
+ }
61
+
62
+ /** Sole-argument string payload, if the call has exactly one string argument. */
63
+ function bareStringArg(args: Record<string, unknown>): string | undefined {
64
+ let sole: unknown;
65
+ let count = 0;
66
+ for (const key in args) {
67
+ count++;
68
+ sole = args[key];
69
+ }
70
+ return count === 1 && typeof sole === "string" ? sole : undefined;
71
+ }
@@ -1,5 +1,5 @@
1
1
  import { jsonSchemaToTypeScript, toolWireSchema } from "../utils/schema";
2
- import { renderToolExamples } from "./examples";
2
+ import { renderToolExamplesJsdoc } from "./examples";
3
3
  import type { InbandTool } from "./types";
4
4
 
5
5
  /**
@@ -18,7 +18,7 @@ export function renderToolInventory(tools: readonly InbandTool[]): string {
18
18
  if (description) {
19
19
  for (const line of description.split("\n")) lines.push(`// ${line}`.trimEnd());
20
20
  }
21
- const examples = renderToolExamples(tool);
21
+ const examples = renderToolExamplesJsdoc(tool);
22
22
  if (examples) {
23
23
  if (description) lines.push("//");
24
24
  for (const line of examples.split("\n")) lines.push(`// ${line}`.trimEnd());