@poe-platform/safe-bash 0.1.759 → 0.1.760
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.
- package/dist/image-ast/index.browser.js +26 -11
- package/dist/image-ast/index.js +26 -11
- package/dist/pdf-ast/ast.d.ts +8 -3
- package/dist/pdf-ast/index.js +30 -14
- package/dist/safe-bash/chunks/{chunk-AYPUGSOV.js → chunk-CRQDMBQA.js} +123 -8
- package/dist/safe-bash/command-chunks/{chunk-HVEAK3OS.js → chunk-MC4XXPQJ.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-BAUGDXLZ.js → chunk-S3SCPBHC.js} +26 -11
- package/dist/safe-bash/command-chunks/{chunk-7JA44PVV.js → chunk-UCI6ZQFB.js} +1 -1
- package/dist/safe-bash/commands/python/index.browser.js +1 -1
- package/dist/safe-bash/commands/python/index.d.ts +1 -1
- package/dist/safe-bash/commands/python/llm-capability.d.ts +7 -3
- package/dist/safe-bash/commands/python/llm-capability.js +149 -10
- package/dist/safe-bash/core.browser.js +1 -1
- package/dist/safe-bash-command-ffmpeg/index.js +2929 -2921
- package/dist/safe-bash-command-gh/index.js +128 -27
- package/dist/safe-bash-command-imagemagick/index.js +2 -2
- package/dist/safe-bash-command-pandoc/command.js +3 -3
- package/dist/safe-bash-command-pandoc/index.js +3 -3
- package/dist/safe-bash-command-pdfimages/index.js +26 -11
- package/dist/safe-bash-command-pdfinfo/index.js +30 -14
- package/dist/safe-bash-command-pdftk/index.js +26 -11
- package/dist/safe-bash-command-pdftoppm/index.js +30 -14
- package/dist/safe-bash-command-pdftotext/index.js +26 -11
- package/dist/safe-bash-command-qpdf/index.js +26 -11
- package/dist/safe-bash-command-sips/index.js +2 -2
- package/dist/safe-bash-command-soffice/index.js +1 -1
- package/dist/safe-bash-command-ssconvert/index.js +26 -11
- package/dist/safe-bash-command-wkhtmltopdf/index.js +26 -11
- package/dist/safe-bash-io-engine/internal.d.ts +2 -2
- package/dist/safe-bash-mcp/index.d.ts +1 -1
- package/package.json +2 -2
- package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +8 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { CommandContext } from '../../contracts/index.js';
|
|
2
2
|
import type { LlmService } from '../llm/service.js';
|
|
3
3
|
import type { PythonHostCapability } from './host-capabilities.js';
|
|
4
|
-
|
|
5
|
-
export declare function createPythonLlmCapability(context: Pick<CommandContext, 'fs' | 'cwd' | 'inputBudget'>, service: LlmService, options?: {
|
|
4
|
+
export interface PythonLlmCapabilityOptions {
|
|
6
5
|
readonly maxStreamChunkBytes?: number;
|
|
7
|
-
|
|
6
|
+
readonly maxBufferedResponseBytes?: number;
|
|
7
|
+
readonly maxBufferedEvents?: number;
|
|
8
|
+
readonly maxMetadataBytes?: number;
|
|
9
|
+
}
|
|
10
|
+
/** Reuses the invocation's authorized service; Python receives only model data. */
|
|
11
|
+
export declare function createPythonLlmCapability(context: Pick<CommandContext, 'fs' | 'cwd' | 'inputBudget'>, service: LlmService, options?: PythonLlmCapabilityOptions): PythonHostCapability;
|
|
8
12
|
//# sourceMappingURL=llm-capability.d.ts.map
|
|
@@ -5,11 +5,112 @@ function record(value) {
|
|
|
5
5
|
throw new TypeError('Expected a structured Python LLM request');
|
|
6
6
|
return value;
|
|
7
7
|
}
|
|
8
|
+
/** Count the wire representation before retaining/serializing host metadata. */
|
|
9
|
+
function jsonBytes(value, limit) {
|
|
10
|
+
if (limit === Infinity)
|
|
11
|
+
return 0;
|
|
12
|
+
let bytes = 0;
|
|
13
|
+
const ancestors = new Set();
|
|
14
|
+
const add = (size) => {
|
|
15
|
+
if (size > limit - bytes)
|
|
16
|
+
throw new RangeError('Python LLM serialized response limit exceeded');
|
|
17
|
+
bytes += size;
|
|
18
|
+
};
|
|
19
|
+
const string = (text) => {
|
|
20
|
+
add(2);
|
|
21
|
+
if (text.length > limit - bytes)
|
|
22
|
+
throw new RangeError('Python LLM serialized response limit exceeded');
|
|
23
|
+
for (let i = 0; i < text.length; i++) {
|
|
24
|
+
const point = text.codePointAt(i);
|
|
25
|
+
if (point > 65535) {
|
|
26
|
+
add(4);
|
|
27
|
+
i++;
|
|
28
|
+
}
|
|
29
|
+
else if (point === 34 || point === 92)
|
|
30
|
+
add(2);
|
|
31
|
+
else if (point < 32)
|
|
32
|
+
add([8, 9, 10, 12, 13].includes(point) ? 2 : 6);
|
|
33
|
+
else if (point >= 0xd800 && point <= 0xdfff)
|
|
34
|
+
add(6);
|
|
35
|
+
else
|
|
36
|
+
add(point < 128 ? 1 : point < 2048 ? 2 : 3);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const visit = (item) => {
|
|
40
|
+
if (typeof item === 'string') {
|
|
41
|
+
string(item);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (item === null || typeof item === 'boolean' || typeof item === 'number' && Number.isFinite(item)) {
|
|
45
|
+
add(JSON.stringify(item).length);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!item || typeof item !== 'object' || ancestors.has(item))
|
|
49
|
+
throw new TypeError('Python LLM response must contain acyclic data');
|
|
50
|
+
ancestors.add(item);
|
|
51
|
+
add(2);
|
|
52
|
+
let entries = 0;
|
|
53
|
+
if (Array.isArray(item)) {
|
|
54
|
+
if (item.length > limit - bytes)
|
|
55
|
+
throw new RangeError('Python LLM serialized response limit exceeded');
|
|
56
|
+
for (let i = 0; i < item.length; i++) {
|
|
57
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, String(i));
|
|
58
|
+
if (!descriptor || !('value' in descriptor))
|
|
59
|
+
throw new TypeError('Python LLM response must contain data');
|
|
60
|
+
if (entries++)
|
|
61
|
+
add(1);
|
|
62
|
+
visit(descriptor.value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
for (const key in item) {
|
|
67
|
+
if (!Object.hasOwn(item, key))
|
|
68
|
+
continue;
|
|
69
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
70
|
+
if (!('value' in descriptor))
|
|
71
|
+
throw new TypeError('Python LLM response must contain data');
|
|
72
|
+
if (entries++)
|
|
73
|
+
add(1);
|
|
74
|
+
string(key);
|
|
75
|
+
add(1);
|
|
76
|
+
visit(descriptor.value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
ancestors.delete(item);
|
|
80
|
+
};
|
|
81
|
+
visit(value);
|
|
82
|
+
return bytes;
|
|
83
|
+
}
|
|
84
|
+
function* textFragments(text, limit) {
|
|
85
|
+
let start = 0, bytes = 0;
|
|
86
|
+
for (let i = 0; i < text.length;) {
|
|
87
|
+
const point = text.codePointAt(i);
|
|
88
|
+
const width = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
|
|
89
|
+
if (width > limit)
|
|
90
|
+
throw new RangeError('Python LLM stream chunk limit cannot fit a Unicode scalar');
|
|
91
|
+
if (width > limit - bytes) {
|
|
92
|
+
yield text.slice(start, i);
|
|
93
|
+
start = i;
|
|
94
|
+
bytes = 0;
|
|
95
|
+
}
|
|
96
|
+
bytes += width;
|
|
97
|
+
i += point > 65535 ? 2 : 1;
|
|
98
|
+
}
|
|
99
|
+
if (start < text.length || !text.length)
|
|
100
|
+
yield text.slice(start);
|
|
101
|
+
}
|
|
8
102
|
/** Reuses the invocation's authorized service; Python receives only model data. */
|
|
9
103
|
export function createPythonLlmCapability(context, service, options = {}) {
|
|
10
104
|
const chunkBytes = options.maxStreamChunkBytes ?? 16384;
|
|
11
105
|
if (!Number.isSafeInteger(chunkBytes) || chunkBytes < 1)
|
|
12
106
|
throw new RangeError('Invalid Python LLM stream chunk limit');
|
|
107
|
+
const bufferedLimit = options.maxBufferedResponseBytes ?? Infinity;
|
|
108
|
+
const eventLimit = options.maxBufferedEvents ?? bufferedLimit;
|
|
109
|
+
const metadataLimit = options.maxMetadataBytes ?? bufferedLimit;
|
|
110
|
+
for (const limit of [bufferedLimit, eventLimit, metadataLimit]) {
|
|
111
|
+
if (limit !== Infinity && (!Number.isSafeInteger(limit) || limit < 1))
|
|
112
|
+
throw new RangeError('Invalid Python LLM host limit');
|
|
113
|
+
}
|
|
13
114
|
const prepare = async (value, signal) => {
|
|
14
115
|
const payload = record(value);
|
|
15
116
|
for (const key of ['template', 'conversation']) {
|
|
@@ -73,8 +174,16 @@ export function createPythonLlmCapability(context, service, options = {}) {
|
|
|
73
174
|
yield { type: 'bytes', data: Array.from(event.data.subarray(offset, offset + chunkBytes)) };
|
|
74
175
|
}
|
|
75
176
|
}
|
|
76
|
-
else
|
|
177
|
+
else if (event.type === 'text') {
|
|
178
|
+
for (const text of textFragments(event.text, chunkBytes)) {
|
|
179
|
+
request.signal.throwIfAborted();
|
|
180
|
+
yield { type: 'text', text };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
jsonBytes(event.response, metadataLimit);
|
|
77
185
|
yield event;
|
|
186
|
+
}
|
|
78
187
|
}
|
|
79
188
|
};
|
|
80
189
|
return {
|
|
@@ -93,19 +202,49 @@ export function createPythonLlmCapability(context, service, options = {}) {
|
|
|
93
202
|
}
|
|
94
203
|
if (operation.operation !== 'complete')
|
|
95
204
|
throw new TypeError('Unsupported Python LLM operation');
|
|
96
|
-
const
|
|
205
|
+
const request = await prepare(payload, signal);
|
|
206
|
+
const bounded = { ...request, maxOutputBytes: Math.min(request.maxOutputBytes ?? Infinity, bufferedLimit) };
|
|
207
|
+
let text = '', textBytes = 0, dataBytes = 0, received = 0;
|
|
208
|
+
const data = [];
|
|
97
209
|
let response = {};
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
210
|
+
let envelopeBytes = jsonBytes({ text: '', data: [] }, bufferedLimit);
|
|
211
|
+
const admit = (size) => {
|
|
212
|
+
if (size > bufferedLimit - envelopeBytes - textBytes - dataBytes)
|
|
213
|
+
throw new RangeError('Python LLM buffered response limit exceeded');
|
|
214
|
+
};
|
|
215
|
+
for await (const event of service.stream(bounded)) {
|
|
216
|
+
bounded.signal.throwIfAborted();
|
|
217
|
+
if (++received > eventLimit)
|
|
218
|
+
throw new RangeError('Python LLM buffered event limit exceeded');
|
|
219
|
+
if (event.type === 'text') {
|
|
220
|
+
const size = bufferedLimit === Infinity || !event.text ? 0 : jsonBytes(event.text, bufferedLimit - envelopeBytes - textBytes - dataBytes + 2) - 2;
|
|
221
|
+
admit(size);
|
|
222
|
+
textBytes += size;
|
|
223
|
+
if (event.text)
|
|
224
|
+
text += event.text;
|
|
225
|
+
}
|
|
226
|
+
else if (event.type === 'bytes') {
|
|
227
|
+
let size = 0;
|
|
228
|
+
if (bufferedLimit !== Infinity)
|
|
229
|
+
for (let i = 0; i < event.data.length; i++) {
|
|
230
|
+
size += String(event.data[i]).length + (data.length || i ? 1 : 0);
|
|
231
|
+
admit(size);
|
|
232
|
+
}
|
|
233
|
+
dataBytes += size;
|
|
103
234
|
for (const byte of event.data)
|
|
104
235
|
data.push(byte);
|
|
105
|
-
|
|
106
|
-
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
jsonBytes(event.response, metadataLimit);
|
|
239
|
+
const details = record(event.response);
|
|
240
|
+
const size = jsonBytes({ ...details, text: '', data: [] }, bufferedLimit);
|
|
241
|
+
if (size > bufferedLimit - textBytes - dataBytes)
|
|
242
|
+
throw new RangeError('Python LLM buffered response limit exceeded');
|
|
243
|
+
envelopeBytes = size;
|
|
244
|
+
response = { ...details };
|
|
245
|
+
}
|
|
107
246
|
}
|
|
108
|
-
return { ...response, text
|
|
247
|
+
return { ...response, text, data };
|
|
109
248
|
},
|
|
110
249
|
stream: events,
|
|
111
250
|
};
|