@namzu/sdk 5.1.0 → 6.0.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 (188) hide show
  1. package/CHANGELOG.md +465 -0
  2. package/dist/agents/__tests__/run-agent-forwarding.test.d.ts +2 -0
  3. package/dist/agents/__tests__/run-agent-forwarding.test.d.ts.map +1 -0
  4. package/dist/agents/__tests__/run-agent-forwarding.test.js +76 -0
  5. package/dist/agents/__tests__/run-agent-forwarding.test.js.map +1 -0
  6. package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts +2 -0
  7. package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts.map +1 -0
  8. package/dist/agents/__tests__/run-completed-stop-reason.test.js +50 -0
  9. package/dist/agents/__tests__/run-completed-stop-reason.test.js.map +1 -0
  10. package/dist/agents/index.d.ts +1 -0
  11. package/dist/agents/index.d.ts.map +1 -1
  12. package/dist/agents/index.js +4 -0
  13. package/dist/agents/index.js.map +1 -1
  14. package/dist/agents/runAgent.d.ts +34 -0
  15. package/dist/agents/runAgent.d.ts.map +1 -1
  16. package/dist/agents/runAgent.js +5 -3
  17. package/dist/agents/runAgent.js.map +1 -1
  18. package/dist/config/runtime.d.ts +30 -30
  19. package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts +2 -0
  20. package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts.map +1 -0
  21. package/dist/constants/tools/__tests__/dangerous-patterns.test.js +54 -0
  22. package/dist/constants/tools/__tests__/dangerous-patterns.test.js.map +1 -0
  23. package/dist/constants/tools/index.d.ts.map +1 -1
  24. package/dist/constants/tools/index.js +28 -1
  25. package/dist/constants/tools/index.js.map +1 -1
  26. package/dist/contracts/a2a.d.ts +44 -44
  27. package/dist/directory/__tests__/derive.test.d.ts +2 -0
  28. package/dist/directory/__tests__/derive.test.d.ts.map +1 -0
  29. package/dist/directory/__tests__/derive.test.js +111 -0
  30. package/dist/directory/__tests__/derive.test.js.map +1 -0
  31. package/dist/directory/__tests__/load-diagnostics.test.d.ts +2 -0
  32. package/dist/directory/__tests__/load-diagnostics.test.d.ts.map +1 -0
  33. package/dist/directory/__tests__/load-diagnostics.test.js +106 -0
  34. package/dist/directory/__tests__/load-diagnostics.test.js.map +1 -0
  35. package/dist/directory/__tests__/load-directory.test.d.ts +2 -0
  36. package/dist/directory/__tests__/load-directory.test.d.ts.map +1 -0
  37. package/dist/directory/__tests__/load-directory.test.js +196 -0
  38. package/dist/directory/__tests__/load-directory.test.js.map +1 -0
  39. package/dist/directory/__tests__/subagents.test.d.ts +2 -0
  40. package/dist/directory/__tests__/subagents.test.d.ts.map +1 -0
  41. package/dist/directory/__tests__/subagents.test.js +117 -0
  42. package/dist/directory/__tests__/subagents.test.js.map +1 -0
  43. package/dist/directory/__tests__/supervisor-budget.test.d.ts +2 -0
  44. package/dist/directory/__tests__/supervisor-budget.test.d.ts.map +1 -0
  45. package/dist/directory/__tests__/supervisor-budget.test.js +97 -0
  46. package/dist/directory/__tests__/supervisor-budget.test.js.map +1 -0
  47. package/dist/directory/derive-supervisor.d.ts +58 -0
  48. package/dist/directory/derive-supervisor.d.ts.map +1 -0
  49. package/dist/directory/derive-supervisor.js +88 -0
  50. package/dist/directory/derive-supervisor.js.map +1 -0
  51. package/dist/directory/derive.d.ts +12 -0
  52. package/dist/directory/derive.d.ts.map +1 -0
  53. package/dist/directory/derive.js +58 -0
  54. package/dist/directory/derive.js.map +1 -0
  55. package/dist/directory/index.d.ts +7 -0
  56. package/dist/directory/index.d.ts.map +1 -0
  57. package/dist/directory/index.js +5 -0
  58. package/dist/directory/index.js.map +1 -0
  59. package/dist/directory/load.d.ts +14 -0
  60. package/dist/directory/load.d.ts.map +1 -0
  61. package/dist/directory/load.js +488 -0
  62. package/dist/directory/load.js.map +1 -0
  63. package/dist/directory/scan.d.ts +36 -0
  64. package/dist/directory/scan.d.ts.map +1 -0
  65. package/dist/directory/scan.js +136 -0
  66. package/dist/directory/scan.js.map +1 -0
  67. package/dist/directory/types.d.ts +215 -0
  68. package/dist/directory/types.d.ts.map +1 -0
  69. package/dist/directory/types.js +8 -0
  70. package/dist/directory/types.js.map +1 -0
  71. package/dist/plugin/__tests__/path-containment.test.d.ts +2 -0
  72. package/dist/plugin/__tests__/path-containment.test.d.ts.map +1 -0
  73. package/dist/plugin/__tests__/path-containment.test.js +91 -0
  74. package/dist/plugin/__tests__/path-containment.test.js.map +1 -0
  75. package/dist/plugin/lifecycle.d.ts.map +1 -1
  76. package/dist/plugin/lifecycle.js +3 -3
  77. package/dist/plugin/lifecycle.js.map +1 -1
  78. package/dist/plugin/loader.d.ts.map +1 -1
  79. package/dist/plugin/loader.js +12 -2
  80. package/dist/plugin/loader.js.map +1 -1
  81. package/dist/provider/__tests__/model-version.test.d.ts +2 -0
  82. package/dist/provider/__tests__/model-version.test.d.ts.map +1 -0
  83. package/dist/provider/__tests__/model-version.test.js +80 -0
  84. package/dist/provider/__tests__/model-version.test.js.map +1 -0
  85. package/dist/provider/__tests__/strict-schema.test.d.ts +2 -0
  86. package/dist/provider/__tests__/strict-schema.test.d.ts.map +1 -0
  87. package/dist/provider/__tests__/strict-schema.test.js +157 -0
  88. package/dist/provider/__tests__/strict-schema.test.js.map +1 -0
  89. package/dist/provider/__tests__/vendor-detail.test.d.ts +2 -0
  90. package/dist/provider/__tests__/vendor-detail.test.d.ts.map +1 -0
  91. package/dist/provider/__tests__/vendor-detail.test.js +89 -0
  92. package/dist/provider/__tests__/vendor-detail.test.js.map +1 -0
  93. package/dist/provider/errors.d.ts +38 -5
  94. package/dist/provider/errors.d.ts.map +1 -1
  95. package/dist/provider/errors.js +107 -5
  96. package/dist/provider/errors.js.map +1 -1
  97. package/dist/provider/model-version.d.ts +60 -0
  98. package/dist/provider/model-version.d.ts.map +1 -0
  99. package/dist/provider/model-version.js +64 -0
  100. package/dist/provider/model-version.js.map +1 -0
  101. package/dist/provider/strict-schema.d.ts +49 -0
  102. package/dist/provider/strict-schema.d.ts.map +1 -0
  103. package/dist/provider/strict-schema.js +168 -0
  104. package/dist/provider/strict-schema.js.map +1 -0
  105. package/dist/public-runtime.d.ts +9 -1
  106. package/dist/public-runtime.d.ts.map +1 -1
  107. package/dist/public-runtime.js +27 -1
  108. package/dist/public-runtime.js.map +1 -1
  109. package/dist/public-types.d.ts +2 -0
  110. package/dist/public-types.d.ts.map +1 -1
  111. package/dist/registry/tool/__tests__/dialect.test.d.ts +2 -0
  112. package/dist/registry/tool/__tests__/dialect.test.d.ts.map +1 -0
  113. package/dist/registry/tool/__tests__/dialect.test.js +143 -0
  114. package/dist/registry/tool/__tests__/dialect.test.js.map +1 -0
  115. package/dist/registry/tool/__tests__/strict-registration.test.d.ts +2 -0
  116. package/dist/registry/tool/__tests__/strict-registration.test.d.ts.map +1 -0
  117. package/dist/registry/tool/__tests__/strict-registration.test.js +82 -0
  118. package/dist/registry/tool/__tests__/strict-registration.test.js.map +1 -0
  119. package/dist/registry/tool/dialect.d.ts +50 -0
  120. package/dist/registry/tool/dialect.d.ts.map +1 -0
  121. package/dist/registry/tool/dialect.js +131 -0
  122. package/dist/registry/tool/dialect.js.map +1 -0
  123. package/dist/registry/tool/execute.d.ts.map +1 -1
  124. package/dist/registry/tool/execute.js +16 -0
  125. package/dist/registry/tool/execute.js.map +1 -1
  126. package/dist/registry/toolset/catalog.d.ts.map +1 -1
  127. package/dist/registry/toolset/catalog.js +10 -5
  128. package/dist/registry/toolset/catalog.js.map +1 -1
  129. package/dist/runtime/query/__tests__/stream-recovery.test.js +6 -0
  130. package/dist/runtime/query/__tests__/stream-recovery.test.js.map +1 -1
  131. package/dist/runtime/query/result.d.ts.map +1 -1
  132. package/dist/runtime/query/result.js +11 -0
  133. package/dist/runtime/query/result.js.map +1 -1
  134. package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +7 -1
  135. package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -1
  136. package/dist/tools/builtins/__tests__/edit.test.js +1 -1
  137. package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
  138. package/dist/tools/builtins/edit.d.ts.map +1 -1
  139. package/dist/tools/builtins/edit.js +20 -2
  140. package/dist/tools/builtins/edit.js.map +1 -1
  141. package/dist/types/plugin/index.d.ts +4 -4
  142. package/dist/types/provider/error.d.ts +20 -4
  143. package/dist/types/provider/error.d.ts.map +1 -1
  144. package/dist/types/run/events.d.ts +17 -2
  145. package/dist/types/run/events.d.ts.map +1 -1
  146. package/dist/types/run/events.js.map +1 -1
  147. package/dist/types/verification/index.d.ts +6 -6
  148. package/package.json +1 -1
  149. package/src/agents/__tests__/run-agent-forwarding.test.ts +85 -0
  150. package/src/agents/__tests__/run-completed-stop-reason.test.ts +59 -0
  151. package/src/agents/index.ts +8 -0
  152. package/src/agents/runAgent.ts +30 -4
  153. package/src/constants/tools/__tests__/dangerous-patterns.test.ts +62 -0
  154. package/src/constants/tools/index.ts +28 -1
  155. package/src/directory/__tests__/derive.test.ts +135 -0
  156. package/src/directory/__tests__/load-diagnostics.test.ts +126 -0
  157. package/src/directory/__tests__/load-directory.test.ts +243 -0
  158. package/src/directory/__tests__/subagents.test.ts +155 -0
  159. package/src/directory/__tests__/supervisor-budget.test.ts +117 -0
  160. package/src/directory/derive-supervisor.ts +149 -0
  161. package/src/directory/derive.ts +70 -0
  162. package/src/directory/index.ts +27 -0
  163. package/src/directory/load.ts +556 -0
  164. package/src/directory/scan.ts +163 -0
  165. package/src/directory/types.ts +254 -0
  166. package/src/plugin/__tests__/path-containment.test.ts +107 -0
  167. package/src/plugin/lifecycle.ts +3 -3
  168. package/src/plugin/loader.ts +12 -2
  169. package/src/provider/__tests__/model-version.test.ts +93 -0
  170. package/src/provider/__tests__/strict-schema.test.ts +189 -0
  171. package/src/provider/__tests__/vendor-detail.test.ts +107 -0
  172. package/src/provider/errors.ts +106 -5
  173. package/src/provider/model-version.ts +98 -0
  174. package/src/provider/strict-schema.ts +182 -0
  175. package/src/public-runtime.ts +38 -0
  176. package/src/public-types.ts +8 -0
  177. package/src/registry/tool/__tests__/dialect.test.ts +197 -0
  178. package/src/registry/tool/__tests__/strict-registration.test.ts +115 -0
  179. package/src/registry/tool/dialect.ts +136 -0
  180. package/src/registry/tool/execute.ts +16 -0
  181. package/src/registry/toolset/catalog.ts +10 -5
  182. package/src/runtime/query/__tests__/stream-recovery.test.ts +6 -0
  183. package/src/runtime/query/result.ts +11 -0
  184. package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +8 -2
  185. package/src/tools/builtins/__tests__/edit.test.ts +1 -1
  186. package/src/tools/builtins/edit.ts +20 -2
  187. package/src/types/provider/error.ts +20 -4
  188. package/src/types/run/events.ts +15 -2
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/plugin/loader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,0BAA0B,CAAA;AAKpF;;;GAGG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwB1E;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAOnF;AAYD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAQ/D;AAED,6GAA6G;AAC7G,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACtC,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;IAChC,yDAAyD;IACzD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,qBAAqB,CAC1C,gBAAgB,CAAC,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA6BhD"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/plugin/loader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,0BAA0B,CAAA;AAKpF;;;GAGG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkC1E;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAOnF;AAYD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAQ/D;AAED,6GAA6G;AAC7G,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACtC,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;IAChC,yDAAyD;IACzD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,qBAAqB,CAC1C,gBAAgB,CAAC,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA6BhD"}
@@ -1,4 +1,4 @@
1
- import { readFile, readdir, stat } from 'node:fs/promises';
1
+ import { lstat, readFile, readdir, stat } from 'node:fs/promises';
2
2
  import { homedir } from 'node:os';
3
3
  import { join } from 'node:path';
4
4
  import { PLUGIN_MANIFEST_FILENAME, PROJECT_PLUGIN_DIR, USER_PLUGIN_DIR, } from '../constants/plugin/index.js';
@@ -17,7 +17,17 @@ export async function discoverPlugins(parentDir) {
17
17
  if (entry.startsWith('.') || entry.startsWith('_'))
18
18
  continue;
19
19
  const fullPath = join(parentDir, entry);
20
- const s = await stat(fullPath);
20
+ // `lstat`, not `stat`: `stat` follows the link and reports on its
21
+ // TARGET, so a symlinked entry pointing anywhere on disk was
22
+ // admitted as a plugin directory and its manifest read from there.
23
+ // A plugins directory holds third-party code by definition, which
24
+ // makes following a link out of it the worse half of CWE-59 — the
25
+ // directory listed is not the directory loaded.
26
+ const s = await lstat(fullPath);
27
+ if (s.isSymbolicLink()) {
28
+ logger.warn('Refusing a symlinked plugin directory', { path: fullPath });
29
+ continue;
30
+ }
21
31
  if (!s.isDirectory())
22
32
  continue;
23
33
  const manifestPath = join(fullPath, PLUGIN_MANIFEST_FILENAME);
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/plugin/loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/plugin/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=model-version.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-version.test.d.ts","sourceRoot":"","sources":["../../../src/provider/__tests__/model-version.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,80 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { modelVersionAtLeast, parseVersionedModelId } from '../model-version.js';
3
+ /**
4
+ * The defect this module exists to end: the minor-version group was `\d+`, so
5
+ * it swallowed the 8-digit release date. An id naming no minor therefore
6
+ * parsed as `major.<the date>` and compared as enormously NEWER than one that
7
+ * does, inverting every capability gate keyed on `minor >= n` — a model was
8
+ * told it supported features it does not.
9
+ *
10
+ * Three drivers had each written the same matcher, and all three had it. The
11
+ * vocabulary below is deliberately invented: the shape is what lives here, and
12
+ * a test that needed real product names would be testing the wrong layer.
13
+ */
14
+ const GRAMMAR = {
15
+ product: 'widget',
16
+ families: ['small', 'large'],
17
+ routingPrefix: 'vendor/',
18
+ };
19
+ describe('a date suffix is not a minor version', () => {
20
+ it.each([
21
+ ['widget-small-4-20250514', 'small', 4, 0],
22
+ ['widget-large-4-20250514', 'large', 4, 0],
23
+ ['widget-small-3-20240307', 'small', 3, 0],
24
+ ])('%s parses as %s %d.%d', (id, family, major, minor) => {
25
+ expect(parseVersionedModelId(id, GRAMMAR)).toEqual({ family, major, minor });
26
+ });
27
+ it('still reads a real minor that is followed by a date', () => {
28
+ expect(parseVersionedModelId('widget-large-4-1-20250805', GRAMMAR)).toEqual({
29
+ family: 'large',
30
+ major: 4,
31
+ minor: 1,
32
+ });
33
+ expect(parseVersionedModelId('widget-small-4-5-20250929', GRAMMAR)?.minor).toBe(5);
34
+ });
35
+ it('treats a missing minor as .0 rather than as absent', () => {
36
+ expect(parseVersionedModelId('widget-large-5', GRAMMAR)).toEqual({
37
+ family: 'large',
38
+ major: 5,
39
+ minor: 0,
40
+ });
41
+ });
42
+ it('tolerates the routing prefix, the other separators, and case', () => {
43
+ expect(parseVersionedModelId('vendor/widget-large-4-5', GRAMMAR)?.minor).toBe(5);
44
+ expect(parseVersionedModelId('widget-large-4.5', GRAMMAR)?.minor).toBe(5);
45
+ expect(parseVersionedModelId('WIDGET-LARGE-4-5', GRAMMAR)?.major).toBe(4);
46
+ });
47
+ it('returns undefined for what the grammar does not describe', () => {
48
+ for (const id of ['other-large-4', 'widget', 'widget-large', 'widget-medium-4', '']) {
49
+ expect(parseVersionedModelId(id, GRAMMAR)).toBeUndefined();
50
+ }
51
+ });
52
+ it('escapes regex metacharacters in the grammar', () => {
53
+ // A product or prefix containing `.` or `+` must match literally, not
54
+ // as a wildcard. `.map(escape)` — the global, deprecated one — would
55
+ // percent-encode instead, and pass every other test in this file
56
+ // because no ordinary name contains a character it changes.
57
+ const odd = { product: 'a.b', families: ['c+d'] };
58
+ expect(parseVersionedModelId('a.b-c+d-4', odd)?.major).toBe(4);
59
+ expect(parseVersionedModelId('axb-cxd-4', odd)).toBeUndefined();
60
+ });
61
+ });
62
+ describe('modelVersionAtLeast', () => {
63
+ it('does not let a dated id clear a gate it is below', () => {
64
+ // The whole point. With the old `\d+` minor this was `true`, because
65
+ // 4.20250514 >= 4.5.
66
+ expect(modelVersionAtLeast('widget-small-4-20250514', GRAMMAR, 4, 5)).toBe(false);
67
+ expect(modelVersionAtLeast('widget-large-4-20250514', GRAMMAR, 4, 7)).toBe(false);
68
+ });
69
+ it('admits versions that genuinely clear it', () => {
70
+ expect(modelVersionAtLeast('widget-small-4-5-20250929', GRAMMAR, 4, 5)).toBe(true);
71
+ expect(modelVersionAtLeast('widget-large-5', GRAMMAR, 4, 7)).toBe(true);
72
+ expect(modelVersionAtLeast('widget-large-4-1', GRAMMAR, 4, 5)).toBe(false);
73
+ });
74
+ it('refuses a name it cannot parse rather than opening the gate', () => {
75
+ // Fail-safe: a capability gate must not open for an id it does not
76
+ // understand.
77
+ expect(modelVersionAtLeast('something-else', GRAMMAR, 4, 5)).toBe(false);
78
+ });
79
+ });
80
+ //# sourceMappingURL=model-version.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-version.test.js","sourceRoot":"","sources":["../../../src/provider/__tests__/model-version.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAGhF;;;;;;;;;;GAUG;AAEH,MAAM,OAAO,GAAmB;IAC/B,OAAO,EAAE,QAAQ;IACjB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,SAAS;CACxB,CAAA;AAED,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACrD,EAAE,CAAC,IAAI,CAAC;QACP,CAAC,yBAAyB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC,yBAAyB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC,yBAAyB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;KAC1C,CAAC,CAAC,uBAAuB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACxD,MAAM,CAAC,qBAAqB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;IAC7E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,qBAAqB,CAAC,2BAA2B,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3E,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,CAAC;SACR,CAAC,CAAA;QACF,MAAM,CAAC,qBAAqB,CAAC,2BAA2B,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YAChE,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,CAAC;SACR,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,qBAAqB,CAAC,yBAAyB,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAChF,MAAM,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QACnE,KAAK,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,EAAE,CAAC,EAAE,CAAC;YACrF,MAAM,CAAC,qBAAqB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;QAC3D,CAAC;IACF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACtD,sEAAsE;QACtE,qEAAqE;QACrE,iEAAiE;QACjE,4DAA4D;QAC5D,MAAM,GAAG,GAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,CAAA;QAEjE,MAAM,CAAC,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC9D,MAAM,CAAC,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IAChE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC3D,qEAAqE;QACrE,qBAAqB;QACrB,MAAM,CAAC,mBAAmB,CAAC,yBAAyB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjF,MAAM,CAAC,mBAAmB,CAAC,yBAAyB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,mBAAmB,CAAC,2BAA2B,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClF,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACvE,MAAM,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACtE,mEAAmE;QACnE,cAAc;QACd,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=strict-schema.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict-schema.test.d.ts","sourceRoot":"","sources":["../../../src/provider/__tests__/strict-schema.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,157 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getBuiltinTools } from '../../tools/builtins/index.js';
3
+ import { assertStrictSchema, findStrictSchemaViolations } from '../strict-schema.js';
4
+ /**
5
+ * Strict tool input validates against a SUBSET of JSON Schema, and a keyword
6
+ * outside that subset is not degraded — the vendor rejects the entire request,
7
+ * so one unexpressible field in one tool takes down every tool in the call and
8
+ * the turn dies before producing a token.
9
+ *
10
+ * That shipped. The edit tool declared its integer-or-`"end"` field with
11
+ * `oneOf`, which is outside the subset while the equivalent `anyOf` is inside
12
+ * it, and the driver marked the tool strict without asking whether the schema
13
+ * it was vouching for could be said in that dialect.
14
+ *
15
+ * Measured against the live API:
16
+ *
17
+ * | body | result |
18
+ * |------------------------|----------|
19
+ * | strict: true + oneOf | 400 |
20
+ * | strict: false + oneOf | accepted |
21
+ * | strict: true + anyOf | accepted |
22
+ *
23
+ * The middle row is why nothing caught it. Neither half is wrong alone — the
24
+ * schema is valid JSON Schema, and turning strict on is correct policy — so no
25
+ * test of either one fails. Only the pairing does, and the pairing had no
26
+ * owner. The sweep below is that owner.
27
+ */
28
+ describe('every tool that asks for strict validation can be expressed strictly', () => {
29
+ // The regression test that matters. Checking only the tool that broke
30
+ // would leave the next one to be found in production, which is how this
31
+ // one was found.
32
+ it.each(getBuiltinTools()
33
+ .filter((t) => t.enforceModelInput)
34
+ .map((t) => [t.name, t]))('%s', (name, tool) => {
35
+ const violations = findStrictSchemaViolations(tool.modelInputSchema);
36
+ expect(violations, violations.map((v) => `${name}.${v.path}: ${v.remedy}`).join('\n')).toEqual([]);
37
+ });
38
+ it('found at least one tool to check', () => {
39
+ // Guards the sweep itself: a filter that matches nothing passes
40
+ // vacuously, and a rename of `enforceModelInput` would silently turn
41
+ // this whole file into a no-op.
42
+ expect(getBuiltinTools().filter((t) => t.enforceModelInput).length).toBeGreaterThan(0);
43
+ });
44
+ });
45
+ describe('the violation report names the exact path', () => {
46
+ it('points at the keyword inside a nested property', () => {
47
+ const schema = {
48
+ type: 'object',
49
+ properties: {
50
+ insertLine: { oneOf: [{ type: 'integer' }, { const: 'end' }] },
51
+ },
52
+ };
53
+ expect(findStrictSchemaViolations(schema)).toEqual([
54
+ {
55
+ path: 'properties.insertLine.oneOf',
56
+ keyword: 'oneOf',
57
+ remedy: 'use `anyOf` — for disjoint branches the two are equivalent',
58
+ },
59
+ ]);
60
+ });
61
+ it('accepts the anyOf spelling of the same union', () => {
62
+ const schema = {
63
+ type: 'object',
64
+ properties: {
65
+ insertLine: { anyOf: [{ type: 'integer' }, { const: 'end' }] },
66
+ },
67
+ };
68
+ expect(findStrictSchemaViolations(schema)).toEqual([]);
69
+ });
70
+ it('reports the bounds the wire refuses, and only those', () => {
71
+ // Measured against the live API rather than read off a page. The first
72
+ // version of this list was derived from documentation and was wrong in
73
+ // both directions: it refused `maxLength`, which the wire accepts, and
74
+ // permitted `prefixItems`, which it rejects.
75
+ const schema = {
76
+ type: 'object',
77
+ properties: {
78
+ n: { type: 'integer', minimum: 0 },
79
+ s: { type: 'string', maxLength: 10 },
80
+ a: { type: 'array', items: { type: 'string' }, maxItems: 3, minItems: 1 },
81
+ },
82
+ };
83
+ expect(findStrictSchemaViolations(schema)
84
+ .map((v) => v.keyword)
85
+ .sort()).toEqual(['maxItems', 'minimum']);
86
+ });
87
+ it('leaves string length alone, because strict accepts it', () => {
88
+ // The false positive that would have refused tools which work.
89
+ expect(findStrictSchemaViolations({ s: { type: 'string', minLength: 1, maxLength: 9 } })).toEqual([]);
90
+ });
91
+ it('catches a tuple in either spelling, because strict admits neither', () => {
92
+ // The interaction worth pinning, and the one a `prefixItems` entry alone
93
+ // got wrong. This check runs at REGISTRATION, on the schema as rendered
94
+ // — draft-07, where a tuple is `items: [a, b]` — while the wire sees the
95
+ // `prefixItems` the driver converts it to. So denying only `prefixItems`
96
+ // was a guard that could not fire on the path that produces tuples.
97
+ //
98
+ // Measured, strict rejects both, which is why a tool that is both strict
99
+ // and tuple-shaped cannot be expressed at all. Converting it only
100
+ // changes which error comes back.
101
+ for (const items of [
102
+ { prefixItems: [{ type: 'integer' }, { type: 'integer' }] },
103
+ { items: [{ type: 'integer' }, { type: 'integer' }] },
104
+ ]) {
105
+ const violations = findStrictSchemaViolations({
106
+ properties: { range: { type: 'array', ...items } },
107
+ });
108
+ expect(violations, JSON.stringify(items)).toHaveLength(1);
109
+ expect(violations[0]?.remedy).toContain('tuple cannot be expressed');
110
+ }
111
+ });
112
+ it('leaves an ordinary array alone, where `items` is one schema', () => {
113
+ // The false positive the tuple rule must not become: `items` is the
114
+ // normal spelling for a homogeneous array and strict accepts it. Only
115
+ // the array-of-schemas form is a tuple.
116
+ expect(findStrictSchemaViolations({ type: 'array', items: { type: 'string' } })).toEqual([]);
117
+ });
118
+ it('admits minItems at 0 or 1 and refuses it above, as the wire does', () => {
119
+ // A blanket denial here was a false positive with a real cost: it
120
+ // refuses `z.array(...).nonempty()`, which renders `minItems: 1` and
121
+ // which the wire accepts. The constraint is on the VALUE, and the
122
+ // vendor's error says so — "'minItems' values other than 0 or 1 are not
123
+ // supported".
124
+ expect(findStrictSchemaViolations({ type: 'array', minItems: 0 })).toEqual([]);
125
+ expect(findStrictSchemaViolations({ type: 'array', minItems: 1 })).toEqual([]);
126
+ const violations = findStrictSchemaViolations({ type: 'array', minItems: 2 });
127
+ expect(violations).toHaveLength(1);
128
+ expect(violations[0]?.keyword).toBe('minItems');
129
+ });
130
+ it('admits additionalProperties only as false', () => {
131
+ expect(findStrictSchemaViolations({ additionalProperties: false })).toEqual([]);
132
+ expect(findStrictSchemaViolations({ additionalProperties: { type: 'string' } })).toHaveLength(1);
133
+ });
134
+ it('walks into arrays of subschemas', () => {
135
+ const schema = { anyOf: [{ type: 'string' }, { not: { type: 'null' } }] };
136
+ expect(findStrictSchemaViolations(schema)[0]?.path).toBe('anyOf[1].not');
137
+ });
138
+ it('leaves ordinary annotations alone', () => {
139
+ const schema = {
140
+ type: 'object',
141
+ description: 'a tool',
142
+ properties: { a: { type: 'string', description: 'x', enum: ['y'] } },
143
+ required: ['a'],
144
+ additionalProperties: false,
145
+ };
146
+ expect(findStrictSchemaViolations(schema)).toEqual([]);
147
+ });
148
+ });
149
+ describe('assertStrictSchema refuses rather than letting the request go', () => {
150
+ it('throws naming the tool, the path and the fix', () => {
151
+ expect(() => assertStrictSchema('edit', { properties: { insertLine: { oneOf: [] } } })).toThrow(/edit\.properties\.insertLine\.oneOf/);
152
+ });
153
+ it('says nothing about a schema that is expressible', () => {
154
+ expect(() => assertStrictSchema('edit', { type: 'object' })).not.toThrow();
155
+ });
156
+ });
157
+ //# sourceMappingURL=strict-schema.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict-schema.test.js","sourceRoot":"","sources":["../../../src/provider/__tests__/strict-schema.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=vendor-detail.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vendor-detail.test.d.ts","sourceRoot":"","sources":["../../../src/provider/__tests__/vendor-detail.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { providerHttpError, redactSecrets, vendorDetail } from '../errors.js';
3
+ /**
4
+ * The provider's own account of what was wrong, kept — and scrubbed.
5
+ *
6
+ * `ProviderRequestErrorInit` declared `detail` from the beginning and the
7
+ * constructor never read it, so the field existed and carried nothing. The
8
+ * body was read to classify and then dropped, deliberately, because an error
9
+ * body can echo a request and a request can carry a key.
10
+ *
11
+ * The cost of that trade showed up in production: the wire had been saying
12
+ * `tools.0.custom.input_schema: … must match JSON Schema draft 2020-12` and
13
+ * the SDK deleted the sentence, so diagnosing it took seven eliminated
14
+ * hypotheses and a day of downtime. Keeping the sentence and scrubbing the
15
+ * credential shapes is the trade that was actually available.
16
+ */
17
+ describe('the sentence that names the broken field survives', () => {
18
+ it('lifts the structured message out of a vendor body', () => {
19
+ const body = JSON.stringify({
20
+ type: 'error',
21
+ error: {
22
+ type: 'invalid_request_error',
23
+ message: 'tools.0.custom.input_schema: JSON schema is invalid. It must match JSON Schema draft 2020-12',
24
+ },
25
+ });
26
+ expect(vendorDetail(body)).toBe('tools.0.custom.input_schema: JSON schema is invalid. It must match JSON Schema draft 2020-12');
27
+ });
28
+ it('reaches the error a caller actually catches', () => {
29
+ const err = providerHttpError({
30
+ providerId: 'anthropic',
31
+ status: 400,
32
+ body: JSON.stringify({ error: { message: "Schema type 'oneOf' is not supported" } }),
33
+ });
34
+ expect(err.detail).toContain('oneOf');
35
+ // …and the message too, so a log line that prints only the message is
36
+ // still enough to act on.
37
+ expect(err.message).toContain('oneOf');
38
+ });
39
+ it('falls back to the raw text when the body is not JSON', () => {
40
+ expect(vendorDetail('upstream connect error, transport failure')).toBe('upstream connect error, transport failure');
41
+ });
42
+ it('says nothing rather than something empty', () => {
43
+ expect(vendorDetail(undefined)).toBeUndefined();
44
+ expect(vendorDetail(null)).toBeUndefined();
45
+ expect(vendorDetail(' ')).toBeUndefined();
46
+ expect(vendorDetail({})).toBeUndefined();
47
+ });
48
+ it('truncates a body that is not a sentence', () => {
49
+ const detail = vendorDetail('x'.repeat(5_000));
50
+ expect(detail?.length).toBeLessThanOrEqual(401);
51
+ expect(detail?.endsWith('…')).toBe(true);
52
+ });
53
+ });
54
+ describe('a credential never rides along', () => {
55
+ it.each([
56
+ ['sk-ant-api03-AbCdEfGhIjKlMnOpQrStUv', 'anthropic-style key'],
57
+ ['npm_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345', 'npm token'],
58
+ ['ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345', 'github token'],
59
+ ['AKIAIOSFODNN7EXAMPLE', 'aws access key id'],
60
+ ])('scrubs %s (%s)', (secret) => {
61
+ const scrubbed = redactSecrets(`upstream rejected token ${secret} for this request`);
62
+ expect(scrubbed).not.toContain(secret);
63
+ expect(scrubbed).toContain('[redacted]');
64
+ });
65
+ it('scrubs a bearer header the vendor echoed back', () => {
66
+ const scrubbed = redactSecrets('bad header: Authorization: Bearer abcdef0123456789ABCDEF');
67
+ expect(scrubbed).not.toContain('abcdef0123456789ABCDEF');
68
+ });
69
+ it('scrubs a credential-named JSON field without eating the rest', () => {
70
+ const scrubbed = redactSecrets('{"api_key":"sk-live-9999","model":"the-model-that-failed"}');
71
+ expect(scrubbed).not.toContain('sk-live-9999');
72
+ // The surrounding sentence is the whole point — scrubbing must not
73
+ // degrade into deleting the message.
74
+ expect(scrubbed).toContain('the-model-that-failed');
75
+ });
76
+ it('scrubs on the real path, not only in the helper', () => {
77
+ const err = providerHttpError({
78
+ providerId: 'anthropic',
79
+ status: 401,
80
+ body: JSON.stringify({
81
+ error: { message: 'invalid key sk-ant-api03-AbCdEfGhIjKlMnOpQrStUv supplied' },
82
+ }),
83
+ });
84
+ expect(err.detail).not.toContain('AbCdEfGhIjKlMnOpQrStUv');
85
+ expect(err.detail).toContain('[redacted]');
86
+ expect(err.message).not.toContain('AbCdEfGhIjKlMnOpQrStUv');
87
+ });
88
+ });
89
+ //# sourceMappingURL=vendor-detail.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vendor-detail.test.js","sourceRoot":"","sources":["../../../src/provider/__tests__/vendor-detail.test.ts"],"names":[],"mappings":"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"}
@@ -11,11 +11,19 @@
11
11
  *
12
12
  * So the contract here is deliberately narrow:
13
13
  *
14
- * - the message is built from the STATUS LINE and the classified `kind`. The
15
- * response body is read to classify and then dropped. It is never
16
- * interpolated, never re-thrown, and never attached as `cause` — a `cause`
17
- * survives every logger that serializes an error chain, which defeats the
18
- * point.
14
+ * - the message is built from the STATUS LINE, the classified `kind`, and the
15
+ * provider's own complaint in `detail` truncated and scrubbed of anything
16
+ * credential-shaped. The raw body is never re-thrown and never attached as
17
+ * `cause`; a `cause` survives every logger that serializes an error chain,
18
+ * which defeats the point.
19
+ *
20
+ * The body used to be dropped entirely. That was over-corrected: a provider
21
+ * rejecting a request names the exact offending field, and deleting that
22
+ * sentence turned a one-line diagnosis into hypothesis elimination against a
23
+ * live API — once at the cost of a day of production downtime, while the
24
+ * wire had been saying `tools.0.custom.input_schema: … must match JSON
25
+ * Schema draft 2020-12` the entire time. Scrubbing what looks like a
26
+ * credential keeps the safety and returns the sentence.
19
27
  * - `retryAfterMs` is DATA. Nothing in this module sleeps, backs off or
20
28
  * retries. A retry loop inside a driver burns the run's wall clock and hides
21
29
  * the failure from the layer that should decide.
@@ -35,8 +43,33 @@ export declare class ProviderRequestError extends Error {
35
43
  readonly providerId: string;
36
44
  readonly status?: number;
37
45
  readonly retryAfterMs?: number;
46
+ /**
47
+ * What the provider said was wrong, truncated and redacted.
48
+ *
49
+ * `ProviderRequestErrorInit` has declared this field all along and the
50
+ * constructor never read it, so every caller that set it was writing to
51
+ * nothing. That is not a cosmetic gap: a provider rejecting a request
52
+ * usually names the exact offending field, and losing that sentence turns
53
+ * a one-line diagnosis into hypothesis elimination against a live API. It
54
+ * did — a tool schema in the wrong JSON Schema dialect cost a day of
55
+ * production downtime while the wire had been saying
56
+ * `tools.0.custom.input_schema: … must match JSON Schema draft 2020-12`
57
+ * the whole time.
58
+ *
59
+ * See {@link vendorDetail} for what is kept and what is scrubbed.
60
+ */
61
+ readonly detail?: string;
38
62
  constructor(init: ProviderRequestErrorInit);
39
63
  }
64
+ /**
65
+ * The provider's own account of what was wrong, safe to log.
66
+ *
67
+ * Prefers the structured `error.message` a JSON body carries, because that is
68
+ * the field vendors put the actionable sentence in and it is bounded; falls
69
+ * back to the raw text. Truncated, and every credential shape replaced.
70
+ */
71
+ export declare function vendorDetail(body: unknown): string | undefined;
72
+ export declare function redactSecrets(text: string): string;
40
73
  /** Is this a classified provider failure, whichever SDK copy threw it? */
41
74
  export declare function isProviderRequestError(err: unknown): err is ProviderRequestError;
42
75
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/provider/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAC7F,YAAY,EACX,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,GACxB,MAAM,4BAA4B,CAAA;AAWnC;;;;;;;GAOG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,SAAgB,IAAI,EAAE,iBAAiB,CAAA;IACvC,SAAgB,UAAU,EAAE,MAAM,CAAA;IAClC,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAA;IAC/B,SAAgB,YAAY,CAAC,EAAE,MAAM,CAAA;gBAEzB,IAAI,EAAE,wBAAwB;CAQ1C;AAED,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,oBAAoB,CAOhF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAKhF;AAwCD,sEAAsE;AACtE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAGhF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,GAAG,GAAE,MAAmB,GACtB,MAAM,GAAG,SAAS,CAepB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAClB,iBAAiB,CAanB;AAyED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,oBAAoB,CAwCvB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,oBAAoB,CASvB"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/provider/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAC7F,YAAY,EACX,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,GACxB,MAAM,4BAA4B,CAAA;AAWnC;;;;;;;GAOG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,SAAgB,IAAI,EAAE,iBAAiB,CAAA;IACvC,SAAgB,UAAU,EAAE,MAAM,CAAA;IAClC,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAA;IAC/B,SAAgB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrC;;;;;;;;;;;;;;OAcG;IACH,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAA;gBAEnB,IAAI,EAAE,wBAAwB;CAS1C;AAsBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAiB9D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAkBD,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,oBAAoB,CAOhF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAKhF;AAwCD,sEAAsE;AACtE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAGhF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,GAAG,GAAE,MAAmB,GACtB,MAAM,GAAG,SAAS,CAepB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAClB,iBAAiB,CAanB;AAyED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,oBAAoB,CA0CvB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,oBAAoB,CAWvB"}