@jxburros/ai-nugget 0.4.1 → 0.7.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 (187) hide show
  1. package/README.md +158 -382
  2. package/UPGRADING.md +182 -0
  3. package/dist/adapters/engines/anthropic.d.ts +7 -1
  4. package/dist/adapters/engines/anthropic.js +82 -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 +80 -29
  9. package/dist/adapters/engines/ollama.d.ts +2 -1
  10. package/dist/adapters/engines/ollama.js +57 -15
  11. package/dist/adapters/engines/openaiChat.d.ts +8 -1
  12. package/dist/adapters/engines/openaiChat.js +109 -29
  13. package/dist/adapters/profiles.d.ts +21 -1
  14. package/dist/adapters/profiles.js +12 -2
  15. package/dist/agent/loop.d.ts +45 -1
  16. package/dist/agent/loop.js +117 -12
  17. package/dist/cjs/adapters/engines/anthropic.js +326 -0
  18. package/dist/cjs/adapters/engines/base.js +147 -0
  19. package/dist/cjs/adapters/engines/google.js +291 -0
  20. package/dist/cjs/adapters/engines/ollama.js +205 -0
  21. package/dist/cjs/adapters/engines/openaiChat.js +312 -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 +373 -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 +586 -0
  30. package/dist/cjs/index.js +28 -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/reasoning.js +159 -0
  36. package/dist/cjs/redact.js +78 -0
  37. package/dist/cjs/tokens.js +22 -0
  38. package/dist/cjs/transport.js +172 -0
  39. package/dist/cjs/types.js +6 -0
  40. package/dist/cjs/util.js +126 -0
  41. package/dist/errors.js +25 -1
  42. package/dist/handler.d.ts +67 -1
  43. package/dist/handler.js +266 -61
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.js +1 -0
  46. package/dist/reasoning.d.ts +45 -0
  47. package/dist/reasoning.js +154 -0
  48. package/dist/redact.d.ts +18 -0
  49. package/dist/redact.js +29 -1
  50. package/dist/transport.d.ts +3 -1
  51. package/dist/transport.js +21 -1
  52. package/dist/types.d.ts +112 -2
  53. package/dist/util.d.ts +22 -0
  54. package/dist/util.js +59 -0
  55. package/nugget/VERSION.txt +2 -2
  56. package/nugget/dist/adapters/engines/anthropic.d.ts +14 -0
  57. package/nugget/dist/adapters/engines/anthropic.d.ts.map +1 -0
  58. package/nugget/dist/adapters/engines/anthropic.js +323 -0
  59. package/nugget/dist/adapters/engines/anthropic.js.map +1 -0
  60. package/nugget/dist/adapters/engines/base.d.ts +50 -0
  61. package/nugget/dist/adapters/engines/base.d.ts.map +1 -0
  62. package/nugget/dist/adapters/engines/base.js +137 -0
  63. package/nugget/dist/adapters/engines/base.js.map +1 -0
  64. package/nugget/dist/adapters/engines/google.d.ts +24 -0
  65. package/nugget/dist/adapters/engines/google.d.ts.map +1 -0
  66. package/nugget/dist/adapters/engines/google.js +288 -0
  67. package/nugget/dist/adapters/engines/google.js.map +1 -0
  68. package/nugget/dist/adapters/engines/ollama.d.ts +11 -0
  69. package/nugget/dist/adapters/engines/ollama.d.ts.map +1 -0
  70. package/nugget/dist/adapters/engines/ollama.js +202 -0
  71. package/nugget/dist/adapters/engines/ollama.js.map +1 -0
  72. package/nugget/dist/adapters/engines/openaiChat.d.ts +22 -0
  73. package/nugget/dist/adapters/engines/openaiChat.d.ts.map +1 -0
  74. package/nugget/dist/adapters/engines/openaiChat.js +308 -0
  75. package/nugget/dist/adapters/engines/openaiChat.js.map +1 -0
  76. package/nugget/dist/adapters/index.d.ts +5 -0
  77. package/nugget/dist/adapters/index.d.ts.map +1 -0
  78. package/nugget/dist/adapters/index.js +17 -0
  79. package/nugget/dist/adapters/index.js.map +1 -0
  80. package/nugget/dist/adapters/profiles.d.ts +62 -0
  81. package/nugget/dist/adapters/profiles.d.ts.map +1 -0
  82. package/nugget/dist/adapters/profiles.js +121 -0
  83. package/nugget/dist/adapters/profiles.js.map +1 -0
  84. package/nugget/dist/agent/index.d.ts +3 -0
  85. package/nugget/dist/agent/index.d.ts.map +1 -0
  86. package/nugget/dist/agent/index.js +3 -0
  87. package/nugget/dist/agent/index.js.map +1 -0
  88. package/nugget/dist/agent/loop.d.ts +114 -0
  89. package/nugget/dist/agent/loop.d.ts.map +1 -0
  90. package/nugget/dist/agent/loop.js +371 -0
  91. package/nugget/dist/agent/loop.js.map +1 -0
  92. package/nugget/dist/agent/tools.d.ts +29 -0
  93. package/nugget/dist/agent/tools.d.ts.map +1 -0
  94. package/nugget/dist/agent/tools.js +48 -0
  95. package/nugget/dist/agent/tools.js.map +1 -0
  96. package/nugget/dist/cjs/adapters/engines/anthropic.js +326 -0
  97. package/nugget/dist/cjs/adapters/engines/base.js +147 -0
  98. package/nugget/dist/cjs/adapters/engines/google.js +291 -0
  99. package/nugget/dist/cjs/adapters/engines/ollama.js +205 -0
  100. package/nugget/dist/cjs/adapters/engines/openaiChat.js +312 -0
  101. package/nugget/dist/cjs/adapters/index.js +22 -0
  102. package/nugget/dist/cjs/adapters/profiles.js +125 -0
  103. package/nugget/dist/cjs/agent/index.js +18 -0
  104. package/nugget/dist/cjs/agent/loop.js +373 -0
  105. package/nugget/dist/cjs/agent/tools.js +51 -0
  106. package/nugget/dist/cjs/connect.js +27 -0
  107. package/nugget/dist/cjs/errors.js +110 -0
  108. package/nugget/dist/cjs/handler.js +586 -0
  109. package/nugget/dist/cjs/index.js +28 -0
  110. package/nugget/dist/cjs/json.js +121 -0
  111. package/nugget/dist/cjs/keys.js +81 -0
  112. package/nugget/dist/cjs/package.json +3 -0
  113. package/nugget/dist/cjs/policy.js +42 -0
  114. package/nugget/dist/cjs/reasoning.js +159 -0
  115. package/nugget/dist/cjs/redact.js +78 -0
  116. package/nugget/dist/cjs/tokens.js +22 -0
  117. package/nugget/dist/cjs/transport.js +172 -0
  118. package/nugget/dist/cjs/types.js +6 -0
  119. package/nugget/dist/cjs/util.js +126 -0
  120. package/nugget/dist/connect.d.ts +31 -0
  121. package/nugget/dist/connect.d.ts.map +1 -0
  122. package/nugget/dist/connect.js +25 -0
  123. package/nugget/dist/connect.js.map +1 -0
  124. package/nugget/dist/errors.d.ts +22 -0
  125. package/nugget/dist/errors.d.ts.map +1 -0
  126. package/nugget/dist/errors.js +104 -0
  127. package/nugget/dist/errors.js.map +1 -0
  128. package/nugget/dist/handler.d.ts +114 -0
  129. package/nugget/dist/handler.d.ts.map +1 -0
  130. package/nugget/dist/handler.js +582 -0
  131. package/nugget/dist/handler.js.map +1 -0
  132. package/nugget/dist/index.d.ts +13 -0
  133. package/nugget/dist/index.d.ts.map +1 -0
  134. package/nugget/dist/index.js +13 -0
  135. package/nugget/dist/index.js.map +1 -0
  136. package/nugget/dist/json.d.ts +7 -0
  137. package/nugget/dist/json.d.ts.map +1 -0
  138. package/nugget/dist/json.js +114 -0
  139. package/nugget/dist/json.js.map +1 -0
  140. package/nugget/dist/keys.d.ts +7 -0
  141. package/nugget/dist/keys.d.ts.map +1 -0
  142. package/nugget/dist/keys.js +75 -0
  143. package/nugget/dist/keys.js.map +1 -0
  144. package/nugget/dist/policy.d.ts +6 -0
  145. package/nugget/dist/policy.d.ts.map +1 -0
  146. package/nugget/dist/policy.js +37 -0
  147. package/nugget/dist/policy.js.map +1 -0
  148. package/nugget/dist/reasoning.d.ts +45 -0
  149. package/nugget/dist/reasoning.d.ts.map +1 -0
  150. package/nugget/dist/reasoning.js +154 -0
  151. package/nugget/dist/reasoning.js.map +1 -0
  152. package/nugget/dist/redact.d.ts +26 -0
  153. package/nugget/dist/redact.d.ts.map +1 -0
  154. package/nugget/dist/redact.js +74 -0
  155. package/nugget/dist/redact.js.map +1 -0
  156. package/nugget/dist/tokens.d.ts +5 -0
  157. package/nugget/dist/tokens.d.ts.map +1 -0
  158. package/nugget/dist/tokens.js +18 -0
  159. package/nugget/dist/tokens.js.map +1 -0
  160. package/nugget/dist/transport.d.ts +30 -0
  161. package/nugget/dist/transport.d.ts.map +1 -0
  162. package/nugget/dist/transport.js +165 -0
  163. package/nugget/dist/transport.js.map +1 -0
  164. package/nugget/dist/types.d.ts +301 -0
  165. package/nugget/dist/types.d.ts.map +1 -0
  166. package/nugget/dist/types.js +4 -0
  167. package/nugget/dist/types.js.map +1 -0
  168. package/nugget/dist/util.d.ts +31 -0
  169. package/nugget/dist/util.d.ts.map +1 -0
  170. package/nugget/dist/util.js +114 -0
  171. package/nugget/dist/util.js.map +1 -0
  172. package/nugget/src/adapters/engines/anthropic.ts +78 -37
  173. package/nugget/src/adapters/engines/base.ts +50 -7
  174. package/nugget/src/adapters/engines/google.ts +79 -29
  175. package/nugget/src/adapters/engines/ollama.ts +56 -17
  176. package/nugget/src/adapters/engines/openaiChat.ts +104 -30
  177. package/nugget/src/adapters/profiles.ts +53 -3
  178. package/nugget/src/agent/loop.ts +156 -13
  179. package/nugget/src/errors.ts +25 -1
  180. package/nugget/src/handler.ts +308 -59
  181. package/nugget/src/index.ts +1 -0
  182. package/nugget/src/reasoning.ts +174 -0
  183. package/nugget/src/redact.ts +32 -1
  184. package/nugget/src/transport.ts +20 -1
  185. package/nugget/src/types.ts +113 -1
  186. package/nugget/src/util.ts +64 -0
  187. package/package.json +18 -5
@@ -0,0 +1,7 @@
1
+ export declare function extractJson(text: string): unknown | null;
2
+ export declare function extractJsonWithSchema<T>(text: string, parse: (value: unknown) => T): T;
3
+ export declare function requireString(record: Record<string, unknown>, key: string): string;
4
+ export declare function requireNumber(record: Record<string, unknown>, key: string): number;
5
+ export declare function requireStringArray(record: Record<string, unknown>, key: string): string[];
6
+ export declare function requireOptionalString(record: Record<string, unknown>, key: string): string | undefined;
7
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAmBxD;AA0CD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAStF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAMzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKtG"}
@@ -0,0 +1,114 @@
1
+ import { AIError } from './errors.js';
2
+ export function extractJson(text) {
3
+ const trimmed = text.trim();
4
+ if (!trimmed)
5
+ return null;
6
+ const direct = tryParse(trimmed);
7
+ if (direct.ok)
8
+ return direct.value;
9
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(text);
10
+ if (fenced?.[1]) {
11
+ const parsed = tryParse(fenced[1].trim());
12
+ if (parsed.ok)
13
+ return parsed.value;
14
+ }
15
+ for (const [open, close] of [['{', '}'], ['[', ']']]) {
16
+ for (const span of balancedSpans(text, open, close)) {
17
+ const parsed = tryParse(span);
18
+ if (parsed.ok)
19
+ return parsed.value;
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+ /**
25
+ * Yields each top-level `open`/`close` balanced substring of `text`, tracking
26
+ * nesting depth and skipping over string-literal content (including escapes)
27
+ * so a stray brace inside a string or trailing prose can't prematurely close
28
+ * or extend a span. Used instead of first-`indexOf`/last-`lastIndexOf` so
29
+ * multiple JSON regions (or JSON followed by unrelated braces) don't get
30
+ * spliced into one bogus span.
31
+ */
32
+ function* balancedSpans(text, open, close) {
33
+ let depth = 0;
34
+ let spanStart = -1;
35
+ let inString = false;
36
+ let escaped = false;
37
+ for (let i = 0; i < text.length; i += 1) {
38
+ const ch = text[i];
39
+ if (inString) {
40
+ if (escaped)
41
+ escaped = false;
42
+ else if (ch === '\\')
43
+ escaped = true;
44
+ else if (ch === '"')
45
+ inString = false;
46
+ continue;
47
+ }
48
+ if (ch === '"') {
49
+ inString = true;
50
+ continue;
51
+ }
52
+ if (ch === open) {
53
+ if (depth === 0)
54
+ spanStart = i;
55
+ depth += 1;
56
+ continue;
57
+ }
58
+ if (ch === close && depth > 0) {
59
+ depth -= 1;
60
+ if (depth === 0 && spanStart >= 0) {
61
+ yield text.slice(spanStart, i + 1);
62
+ spanStart = -1;
63
+ }
64
+ }
65
+ }
66
+ }
67
+ export function extractJsonWithSchema(text, parse) {
68
+ const value = extractJson(text);
69
+ if (value === null)
70
+ throw new AIError('No JSON object or array found in model output', { kind: 'invalid_response' });
71
+ try {
72
+ return parse(value);
73
+ }
74
+ catch (error) {
75
+ const message = error instanceof Error ? error.message : 'JSON did not match expected schema';
76
+ throw new AIError(message, { kind: 'invalid_response', cause: error });
77
+ }
78
+ }
79
+ export function requireString(record, key) {
80
+ const value = record[key];
81
+ if (typeof value !== 'string')
82
+ throw new Error(`Expected ${key} to be a string`);
83
+ return value;
84
+ }
85
+ export function requireNumber(record, key) {
86
+ const value = record[key];
87
+ if (typeof value !== 'number' || !Number.isFinite(value))
88
+ throw new Error(`Expected ${key} to be a number`);
89
+ return value;
90
+ }
91
+ export function requireStringArray(record, key) {
92
+ const value = record[key];
93
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string')) {
94
+ throw new Error(`Expected ${key} to be a string array`);
95
+ }
96
+ return value;
97
+ }
98
+ export function requireOptionalString(record, key) {
99
+ const value = record[key];
100
+ if (value === undefined || value === null)
101
+ return undefined;
102
+ if (typeof value !== 'string')
103
+ throw new Error(`Expected ${key} to be a string when present`);
104
+ return value;
105
+ }
106
+ function tryParse(text) {
107
+ try {
108
+ return { ok: true, value: JSON.parse(text) };
109
+ }
110
+ catch {
111
+ return { ok: false };
112
+ }
113
+ }
114
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { KeyRef, KeySource } from './types.js';
2
+ export declare function parseKeyRef(value?: string | null): KeyRef;
3
+ export declare function envKeySource(env?: Record<string, string | undefined>): KeySource;
4
+ export declare function literalKeySource(): KeySource;
5
+ export declare function memoryKeySource(values: Record<string, string | null | undefined>): KeySource;
6
+ export declare function chainKeySources(...sources: KeySource[]): KeySource;
7
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGpD,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAWzD;AAED,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,SAAS,CAS7F;AAED,wBAAgB,gBAAgB,IAAI,SAAS,CAQ5C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,SAAS,CAU5F;AAED,wBAAgB,eAAe,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,CAgBlE"}
@@ -0,0 +1,75 @@
1
+ import { globalEnv } from './util.js';
2
+ export function parseKeyRef(value) {
3
+ const trimmed = value?.trim();
4
+ if (!trimmed)
5
+ return { kind: 'none' };
6
+ const braced = /^\$\{([A-Z0-9_]+)\}$/.exec(trimmed);
7
+ if (braced?.[1])
8
+ return { kind: 'env', name: braced[1] };
9
+ const dollar = /^\$([A-Z0-9_]+)$/.exec(trimmed);
10
+ if (dollar?.[1])
11
+ return { kind: 'env', name: dollar[1] };
12
+ if (/^[A-Z][A-Z0-9_]{2,}$/.test(trimmed))
13
+ return { kind: 'env', name: trimmed };
14
+ if (trimmed.startsWith('secret://'))
15
+ return { kind: 'brokered', ref: trimmed };
16
+ if (trimmed.startsWith('stored://'))
17
+ return { kind: 'stored', ref: trimmed.slice('stored://'.length) };
18
+ return { kind: 'literal', value: trimmed };
19
+ }
20
+ export function envKeySource(env = globalEnv()) {
21
+ return {
22
+ async resolve(ref) {
23
+ if (ref.kind === 'none')
24
+ return { ok: true, apiKey: null };
25
+ if (ref.kind !== 'env')
26
+ return { ok: false, reason: 'denied' };
27
+ const apiKey = env[ref.name]?.trim();
28
+ return apiKey ? { ok: true, apiKey } : { ok: false, reason: 'missing' };
29
+ },
30
+ };
31
+ }
32
+ export function literalKeySource() {
33
+ return {
34
+ async resolve(ref) {
35
+ if (ref.kind === 'none')
36
+ return { ok: true, apiKey: null };
37
+ if (ref.kind === 'literal')
38
+ return { ok: true, apiKey: ref.value };
39
+ return { ok: false, reason: 'denied' };
40
+ },
41
+ };
42
+ }
43
+ export function memoryKeySource(values) {
44
+ return {
45
+ async resolve(ref) {
46
+ if (ref.kind === 'none')
47
+ return { ok: true, apiKey: null };
48
+ if (ref.kind === 'literal')
49
+ return { ok: true, apiKey: ref.value };
50
+ const key = ref.kind === 'env' ? ref.name : ref.ref;
51
+ const value = values[key]?.trim();
52
+ return value ? { ok: true, apiKey: value } : { ok: false, reason: 'missing' };
53
+ },
54
+ };
55
+ }
56
+ export function chainKeySources(...sources) {
57
+ return {
58
+ async resolve(ref) {
59
+ let missing = false;
60
+ for (const source of sources) {
61
+ const result = await source.resolve(ref);
62
+ if (result.ok)
63
+ return result;
64
+ if (result.reason === 'locked')
65
+ return result;
66
+ if (result.reason === 'missing') {
67
+ missing = true;
68
+ continue;
69
+ }
70
+ }
71
+ return missing ? { ok: false, reason: 'missing' } : { ok: false, reason: 'denied' };
72
+ },
73
+ };
74
+ }
75
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { GovernancePolicy } from './types.js';
2
+ export declare function allowAllPolicy(): GovernancePolicy;
3
+ export declare function blocklistPolicy(patterns: RegExp[]): GovernancePolicy;
4
+ export declare function allowlistPolicy(prefixesByProvider: Record<string, string[]>): GovernancePolicy;
5
+ export declare function composePolicies(...policies: GovernancePolicy[]): GovernancePolicy;
6
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,cAAc,IAAI,gBAAgB,CAEjD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAQpE;AAED,wBAAgB,eAAe,CAAC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,gBAAgB,CAU9F;AAED,wBAAgB,eAAe,CAAC,GAAG,QAAQ,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,CAUjF"}
@@ -0,0 +1,37 @@
1
+ export function allowAllPolicy() {
2
+ return { checkModel: () => ({ allowed: true }) };
3
+ }
4
+ export function blocklistPolicy(patterns) {
5
+ return {
6
+ checkModel(provider, model) {
7
+ const target = `${provider}/${model}`;
8
+ const blocked = patterns.find((pattern) => pattern.test(target));
9
+ return blocked ? { allowed: false, reason: `Model blocked by policy: ${blocked}` } : { allowed: true };
10
+ },
11
+ };
12
+ }
13
+ export function allowlistPolicy(prefixesByProvider) {
14
+ return {
15
+ checkModel(provider, model) {
16
+ const prefixes = prefixesByProvider[provider];
17
+ if (!prefixes || prefixes.length === 0)
18
+ return { allowed: false, reason: `No models are allowed for provider ${provider}` };
19
+ return prefixes.some((prefix) => prefix === '*' || model.startsWith(prefix))
20
+ ? { allowed: true }
21
+ : { allowed: false, reason: `Model is not allowed for provider ${provider}` };
22
+ },
23
+ };
24
+ }
25
+ export function composePolicies(...policies) {
26
+ return {
27
+ checkModel(provider, model) {
28
+ for (const policy of policies) {
29
+ const result = policy.checkModel(provider, model);
30
+ if (!result.allowed)
31
+ return result;
32
+ }
33
+ return { allowed: true };
34
+ },
35
+ };
36
+ }
37
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc;IAC5B,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAkB;IAChD,OAAO;QACL,UAAU,CAAC,QAAQ,EAAE,KAAK;YACxB,MAAM,MAAM,GAAG,GAAG,QAAQ,IAAI,KAAK,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACjE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACzG,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,kBAA4C;IAC1E,OAAO;QACL,UAAU,CAAC,QAAQ,EAAE,KAAK;YACxB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sCAAsC,QAAQ,EAAE,EAAE,CAAC;YAC5H,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBAC1E,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;gBACnB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,qCAAqC,QAAQ,EAAE,EAAE,CAAC;QAClF,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAG,QAA4B;IAC7D,OAAO;QACL,UAAU,CAAC,QAAQ,EAAE,KAAK;YACxB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAClD,IAAI,CAAC,MAAM,CAAC,OAAO;oBAAE,OAAO,MAAM,CAAC;YACrC,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Inline reasoning stripper — keeps a reasoning model's chain of thought out of `delta` events
3
+ * and `ChatResult.text`, routing it to the `reasoning` stream event instead.
4
+ *
5
+ * Reasoning models (deepseek-r1, phi4-reasoning, qwq, …) emit their thinking either in the
6
+ * provider's dedicated field — which every engine already maps to `{ type: 'reasoning' }` — or
7
+ * INLINE in the answer as `<think>…</think>`-style blocks. Inline reasoning routinely quotes the
8
+ * system prompt and tool instructions back verbatim, so an app that streams `delta` straight to
9
+ * a screen, a database or a JSON parser leaks it. Every consumer would otherwise write this
10
+ * state machine, and most would get the split-tag and template-opened cases wrong; the handler
11
+ * runs it once, on every engine, unless `HandlerOptions.stripInlineReasoning` is `false`.
12
+ *
13
+ * Ported from AI Server Studio's `services/reasoningFilter.ts` (2026-09-05), which had to exist
14
+ * because the nugget did not do this.
15
+ *
16
+ * Two subtleties the tests pin:
17
+ * - Tags may be split across chunks, so a trailing partial `<thi` is held back until the next
18
+ * chunk decides whether it opens a tag. An unterminated block is reasoning to the end.
19
+ * - The **orphan close**: a closing tag with no opening one at the head of the stream, because
20
+ * the runtime's chat template emitted `<think>` itself. Handled once per stream, only before
21
+ * any visible text has gone out, and only when the closing tag starts its own line — a
22
+ * `</think>` quoted mid-sentence in a real answer is left alone.
23
+ */
24
+ export interface ReasoningStripResult {
25
+ /** Text safe to show from this chunk (may be empty). */
26
+ visible: string;
27
+ /** Reasoning text removed from this chunk (may be empty). */
28
+ reasoning: string;
29
+ }
30
+ export interface ReasoningStripper {
31
+ /** Feed the next raw delta; returns what may be shown and what was reasoning. */
32
+ push(chunk: string): ReasoningStripResult;
33
+ /** End of stream: flushes any held-back prefix that never became a tag. */
34
+ end(): ReasoningStripResult;
35
+ /** True while inside an unterminated reasoning block. */
36
+ readonly inReasoning: boolean;
37
+ }
38
+ export declare function createReasoningStripper(): ReasoningStripper;
39
+ /** Whole-string form: `{ visible, reasoning }` for already-buffered text. */
40
+ export declare function stripReasoningBlocksDetailed(text: string): ReasoningStripResult;
41
+ /** Whole-string form returning only the visible text. */
42
+ export declare function stripReasoningBlocks(text: string): string;
43
+ /** Cheap pre-check: does `text` carry any inline reasoning tag (open or close)? */
44
+ export declare function containsReasoningBlock(text: string): boolean;
45
+ //# sourceMappingURL=reasoning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reasoning.d.ts","sourceRoot":"","sources":["../src/reasoning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAWH,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAAC;IAC1C,2EAA2E;IAC3E,GAAG,IAAI,oBAAoB,CAAC;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAqBD,wBAAgB,uBAAuB,IAAI,iBAAiB,CAqF3D;AAED,6EAA6E;AAC7E,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAM/E;AAED,yDAAyD;AACzD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG5D"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Inline reasoning stripper — keeps a reasoning model's chain of thought out of `delta` events
3
+ * and `ChatResult.text`, routing it to the `reasoning` stream event instead.
4
+ *
5
+ * Reasoning models (deepseek-r1, phi4-reasoning, qwq, …) emit their thinking either in the
6
+ * provider's dedicated field — which every engine already maps to `{ type: 'reasoning' }` — or
7
+ * INLINE in the answer as `<think>…</think>`-style blocks. Inline reasoning routinely quotes the
8
+ * system prompt and tool instructions back verbatim, so an app that streams `delta` straight to
9
+ * a screen, a database or a JSON parser leaks it. Every consumer would otherwise write this
10
+ * state machine, and most would get the split-tag and template-opened cases wrong; the handler
11
+ * runs it once, on every engine, unless `HandlerOptions.stripInlineReasoning` is `false`.
12
+ *
13
+ * Ported from AI Server Studio's `services/reasoningFilter.ts` (2026-09-05), which had to exist
14
+ * because the nugget did not do this.
15
+ *
16
+ * Two subtleties the tests pin:
17
+ * - Tags may be split across chunks, so a trailing partial `<thi` is held back until the next
18
+ * chunk decides whether it opens a tag. An unterminated block is reasoning to the end.
19
+ * - The **orphan close**: a closing tag with no opening one at the head of the stream, because
20
+ * the runtime's chat template emitted `<think>` itself. Handled once per stream, only before
21
+ * any visible text has gone out, and only when the closing tag starts its own line — a
22
+ * `</think>` quoted mid-sentence in a real answer is left alone.
23
+ */
24
+ const TAG_PAIRS = [
25
+ { open: '<think>', close: '</think>' },
26
+ { open: '<thinking>', close: '</thinking>' },
27
+ { open: '<reasoning>', close: '</reasoning>' },
28
+ { open: '<|begin_of_thought|>', close: '<|end_of_thought|>' },
29
+ ];
30
+ const LONGEST_TAG = Math.max(...TAG_PAIRS.flatMap((p) => [p.open.length, p.close.length]));
31
+ function partialTagSuffixLength(text) {
32
+ const lower = text.toLowerCase();
33
+ const maxLen = Math.min(LONGEST_TAG - 1, lower.length);
34
+ for (let len = maxLen; len >= 1; len -= 1) {
35
+ const tail = lower.slice(lower.length - len);
36
+ if (tail[0] !== '<')
37
+ continue;
38
+ for (const pair of TAG_PAIRS) {
39
+ if (pair.open.startsWith(tail) || pair.close.startsWith(tail))
40
+ return len;
41
+ }
42
+ }
43
+ return 0;
44
+ }
45
+ function closesOwnLine(text, idx) {
46
+ let i = idx - 1;
47
+ while (i >= 0 && (text[i] === ' ' || text[i] === '\t' || text[i] === '\r'))
48
+ i -= 1;
49
+ return i < 0 || text[i] === '\n';
50
+ }
51
+ export function createReasoningStripper() {
52
+ let pending = '';
53
+ let inReasoning = false;
54
+ let closeTag = '';
55
+ let emittedVisible = false;
56
+ let orphanConsumed = false;
57
+ function process(input, flushAll) {
58
+ let text = pending + input;
59
+ pending = '';
60
+ let visible = '';
61
+ let reasoning = '';
62
+ while (text.length > 0) {
63
+ const lower = text.toLowerCase();
64
+ if (inReasoning) {
65
+ const idx = lower.indexOf(closeTag);
66
+ if (idx === -1) {
67
+ const hold = flushAll ? 0 : partialTagSuffixLength(text);
68
+ const consumed = text.length - hold;
69
+ reasoning += text.slice(0, consumed);
70
+ pending = text.slice(consumed);
71
+ text = '';
72
+ if (flushAll) {
73
+ reasoning += pending;
74
+ pending = '';
75
+ }
76
+ break;
77
+ }
78
+ reasoning += text.slice(0, idx);
79
+ text = text.slice(idx + closeTag.length);
80
+ inReasoning = false;
81
+ closeTag = '';
82
+ if (text.startsWith('\n'))
83
+ text = text.slice(1);
84
+ continue;
85
+ }
86
+ let openIdx = -1;
87
+ let pair = null;
88
+ for (const p of TAG_PAIRS) {
89
+ const i = lower.indexOf(p.open);
90
+ if (i !== -1 && (openIdx === -1 || i < openIdx)) {
91
+ openIdx = i;
92
+ pair = p;
93
+ }
94
+ }
95
+ let orphanCloseIdx = -1;
96
+ let orphanCloseLen = 0;
97
+ if (!emittedVisible && !orphanConsumed) {
98
+ for (const p of TAG_PAIRS) {
99
+ const i = lower.indexOf(p.close);
100
+ if (i !== -1 && (orphanCloseIdx === -1 || i < orphanCloseIdx) && closesOwnLine(text, i)) {
101
+ orphanCloseIdx = i;
102
+ orphanCloseLen = p.close.length;
103
+ }
104
+ }
105
+ }
106
+ if (orphanCloseIdx !== -1 && (openIdx === -1 || orphanCloseIdx < openIdx)) {
107
+ orphanConsumed = true;
108
+ reasoning += text.slice(0, orphanCloseIdx);
109
+ text = text.slice(orphanCloseIdx + orphanCloseLen).replace(/^\n+/, '');
110
+ continue;
111
+ }
112
+ if (openIdx === -1 || !pair) {
113
+ const hold = flushAll ? 0 : partialTagSuffixLength(text);
114
+ visible += text.slice(0, text.length - hold);
115
+ pending = text.slice(text.length - hold);
116
+ text = '';
117
+ break;
118
+ }
119
+ visible += text.slice(0, openIdx);
120
+ text = text.slice(openIdx + pair.open.length);
121
+ inReasoning = true;
122
+ closeTag = pair.close;
123
+ }
124
+ if (visible.trim().length > 0)
125
+ emittedVisible = true;
126
+ return { visible, reasoning };
127
+ }
128
+ return {
129
+ push: (chunk) => process(chunk, false),
130
+ end: () => process('', true),
131
+ get inReasoning() {
132
+ return inReasoning;
133
+ },
134
+ };
135
+ }
136
+ /** Whole-string form: `{ visible, reasoning }` for already-buffered text. */
137
+ export function stripReasoningBlocksDetailed(text) {
138
+ if (!text)
139
+ return { visible: '', reasoning: '' };
140
+ const stripper = createReasoningStripper();
141
+ const a = stripper.push(text);
142
+ const b = stripper.end();
143
+ return { visible: (a.visible + b.visible).trim(), reasoning: a.reasoning + b.reasoning };
144
+ }
145
+ /** Whole-string form returning only the visible text. */
146
+ export function stripReasoningBlocks(text) {
147
+ return stripReasoningBlocksDetailed(text).visible;
148
+ }
149
+ /** Cheap pre-check: does `text` carry any inline reasoning tag (open or close)? */
150
+ export function containsReasoningBlock(text) {
151
+ const lower = text.toLowerCase();
152
+ return TAG_PAIRS.some((p) => lower.includes(p.open) || lower.includes(p.close));
153
+ }
154
+ //# sourceMappingURL=reasoning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reasoning.js","sourceRoot":"","sources":["../src/reasoning.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Redactor } from './types.js';
2
+ /**
3
+ * Prefixed secret formats. Each pattern is anchored on a vendor prefix that is
4
+ * distinctive enough that a match is a secret, not a coincidence.
5
+ */
6
+ export declare const SECRET_PATTERNS: RegExp[];
7
+ /**
8
+ * Unprefixed/opaque secrets — Azure OpenAI `api-key` values, AWS *secret*
9
+ * access keys, generic bearer/session tokens — carry no distinctive prefix, so
10
+ * matching them on shape alone would redact commit SHAs, content hashes, and
11
+ * base64 payloads. These patterns instead anchor on the *label* that precedes
12
+ * the value (`api-key: …`, `"aws_secret_access_key": "…"`, `password=…`) and
13
+ * redact only the value, keeping the label readable in logs.
14
+ *
15
+ * Exact-match registration (`SessionRedactor.addSecret`, which the handler does
16
+ * for every resolved key) remains the only guaranteed catch for a bare,
17
+ * unlabeled, unprefixed secret.
18
+ */
19
+ export declare const LABELED_SECRET_PATTERNS: RegExp[];
20
+ export declare function createDefaultRedactor(extraSecrets?: Iterable<string>): Redactor;
21
+ export declare class SessionRedactor implements Redactor {
22
+ private secrets;
23
+ addSecret(value: string | null | undefined): void;
24
+ redact(text: string): string;
25
+ }
26
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,EAqBnC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,EAU3C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,YAAY,GAAE,QAAQ,CAAC,MAAM,CAAM,GAAG,QAAQ,CAanF;AAED,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,OAAO,CAAqB;IAEpC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAIjD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAG7B"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Prefixed secret formats. Each pattern is anchored on a vendor prefix that is
3
+ * distinctive enough that a match is a secret, not a coincidence.
4
+ */
5
+ export const SECRET_PATTERNS = [
6
+ /sk-[A-Za-z0-9_-]{20,}/g,
7
+ /sk-proj-[A-Za-z0-9_-]{20,}/g,
8
+ /sk-ant-[A-Za-z0-9_-]{20,}/g,
9
+ /AIza[0-9A-Za-z_-]{20,}/g,
10
+ /gsk_[0-9A-Za-z_-]{20,}/g,
11
+ /xai-[0-9A-Za-z_-]{20,}/g,
12
+ /hf_[0-9A-Za-z]{20,}/g,
13
+ /nvapi-[0-9A-Za-z_-]{20,}/g,
14
+ /ghp_[0-9A-Za-z_]{20,}/g,
15
+ /github_pat_[0-9A-Za-z_]{20,}/g,
16
+ /glpat-[0-9A-Za-z_-]{20,}/g,
17
+ /\bBearer\s+[A-Za-z0-9._~+/=-]{20,}/gi,
18
+ /xox[baprs]-[0-9A-Za-z-]{10,}/g,
19
+ /AKIA[0-9A-Z]{16}/g,
20
+ /ASIA[0-9A-Z]{16}/g,
21
+ /SG\.[0-9A-Za-z_-]{10,}\.[0-9A-Za-z_-]{10,}/g,
22
+ /rk_live_[0-9A-Za-z]{20,}/g,
23
+ /pk_live_[0-9A-Za-z]{20,}/g,
24
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
25
+ /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
26
+ ];
27
+ /**
28
+ * Unprefixed/opaque secrets — Azure OpenAI `api-key` values, AWS *secret*
29
+ * access keys, generic bearer/session tokens — carry no distinctive prefix, so
30
+ * matching them on shape alone would redact commit SHAs, content hashes, and
31
+ * base64 payloads. These patterns instead anchor on the *label* that precedes
32
+ * the value (`api-key: …`, `"aws_secret_access_key": "…"`, `password=…`) and
33
+ * redact only the value, keeping the label readable in logs.
34
+ *
35
+ * Exact-match registration (`SessionRedactor.addSecret`, which the handler does
36
+ * for every resolved key) remains the only guaranteed catch for a bare,
37
+ * unlabeled, unprefixed secret.
38
+ */
39
+ export const LABELED_SECRET_PATTERNS = [
40
+ new RegExp(
41
+ // Lookbehind rather than `\b` so an underscore-joined prefix still matches
42
+ // the label (`aws_secret_access_key`, `azure_api_key`).
43
+ String.raw `(?<![A-Za-z0-9])(api[_-]?key|apikey|secret[_-]?access[_-]?key|access[_-]?token|auth[_-]?token|session[_-]?token|client[_-]?secret|refresh[_-]?token|private[_-]?key|password|passwd)` +
44
+ // Optional closing quote handles JSON keys (`"api_key": "…"`).
45
+ String.raw `(["']?\s*[:=]\s*|\s+)` +
46
+ String.raw `(["']?)([A-Za-z0-9/+_.~-]{16,}={0,2})\3`, 'gi'),
47
+ ];
48
+ export function createDefaultRedactor(extraSecrets = []) {
49
+ const secrets = new Set([...extraSecrets].filter((value) => value.length >= 6));
50
+ return {
51
+ redact(text) {
52
+ let output = text;
53
+ for (const pattern of SECRET_PATTERNS)
54
+ output = output.replace(pattern, '[REDACTED]');
55
+ for (const pattern of LABELED_SECRET_PATTERNS) {
56
+ output = output.replace(pattern, (_match, label, separator, quote) => `${label}${separator}${quote}[REDACTED]${quote}`);
57
+ }
58
+ for (const secret of secrets)
59
+ output = output.split(secret).join('[REDACTED]');
60
+ return output;
61
+ },
62
+ };
63
+ }
64
+ export class SessionRedactor {
65
+ secrets = new Set();
66
+ addSecret(value) {
67
+ if (value && value.length >= 6)
68
+ this.secrets.add(value);
69
+ }
70
+ redact(text) {
71
+ return createDefaultRedactor(this.secrets).redact(text);
72
+ }
73
+ }
74
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAa;IACvC,wBAAwB;IACxB,6BAA6B;IAC7B,4BAA4B;IAC5B,yBAAyB;IACzB,yBAAyB;IACzB,yBAAyB;IACzB,sBAAsB;IACtB,2BAA2B;IAC3B,wBAAwB;IACxB,+BAA+B;IAC/B,2BAA2B;IAC3B,sCAAsC;IACtC,+BAA+B;IAC/B,mBAAmB;IACnB,mBAAmB;IACnB,6CAA6C;IAC7C,2BAA2B;IAC3B,2BAA2B;IAC3B,6EAA6E;IAC7E,oDAAoD;CACrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAa;IAC/C,IAAI,MAAM;IACR,2EAA2E;IAC3E,wDAAwD;IACxD,MAAM,CAAC,GAAG,CAAA,sLAAsL;QAC9L,+DAA+D;QAC/D,MAAM,CAAC,GAAG,CAAA,uBAAuB;QACjC,MAAM,CAAC,GAAG,CAAA,yCAAyC,EACrD,IAAI,CACL;CACF,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,eAAiC,EAAE;IACvE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;IAChF,OAAO;QACL,MAAM,CAAC,IAAY;YACjB,IAAI,MAAM,GAAG,IAAI,CAAC;YAClB,KAAK,MAAM,OAAO,IAAI,eAAe;gBAAE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACtF,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;gBAC9C,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,KAAa,EAAE,SAAiB,EAAE,KAAa,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,aAAa,KAAK,EAAE,CAAC,CAAC;YAClJ,CAAC;YACD,KAAK,MAAM,MAAM,IAAI,OAAO;gBAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC/E,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,eAAe;IAClB,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,SAAS,CAAC,KAAgC;QACxC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,OAAO,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ import type { Usage } from './types.js';
2
+ export declare function estimateTokens(text: string): number;
3
+ export declare function estimatedUsage(inputText: string, outputText: string): Usage;
4
+ export declare function mergeUsage(a: Usage, b: Usage): Usage;
5
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,CAM3E;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAMpD"}
@@ -0,0 +1,18 @@
1
+ export function estimateTokens(text) {
2
+ return Math.ceil(text.length / 4);
3
+ }
4
+ export function estimatedUsage(inputText, outputText) {
5
+ return {
6
+ inputTokens: estimateTokens(inputText),
7
+ outputTokens: estimateTokens(outputText),
8
+ estimated: true,
9
+ };
10
+ }
11
+ export function mergeUsage(a, b) {
12
+ return {
13
+ inputTokens: (a.inputTokens ?? 0) + (b.inputTokens ?? 0),
14
+ outputTokens: (a.outputTokens ?? 0) + (b.outputTokens ?? 0),
15
+ estimated: a.estimated || b.estimated,
16
+ };
17
+ }
18
+ //# sourceMappingURL=tokens.js.map