@jxburros/ai-nugget 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +132 -385
  2. package/UPGRADING.md +158 -0
  3. package/dist/adapters/engines/anthropic.d.ts +7 -1
  4. package/dist/adapters/engines/anthropic.js +64 -37
  5. package/dist/adapters/engines/base.d.ts +29 -2
  6. package/dist/adapters/engines/base.js +52 -8
  7. package/dist/adapters/engines/google.d.ts +7 -1
  8. package/dist/adapters/engines/google.js +73 -29
  9. package/dist/adapters/engines/ollama.d.ts +2 -1
  10. package/dist/adapters/engines/ollama.js +51 -15
  11. package/dist/adapters/engines/openaiChat.d.ts +2 -1
  12. package/dist/adapters/engines/openaiChat.js +60 -30
  13. package/dist/adapters/profiles.d.ts +21 -1
  14. package/dist/adapters/profiles.js +12 -2
  15. package/dist/agent/loop.d.ts +43 -1
  16. package/dist/agent/loop.js +116 -12
  17. package/dist/cjs/adapters/engines/anthropic.js +308 -0
  18. package/dist/cjs/adapters/engines/base.js +147 -0
  19. package/dist/cjs/adapters/engines/google.js +284 -0
  20. package/dist/cjs/adapters/engines/ollama.js +199 -0
  21. package/dist/cjs/adapters/engines/openaiChat.js +261 -0
  22. package/dist/cjs/adapters/index.js +22 -0
  23. package/dist/cjs/adapters/profiles.js +125 -0
  24. package/dist/cjs/agent/index.js +18 -0
  25. package/dist/cjs/agent/loop.js +372 -0
  26. package/dist/cjs/agent/tools.js +51 -0
  27. package/dist/cjs/connect.js +27 -0
  28. package/dist/cjs/errors.js +110 -0
  29. package/dist/cjs/handler.js +561 -0
  30. package/dist/cjs/index.js +27 -0
  31. package/dist/cjs/json.js +121 -0
  32. package/dist/cjs/keys.js +81 -0
  33. package/dist/cjs/package.json +3 -0
  34. package/dist/cjs/policy.js +42 -0
  35. package/dist/cjs/redact.js +78 -0
  36. package/dist/cjs/tokens.js +22 -0
  37. package/dist/cjs/transport.js +172 -0
  38. package/dist/cjs/types.js +6 -0
  39. package/dist/cjs/util.js +112 -0
  40. package/dist/errors.js +25 -1
  41. package/dist/handler.d.ts +61 -1
  42. package/dist/handler.js +239 -59
  43. package/dist/redact.d.ts +18 -0
  44. package/dist/redact.js +29 -1
  45. package/dist/transport.d.ts +3 -1
  46. package/dist/transport.js +21 -1
  47. package/dist/types.d.ts +96 -2
  48. package/dist/util.d.ts +15 -0
  49. package/dist/util.js +46 -0
  50. package/nugget/VERSION.txt +2 -2
  51. package/nugget/dist/adapters/engines/anthropic.d.ts +14 -0
  52. package/nugget/dist/adapters/engines/anthropic.d.ts.map +1 -0
  53. package/nugget/dist/adapters/engines/anthropic.js +305 -0
  54. package/nugget/dist/adapters/engines/anthropic.js.map +1 -0
  55. package/nugget/dist/adapters/engines/base.d.ts +50 -0
  56. package/nugget/dist/adapters/engines/base.d.ts.map +1 -0
  57. package/nugget/dist/adapters/engines/base.js +137 -0
  58. package/nugget/dist/adapters/engines/base.js.map +1 -0
  59. package/nugget/dist/adapters/engines/google.d.ts +24 -0
  60. package/nugget/dist/adapters/engines/google.d.ts.map +1 -0
  61. package/nugget/dist/adapters/engines/google.js +281 -0
  62. package/nugget/dist/adapters/engines/google.js.map +1 -0
  63. package/nugget/dist/adapters/engines/ollama.d.ts +11 -0
  64. package/nugget/dist/adapters/engines/ollama.d.ts.map +1 -0
  65. package/nugget/dist/adapters/engines/ollama.js +196 -0
  66. package/nugget/dist/adapters/engines/ollama.js.map +1 -0
  67. package/nugget/dist/adapters/engines/openaiChat.d.ts +16 -0
  68. package/nugget/dist/adapters/engines/openaiChat.d.ts.map +1 -0
  69. package/nugget/dist/adapters/engines/openaiChat.js +258 -0
  70. package/nugget/dist/adapters/engines/openaiChat.js.map +1 -0
  71. package/nugget/dist/adapters/index.d.ts +5 -0
  72. package/nugget/dist/adapters/index.d.ts.map +1 -0
  73. package/nugget/dist/adapters/index.js +17 -0
  74. package/nugget/dist/adapters/index.js.map +1 -0
  75. package/nugget/dist/adapters/profiles.d.ts +62 -0
  76. package/nugget/dist/adapters/profiles.d.ts.map +1 -0
  77. package/nugget/dist/adapters/profiles.js +121 -0
  78. package/nugget/dist/adapters/profiles.js.map +1 -0
  79. package/nugget/dist/agent/index.d.ts +3 -0
  80. package/nugget/dist/agent/index.d.ts.map +1 -0
  81. package/nugget/dist/agent/index.js +3 -0
  82. package/nugget/dist/agent/index.js.map +1 -0
  83. package/nugget/dist/agent/loop.d.ts +112 -0
  84. package/nugget/dist/agent/loop.d.ts.map +1 -0
  85. package/nugget/dist/agent/loop.js +370 -0
  86. package/nugget/dist/agent/loop.js.map +1 -0
  87. package/nugget/dist/agent/tools.d.ts +29 -0
  88. package/nugget/dist/agent/tools.d.ts.map +1 -0
  89. package/nugget/dist/agent/tools.js +48 -0
  90. package/nugget/dist/agent/tools.js.map +1 -0
  91. package/nugget/dist/cjs/adapters/engines/anthropic.js +308 -0
  92. package/nugget/dist/cjs/adapters/engines/base.js +147 -0
  93. package/nugget/dist/cjs/adapters/engines/google.js +284 -0
  94. package/nugget/dist/cjs/adapters/engines/ollama.js +199 -0
  95. package/nugget/dist/cjs/adapters/engines/openaiChat.js +261 -0
  96. package/nugget/dist/cjs/adapters/index.js +22 -0
  97. package/nugget/dist/cjs/adapters/profiles.js +125 -0
  98. package/nugget/dist/cjs/agent/index.js +18 -0
  99. package/nugget/dist/cjs/agent/loop.js +372 -0
  100. package/nugget/dist/cjs/agent/tools.js +51 -0
  101. package/nugget/dist/cjs/connect.js +27 -0
  102. package/nugget/dist/cjs/errors.js +110 -0
  103. package/nugget/dist/cjs/handler.js +561 -0
  104. package/nugget/dist/cjs/index.js +27 -0
  105. package/nugget/dist/cjs/json.js +121 -0
  106. package/nugget/dist/cjs/keys.js +81 -0
  107. package/nugget/dist/cjs/package.json +3 -0
  108. package/nugget/dist/cjs/policy.js +42 -0
  109. package/nugget/dist/cjs/redact.js +78 -0
  110. package/nugget/dist/cjs/tokens.js +22 -0
  111. package/nugget/dist/cjs/transport.js +172 -0
  112. package/nugget/dist/cjs/types.js +6 -0
  113. package/nugget/dist/cjs/util.js +112 -0
  114. package/nugget/dist/connect.d.ts +31 -0
  115. package/nugget/dist/connect.d.ts.map +1 -0
  116. package/nugget/dist/connect.js +25 -0
  117. package/nugget/dist/connect.js.map +1 -0
  118. package/nugget/dist/errors.d.ts +22 -0
  119. package/nugget/dist/errors.d.ts.map +1 -0
  120. package/nugget/dist/errors.js +104 -0
  121. package/nugget/dist/errors.js.map +1 -0
  122. package/nugget/dist/handler.d.ts +108 -0
  123. package/nugget/dist/handler.d.ts.map +1 -0
  124. package/nugget/dist/handler.js +557 -0
  125. package/nugget/dist/handler.js.map +1 -0
  126. package/nugget/dist/index.d.ts +12 -0
  127. package/nugget/dist/index.d.ts.map +1 -0
  128. package/nugget/dist/index.js +12 -0
  129. package/nugget/dist/index.js.map +1 -0
  130. package/nugget/dist/json.d.ts +7 -0
  131. package/nugget/dist/json.d.ts.map +1 -0
  132. package/nugget/dist/json.js +114 -0
  133. package/nugget/dist/json.js.map +1 -0
  134. package/nugget/dist/keys.d.ts +7 -0
  135. package/nugget/dist/keys.d.ts.map +1 -0
  136. package/nugget/dist/keys.js +75 -0
  137. package/nugget/dist/keys.js.map +1 -0
  138. package/nugget/dist/policy.d.ts +6 -0
  139. package/nugget/dist/policy.d.ts.map +1 -0
  140. package/nugget/dist/policy.js +37 -0
  141. package/nugget/dist/policy.js.map +1 -0
  142. package/nugget/dist/redact.d.ts +26 -0
  143. package/nugget/dist/redact.d.ts.map +1 -0
  144. package/nugget/dist/redact.js +74 -0
  145. package/nugget/dist/redact.js.map +1 -0
  146. package/nugget/dist/tokens.d.ts +5 -0
  147. package/nugget/dist/tokens.d.ts.map +1 -0
  148. package/nugget/dist/tokens.js +18 -0
  149. package/nugget/dist/tokens.js.map +1 -0
  150. package/nugget/dist/transport.d.ts +30 -0
  151. package/nugget/dist/transport.d.ts.map +1 -0
  152. package/nugget/dist/transport.js +165 -0
  153. package/nugget/dist/transport.js.map +1 -0
  154. package/nugget/dist/types.d.ts +285 -0
  155. package/nugget/dist/types.d.ts.map +1 -0
  156. package/nugget/dist/types.js +4 -0
  157. package/nugget/dist/types.js.map +1 -0
  158. package/nugget/dist/util.d.ts +24 -0
  159. package/nugget/dist/util.d.ts.map +1 -0
  160. package/nugget/dist/util.js +101 -0
  161. package/nugget/dist/util.js.map +1 -0
  162. package/nugget/src/adapters/engines/anthropic.ts +62 -37
  163. package/nugget/src/adapters/engines/base.ts +50 -7
  164. package/nugget/src/adapters/engines/google.ts +72 -29
  165. package/nugget/src/adapters/engines/ollama.ts +51 -17
  166. package/nugget/src/adapters/engines/openaiChat.ts +61 -32
  167. package/nugget/src/adapters/profiles.ts +53 -3
  168. package/nugget/src/agent/loop.ts +153 -13
  169. package/nugget/src/errors.ts +25 -1
  170. package/nugget/src/handler.ts +279 -57
  171. package/nugget/src/redact.ts +32 -1
  172. package/nugget/src/transport.ts +20 -1
  173. package/nugget/src/types.ts +96 -1
  174. package/nugget/src/util.ts +50 -0
  175. package/package.json +18 -5
@@ -0,0 +1,25 @@
1
+ import { globalEnv } from './util.js';
2
+ /**
3
+ * Resolves a server-side `Connection` plus a default `model` from app-owned
4
+ * env vars (`AI_PROVIDER`, `AI_MODEL`, `AI_KEY_ENV`, `AI_BASE_URL` unless
5
+ * overridden). This only collapses the config-reading boilerplate that was
6
+ * being hand-rolled the same way in every small server app; it does not add
7
+ * policy. `provider`/`baseUrl` still come from the server's own environment,
8
+ * never from client input, and the returned `keyRef` still resolves through
9
+ * `KeySource` at call time like any other `Connection`.
10
+ */
11
+ export function envConnection(options = {}) {
12
+ const env = options.env ?? globalEnv();
13
+ const provider = env[options.providerVar ?? 'AI_PROVIDER']?.trim() || options.defaultProvider || 'openai';
14
+ const model = env[options.modelVar ?? 'AI_MODEL']?.trim() || options.defaultModel || 'gpt-4o-mini';
15
+ const keyEnvName = env[options.keyEnvVar ?? 'AI_KEY_ENV']?.trim() || options.defaultKeyEnv || 'OPENAI_API_KEY';
16
+ const baseUrl = env[options.baseUrlVar ?? 'AI_BASE_URL']?.trim();
17
+ const connection = {
18
+ id: options.id ?? 'app',
19
+ provider,
20
+ keyRef: { kind: 'env', name: keyEnvName },
21
+ ...(baseUrl ? { baseUrl } : {}),
22
+ };
23
+ return { connection, model };
24
+ }
25
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAuBtC;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,UAAgC,EAAE;IAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,eAAe,IAAI,QAAQ,CAAC;IAC1G,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,YAAY,IAAI,aAAa,CAAC;IACnG,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,aAAa,IAAI,gBAAgB,CAAC;IAC/G,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC;IAEjE,MAAM,UAAU,GAAe;QAC7B,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,KAAK;QACvB,QAAQ;QACR,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE;QACzC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChC,CAAC;IACF,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { AIErrorKind } from './types.js';
2
+ export declare class AIError extends Error {
3
+ kind: AIErrorKind;
4
+ status?: number;
5
+ retryable: boolean;
6
+ provider?: string;
7
+ raw?: string;
8
+ retryAfterMs?: number;
9
+ constructor(message: string, opts: {
10
+ kind: AIErrorKind;
11
+ status?: number;
12
+ retryable?: boolean;
13
+ provider?: string;
14
+ raw?: string;
15
+ retryAfterMs?: number;
16
+ cause?: unknown;
17
+ });
18
+ }
19
+ export declare function defaultRetryable(kind: AIErrorKind): boolean;
20
+ export declare function classify(status: number, body?: string, provider?: string, headers?: Headers): AIError;
21
+ export declare function fromUnknown(error: unknown, provider?: string): AIError;
22
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAW9C,qBAAa,OAAQ,SAAQ,KAAK;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;QACjC,IAAI,EAAE,WAAW,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;CAWF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE3D;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAK,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAmCjG;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAYtE"}
@@ -0,0 +1,104 @@
1
+ import { createDefaultRedactor } from './redact.js';
2
+ /**
3
+ * Pattern-based redaction applied at the wire boundary, before an error object
4
+ * exists. `AIHandler` redacts again on the way out (adding session-registered
5
+ * exact secrets), but doing it here means a provider body that echoes a
6
+ * recognizable secret can never be carried by an `AIError` in the first place —
7
+ * including on code paths that never reach the handler's own catch blocks.
8
+ */
9
+ const wireRedactor = createDefaultRedactor();
10
+ export class AIError extends Error {
11
+ kind;
12
+ status;
13
+ retryable;
14
+ provider;
15
+ raw;
16
+ retryAfterMs;
17
+ constructor(message, opts) {
18
+ super(message);
19
+ this.name = 'AIError';
20
+ this.kind = opts.kind;
21
+ this.retryable = opts.retryable ?? defaultRetryable(opts.kind);
22
+ if (opts.status !== undefined)
23
+ this.status = opts.status;
24
+ if (opts.provider !== undefined)
25
+ this.provider = opts.provider;
26
+ if (opts.raw !== undefined)
27
+ this.raw = opts.raw;
28
+ if (opts.retryAfterMs !== undefined)
29
+ this.retryAfterMs = opts.retryAfterMs;
30
+ if (opts.cause !== undefined)
31
+ this.cause = opts.cause;
32
+ }
33
+ }
34
+ export function defaultRetryable(kind) {
35
+ return kind === 'rate_limit' || kind === 'timeout' || kind === 'network' || kind === 'server' || kind === 'invalid_response';
36
+ }
37
+ export function classify(status, body = '', provider, headers) {
38
+ const excerpt = wireRedactor.redact(body.slice(0, 200));
39
+ const lower = body.toLowerCase();
40
+ let kind = 'server';
41
+ // 403 is classified as `auth` (non-retryable) deliberately: a forbidden
42
+ // response almost always means a bad/insufficient credential or a blocked
43
+ // region/model, none of which a retry fixes. Callers that know a specific
44
+ // provider returns a retryable 403 can reclassify in a `beforeCall`/adapter.
45
+ if (status === 401 || status === 403)
46
+ kind = 'auth';
47
+ else if (status === 408)
48
+ kind = 'timeout';
49
+ else if (status === 429)
50
+ kind = 'rate_limit';
51
+ else if (status === 400 || status === 422) {
52
+ kind = lower.includes('context') || lower.includes('maximum context') || lower.includes('token limit')
53
+ ? 'context_length'
54
+ : 'invalid_request';
55
+ }
56
+ else if (status === 404 || status === 410) {
57
+ // A missing route/deployment is not a malformed request: it is usually a
58
+ // wrong baseUrl or model name, and sometimes a temporarily misrouted load
59
+ // balancer. `not_found` keeps it distinguishable from `invalid_request` so
60
+ // apps don't tell a user "your request was invalid" for an infra problem.
61
+ // Non-retryable by default — a caller that knows its 404s are transient can
62
+ // retry on `kind === 'not_found'` itself.
63
+ kind = 'not_found';
64
+ }
65
+ else if (status >= 500)
66
+ kind = 'server';
67
+ // Everything else in 4xx (409 conflict, 405, 415, 451, …) is a genuine
68
+ // client-side request problem, so `invalid_request` is honest for it.
69
+ else
70
+ kind = 'invalid_request';
71
+ return new AIError(`HTTP ${status}: ${excerpt}`, {
72
+ kind,
73
+ status,
74
+ provider,
75
+ raw: excerpt,
76
+ retryAfterMs: parseRetryAfter(headers?.get('retry-after') ?? null),
77
+ });
78
+ }
79
+ export function fromUnknown(error, provider) {
80
+ if (error instanceof AIError)
81
+ return error;
82
+ if (error instanceof DOMException && error.name === 'AbortError') {
83
+ return new AIError('Request was canceled', { kind: 'canceled', retryable: false, provider, cause: error });
84
+ }
85
+ if (error instanceof Error && /timeout|timed out/i.test(error.message)) {
86
+ return new AIError(error.message, { kind: 'timeout', provider, cause: error });
87
+ }
88
+ if (error instanceof Error) {
89
+ return new AIError(error.message, { kind: 'network', provider, cause: error });
90
+ }
91
+ return new AIError('Unknown AI provider error', { kind: 'network', provider, cause: error });
92
+ }
93
+ function parseRetryAfter(value) {
94
+ if (!value)
95
+ return undefined;
96
+ const seconds = Number(value);
97
+ if (Number.isFinite(seconds))
98
+ return Math.max(0, seconds * 1000);
99
+ const time = Date.parse(value);
100
+ if (!Number.isNaN(time))
101
+ return Math.max(0, time - Date.now());
102
+ return undefined;
103
+ }
104
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import type { CallInfo, CallRecord, ChatRequest, ChatResult, Connection, EmbedRequest, EmbedResult, GovernancePolicy, KeySource, ModelInfo, ParsedResult, Redactor, StandardSchemaV1, StreamEvent, TelemetrySink, Usage } from './types.js';
2
+ export interface HandlerOptions {
3
+ keySource: KeySource;
4
+ policy?: GovernancePolicy;
5
+ redactor?: Redactor;
6
+ telemetry?: TelemetrySink;
7
+ hooks?: {
8
+ beforeCall?(info: CallInfo): Promise<void | 'deny'>;
9
+ afterCall?(record: CallRecord): Promise<void>;
10
+ };
11
+ retry?: {
12
+ maxAttempts?: number;
13
+ baseDelayMs?: number;
14
+ maxDelayMs?: number;
15
+ };
16
+ /**
17
+ * Concurrency and pacing limits, enforced by an **in-memory queue on this
18
+ * handler instance only**. There is no shared/external coordination, so N
19
+ * instances behind a load balancer allow N × `maxConcurrent` in flight against
20
+ * the provider. Size these per instance, or put a shared limiter in front if a
21
+ * global ceiling matters.
22
+ */
23
+ limits?: {
24
+ maxConcurrent?: number;
25
+ minIntervalMs?: number;
26
+ };
27
+ /**
28
+ * Silence the one-time startup notice logged when no `policy` is supplied.
29
+ * Set this only when running unrestricted is a deliberate choice — passing an
30
+ * explicit `policy: allowAllPolicy()` says the same thing and is clearer.
31
+ */
32
+ silencePolicyWarning?: boolean;
33
+ /**
34
+ * Optional cost estimator. Called once per successful call/embedding with the
35
+ * final usage; its return value (USD) is stored on the telemetry record's
36
+ * `costUsd`. Return undefined to leave a call uncosted. Pricing tables live in
37
+ * the app, not the library — this is only the seam to attach one.
38
+ */
39
+ pricing?(info: {
40
+ provider: string;
41
+ model: string;
42
+ usage: Usage;
43
+ }): number | undefined;
44
+ }
45
+ /** Test seam: reset the once-per-process startup notice. */
46
+ export declare function resetPolicyWarningForTests(): void;
47
+ export declare class AIHandler {
48
+ private opts;
49
+ private active;
50
+ private queue;
51
+ private lastStarted;
52
+ private sessionRedactor;
53
+ private policy;
54
+ constructor(opts: HandlerOptions);
55
+ chat(conn: Connection, req: ChatRequest): Promise<ChatResult>;
56
+ stream(conn: Connection, req: ChatRequest): AsyncIterable<StreamEvent>;
57
+ /**
58
+ * The shared pre-call preamble: policy check → key resolution → `beforeCall`
59
+ * hook. Every entry point (`stream`, `embed`, `listModels`/`testConnection`)
60
+ * runs exactly this sequence, so it lives once. Failures are *returned*, not
61
+ * recorded — each caller owns its own telemetry shape (`recordFailure` for
62
+ * chat/probe, `recordEmbed` for embeddings) and records the returned error.
63
+ */
64
+ private preflight;
65
+ /** Record a failed call and emit the single redacted `error` event for it. */
66
+ private failStream;
67
+ listModels(conn: Connection): Promise<ModelInfo[]>;
68
+ testConnection(conn: Connection): Promise<{
69
+ ok: boolean;
70
+ message: string;
71
+ }>;
72
+ /**
73
+ * Warm a connection so the first real call doesn't pay cold DNS/TLS and
74
+ * (for a local daemon) process spin-up on the hot path. Runs a lightweight
75
+ * health probe and never throws — call it once at boot. Combined with a CJS
76
+ * `require` path it removes the cold-start "offline" false negative.
77
+ */
78
+ prewarm(conn: Connection): Promise<void>;
79
+ /**
80
+ * Chat that returns typed, validated output. Requests JSON mode, extracts the
81
+ * JSON from the reply, and validates it against any Standard Schema validator
82
+ * (Zod / Valibot / ArkType). On a validation miss it performs exactly one
83
+ * corrective retry that shows the model its error, then throws
84
+ * `invalid_response` if still invalid. No schema library is bundled — the
85
+ * caller supplies the schema.
86
+ */
87
+ chatParsed<T>(conn: Connection, req: ChatRequest, schema: StandardSchemaV1<T>): Promise<ParsedResult<T>>;
88
+ /**
89
+ * Produce embeddings through the same governed pipeline as chat: policy check,
90
+ * key resolution, `beforeCall` hook, concurrency, and exactly one redacted
91
+ * telemetry record. Throws a typed `invalid_request` error for providers whose
92
+ * adapter has no `embed` (Anthropic, Google) rather than failing silently.
93
+ */
94
+ embed(conn: Connection, req: EmbedRequest): Promise<EmbedResult>;
95
+ private recordEmbed;
96
+ private runProbe;
97
+ private resolveConnection;
98
+ private acquire;
99
+ private release;
100
+ private retryDelay;
101
+ private recordSuccess;
102
+ private recordFailure;
103
+ private record;
104
+ private redact;
105
+ private redactedError;
106
+ private redactedCause;
107
+ }
108
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"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"}