@yeshwanthyk/ai 0.1.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 (94) hide show
  1. package/README.md +1142 -0
  2. package/dist/agent/agent-loop.d.ts +16 -0
  3. package/dist/agent/agent-loop.d.ts.map +1 -0
  4. package/dist/agent/agent-loop.js +307 -0
  5. package/dist/agent/agent-loop.js.map +1 -0
  6. package/dist/agent/index.d.ts +4 -0
  7. package/dist/agent/index.d.ts.map +1 -0
  8. package/dist/agent/index.js +3 -0
  9. package/dist/agent/index.js.map +1 -0
  10. package/dist/agent/tools/calculate.d.ts +15 -0
  11. package/dist/agent/tools/calculate.d.ts.map +1 -0
  12. package/dist/agent/tools/calculate.js +23 -0
  13. package/dist/agent/tools/calculate.js.map +1 -0
  14. package/dist/agent/tools/get-current-time.d.ts +15 -0
  15. package/dist/agent/tools/get-current-time.d.ts.map +1 -0
  16. package/dist/agent/tools/get-current-time.js +38 -0
  17. package/dist/agent/tools/get-current-time.js.map +1 -0
  18. package/dist/agent/tools/index.d.ts +3 -0
  19. package/dist/agent/tools/index.d.ts.map +1 -0
  20. package/dist/agent/tools/index.js +3 -0
  21. package/dist/agent/tools/index.js.map +1 -0
  22. package/dist/agent/types.d.ts +69 -0
  23. package/dist/agent/types.d.ts.map +1 -0
  24. package/dist/agent/types.js +2 -0
  25. package/dist/agent/types.js.map +1 -0
  26. package/dist/index.d.ts +15 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +15 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/models.d.ts +11 -0
  31. package/dist/models.d.ts.map +1 -0
  32. package/dist/models.generated.d.ts +7406 -0
  33. package/dist/models.generated.d.ts.map +1 -0
  34. package/dist/models.generated.js +7268 -0
  35. package/dist/models.generated.js.map +1 -0
  36. package/dist/models.js +35 -0
  37. package/dist/models.js.map +1 -0
  38. package/dist/providers/anthropic.d.ts +12 -0
  39. package/dist/providers/anthropic.d.ts.map +1 -0
  40. package/dist/providers/anthropic.js +538 -0
  41. package/dist/providers/anthropic.js.map +1 -0
  42. package/dist/providers/google.d.ts +12 -0
  43. package/dist/providers/google.d.ts.map +1 -0
  44. package/dist/providers/google.js +427 -0
  45. package/dist/providers/google.js.map +1 -0
  46. package/dist/providers/openai-completions.d.ts +12 -0
  47. package/dist/providers/openai-completions.d.ts.map +1 -0
  48. package/dist/providers/openai-completions.js +540 -0
  49. package/dist/providers/openai-completions.js.map +1 -0
  50. package/dist/providers/openai-responses.d.ts +14 -0
  51. package/dist/providers/openai-responses.d.ts.map +1 -0
  52. package/dist/providers/openai-responses.js +553 -0
  53. package/dist/providers/openai-responses.js.map +1 -0
  54. package/dist/providers/transform-messages.d.ts +3 -0
  55. package/dist/providers/transform-messages.d.ts.map +1 -0
  56. package/dist/providers/transform-messages.js +111 -0
  57. package/dist/providers/transform-messages.js.map +1 -0
  58. package/dist/stream.d.ts +11 -0
  59. package/dist/stream.d.ts.map +1 -0
  60. package/dist/stream.js +204 -0
  61. package/dist/stream.js.map +1 -0
  62. package/dist/types.d.ts +203 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +4 -0
  65. package/dist/types.js.map +1 -0
  66. package/dist/utils/event-stream.d.ts +19 -0
  67. package/dist/utils/event-stream.d.ts.map +1 -0
  68. package/dist/utils/event-stream.js +77 -0
  69. package/dist/utils/event-stream.js.map +1 -0
  70. package/dist/utils/json-parse.d.ts +9 -0
  71. package/dist/utils/json-parse.d.ts.map +1 -0
  72. package/dist/utils/json-parse.js +29 -0
  73. package/dist/utils/json-parse.js.map +1 -0
  74. package/dist/utils/oauth/anthropic.d.ts +20 -0
  75. package/dist/utils/oauth/anthropic.d.ts.map +1 -0
  76. package/dist/utils/oauth/anthropic.js +103 -0
  77. package/dist/utils/oauth/anthropic.js.map +1 -0
  78. package/dist/utils/overflow.d.ts +51 -0
  79. package/dist/utils/overflow.d.ts.map +1 -0
  80. package/dist/utils/overflow.js +106 -0
  81. package/dist/utils/overflow.js.map +1 -0
  82. package/dist/utils/sanitize-unicode.d.ts +22 -0
  83. package/dist/utils/sanitize-unicode.d.ts.map +1 -0
  84. package/dist/utils/sanitize-unicode.js +26 -0
  85. package/dist/utils/sanitize-unicode.js.map +1 -0
  86. package/dist/utils/typebox-helpers.d.ts +17 -0
  87. package/dist/utils/typebox-helpers.d.ts.map +1 -0
  88. package/dist/utils/typebox-helpers.js +21 -0
  89. package/dist/utils/typebox-helpers.js.map +1 -0
  90. package/dist/utils/validation.d.ts +18 -0
  91. package/dist/utils/validation.d.ts.map +1 -0
  92. package/dist/utils/validation.js +69 -0
  93. package/dist/utils/validation.js.map +1 -0
  94. package/package.json +60 -0
@@ -0,0 +1,77 @@
1
+ // Generic event stream class for async iteration
2
+ export class EventStream {
3
+ isComplete;
4
+ extractResult;
5
+ queue = [];
6
+ waiting = [];
7
+ done = false;
8
+ finalResultPromise;
9
+ resolveFinalResult;
10
+ constructor(isComplete, extractResult) {
11
+ this.isComplete = isComplete;
12
+ this.extractResult = extractResult;
13
+ this.finalResultPromise = new Promise((resolve) => {
14
+ this.resolveFinalResult = resolve;
15
+ });
16
+ }
17
+ push(event) {
18
+ if (this.done)
19
+ return;
20
+ if (this.isComplete(event)) {
21
+ this.done = true;
22
+ this.resolveFinalResult(this.extractResult(event));
23
+ }
24
+ // Deliver to waiting consumer or queue it
25
+ const waiter = this.waiting.shift();
26
+ if (waiter) {
27
+ waiter({ value: event, done: false });
28
+ }
29
+ else {
30
+ this.queue.push(event);
31
+ }
32
+ }
33
+ end(result) {
34
+ this.done = true;
35
+ if (result !== undefined) {
36
+ this.resolveFinalResult(result);
37
+ }
38
+ // Notify all waiting consumers that we're done
39
+ while (this.waiting.length > 0) {
40
+ const waiter = this.waiting.shift();
41
+ waiter({ value: undefined, done: true });
42
+ }
43
+ }
44
+ async *[Symbol.asyncIterator]() {
45
+ while (true) {
46
+ if (this.queue.length > 0) {
47
+ yield this.queue.shift();
48
+ }
49
+ else if (this.done) {
50
+ return;
51
+ }
52
+ else {
53
+ const result = await new Promise((resolve) => this.waiting.push(resolve));
54
+ if (result.done)
55
+ return;
56
+ yield result.value;
57
+ }
58
+ }
59
+ }
60
+ result() {
61
+ return this.finalResultPromise;
62
+ }
63
+ }
64
+ export class AssistantMessageEventStream extends EventStream {
65
+ constructor() {
66
+ super((event) => event.type === "done" || event.type === "error", (event) => {
67
+ if (event.type === "done") {
68
+ return event.message;
69
+ }
70
+ else if (event.type === "error") {
71
+ return event.error;
72
+ }
73
+ throw new Error("Unexpected event type for final result");
74
+ });
75
+ }
76
+ }
77
+ //# sourceMappingURL=event-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-stream.js","sourceRoot":"","sources":["../../src/utils/event-stream.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,MAAM,OAAO,WAAW;IAQd,UAAU;IACV,aAAa;IARd,KAAK,GAAQ,EAAE,CAAC;IAChB,OAAO,GAA2C,EAAE,CAAC;IACrD,IAAI,GAAG,KAAK,CAAC;IACb,kBAAkB,CAAa;IAC/B,kBAAkB,CAAuB;IAEjD,YACS,UAAiC,EACjC,aAA8B,EACrC;0BAFO,UAAU;6BACV,aAAa;QAErB,IAAI,CAAC,kBAAkB,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YAClD,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC;QAAA,CAClC,CAAC,CAAC;IAAA,CACH;IAED,IAAI,CAAC,KAAQ,EAAQ;QACpB,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QAEtB,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,0CAA0C;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IAAA,CACD;IAED,GAAG,CAAC,MAAU,EAAQ;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,+CAA+C;QAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAG,CAAC;YACrC,MAAM,CAAC,EAAE,KAAK,EAAE,SAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,CAAC;IAAA,CACD;IAED,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,GAAqB;QACjD,OAAO,IAAI,EAAE,CAAC;YACb,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAG,CAAC;YAC3B,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACtB,OAAO;YACR,CAAC;iBAAM,CAAC;gBACP,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAoB,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC7F,IAAI,MAAM,CAAC,IAAI;oBAAE,OAAO;gBACxB,MAAM,MAAM,CAAC,KAAK,CAAC;YACpB,CAAC;QACF,CAAC;IAAA,CACD;IAED,MAAM,GAAe;QACpB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IAAA,CAC/B;CACD;AAED,MAAM,OAAO,2BAA4B,SAAQ,WAAoD;IACpG,cAAc;QACb,KAAK,CACJ,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAC1D,CAAC,KAAK,EAAE,EAAE,CAAC;YACV,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;YACtB,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACnC,OAAO,KAAK,CAAC,KAAK,CAAC;YACpB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAAA,CAC1D,CACD,CAAC;IAAA,CACF;CACD"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Attempts to parse potentially incomplete JSON during streaming.
3
+ * Always returns a valid object, even if the JSON is incomplete.
4
+ *
5
+ * @param partialJson The partial JSON string from streaming
6
+ * @returns Parsed object or empty object if parsing fails
7
+ */
8
+ export declare function parseStreamingJson<T = any>(partialJson: string | undefined): T;
9
+ //# sourceMappingURL=json-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-parse.d.ts","sourceRoot":"","sources":["../../src/utils/json-parse.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,GAAG,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,CAkB9E"}
@@ -0,0 +1,29 @@
1
+ import { parse as partialParse } from "partial-json";
2
+ /**
3
+ * Attempts to parse potentially incomplete JSON during streaming.
4
+ * Always returns a valid object, even if the JSON is incomplete.
5
+ *
6
+ * @param partialJson The partial JSON string from streaming
7
+ * @returns Parsed object or empty object if parsing fails
8
+ */
9
+ export function parseStreamingJson(partialJson) {
10
+ if (!partialJson || partialJson.trim() === "") {
11
+ return {};
12
+ }
13
+ // Try standard parsing first (fastest for complete JSON)
14
+ try {
15
+ return JSON.parse(partialJson);
16
+ }
17
+ catch {
18
+ // Try partial-json for incomplete JSON
19
+ try {
20
+ const result = partialParse(partialJson);
21
+ return (result ?? {});
22
+ }
23
+ catch {
24
+ // If all parsing fails, return empty object
25
+ return {};
26
+ }
27
+ }
28
+ }
29
+ //# sourceMappingURL=json-parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-parse.js","sourceRoot":"","sources":["../../src/utils/json-parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAU,WAA+B,EAAK;IAC/E,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/C,OAAO,EAAO,CAAC;IAChB,CAAC;IAED,yDAAyD;IACzD,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAM,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACR,uCAAuC;QACvC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;YACzC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAM,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACR,4CAA4C;YAC5C,OAAO,EAAO,CAAC;QAChB,CAAC;IACF,CAAC;AAAA,CACD"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Anthropic OAuth flow (Claude Pro/Max)
3
+ */
4
+ export type AnthropicOAuthCredentials = {
5
+ refresh: string;
6
+ access: string;
7
+ expires: number;
8
+ };
9
+ /**
10
+ * Login with Anthropic OAuth
11
+ *
12
+ * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
13
+ * @param onPromptCode - Callback to prompt user for the authorization code
14
+ */
15
+ export declare function loginAnthropic(onAuthUrl: (url: string) => void, onPromptCode: () => Promise<string>): Promise<AnthropicOAuthCredentials>;
16
+ /**
17
+ * Refresh Anthropic OAuth token
18
+ */
19
+ export declare function refreshAnthropicToken(refreshToken: string): Promise<AnthropicOAuthCredentials>;
20
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CACf,CAAA;AAgCD;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,yBAAyB,CAAC,CAwDpC;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CA2BpG"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Anthropic OAuth flow (Claude Pro/Max)
3
+ */
4
+ // PKCE utilities
5
+ function base64urlEncode(bytes) {
6
+ let binary = "";
7
+ for (const byte of bytes) {
8
+ binary += String.fromCharCode(byte);
9
+ }
10
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
11
+ }
12
+ async function generatePKCE() {
13
+ const verifierBytes = new Uint8Array(32);
14
+ crypto.getRandomValues(verifierBytes);
15
+ const verifier = base64urlEncode(verifierBytes);
16
+ const encoder = new TextEncoder();
17
+ const data = encoder.encode(verifier);
18
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
19
+ const challenge = base64urlEncode(new Uint8Array(hashBuffer));
20
+ return { verifier, challenge };
21
+ }
22
+ // OAuth constants
23
+ const decode = (s) => atob(s);
24
+ const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
25
+ const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
26
+ const TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
27
+ const REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
28
+ const SCOPES = "org:create_api_key user:profile user:inference";
29
+ /**
30
+ * Login with Anthropic OAuth
31
+ *
32
+ * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
33
+ * @param onPromptCode - Callback to prompt user for the authorization code
34
+ */
35
+ export async function loginAnthropic(onAuthUrl, onPromptCode) {
36
+ const { verifier, challenge } = await generatePKCE();
37
+ const authParams = new URLSearchParams({
38
+ code: "true",
39
+ client_id: CLIENT_ID,
40
+ response_type: "code",
41
+ redirect_uri: REDIRECT_URI,
42
+ scope: SCOPES,
43
+ code_challenge: challenge,
44
+ code_challenge_method: "S256",
45
+ state: verifier,
46
+ });
47
+ const authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;
48
+ onAuthUrl(authUrl);
49
+ const authCode = await onPromptCode();
50
+ const splits = authCode.split("#");
51
+ const code = splits[0];
52
+ const state = splits[1];
53
+ const tokenResponse = await fetch(TOKEN_URL, {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ },
58
+ body: JSON.stringify({
59
+ grant_type: "authorization_code",
60
+ client_id: CLIENT_ID,
61
+ code: code,
62
+ state: state,
63
+ redirect_uri: REDIRECT_URI,
64
+ code_verifier: verifier,
65
+ }),
66
+ });
67
+ if (!tokenResponse.ok) {
68
+ const error = await tokenResponse.text();
69
+ throw new Error(`Token exchange failed: ${error}`);
70
+ }
71
+ const tokenData = (await tokenResponse.json());
72
+ const expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;
73
+ return {
74
+ refresh: tokenData.refresh_token,
75
+ access: tokenData.access_token,
76
+ expires: expiresAt,
77
+ };
78
+ }
79
+ /**
80
+ * Refresh Anthropic OAuth token
81
+ */
82
+ export async function refreshAnthropicToken(refreshToken) {
83
+ const response = await fetch(TOKEN_URL, {
84
+ method: "POST",
85
+ headers: { "Content-Type": "application/json" },
86
+ body: JSON.stringify({
87
+ grant_type: "refresh_token",
88
+ client_id: CLIENT_ID,
89
+ refresh_token: refreshToken,
90
+ }),
91
+ });
92
+ if (!response.ok) {
93
+ const error = await response.text();
94
+ throw new Error(`Anthropic token refresh failed: ${error}`);
95
+ }
96
+ const data = (await response.json());
97
+ return {
98
+ refresh: data.refresh_token,
99
+ access: data.access_token,
100
+ expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,
101
+ };
102
+ }
103
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { AssistantMessage } from "../types.js";
2
+ /**
3
+ * Check if an assistant message represents a context overflow error.
4
+ *
5
+ * This handles two cases:
6
+ * 1. Error-based overflow: Most providers return stopReason "error" with a
7
+ * specific error message pattern.
8
+ * 2. Silent overflow: Some providers accept overflow requests and return
9
+ * successfully. For these, we check if usage.input exceeds the context window.
10
+ *
11
+ * ## Reliability by Provider
12
+ *
13
+ * **Reliable detection (returns error with detectable message):**
14
+ * - Anthropic: "prompt is too long: X tokens > Y maximum"
15
+ * - OpenAI (Completions & Responses): "exceeds the context window"
16
+ * - Google Gemini: "input token count exceeds the maximum"
17
+ * - xAI (Grok): "maximum prompt length is X but request contains Y"
18
+ * - Groq: "reduce the length of the messages"
19
+ * - Cerebras: 400/413 status code (no body)
20
+ * - Mistral: 400/413 status code (no body)
21
+ * - OpenRouter (all backends): "maximum context length is X tokens"
22
+ * - llama.cpp: "exceeds the available context size"
23
+ * - LM Studio: "greater than the context length"
24
+ *
25
+ * **Unreliable detection:**
26
+ * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),
27
+ * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.
28
+ * - Ollama: Silently truncates input without error. Cannot be detected via this function.
29
+ * The response will have usage.input < expected, but we don't know the expected value.
30
+ *
31
+ * ## Custom Providers
32
+ *
33
+ * If you've added custom models via settings.json, this function may not detect
34
+ * overflow errors from those providers. To add support:
35
+ *
36
+ * 1. Send a request that exceeds the model's context window
37
+ * 2. Check the errorMessage in the response
38
+ * 3. Create a regex pattern that matches the error
39
+ * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or
40
+ * check the errorMessage yourself before calling this function
41
+ *
42
+ * @param message - The assistant message to check
43
+ * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)
44
+ * @returns true if the message indicates a context overflow
45
+ */
46
+ export declare function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean;
47
+ /**
48
+ * Get the overflow patterns for testing purposes.
49
+ */
50
+ export declare function getOverflowPatterns(): RegExp[];
51
+ //# sourceMappingURL=overflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqCpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAuB5F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Regex patterns to detect context overflow errors from different providers.
3
+ *
4
+ * These patterns match error messages returned when the input exceeds
5
+ * the model's context window.
6
+ *
7
+ * Provider-specific patterns (with example error messages):
8
+ *
9
+ * - Anthropic: "prompt is too long: 213462 tokens > 200000 maximum"
10
+ * - OpenAI: "Your input exceeds the context window of this model"
11
+ * - Google: "The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)"
12
+ * - xAI: "This model's maximum prompt length is 131072 but the request contains 537812 tokens"
13
+ * - Groq: "Please reduce the length of the messages or completion"
14
+ * - OpenRouter: "This endpoint's maximum context length is X tokens. However, you requested about Y tokens"
15
+ * - llama.cpp: "the request exceeds the available context size, try increasing it"
16
+ * - LM Studio: "tokens to keep from the initial prompt is greater than the context length"
17
+ * - Cerebras: Returns "400 status code (no body)" - handled separately below
18
+ * - Mistral: Returns "400 status code (no body)" - handled separately below
19
+ * - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow
20
+ * - Ollama: Silently truncates input - not detectable via error message
21
+ */
22
+ const OVERFLOW_PATTERNS = [
23
+ /prompt is too long/i, // Anthropic
24
+ /exceeds the context window/i, // OpenAI (Completions & Responses API)
25
+ /input token count.*exceeds the maximum/i, // Google (Gemini)
26
+ /maximum prompt length is \d+/i, // xAI (Grok)
27
+ /reduce the length of the messages/i, // Groq
28
+ /maximum context length is \d+ tokens/i, // OpenRouter (all backends)
29
+ /exceeds the available context size/i, // llama.cpp server
30
+ /greater than the context length/i, // LM Studio
31
+ /context length exceeded/i, // Generic fallback
32
+ /too many tokens/i, // Generic fallback
33
+ /token limit exceeded/i, // Generic fallback
34
+ ];
35
+ /**
36
+ * Check if an assistant message represents a context overflow error.
37
+ *
38
+ * This handles two cases:
39
+ * 1. Error-based overflow: Most providers return stopReason "error" with a
40
+ * specific error message pattern.
41
+ * 2. Silent overflow: Some providers accept overflow requests and return
42
+ * successfully. For these, we check if usage.input exceeds the context window.
43
+ *
44
+ * ## Reliability by Provider
45
+ *
46
+ * **Reliable detection (returns error with detectable message):**
47
+ * - Anthropic: "prompt is too long: X tokens > Y maximum"
48
+ * - OpenAI (Completions & Responses): "exceeds the context window"
49
+ * - Google Gemini: "input token count exceeds the maximum"
50
+ * - xAI (Grok): "maximum prompt length is X but request contains Y"
51
+ * - Groq: "reduce the length of the messages"
52
+ * - Cerebras: 400/413 status code (no body)
53
+ * - Mistral: 400/413 status code (no body)
54
+ * - OpenRouter (all backends): "maximum context length is X tokens"
55
+ * - llama.cpp: "exceeds the available context size"
56
+ * - LM Studio: "greater than the context length"
57
+ *
58
+ * **Unreliable detection:**
59
+ * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),
60
+ * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.
61
+ * - Ollama: Silently truncates input without error. Cannot be detected via this function.
62
+ * The response will have usage.input < expected, but we don't know the expected value.
63
+ *
64
+ * ## Custom Providers
65
+ *
66
+ * If you've added custom models via settings.json, this function may not detect
67
+ * overflow errors from those providers. To add support:
68
+ *
69
+ * 1. Send a request that exceeds the model's context window
70
+ * 2. Check the errorMessage in the response
71
+ * 3. Create a regex pattern that matches the error
72
+ * 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or
73
+ * check the errorMessage yourself before calling this function
74
+ *
75
+ * @param message - The assistant message to check
76
+ * @param contextWindow - Optional context window size for detecting silent overflow (z.ai)
77
+ * @returns true if the message indicates a context overflow
78
+ */
79
+ export function isContextOverflow(message, contextWindow) {
80
+ // Case 1: Check error message patterns
81
+ if (message.stopReason === "error" && message.errorMessage) {
82
+ // Check known patterns
83
+ if (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage))) {
84
+ return true;
85
+ }
86
+ // Cerebras and Mistral return 400/413 with no body - check for status code pattern
87
+ if (/^4(00|13)\s*(status code)?\s*\(no body\)/i.test(message.errorMessage)) {
88
+ return true;
89
+ }
90
+ }
91
+ // Case 2: Silent overflow (z.ai style) - successful but usage exceeds context
92
+ if (contextWindow && message.stopReason === "stop") {
93
+ const inputTokens = message.usage.input + message.usage.cacheRead;
94
+ if (inputTokens > contextWindow) {
95
+ return true;
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+ /**
101
+ * Get the overflow patterns for testing purposes.
102
+ */
103
+ export function getOverflowPatterns() {
104
+ return [...OVERFLOW_PATTERNS];
105
+ }
106
+ //# sourceMappingURL=overflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overflow.js","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,iBAAiB,GAAG;IACzB,qBAAqB,EAAE,YAAY;IACnC,6BAA6B,EAAE,uCAAuC;IACtE,yCAAyC,EAAE,kBAAkB;IAC7D,+BAA+B,EAAE,aAAa;IAC9C,oCAAoC,EAAE,OAAO;IAC7C,uCAAuC,EAAE,4BAA4B;IACrE,qCAAqC,EAAE,mBAAmB;IAC1D,kCAAkC,EAAE,YAAY;IAChD,0BAA0B,EAAE,mBAAmB;IAC/C,kBAAkB,EAAE,mBAAmB;IACvC,uBAAuB,EAAE,mBAAmB;CAC5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB,EAAE,aAAsB,EAAW;IAC7F,uCAAuC;IACvC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QAC5D,uBAAuB;QACvB,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAa,CAAC,CAAC,EAAE,CAAC;YAClE,OAAO,IAAI,CAAC;QACb,CAAC;QAED,mFAAmF;QACnF,IAAI,2CAA2C,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5E,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,8EAA8E;IAC9E,IAAI,aAAa,IAAI,OAAO,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;QAClE,IAAI,WAAW,GAAG,aAAa,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,GAAa;IAC/C,OAAO,CAAC,GAAG,iBAAiB,CAAC,CAAC;AAAA,CAC9B"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Removes unpaired Unicode surrogate characters from a string.
3
+ *
4
+ * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
5
+ * or vice versa) cause JSON serialization errors in many API providers.
6
+ *
7
+ * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
8
+ * surrogates and will NOT be affected by this function.
9
+ *
10
+ * @param text - The text to sanitize
11
+ * @returns The sanitized text with unpaired surrogates removed
12
+ *
13
+ * @example
14
+ * // Valid emoji (properly paired surrogates) are preserved
15
+ * sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
16
+ *
17
+ * // Unpaired high surrogate is removed
18
+ * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
19
+ * sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
20
+ */
21
+ export declare function sanitizeSurrogates(text: string): string;
22
+ //# sourceMappingURL=sanitize-unicode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-unicode.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Removes unpaired Unicode surrogate characters from a string.
3
+ *
4
+ * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
5
+ * or vice versa) cause JSON serialization errors in many API providers.
6
+ *
7
+ * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
8
+ * surrogates and will NOT be affected by this function.
9
+ *
10
+ * @param text - The text to sanitize
11
+ * @returns The sanitized text with unpaired surrogates removed
12
+ *
13
+ * @example
14
+ * // Valid emoji (properly paired surrogates) are preserved
15
+ * sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
16
+ *
17
+ * // Unpaired high surrogate is removed
18
+ * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
19
+ * sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
20
+ */
21
+ export function sanitizeSurrogates(text) {
22
+ // Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)
23
+ // Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)
24
+ return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
25
+ }
26
+ //# sourceMappingURL=sanitize-unicode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitize-unicode.js","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAU;IACxD,iFAAiF;IACjF,iFAAiF;IACjF,OAAO,IAAI,CAAC,OAAO,CAAC,yEAAyE,EAAE,EAAE,CAAC,CAAC;AAAA,CACnG"}
@@ -0,0 +1,17 @@
1
+ import { type TUnsafe } from "@sinclair/typebox";
2
+ /**
3
+ * Creates a string enum schema compatible with Google's API and other providers
4
+ * that don't support anyOf/const patterns.
5
+ *
6
+ * @example
7
+ * const OperationSchema = StringEnum(["add", "subtract", "multiply", "divide"], {
8
+ * description: "The operation to perform"
9
+ * });
10
+ *
11
+ * type Operation = Static<typeof OperationSchema>; // "add" | "subtract" | "multiply" | "divide"
12
+ */
13
+ export declare function StringEnum<T extends readonly string[]>(values: T, options?: {
14
+ description?: string;
15
+ default?: T[number];
16
+ }): TUnsafe<T[number]>;
17
+ //# sourceMappingURL=typebox-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typebox-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACrD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;CAAE,GACrD,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAOpB"}
@@ -0,0 +1,21 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ /**
3
+ * Creates a string enum schema compatible with Google's API and other providers
4
+ * that don't support anyOf/const patterns.
5
+ *
6
+ * @example
7
+ * const OperationSchema = StringEnum(["add", "subtract", "multiply", "divide"], {
8
+ * description: "The operation to perform"
9
+ * });
10
+ *
11
+ * type Operation = Static<typeof OperationSchema>; // "add" | "subtract" | "multiply" | "divide"
12
+ */
13
+ export function StringEnum(values, options) {
14
+ return Type.Unsafe({
15
+ type: "string",
16
+ enum: values,
17
+ ...(options?.description && { description: options.description }),
18
+ ...(options?.default && { default: options.default }),
19
+ });
20
+ }
21
+ //# sourceMappingURL=typebox-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typebox-helpers.js","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACzB,MAAS,EACT,OAAuD,EAClC;IACrB,OAAO,IAAI,CAAC,MAAM,CAAY;QAC7B,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,MAAa;QACnB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;QACjE,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;KACrD,CAAC,CAAC;AAAA,CACH"}
@@ -0,0 +1,18 @@
1
+ import type { Tool, ToolCall } from "../types.js";
2
+ /**
3
+ * Finds a tool by name and validates the tool call arguments against its TypeBox schema
4
+ * @param tools Array of tool definitions
5
+ * @param toolCall The tool call from the LLM
6
+ * @returns The validated arguments
7
+ * @throws Error if tool is not found or validation fails
8
+ */
9
+ export declare function validateToolCall(tools: Tool[], toolCall: ToolCall): any;
10
+ /**
11
+ * Validates tool call arguments against the tool's TypeBox schema
12
+ * @param tool The tool definition with TypeBox schema
13
+ * @param toolCall The tool call from the LLM
14
+ * @returns The validated arguments
15
+ * @throws Error with formatted message if validation fails
16
+ */
17
+ export declare function validateToolArguments(tool: Tool, toolCall: ToolCall): any;
18
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAsBlD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CAMvE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CA4BzE"}
@@ -0,0 +1,69 @@
1
+ import AjvModule from "ajv";
2
+ import addFormatsModule from "ajv-formats";
3
+ // Handle both default and named exports
4
+ const Ajv = AjvModule.default || AjvModule;
5
+ const addFormats = addFormatsModule.default || addFormatsModule;
6
+ // Detect if we're in a browser extension environment with strict CSP
7
+ // Chrome extensions with Manifest V3 don't allow eval/Function constructor
8
+ const isBrowserExtension = typeof globalThis !== "undefined" && globalThis.chrome?.runtime?.id !== undefined;
9
+ // Create a singleton AJV instance with formats (only if not in browser extension)
10
+ // AJV requires 'unsafe-eval' CSP which is not allowed in Manifest V3
11
+ let ajv = null;
12
+ if (!isBrowserExtension) {
13
+ try {
14
+ ajv = new Ajv({
15
+ allErrors: true,
16
+ strict: false,
17
+ });
18
+ addFormats(ajv);
19
+ }
20
+ catch (e) {
21
+ // AJV initialization failed (likely CSP restriction)
22
+ console.warn("AJV validation disabled due to CSP restrictions");
23
+ }
24
+ }
25
+ /**
26
+ * Finds a tool by name and validates the tool call arguments against its TypeBox schema
27
+ * @param tools Array of tool definitions
28
+ * @param toolCall The tool call from the LLM
29
+ * @returns The validated arguments
30
+ * @throws Error if tool is not found or validation fails
31
+ */
32
+ export function validateToolCall(tools, toolCall) {
33
+ const tool = tools.find((t) => t.name === toolCall.name);
34
+ if (!tool) {
35
+ throw new Error(`Tool "${toolCall.name}" not found`);
36
+ }
37
+ return validateToolArguments(tool, toolCall);
38
+ }
39
+ /**
40
+ * Validates tool call arguments against the tool's TypeBox schema
41
+ * @param tool The tool definition with TypeBox schema
42
+ * @param toolCall The tool call from the LLM
43
+ * @returns The validated arguments
44
+ * @throws Error with formatted message if validation fails
45
+ */
46
+ export function validateToolArguments(tool, toolCall) {
47
+ // Skip validation in browser extension environment (CSP restrictions prevent AJV from working)
48
+ if (!ajv || isBrowserExtension) {
49
+ // Trust the LLM's output without validation
50
+ // Browser extensions can't use AJV due to Manifest V3 CSP restrictions
51
+ return toolCall.arguments;
52
+ }
53
+ // Compile the schema
54
+ const validate = ajv.compile(tool.parameters);
55
+ // Validate the arguments
56
+ if (validate(toolCall.arguments)) {
57
+ return toolCall.arguments;
58
+ }
59
+ // Format validation errors nicely
60
+ const errors = validate.errors
61
+ ?.map((err) => {
62
+ const path = err.instancePath ? err.instancePath.substring(1) : err.params.missingProperty || "root";
63
+ return ` - ${path}: ${err.message}`;
64
+ })
65
+ .join("\n") || "Unknown validation error";
66
+ const errorMessage = `Validation failed for tool "${toolCall.name}":\n${errors}\n\nReceived arguments:\n${JSON.stringify(toolCall.arguments, null, 2)}`;
67
+ throw new Error(errorMessage);
68
+ }
69
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,KAAK,CAAC;AAC5B,OAAO,gBAAgB,MAAM,aAAa,CAAC;AAE3C,wCAAwC;AACxC,MAAM,GAAG,GAAI,SAAiB,CAAC,OAAO,IAAI,SAAS,CAAC;AACpD,MAAM,UAAU,GAAI,gBAAwB,CAAC,OAAO,IAAI,gBAAgB,CAAC;AAIzE,qEAAqE;AACrE,2EAA2E;AAC3E,MAAM,kBAAkB,GAAG,OAAO,UAAU,KAAK,WAAW,IAAK,UAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,SAAS,CAAC;AAEtH,kFAAkF;AAClF,qEAAqE;AACrE,IAAI,GAAG,GAAQ,IAAI,CAAC;AACpB,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACzB,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,GAAG,CAAC;YACb,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,KAAK;SACb,CAAC,CAAC;QACH,UAAU,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,qDAAqD;QACrD,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,QAAkB,EAAO;IACxE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,SAAS,QAAQ,CAAC,IAAI,aAAa,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,qBAAqB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,CAC7C;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAU,EAAE,QAAkB,EAAO;IAC1E,+FAA+F;IAC/F,IAAI,CAAC,GAAG,IAAI,kBAAkB,EAAE,CAAC;QAChC,4CAA4C;QAC5C,uEAAuE;QACvE,OAAO,QAAQ,CAAC,SAAS,CAAC;IAC3B,CAAC;IAED,qBAAqB;IACrB,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAE9C,yBAAyB;IACzB,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,QAAQ,CAAC,SAAS,CAAC;IAC3B,CAAC;IAED,kCAAkC;IAClC,MAAM,MAAM,GACX,QAAQ,CAAC,MAAM;QACd,EAAE,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC;QACrG,OAAO,OAAO,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;IAAA,CACrC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,IAAI,0BAA0B,CAAC;IAE5C,MAAM,YAAY,GAAG,+BAA+B,QAAQ,CAAC,IAAI,OAAO,MAAM,4BAA4B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IAExJ,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;AAAA,CAC9B"}