@ljoukov/llm 7.0.14 → 7.0.16
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/README.md +51 -0
- package/dist/index.cjs +166 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -2
- package/dist/index.d.ts +66 -2
- package/dist/index.js +162 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -699,6 +699,57 @@ console.log(result.text);
|
|
|
699
699
|
|
|
700
700
|
`{ type: "shell" }` uses OpenAI hosted shell containers by default. It is only supported for OpenAI API models; ChatGPT-authenticated, Gemini, and Fireworks providers reject it.
|
|
701
701
|
|
|
702
|
+
When the shell writes artifacts under `/mnt/data`, `generateText()` returns the
|
|
703
|
+
OpenAI container reference and the library can retrieve the resulting files:
|
|
704
|
+
|
|
705
|
+
```ts
|
|
706
|
+
import { downloadOpenAiContainerFile, generateText, listOpenAiContainerFiles } from "@ljoukov/llm";
|
|
707
|
+
|
|
708
|
+
const result = await generateText({
|
|
709
|
+
model: "gpt-5.5",
|
|
710
|
+
input:
|
|
711
|
+
"Use the shell to write /mnt/data/report.txt containing 'hello'. Reply only when done.",
|
|
712
|
+
tools: [{ type: "shell" }],
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
const containerId = result.openAi?.containers.find((c) => c.toolType === "shell")?.containerId;
|
|
716
|
+
if (!containerId) throw new Error("The response did not include a hosted shell container.");
|
|
717
|
+
|
|
718
|
+
const files = await listOpenAiContainerFiles(containerId);
|
|
719
|
+
const report = files.find((file) => file.path === "/mnt/data/report.txt");
|
|
720
|
+
if (!report) throw new Error("The shell did not create report.txt.");
|
|
721
|
+
|
|
722
|
+
const bytes = await downloadOpenAiContainerFile({
|
|
723
|
+
containerId,
|
|
724
|
+
fileId: report.id,
|
|
725
|
+
});
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
For persistent multi-step shell work, create a container first, upload any input
|
|
729
|
+
assets, then pass it back as a `container-reference`:
|
|
730
|
+
|
|
731
|
+
```ts
|
|
732
|
+
import {
|
|
733
|
+
createOpenAiContainer,
|
|
734
|
+
generateText,
|
|
735
|
+
uploadOpenAiContainerFile,
|
|
736
|
+
} from "@ljoukov/llm";
|
|
737
|
+
|
|
738
|
+
const container = await createOpenAiContainer({ name: "latex-build", memoryLimit: "1g" });
|
|
739
|
+
const cover = await uploadOpenAiContainerFile({
|
|
740
|
+
containerId: container.id,
|
|
741
|
+
filename: "cover.png",
|
|
742
|
+
data: coverPngBytes,
|
|
743
|
+
mimeType: "image/png",
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
await generateText({
|
|
747
|
+
model: "gpt-5.5",
|
|
748
|
+
input: `Use ${cover.path}, write LaTeX, run xelatex, and save /mnt/data/article.pdf.`,
|
|
749
|
+
tools: [{ type: "shell", environment: { type: "container-reference", containerId: container.id } }],
|
|
750
|
+
});
|
|
751
|
+
```
|
|
752
|
+
|
|
702
753
|
### Runtime Tools (`runToolLoop()`)
|
|
703
754
|
|
|
704
755
|
Use this when the model should call your local runtime functions.
|
package/dist/index.cjs
CHANGED
|
@@ -84,12 +84,16 @@ __export(index_exports, {
|
|
|
84
84
|
createListDirectoryTool: () => createListDirectoryTool,
|
|
85
85
|
createModelAgnosticFilesystemToolSet: () => createModelAgnosticFilesystemToolSet,
|
|
86
86
|
createNodeAgentFilesystem: () => createNodeAgentFilesystem,
|
|
87
|
+
createOpenAiContainer: () => createOpenAiContainer,
|
|
87
88
|
createReplaceTool: () => createReplaceTool,
|
|
88
89
|
createRgSearchTool: () => createRgSearchTool,
|
|
89
90
|
createToolLoopSteeringChannel: () => createToolLoopSteeringChannel,
|
|
90
91
|
createViewImageTool: () => createViewImageTool,
|
|
91
92
|
createWriteFileTool: () => createWriteFileTool,
|
|
92
93
|
customTool: () => customTool,
|
|
94
|
+
deleteOpenAiContainer: () => deleteOpenAiContainer,
|
|
95
|
+
downloadOpenAiContainerFile: () => downloadOpenAiContainerFile,
|
|
96
|
+
downloadOpenAiContainerFileText: () => downloadOpenAiContainerFileText,
|
|
93
97
|
emptyFileUploadMetrics: () => emptyFileUploadMetrics,
|
|
94
98
|
encodeChatGptAuthJson: () => encodeChatGptAuthJson,
|
|
95
99
|
encodeChatGptAuthJsonB64: () => encodeChatGptAuthJsonB64,
|
|
@@ -114,6 +118,7 @@ __export(index_exports, {
|
|
|
114
118
|
isLlmTextModelId: () => isLlmTextModelId,
|
|
115
119
|
isOpenAiImageModelId: () => isOpenAiImageModelId,
|
|
116
120
|
isOpenAiModelId: () => isOpenAiModelId,
|
|
121
|
+
listOpenAiContainerFiles: () => listOpenAiContainerFiles,
|
|
117
122
|
loadEnvFromFile: () => loadEnvFromFile,
|
|
118
123
|
loadLocalEnv: () => loadLocalEnv,
|
|
119
124
|
parseJsonFromLlmText: () => parseJsonFromLlmText,
|
|
@@ -134,6 +139,7 @@ __export(index_exports, {
|
|
|
134
139
|
stripCodexCitationMarkers: () => stripCodexCitationMarkers,
|
|
135
140
|
toGeminiJsonSchema: () => toGeminiJsonSchema,
|
|
136
141
|
tool: () => tool,
|
|
142
|
+
uploadOpenAiContainerFile: () => uploadOpenAiContainerFile,
|
|
137
143
|
validateOpenAiGptImage2Resolution: () => validateOpenAiGptImage2Resolution
|
|
138
144
|
});
|
|
139
145
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -5328,6 +5334,8 @@ function resolveOpenAiReasoningEffort(modelId, thinkingLevel) {
|
|
|
5328
5334
|
case "medium":
|
|
5329
5335
|
return "medium";
|
|
5330
5336
|
case "high":
|
|
5337
|
+
return "high";
|
|
5338
|
+
case "xhigh":
|
|
5331
5339
|
return "xhigh";
|
|
5332
5340
|
}
|
|
5333
5341
|
}
|
|
@@ -5345,7 +5353,7 @@ function toOpenAiReasoningEffort(effort) {
|
|
|
5345
5353
|
case "high":
|
|
5346
5354
|
return "high";
|
|
5347
5355
|
case "xhigh":
|
|
5348
|
-
return "
|
|
5356
|
+
return "xhigh";
|
|
5349
5357
|
}
|
|
5350
5358
|
}
|
|
5351
5359
|
function resolveOpenAiVerbosity(modelId) {
|
|
@@ -6462,6 +6470,50 @@ function toOpenAiTools(tools, options) {
|
|
|
6462
6470
|
}
|
|
6463
6471
|
});
|
|
6464
6472
|
}
|
|
6473
|
+
function extractOpenAiResponseMetadata(response) {
|
|
6474
|
+
if (!response || typeof response !== "object") {
|
|
6475
|
+
return void 0;
|
|
6476
|
+
}
|
|
6477
|
+
const record = response;
|
|
6478
|
+
const responseId = typeof record.id === "string" ? record.id : void 0;
|
|
6479
|
+
const output = Array.isArray(record.output) ? record.output : [];
|
|
6480
|
+
const containers = [];
|
|
6481
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6482
|
+
const addContainer = (container) => {
|
|
6483
|
+
const key = `${container.toolType}:${container.containerId}:${container.itemId ?? ""}:${container.callId ?? ""}`;
|
|
6484
|
+
if (seen.has(key)) {
|
|
6485
|
+
return;
|
|
6486
|
+
}
|
|
6487
|
+
seen.add(key);
|
|
6488
|
+
containers.push(container);
|
|
6489
|
+
};
|
|
6490
|
+
for (const item of output) {
|
|
6491
|
+
if (!item || typeof item !== "object") {
|
|
6492
|
+
continue;
|
|
6493
|
+
}
|
|
6494
|
+
const itemRecord = item;
|
|
6495
|
+
const itemId = typeof itemRecord.id === "string" ? itemRecord.id : void 0;
|
|
6496
|
+
const callId = typeof itemRecord.call_id === "string" ? itemRecord.call_id : void 0;
|
|
6497
|
+
if (itemRecord.type === "shell_call") {
|
|
6498
|
+
const environment = itemRecord.environment && typeof itemRecord.environment === "object" ? itemRecord.environment : void 0;
|
|
6499
|
+
const containerId = environment?.type === "container_reference" && typeof environment.container_id === "string" ? environment.container_id : void 0;
|
|
6500
|
+
if (containerId) {
|
|
6501
|
+
addContainer({ containerId, toolType: "shell", itemId, callId });
|
|
6502
|
+
}
|
|
6503
|
+
continue;
|
|
6504
|
+
}
|
|
6505
|
+
if (itemRecord.type === "code_interpreter_call") {
|
|
6506
|
+
const containerId = typeof itemRecord.container_id === "string" ? itemRecord.container_id : void 0;
|
|
6507
|
+
if (containerId) {
|
|
6508
|
+
addContainer({ containerId, toolType: "code_interpreter", itemId, callId });
|
|
6509
|
+
}
|
|
6510
|
+
}
|
|
6511
|
+
}
|
|
6512
|
+
if (!responseId && containers.length === 0) {
|
|
6513
|
+
return void 0;
|
|
6514
|
+
}
|
|
6515
|
+
return { ...responseId ? { responseId } : {}, containers };
|
|
6516
|
+
}
|
|
6465
6517
|
function mergeTokenUpdates(current, next) {
|
|
6466
6518
|
if (!next) {
|
|
6467
6519
|
return current;
|
|
@@ -7594,6 +7646,7 @@ function toGeminiThinkingLevel(thinkingLevel) {
|
|
|
7594
7646
|
case "medium":
|
|
7595
7647
|
return import_genai2.ThinkingLevel.MEDIUM;
|
|
7596
7648
|
case "high":
|
|
7649
|
+
case "xhigh":
|
|
7597
7650
|
return import_genai2.ThinkingLevel.HIGH;
|
|
7598
7651
|
}
|
|
7599
7652
|
}
|
|
@@ -7636,6 +7689,7 @@ function resolveGeminiThinkingBudget(modelId, thinkingLevel) {
|
|
|
7636
7689
|
case "medium":
|
|
7637
7690
|
return 4096;
|
|
7638
7691
|
case "high":
|
|
7692
|
+
case "xhigh":
|
|
7639
7693
|
return 32768;
|
|
7640
7694
|
}
|
|
7641
7695
|
}
|
|
@@ -7646,6 +7700,7 @@ function resolveGeminiThinkingBudget(modelId, thinkingLevel) {
|
|
|
7646
7700
|
case "medium":
|
|
7647
7701
|
return 8192;
|
|
7648
7702
|
case "high":
|
|
7703
|
+
case "xhigh":
|
|
7649
7704
|
return 24576;
|
|
7650
7705
|
}
|
|
7651
7706
|
}
|
|
@@ -7656,6 +7711,7 @@ function resolveGeminiThinkingBudget(modelId, thinkingLevel) {
|
|
|
7656
7711
|
case "medium":
|
|
7657
7712
|
return 8192;
|
|
7658
7713
|
case "high":
|
|
7714
|
+
case "xhigh":
|
|
7659
7715
|
return 16384;
|
|
7660
7716
|
}
|
|
7661
7717
|
}
|
|
@@ -8073,6 +8129,7 @@ async function runTextCall(params) {
|
|
|
8073
8129
|
let modelVersion = request.model;
|
|
8074
8130
|
let blocked = false;
|
|
8075
8131
|
let grounding;
|
|
8132
|
+
let openAi;
|
|
8076
8133
|
const responseParts = [];
|
|
8077
8134
|
let responseRole;
|
|
8078
8135
|
let latestUsage;
|
|
@@ -8183,6 +8240,7 @@ async function runTextCall(params) {
|
|
|
8183
8240
|
}
|
|
8184
8241
|
}
|
|
8185
8242
|
const finalResponse = await stream.finalResponse();
|
|
8243
|
+
openAi = extractOpenAiResponseMetadata(finalResponse);
|
|
8186
8244
|
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
8187
8245
|
pushEvent({ type: "model", modelVersion });
|
|
8188
8246
|
if (finalResponse.error) {
|
|
@@ -8426,6 +8484,7 @@ async function runTextCall(params) {
|
|
|
8426
8484
|
costUsd,
|
|
8427
8485
|
usage: latestUsage,
|
|
8428
8486
|
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
8487
|
+
openAi: openAi ? sanitiseLogValue(openAi) : void 0,
|
|
8429
8488
|
responseChars: text.length,
|
|
8430
8489
|
thoughtChars: thoughts.length,
|
|
8431
8490
|
responseImages,
|
|
@@ -8442,7 +8501,8 @@ async function runTextCall(params) {
|
|
|
8442
8501
|
blocked,
|
|
8443
8502
|
usage: latestUsage,
|
|
8444
8503
|
costUsd,
|
|
8445
|
-
grounding
|
|
8504
|
+
grounding,
|
|
8505
|
+
openAi
|
|
8446
8506
|
};
|
|
8447
8507
|
} catch (error) {
|
|
8448
8508
|
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
@@ -11091,6 +11151,104 @@ function appendMarkdownSourcesSection(value, sources) {
|
|
|
11091
11151
|
${lines}`;
|
|
11092
11152
|
}
|
|
11093
11153
|
|
|
11154
|
+
// src/openai/containers.ts
|
|
11155
|
+
var import_openai4 = require("openai");
|
|
11156
|
+
function toOpenAiContainerNetworkPolicy(policy) {
|
|
11157
|
+
if (!policy) {
|
|
11158
|
+
return void 0;
|
|
11159
|
+
}
|
|
11160
|
+
if (policy.type === "disabled") {
|
|
11161
|
+
return { type: "disabled" };
|
|
11162
|
+
}
|
|
11163
|
+
return {
|
|
11164
|
+
type: "allowlist",
|
|
11165
|
+
allowed_domains: Array.from(policy.allowedDomains),
|
|
11166
|
+
...policy.domainSecrets ? {
|
|
11167
|
+
domain_secrets: policy.domainSecrets.map((secret) => ({
|
|
11168
|
+
domain: secret.domain,
|
|
11169
|
+
name: secret.name,
|
|
11170
|
+
value: secret.value
|
|
11171
|
+
}))
|
|
11172
|
+
} : {}
|
|
11173
|
+
};
|
|
11174
|
+
}
|
|
11175
|
+
function toContainer(container) {
|
|
11176
|
+
return {
|
|
11177
|
+
id: String(container.id),
|
|
11178
|
+
name: typeof container.name === "string" ? container.name : "",
|
|
11179
|
+
status: typeof container.status === "string" ? container.status : "",
|
|
11180
|
+
...typeof container.created_at === "number" ? { createdAt: container.created_at } : {},
|
|
11181
|
+
...typeof container.last_active_at === "number" ? { lastActiveAt: container.last_active_at } : {},
|
|
11182
|
+
...typeof container.memory_limit === "string" ? { memoryLimit: container.memory_limit } : {}
|
|
11183
|
+
};
|
|
11184
|
+
}
|
|
11185
|
+
function toContainerFile(file) {
|
|
11186
|
+
return {
|
|
11187
|
+
id: String(file.id),
|
|
11188
|
+
containerId: typeof file.container_id === "string" ? file.container_id : "",
|
|
11189
|
+
path: typeof file.path === "string" ? file.path : "",
|
|
11190
|
+
...typeof file.bytes === "number" || file.bytes === null ? { bytes: file.bytes } : {},
|
|
11191
|
+
...typeof file.created_at === "number" ? { createdAt: file.created_at } : {},
|
|
11192
|
+
...typeof file.source === "string" ? { source: file.source } : {}
|
|
11193
|
+
};
|
|
11194
|
+
}
|
|
11195
|
+
async function createOpenAiContainer(options) {
|
|
11196
|
+
const container = await runOpenAiCall(
|
|
11197
|
+
async (client) => await client.containers.create({
|
|
11198
|
+
name: options.name,
|
|
11199
|
+
...options.fileIds ? { file_ids: Array.from(options.fileIds) } : {},
|
|
11200
|
+
...options.memoryLimit ? { memory_limit: options.memoryLimit } : {},
|
|
11201
|
+
...options.networkPolicy ? { network_policy: toOpenAiContainerNetworkPolicy(options.networkPolicy) } : {},
|
|
11202
|
+
...options.expiresAfterMinutes ? {
|
|
11203
|
+
expires_after: {
|
|
11204
|
+
anchor: "last_active_at",
|
|
11205
|
+
minutes: options.expiresAfterMinutes
|
|
11206
|
+
}
|
|
11207
|
+
} : {}
|
|
11208
|
+
}),
|
|
11209
|
+
"openai-containers"
|
|
11210
|
+
);
|
|
11211
|
+
return toContainer(container);
|
|
11212
|
+
}
|
|
11213
|
+
async function deleteOpenAiContainer(containerId) {
|
|
11214
|
+
await runOpenAiCall(
|
|
11215
|
+
async (client) => await client.containers.delete(containerId),
|
|
11216
|
+
"openai-containers"
|
|
11217
|
+
);
|
|
11218
|
+
}
|
|
11219
|
+
async function listOpenAiContainerFiles(containerId) {
|
|
11220
|
+
const files2 = [];
|
|
11221
|
+
await runOpenAiCall(async (client) => {
|
|
11222
|
+
for await (const file of client.containers.files.list(containerId)) {
|
|
11223
|
+
files2.push(toContainerFile(file));
|
|
11224
|
+
}
|
|
11225
|
+
}, "openai-containers");
|
|
11226
|
+
return files2;
|
|
11227
|
+
}
|
|
11228
|
+
async function uploadOpenAiContainerFile(upload) {
|
|
11229
|
+
const file = await (0, import_openai4.toFile)(upload.data, upload.filename, {
|
|
11230
|
+
...upload.mimeType ? { type: upload.mimeType } : {}
|
|
11231
|
+
});
|
|
11232
|
+
const created = await runOpenAiCall(
|
|
11233
|
+
async (client) => await client.containers.files.create(upload.containerId, { file }),
|
|
11234
|
+
"openai-containers"
|
|
11235
|
+
);
|
|
11236
|
+
return toContainerFile(created);
|
|
11237
|
+
}
|
|
11238
|
+
async function downloadOpenAiContainerFile(params) {
|
|
11239
|
+
const response = await runOpenAiCall(
|
|
11240
|
+
async (client) => await client.containers.files.content.retrieve(params.fileId, {
|
|
11241
|
+
container_id: params.containerId
|
|
11242
|
+
}),
|
|
11243
|
+
"openai-containers"
|
|
11244
|
+
);
|
|
11245
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
11246
|
+
}
|
|
11247
|
+
async function downloadOpenAiContainerFileText(params) {
|
|
11248
|
+
const bytes = await downloadOpenAiContainerFile(params);
|
|
11249
|
+
return new TextDecoder().decode(bytes);
|
|
11250
|
+
}
|
|
11251
|
+
|
|
11094
11252
|
// src/agent.ts
|
|
11095
11253
|
var import_node_crypto4 = require("crypto");
|
|
11096
11254
|
var import_node_path9 = __toESM(require("path"), 1);
|
|
@@ -14891,12 +15049,16 @@ async function runCandidateEvolution(options) {
|
|
|
14891
15049
|
createListDirectoryTool,
|
|
14892
15050
|
createModelAgnosticFilesystemToolSet,
|
|
14893
15051
|
createNodeAgentFilesystem,
|
|
15052
|
+
createOpenAiContainer,
|
|
14894
15053
|
createReplaceTool,
|
|
14895
15054
|
createRgSearchTool,
|
|
14896
15055
|
createToolLoopSteeringChannel,
|
|
14897
15056
|
createViewImageTool,
|
|
14898
15057
|
createWriteFileTool,
|
|
14899
15058
|
customTool,
|
|
15059
|
+
deleteOpenAiContainer,
|
|
15060
|
+
downloadOpenAiContainerFile,
|
|
15061
|
+
downloadOpenAiContainerFileText,
|
|
14900
15062
|
emptyFileUploadMetrics,
|
|
14901
15063
|
encodeChatGptAuthJson,
|
|
14902
15064
|
encodeChatGptAuthJsonB64,
|
|
@@ -14921,6 +15083,7 @@ async function runCandidateEvolution(options) {
|
|
|
14921
15083
|
isLlmTextModelId,
|
|
14922
15084
|
isOpenAiImageModelId,
|
|
14923
15085
|
isOpenAiModelId,
|
|
15086
|
+
listOpenAiContainerFiles,
|
|
14924
15087
|
loadEnvFromFile,
|
|
14925
15088
|
loadLocalEnv,
|
|
14926
15089
|
parseJsonFromLlmText,
|
|
@@ -14941,6 +15104,7 @@ async function runCandidateEvolution(options) {
|
|
|
14941
15104
|
stripCodexCitationMarkers,
|
|
14942
15105
|
toGeminiJsonSchema,
|
|
14943
15106
|
tool,
|
|
15107
|
+
uploadOpenAiContainerFile,
|
|
14944
15108
|
validateOpenAiGptImage2Resolution
|
|
14945
15109
|
});
|
|
14946
15110
|
//# sourceMappingURL=index.cjs.map
|