@ank1015/llm-agents 0.0.2

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 (104) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +117 -0
  4. package/dist/agents/skills/index.d.ts +37 -0
  5. package/dist/agents/skills/index.d.ts.map +1 -0
  6. package/dist/agents/skills/index.js +386 -0
  7. package/dist/agents/skills/index.js.map +1 -0
  8. package/dist/agents/system-prompt.d.ts +7 -0
  9. package/dist/agents/system-prompt.d.ts.map +1 -0
  10. package/dist/agents/system-prompt.js +106 -0
  11. package/dist/agents/system-prompt.js.map +1 -0
  12. package/dist/agents/tools.d.ts +3 -0
  13. package/dist/agents/tools.d.ts.map +1 -0
  14. package/dist/agents/tools.js +3 -0
  15. package/dist/agents/tools.js.map +1 -0
  16. package/dist/helpers/ai-image/ai-image.d.ts +75 -0
  17. package/dist/helpers/ai-image/ai-image.d.ts.map +1 -0
  18. package/dist/helpers/ai-image/ai-image.js +438 -0
  19. package/dist/helpers/ai-image/ai-image.js.map +1 -0
  20. package/dist/helpers/ai-image/index.d.ts +3 -0
  21. package/dist/helpers/ai-image/index.d.ts.map +1 -0
  22. package/dist/helpers/ai-image/index.js +2 -0
  23. package/dist/helpers/ai-image/index.js.map +1 -0
  24. package/dist/helpers/index.d.ts +2 -0
  25. package/dist/helpers/index.d.ts.map +1 -0
  26. package/dist/helpers/index.js +2 -0
  27. package/dist/helpers/index.js.map +1 -0
  28. package/dist/index.d.ts +12 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +12 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/tools/bash.d.ts +55 -0
  33. package/dist/tools/bash.d.ts.map +1 -0
  34. package/dist/tools/bash.js +246 -0
  35. package/dist/tools/bash.js.map +1 -0
  36. package/dist/tools/edit-diff.d.ts +63 -0
  37. package/dist/tools/edit-diff.d.ts.map +1 -0
  38. package/dist/tools/edit-diff.js +246 -0
  39. package/dist/tools/edit-diff.js.map +1 -0
  40. package/dist/tools/edit.d.ts +39 -0
  41. package/dist/tools/edit.d.ts.map +1 -0
  42. package/dist/tools/edit.js +150 -0
  43. package/dist/tools/edit.js.map +1 -0
  44. package/dist/tools/find.d.ts +39 -0
  45. package/dist/tools/find.d.ts.map +1 -0
  46. package/dist/tools/find.js +206 -0
  47. package/dist/tools/find.js.map +1 -0
  48. package/dist/tools/grep.d.ts +45 -0
  49. package/dist/tools/grep.d.ts.map +1 -0
  50. package/dist/tools/grep.js +244 -0
  51. package/dist/tools/grep.js.map +1 -0
  52. package/dist/tools/index.d.ts +73 -0
  53. package/dist/tools/index.d.ts.map +1 -0
  54. package/dist/tools/index.js +66 -0
  55. package/dist/tools/index.js.map +1 -0
  56. package/dist/tools/ls.d.ts +40 -0
  57. package/dist/tools/ls.d.ts.map +1 -0
  58. package/dist/tools/ls.js +121 -0
  59. package/dist/tools/ls.js.map +1 -0
  60. package/dist/tools/path-utils.d.ts +8 -0
  61. package/dist/tools/path-utils.d.ts.map +1 -0
  62. package/dist/tools/path-utils.js +81 -0
  63. package/dist/tools/path-utils.js.map +1 -0
  64. package/dist/tools/read.d.ts +39 -0
  65. package/dist/tools/read.d.ts.map +1 -0
  66. package/dist/tools/read.js +177 -0
  67. package/dist/tools/read.js.map +1 -0
  68. package/dist/tools/truncate.d.ts +70 -0
  69. package/dist/tools/truncate.d.ts.map +1 -0
  70. package/dist/tools/truncate.js +205 -0
  71. package/dist/tools/truncate.js.map +1 -0
  72. package/dist/tools/utils/config.d.ts +16 -0
  73. package/dist/tools/utils/config.d.ts.map +1 -0
  74. package/dist/tools/utils/config.js +40 -0
  75. package/dist/tools/utils/config.js.map +1 -0
  76. package/dist/tools/utils/image-resize.d.ts +36 -0
  77. package/dist/tools/utils/image-resize.d.ts.map +1 -0
  78. package/dist/tools/utils/image-resize.js +183 -0
  79. package/dist/tools/utils/image-resize.js.map +1 -0
  80. package/dist/tools/utils/mime.d.ts +3 -0
  81. package/dist/tools/utils/mime.d.ts.map +1 -0
  82. package/dist/tools/utils/mime.js +41 -0
  83. package/dist/tools/utils/mime.js.map +1 -0
  84. package/dist/tools/utils/photon.d.ts +21 -0
  85. package/dist/tools/utils/photon.d.ts.map +1 -0
  86. package/dist/tools/utils/photon.js +121 -0
  87. package/dist/tools/utils/photon.js.map +1 -0
  88. package/dist/tools/utils/shell.d.ts +26 -0
  89. package/dist/tools/utils/shell.d.ts.map +1 -0
  90. package/dist/tools/utils/shell.js +177 -0
  91. package/dist/tools/utils/shell.js.map +1 -0
  92. package/dist/tools/utils/tools-manager.d.ts +3 -0
  93. package/dist/tools/utils/tools-manager.d.ts.map +1 -0
  94. package/dist/tools/utils/tools-manager.js +209 -0
  95. package/dist/tools/utils/tools-manager.js.map +1 -0
  96. package/dist/tools/write.d.ts +29 -0
  97. package/dist/tools/write.d.ts.map +1 -0
  98. package/dist/tools/write.js +83 -0
  99. package/dist/tools/write.js.map +1 -0
  100. package/package.json +73 -0
  101. package/skills/ai-images/SKILL.md +45 -0
  102. package/skills/ai-images/references/create.md +106 -0
  103. package/skills/ai-images/references/edit.md +107 -0
  104. package/skills/registry.json +10 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Shared truncation utilities for tool outputs.
3
+ *
4
+ * Truncation is based on two independent limits - whichever is hit first wins:
5
+ * - Line limit (default: 2000 lines)
6
+ * - Byte limit (default: 50KB)
7
+ *
8
+ * Never returns partial lines (except bash tail truncation edge case).
9
+ */
10
+ export declare const DEFAULT_MAX_LINES = 2000;
11
+ export declare const DEFAULT_MAX_BYTES: number;
12
+ export declare const GREP_MAX_LINE_LENGTH = 500;
13
+ export interface TruncationResult {
14
+ /** The truncated content */
15
+ content: string;
16
+ /** Whether truncation occurred */
17
+ truncated: boolean;
18
+ /** Which limit was hit: "lines", "bytes", or null if not truncated */
19
+ truncatedBy: 'lines' | 'bytes' | null;
20
+ /** Total number of lines in the original content */
21
+ totalLines: number;
22
+ /** Total number of bytes in the original content */
23
+ totalBytes: number;
24
+ /** Number of complete lines in the truncated output */
25
+ outputLines: number;
26
+ /** Number of bytes in the truncated output */
27
+ outputBytes: number;
28
+ /** Whether the last line was partially truncated (only for tail truncation edge case) */
29
+ lastLinePartial: boolean;
30
+ /** Whether the first line exceeded the byte limit (for head truncation) */
31
+ firstLineExceedsLimit: boolean;
32
+ /** The max lines limit that was applied */
33
+ maxLines: number;
34
+ /** The max bytes limit that was applied */
35
+ maxBytes: number;
36
+ }
37
+ export interface TruncationOptions {
38
+ /** Maximum number of lines (default: 2000) */
39
+ maxLines?: number;
40
+ /** Maximum number of bytes (default: 50KB) */
41
+ maxBytes?: number;
42
+ }
43
+ /**
44
+ * Format bytes as human-readable size.
45
+ */
46
+ export declare function formatSize(bytes: number): string;
47
+ /**
48
+ * Truncate content from the head (keep first N lines/bytes).
49
+ * Suitable for file reads where you want to see the beginning.
50
+ *
51
+ * Never returns partial lines. If first line exceeds byte limit,
52
+ * returns empty content with firstLineExceedsLimit=true.
53
+ */
54
+ export declare function truncateHead(content: string, options?: TruncationOptions): TruncationResult;
55
+ /**
56
+ * Truncate content from the tail (keep last N lines/bytes).
57
+ * Suitable for bash output where you want to see the end (errors, final results).
58
+ *
59
+ * May return partial first line if the last line of original content exceeds byte limit.
60
+ */
61
+ export declare function truncateTail(content: string, options?: TruncationOptions): TruncationResult;
62
+ /**
63
+ * Truncate a single line to max characters, adding [truncated] suffix.
64
+ * Used for grep match lines.
65
+ */
66
+ export declare function truncateLine(line: string, maxChars?: number): {
67
+ text: string;
68
+ wasTruncated: boolean;
69
+ };
70
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;IACtC,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,eAAe,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,qBAAqB,EAAE,OAAO,CAAC;IAC/B,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAkF/F;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAyE/F;AAuBD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAA6B,GACtC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAKzC"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Shared truncation utilities for tool outputs.
3
+ *
4
+ * Truncation is based on two independent limits - whichever is hit first wins:
5
+ * - Line limit (default: 2000 lines)
6
+ * - Byte limit (default: 50KB)
7
+ *
8
+ * Never returns partial lines (except bash tail truncation edge case).
9
+ */
10
+ export const DEFAULT_MAX_LINES = 2000;
11
+ export const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB
12
+ export const GREP_MAX_LINE_LENGTH = 500; // Max chars per grep match line
13
+ /**
14
+ * Format bytes as human-readable size.
15
+ */
16
+ export function formatSize(bytes) {
17
+ if (bytes < 1024) {
18
+ return `${bytes}B`;
19
+ }
20
+ else if (bytes < 1024 * 1024) {
21
+ return `${(bytes / 1024).toFixed(1)}KB`;
22
+ }
23
+ else {
24
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
25
+ }
26
+ }
27
+ /**
28
+ * Truncate content from the head (keep first N lines/bytes).
29
+ * Suitable for file reads where you want to see the beginning.
30
+ *
31
+ * Never returns partial lines. If first line exceeds byte limit,
32
+ * returns empty content with firstLineExceedsLimit=true.
33
+ */
34
+ export function truncateHead(content, options = {}) {
35
+ const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
36
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
37
+ const totalBytes = Buffer.byteLength(content, 'utf-8');
38
+ const lines = content.split('\n');
39
+ const totalLines = lines.length;
40
+ // Check if no truncation needed
41
+ if (totalLines <= maxLines && totalBytes <= maxBytes) {
42
+ return {
43
+ content,
44
+ truncated: false,
45
+ truncatedBy: null,
46
+ totalLines,
47
+ totalBytes,
48
+ outputLines: totalLines,
49
+ outputBytes: totalBytes,
50
+ lastLinePartial: false,
51
+ firstLineExceedsLimit: false,
52
+ maxLines,
53
+ maxBytes,
54
+ };
55
+ }
56
+ // Check if first line alone exceeds byte limit
57
+ const firstLineBytes = Buffer.byteLength(lines[0] ?? '', 'utf-8');
58
+ if (firstLineBytes > maxBytes) {
59
+ return {
60
+ content: '',
61
+ truncated: true,
62
+ truncatedBy: 'bytes',
63
+ totalLines,
64
+ totalBytes,
65
+ outputLines: 0,
66
+ outputBytes: 0,
67
+ lastLinePartial: false,
68
+ firstLineExceedsLimit: true,
69
+ maxLines,
70
+ maxBytes,
71
+ };
72
+ }
73
+ // Collect complete lines that fit
74
+ const outputLinesArr = [];
75
+ let outputBytesCount = 0;
76
+ let truncatedBy = 'lines';
77
+ for (let i = 0; i < lines.length && i < maxLines; i++) {
78
+ const line = lines[i] ?? '';
79
+ const lineBytes = Buffer.byteLength(line, 'utf-8') + (i > 0 ? 1 : 0); // +1 for newline
80
+ if (outputBytesCount + lineBytes > maxBytes) {
81
+ truncatedBy = 'bytes';
82
+ break;
83
+ }
84
+ outputLinesArr.push(line);
85
+ outputBytesCount += lineBytes;
86
+ }
87
+ // If we exited due to line limit
88
+ if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
89
+ truncatedBy = 'lines';
90
+ }
91
+ const outputContent = outputLinesArr.join('\n');
92
+ const finalOutputBytes = Buffer.byteLength(outputContent, 'utf-8');
93
+ return {
94
+ content: outputContent,
95
+ truncated: true,
96
+ truncatedBy,
97
+ totalLines,
98
+ totalBytes,
99
+ outputLines: outputLinesArr.length,
100
+ outputBytes: finalOutputBytes,
101
+ lastLinePartial: false,
102
+ firstLineExceedsLimit: false,
103
+ maxLines,
104
+ maxBytes,
105
+ };
106
+ }
107
+ /**
108
+ * Truncate content from the tail (keep last N lines/bytes).
109
+ * Suitable for bash output where you want to see the end (errors, final results).
110
+ *
111
+ * May return partial first line if the last line of original content exceeds byte limit.
112
+ */
113
+ export function truncateTail(content, options = {}) {
114
+ const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
115
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
116
+ const totalBytes = Buffer.byteLength(content, 'utf-8');
117
+ const lines = content.split('\n');
118
+ const totalLines = lines.length;
119
+ // Check if no truncation needed
120
+ if (totalLines <= maxLines && totalBytes <= maxBytes) {
121
+ return {
122
+ content,
123
+ truncated: false,
124
+ truncatedBy: null,
125
+ totalLines,
126
+ totalBytes,
127
+ outputLines: totalLines,
128
+ outputBytes: totalBytes,
129
+ lastLinePartial: false,
130
+ firstLineExceedsLimit: false,
131
+ maxLines,
132
+ maxBytes,
133
+ };
134
+ }
135
+ // Work backwards from the end
136
+ const outputLinesArr = [];
137
+ let outputBytesCount = 0;
138
+ let truncatedBy = 'lines';
139
+ let lastLinePartial = false;
140
+ for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {
141
+ const line = lines[i] ?? '';
142
+ const lineBytes = Buffer.byteLength(line, 'utf-8') + (outputLinesArr.length > 0 ? 1 : 0); // +1 for newline
143
+ if (outputBytesCount + lineBytes > maxBytes) {
144
+ truncatedBy = 'bytes';
145
+ // Edge case: if we haven't added ANY lines yet and this line exceeds maxBytes,
146
+ // take the end of the line (partial)
147
+ if (outputLinesArr.length === 0) {
148
+ const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);
149
+ outputLinesArr.unshift(truncatedLine);
150
+ outputBytesCount = Buffer.byteLength(truncatedLine, 'utf-8');
151
+ lastLinePartial = true;
152
+ }
153
+ break;
154
+ }
155
+ outputLinesArr.unshift(line);
156
+ outputBytesCount += lineBytes;
157
+ }
158
+ // If we exited due to line limit
159
+ if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
160
+ truncatedBy = 'lines';
161
+ }
162
+ const outputContent = outputLinesArr.join('\n');
163
+ const finalOutputBytes = Buffer.byteLength(outputContent, 'utf-8');
164
+ return {
165
+ content: outputContent,
166
+ truncated: true,
167
+ truncatedBy,
168
+ totalLines,
169
+ totalBytes,
170
+ outputLines: outputLinesArr.length,
171
+ outputBytes: finalOutputBytes,
172
+ lastLinePartial,
173
+ firstLineExceedsLimit: false,
174
+ maxLines,
175
+ maxBytes,
176
+ };
177
+ }
178
+ /**
179
+ * Truncate a string to fit within a byte limit (from the end).
180
+ * Handles multi-byte UTF-8 characters correctly.
181
+ */
182
+ function truncateStringToBytesFromEnd(str, maxBytes) {
183
+ const buf = Buffer.from(str, 'utf-8');
184
+ if (buf.length <= maxBytes) {
185
+ return str;
186
+ }
187
+ // Start from the end, skip maxBytes back
188
+ let start = buf.length - maxBytes;
189
+ // Find a valid UTF-8 boundary (start of a character)
190
+ while (start < buf.length && ((buf[start] ?? 0) & 0xc0) === 0x80) {
191
+ start++;
192
+ }
193
+ return buf.slice(start).toString('utf-8');
194
+ }
195
+ /**
196
+ * Truncate a single line to max characters, adding [truncated] suffix.
197
+ * Used for grep match lines.
198
+ */
199
+ export function truncateLine(line, maxChars = GREP_MAX_LINE_LENGTH) {
200
+ if (line.length <= maxChars) {
201
+ return { text: line, wasTruncated: false };
202
+ }
203
+ return { text: `${line.slice(0, maxChars)}... [truncated]`, wasTruncated: true };
204
+ }
205
+ //# sourceMappingURL=truncate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AACtC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO;AACnD,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC,CAAC,gCAAgC;AAkCzE;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC;QACjB,OAAO,GAAG,KAAK,GAAG,CAAC;IACrB,CAAC;SAAM,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,UAA6B,EAAE;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IAEvD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAEhC,gCAAgC;IAChC,IAAI,UAAU,IAAI,QAAQ,IAAI,UAAU,IAAI,QAAQ,EAAE,CAAC;QACrD,OAAO;YACL,OAAO;YACP,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,IAAI;YACjB,UAAU;YACV,UAAU;YACV,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,UAAU;YACvB,eAAe,EAAE,KAAK;YACtB,qBAAqB,EAAE,KAAK;YAC5B,QAAQ;YACR,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,+CAA+C;IAC/C,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;IAClE,IAAI,cAAc,GAAG,QAAQ,EAAE,CAAC;QAC9B,OAAO;YACL,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,OAAO;YACpB,UAAU;YACV,UAAU;YACV,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,KAAK;YACtB,qBAAqB,EAAE,IAAI;YAC3B,QAAQ;YACR,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,kCAAkC;IAClC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,WAAW,GAAsB,OAAO,CAAC;IAE7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB;QAEvF,IAAI,gBAAgB,GAAG,SAAS,GAAG,QAAQ,EAAE,CAAC;YAC5C,WAAW,GAAG,OAAO,CAAC;YACtB,MAAM;QACR,CAAC;QAED,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,gBAAgB,IAAI,SAAS,CAAC;IAChC,CAAC;IAED,iCAAiC;IACjC,IAAI,cAAc,CAAC,MAAM,IAAI,QAAQ,IAAI,gBAAgB,IAAI,QAAQ,EAAE,CAAC;QACtE,WAAW,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAEnE,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,SAAS,EAAE,IAAI;QACf,WAAW;QACX,UAAU;QACV,UAAU;QACV,WAAW,EAAE,cAAc,CAAC,MAAM;QAClC,WAAW,EAAE,gBAAgB;QAC7B,eAAe,EAAE,KAAK;QACtB,qBAAqB,EAAE,KAAK;QAC5B,QAAQ;QACR,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,UAA6B,EAAE;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IAEvD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAEhC,gCAAgC;IAChC,IAAI,UAAU,IAAI,QAAQ,IAAI,UAAU,IAAI,QAAQ,EAAE,CAAC;QACrD,OAAO;YACL,OAAO;YACP,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,IAAI;YACjB,UAAU;YACV,UAAU;YACV,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,UAAU;YACvB,eAAe,EAAE,KAAK;YACtB,qBAAqB,EAAE,KAAK;YAC5B,QAAQ;YACR,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,WAAW,GAAsB,OAAO,CAAC;IAC7C,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/E,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB;QAE3G,IAAI,gBAAgB,GAAG,SAAS,GAAG,QAAQ,EAAE,CAAC;YAC5C,WAAW,GAAG,OAAO,CAAC;YACtB,+EAA+E;YAC/E,qCAAqC;YACrC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAChC,MAAM,aAAa,GAAG,4BAA4B,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBACnE,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;gBACtC,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;gBAC7D,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;YACD,MAAM;QACR,CAAC;QAED,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,gBAAgB,IAAI,SAAS,CAAC;IAChC,CAAC;IAED,iCAAiC;IACjC,IAAI,cAAc,CAAC,MAAM,IAAI,QAAQ,IAAI,gBAAgB,IAAI,QAAQ,EAAE,CAAC;QACtE,WAAW,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAEnE,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,SAAS,EAAE,IAAI;QACf,WAAW;QACX,UAAU;QACV,UAAU;QACV,WAAW,EAAE,cAAc,CAAC,MAAM;QAClC,WAAW,EAAE,gBAAgB;QAC7B,eAAe;QACf,qBAAqB,EAAE,KAAK;QAC5B,QAAQ;QACR,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,4BAA4B,CAAC,GAAW,EAAE,QAAgB;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACtC,IAAI,GAAG,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC3B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,yCAAyC;IACzC,IAAI,KAAK,GAAG,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;IAElC,qDAAqD;IACrD,OAAO,KAAK,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QACjE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,WAAmB,oBAAoB;IAEvC,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).
3
+ * Walks up from the current file's directory until it finds a package.json.
4
+ */
5
+ export declare function getPackageDir(): string;
6
+ /** Get path to package.json */
7
+ export declare function getPackageJsonPath(): string;
8
+ export declare const APP_NAME: string;
9
+ export declare const CONFIG_DIR_NAME: string;
10
+ /** Get the agent config directory (e.g., ~/.pi/agent/) */
11
+ export declare function getAgentDir(): string;
12
+ /** Get path to managed binaries directory (fd, rg) */
13
+ export declare function getBinDir(): string;
14
+ /** Get path to settings.json */
15
+ export declare function getSettingsPath(): string;
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/config.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAStC;AAED,+BAA+B;AAC/B,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAID,eAAO,MAAM,QAAQ,EAAE,MAAmC,CAAC;AAC3D,eAAO,MAAM,eAAe,EAAE,MAAyC,CAAC;AAExE,0DAA0D;AAC1D,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,gCAAgC;AAChC,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,40 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { dirname, join } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ /**
8
+ * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).
9
+ * Walks up from the current file's directory until it finds a package.json.
10
+ */
11
+ export function getPackageDir() {
12
+ let dir = __dirname;
13
+ while (dir !== dirname(dir)) {
14
+ if (existsSync(join(dir, 'package.json'))) {
15
+ return dir;
16
+ }
17
+ dir = dirname(dir);
18
+ }
19
+ return __dirname;
20
+ }
21
+ /** Get path to package.json */
22
+ export function getPackageJsonPath() {
23
+ return join(getPackageDir(), 'package.json');
24
+ }
25
+ const pkg = JSON.parse(readFileSync(getPackageJsonPath(), 'utf-8'));
26
+ export const APP_NAME = pkg.piConfig?.name || 'pi';
27
+ export const CONFIG_DIR_NAME = pkg.piConfig?.configDir || '.pi';
28
+ /** Get the agent config directory (e.g., ~/.pi/agent/) */
29
+ export function getAgentDir() {
30
+ return join(homedir(), CONFIG_DIR_NAME, 'agent');
31
+ }
32
+ /** Get path to managed binaries directory (fd, rg) */
33
+ export function getBinDir() {
34
+ return join(getAgentDir(), 'bin');
35
+ }
36
+ /** Get path to settings.json */
37
+ export function getSettingsPath() {
38
+ return join(getAgentDir(), 'settings.json');
39
+ }
40
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/tools/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,OAAO,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC1C,OAAO,GAAG,CAAC;QACb,CAAC;QACD,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,cAAc,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE,MAAM,CAAC,MAAM,QAAQ,GAAW,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,IAAI,CAAC;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAW,GAAG,CAAC,QAAQ,EAAE,SAAS,IAAI,KAAK,CAAC;AAExE,0DAA0D;AAC1D,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { ImageContent } from '@ank1015/llm-sdk';
2
+ export interface ImageResizeOptions {
3
+ maxWidth?: number;
4
+ maxHeight?: number;
5
+ maxBytes?: number;
6
+ jpegQuality?: number;
7
+ }
8
+ export interface ResizedImage {
9
+ data: string;
10
+ mimeType: string;
11
+ originalWidth: number;
12
+ originalHeight: number;
13
+ width: number;
14
+ height: number;
15
+ wasResized: boolean;
16
+ }
17
+ /**
18
+ * Resize an image to fit within the specified max dimensions and file size.
19
+ * Returns the original image if it already fits within the limits.
20
+ *
21
+ * Uses Photon (Rust/WASM) for image processing. If Photon is not available,
22
+ * returns the original image unchanged.
23
+ *
24
+ * Strategy for staying under maxBytes:
25
+ * 1. First resize to maxWidth/maxHeight
26
+ * 2. Try both PNG and JPEG formats, pick the smaller one
27
+ * 3. If still too large, try JPEG with decreasing quality
28
+ * 4. If still too large, progressively reduce dimensions
29
+ */
30
+ export declare function resizeImage(img: ImageContent, options?: ImageResizeOptions): Promise<ResizedImage>;
31
+ /**
32
+ * Format a dimension note for resized images.
33
+ * This helps the model understand the coordinate mapping.
34
+ */
35
+ export declare function formatDimensionNote(result: ResizedImage): string | undefined;
36
+ //# sourceMappingURL=image-resize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-resize.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/image-resize.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAoBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,YAAY,EACjB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,CAAC,CA0KvB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAO5E"}
@@ -0,0 +1,183 @@
1
+ import { loadPhoton } from './photon.js';
2
+ // 4.5MB - provides headroom below Anthropic's 5MB limit
3
+ const DEFAULT_MAX_BYTES = 4.5 * 1024 * 1024;
4
+ const DEFAULT_OPTIONS = {
5
+ maxWidth: 2000,
6
+ maxHeight: 2000,
7
+ maxBytes: DEFAULT_MAX_BYTES,
8
+ jpegQuality: 80,
9
+ };
10
+ /** Helper to pick the smaller of two buffers */
11
+ function pickSmaller(a, b) {
12
+ return a.buffer.length <= b.buffer.length ? a : b;
13
+ }
14
+ /**
15
+ * Resize an image to fit within the specified max dimensions and file size.
16
+ * Returns the original image if it already fits within the limits.
17
+ *
18
+ * Uses Photon (Rust/WASM) for image processing. If Photon is not available,
19
+ * returns the original image unchanged.
20
+ *
21
+ * Strategy for staying under maxBytes:
22
+ * 1. First resize to maxWidth/maxHeight
23
+ * 2. Try both PNG and JPEG formats, pick the smaller one
24
+ * 3. If still too large, try JPEG with decreasing quality
25
+ * 4. If still too large, progressively reduce dimensions
26
+ */
27
+ export async function resizeImage(img, options) {
28
+ const opts = { ...DEFAULT_OPTIONS, ...options };
29
+ const inputBuffer = Buffer.from(img.data, 'base64');
30
+ const photon = await loadPhoton();
31
+ if (!photon) {
32
+ // Photon not available, return original image
33
+ return {
34
+ data: img.data,
35
+ mimeType: img.mimeType,
36
+ originalWidth: 0,
37
+ originalHeight: 0,
38
+ width: 0,
39
+ height: 0,
40
+ wasResized: false,
41
+ };
42
+ }
43
+ let image;
44
+ try {
45
+ image = photon.PhotonImage.new_from_byteslice(new Uint8Array(inputBuffer));
46
+ const originalWidth = image.get_width();
47
+ const originalHeight = image.get_height();
48
+ const format = img.mimeType?.split('/')[1] ?? 'png';
49
+ // Check if already within all limits (dimensions AND size)
50
+ const originalSize = inputBuffer.length;
51
+ if (originalWidth <= opts.maxWidth &&
52
+ originalHeight <= opts.maxHeight &&
53
+ originalSize <= opts.maxBytes) {
54
+ return {
55
+ data: img.data,
56
+ mimeType: img.mimeType ?? `image/${format}`,
57
+ originalWidth,
58
+ originalHeight,
59
+ width: originalWidth,
60
+ height: originalHeight,
61
+ wasResized: false,
62
+ };
63
+ }
64
+ // Calculate initial dimensions respecting max limits
65
+ let targetWidth = originalWidth;
66
+ let targetHeight = originalHeight;
67
+ if (targetWidth > opts.maxWidth) {
68
+ targetHeight = Math.round((targetHeight * opts.maxWidth) / targetWidth);
69
+ targetWidth = opts.maxWidth;
70
+ }
71
+ if (targetHeight > opts.maxHeight) {
72
+ targetWidth = Math.round((targetWidth * opts.maxHeight) / targetHeight);
73
+ targetHeight = opts.maxHeight;
74
+ }
75
+ // Helper to resize and encode in both formats, returning the smaller one
76
+ function tryBothFormats(width, height, jpegQuality) {
77
+ const resized = photon.resize(image, width, height, photon.SamplingFilter.Lanczos3);
78
+ try {
79
+ const pngBuffer = resized.get_bytes();
80
+ const jpegBuffer = resized.get_bytes_jpeg(jpegQuality);
81
+ return pickSmaller({ buffer: pngBuffer, mimeType: 'image/png' }, { buffer: jpegBuffer, mimeType: 'image/jpeg' });
82
+ }
83
+ finally {
84
+ resized.free();
85
+ }
86
+ }
87
+ // Try to produce an image under maxBytes
88
+ const qualitySteps = [85, 70, 55, 40];
89
+ const scaleSteps = [1.0, 0.75, 0.5, 0.35, 0.25];
90
+ let best;
91
+ let finalWidth = targetWidth;
92
+ let finalHeight = targetHeight;
93
+ // First attempt: resize to target dimensions, try both formats
94
+ best = tryBothFormats(targetWidth, targetHeight, opts.jpegQuality);
95
+ if (best.buffer.length <= opts.maxBytes) {
96
+ return {
97
+ data: Buffer.from(best.buffer).toString('base64'),
98
+ mimeType: best.mimeType,
99
+ originalWidth,
100
+ originalHeight,
101
+ width: finalWidth,
102
+ height: finalHeight,
103
+ wasResized: true,
104
+ };
105
+ }
106
+ // Still too large - try JPEG with decreasing quality
107
+ for (const quality of qualitySteps) {
108
+ best = tryBothFormats(targetWidth, targetHeight, quality);
109
+ if (best.buffer.length <= opts.maxBytes) {
110
+ return {
111
+ data: Buffer.from(best.buffer).toString('base64'),
112
+ mimeType: best.mimeType,
113
+ originalWidth,
114
+ originalHeight,
115
+ width: finalWidth,
116
+ height: finalHeight,
117
+ wasResized: true,
118
+ };
119
+ }
120
+ }
121
+ // Still too large - reduce dimensions progressively
122
+ for (const scale of scaleSteps) {
123
+ finalWidth = Math.round(targetWidth * scale);
124
+ finalHeight = Math.round(targetHeight * scale);
125
+ if (finalWidth < 100 || finalHeight < 100) {
126
+ break;
127
+ }
128
+ for (const quality of qualitySteps) {
129
+ best = tryBothFormats(finalWidth, finalHeight, quality);
130
+ if (best.buffer.length <= opts.maxBytes) {
131
+ return {
132
+ data: Buffer.from(best.buffer).toString('base64'),
133
+ mimeType: best.mimeType,
134
+ originalWidth,
135
+ originalHeight,
136
+ width: finalWidth,
137
+ height: finalHeight,
138
+ wasResized: true,
139
+ };
140
+ }
141
+ }
142
+ }
143
+ // Last resort: return smallest version we produced
144
+ return {
145
+ data: Buffer.from(best.buffer).toString('base64'),
146
+ mimeType: best.mimeType,
147
+ originalWidth,
148
+ originalHeight,
149
+ width: finalWidth,
150
+ height: finalHeight,
151
+ wasResized: true,
152
+ };
153
+ }
154
+ catch {
155
+ // Failed to load image
156
+ return {
157
+ data: img.data,
158
+ mimeType: img.mimeType,
159
+ originalWidth: 0,
160
+ originalHeight: 0,
161
+ width: 0,
162
+ height: 0,
163
+ wasResized: false,
164
+ };
165
+ }
166
+ finally {
167
+ if (image) {
168
+ image.free();
169
+ }
170
+ }
171
+ }
172
+ /**
173
+ * Format a dimension note for resized images.
174
+ * This helps the model understand the coordinate mapping.
175
+ */
176
+ export function formatDimensionNote(result) {
177
+ if (!result.wasResized) {
178
+ return undefined;
179
+ }
180
+ const scale = result.originalWidth / result.width;
181
+ return `[Image: original ${result.originalWidth}x${result.originalHeight}, displayed at ${result.width}x${result.height}. Multiply coordinates by ${scale.toFixed(2)} to map to original image.]`;
182
+ }
183
+ //# sourceMappingURL=image-resize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-resize.js","sourceRoot":"","sources":["../../../src/tools/utils/image-resize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function detectSupportedBinaryMimeTypeFromBuffer(buffer: Buffer): Promise<string | null>;
2
+ export declare function detectSupportedImageMimeTypeFromFile(filePath: string): Promise<string | null>;
3
+ //# sourceMappingURL=mime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../../../src/tools/utils/mime.ts"],"names":[],"mappings":"AASA,wBAAsB,uCAAuC,CAC3D,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBxB;AAED,wBAAsB,oCAAoC,CACxD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsBxB"}
@@ -0,0 +1,41 @@
1
+ import { open } from 'node:fs/promises';
2
+ import { fileTypeFromBuffer } from 'file-type';
3
+ const IMAGE_MIME_TYPES = new Set(['image/jpeg', 'image/png', 'image/gif', 'image/webp']);
4
+ const PDF_SIGNATURE = Buffer.from('%PDF-');
5
+ const FILE_TYPE_SNIFF_BYTES = 4100;
6
+ export async function detectSupportedBinaryMimeTypeFromBuffer(buffer) {
7
+ if (buffer.length >= PDF_SIGNATURE.length &&
8
+ buffer.subarray(0, PDF_SIGNATURE.length).equals(PDF_SIGNATURE)) {
9
+ return 'application/pdf';
10
+ }
11
+ const fileType = await fileTypeFromBuffer(buffer);
12
+ if (!fileType) {
13
+ return null;
14
+ }
15
+ if (!IMAGE_MIME_TYPES.has(fileType.mime)) {
16
+ return null;
17
+ }
18
+ return fileType.mime;
19
+ }
20
+ export async function detectSupportedImageMimeTypeFromFile(filePath) {
21
+ const fileHandle = await open(filePath, 'r');
22
+ try {
23
+ const buffer = Buffer.alloc(FILE_TYPE_SNIFF_BYTES);
24
+ const { bytesRead } = await fileHandle.read(buffer, 0, FILE_TYPE_SNIFF_BYTES, 0);
25
+ if (bytesRead === 0) {
26
+ return null;
27
+ }
28
+ const fileType = await fileTypeFromBuffer(buffer.subarray(0, bytesRead));
29
+ if (!fileType) {
30
+ return null;
31
+ }
32
+ if (!IMAGE_MIME_TYPES.has(fileType.mime)) {
33
+ return null;
34
+ }
35
+ return fileType.mime;
36
+ }
37
+ finally {
38
+ await fileHandle.close();
39
+ }
40
+ }
41
+ //# sourceMappingURL=mime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime.js","sourceRoot":"","sources":["../../../src/tools/utils/mime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;AACzF,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAE3C,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAC3D,MAAc;IAEd,IACE,MAAM,CAAC,MAAM,IAAI,aAAa,CAAC,MAAM;QACrC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAC9D,CAAC;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oCAAoC,CACxD,QAAgB;IAEhB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACnD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC;QACjF,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC"}