@ljoukov/llm 7.0.14 → 7.0.15
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 +159 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -1
- package/dist/index.d.ts +65 -1
- package/dist/index.js +155 -3
- 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);
|
|
@@ -6462,6 +6468,50 @@ function toOpenAiTools(tools, options) {
|
|
|
6462
6468
|
}
|
|
6463
6469
|
});
|
|
6464
6470
|
}
|
|
6471
|
+
function extractOpenAiResponseMetadata(response) {
|
|
6472
|
+
if (!response || typeof response !== "object") {
|
|
6473
|
+
return void 0;
|
|
6474
|
+
}
|
|
6475
|
+
const record = response;
|
|
6476
|
+
const responseId = typeof record.id === "string" ? record.id : void 0;
|
|
6477
|
+
const output = Array.isArray(record.output) ? record.output : [];
|
|
6478
|
+
const containers = [];
|
|
6479
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6480
|
+
const addContainer = (container) => {
|
|
6481
|
+
const key = `${container.toolType}:${container.containerId}:${container.itemId ?? ""}:${container.callId ?? ""}`;
|
|
6482
|
+
if (seen.has(key)) {
|
|
6483
|
+
return;
|
|
6484
|
+
}
|
|
6485
|
+
seen.add(key);
|
|
6486
|
+
containers.push(container);
|
|
6487
|
+
};
|
|
6488
|
+
for (const item of output) {
|
|
6489
|
+
if (!item || typeof item !== "object") {
|
|
6490
|
+
continue;
|
|
6491
|
+
}
|
|
6492
|
+
const itemRecord = item;
|
|
6493
|
+
const itemId = typeof itemRecord.id === "string" ? itemRecord.id : void 0;
|
|
6494
|
+
const callId = typeof itemRecord.call_id === "string" ? itemRecord.call_id : void 0;
|
|
6495
|
+
if (itemRecord.type === "shell_call") {
|
|
6496
|
+
const environment = itemRecord.environment && typeof itemRecord.environment === "object" ? itemRecord.environment : void 0;
|
|
6497
|
+
const containerId = environment?.type === "container_reference" && typeof environment.container_id === "string" ? environment.container_id : void 0;
|
|
6498
|
+
if (containerId) {
|
|
6499
|
+
addContainer({ containerId, toolType: "shell", itemId, callId });
|
|
6500
|
+
}
|
|
6501
|
+
continue;
|
|
6502
|
+
}
|
|
6503
|
+
if (itemRecord.type === "code_interpreter_call") {
|
|
6504
|
+
const containerId = typeof itemRecord.container_id === "string" ? itemRecord.container_id : void 0;
|
|
6505
|
+
if (containerId) {
|
|
6506
|
+
addContainer({ containerId, toolType: "code_interpreter", itemId, callId });
|
|
6507
|
+
}
|
|
6508
|
+
}
|
|
6509
|
+
}
|
|
6510
|
+
if (!responseId && containers.length === 0) {
|
|
6511
|
+
return void 0;
|
|
6512
|
+
}
|
|
6513
|
+
return { ...responseId ? { responseId } : {}, containers };
|
|
6514
|
+
}
|
|
6465
6515
|
function mergeTokenUpdates(current, next) {
|
|
6466
6516
|
if (!next) {
|
|
6467
6517
|
return current;
|
|
@@ -8073,6 +8123,7 @@ async function runTextCall(params) {
|
|
|
8073
8123
|
let modelVersion = request.model;
|
|
8074
8124
|
let blocked = false;
|
|
8075
8125
|
let grounding;
|
|
8126
|
+
let openAi;
|
|
8076
8127
|
const responseParts = [];
|
|
8077
8128
|
let responseRole;
|
|
8078
8129
|
let latestUsage;
|
|
@@ -8183,6 +8234,7 @@ async function runTextCall(params) {
|
|
|
8183
8234
|
}
|
|
8184
8235
|
}
|
|
8185
8236
|
const finalResponse = await stream.finalResponse();
|
|
8237
|
+
openAi = extractOpenAiResponseMetadata(finalResponse);
|
|
8186
8238
|
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
8187
8239
|
pushEvent({ type: "model", modelVersion });
|
|
8188
8240
|
if (finalResponse.error) {
|
|
@@ -8426,6 +8478,7 @@ async function runTextCall(params) {
|
|
|
8426
8478
|
costUsd,
|
|
8427
8479
|
usage: latestUsage,
|
|
8428
8480
|
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
8481
|
+
openAi: openAi ? sanitiseLogValue(openAi) : void 0,
|
|
8429
8482
|
responseChars: text.length,
|
|
8430
8483
|
thoughtChars: thoughts.length,
|
|
8431
8484
|
responseImages,
|
|
@@ -8442,7 +8495,8 @@ async function runTextCall(params) {
|
|
|
8442
8495
|
blocked,
|
|
8443
8496
|
usage: latestUsage,
|
|
8444
8497
|
costUsd,
|
|
8445
|
-
grounding
|
|
8498
|
+
grounding,
|
|
8499
|
+
openAi
|
|
8446
8500
|
};
|
|
8447
8501
|
} catch (error) {
|
|
8448
8502
|
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
@@ -11091,6 +11145,104 @@ function appendMarkdownSourcesSection(value, sources) {
|
|
|
11091
11145
|
${lines}`;
|
|
11092
11146
|
}
|
|
11093
11147
|
|
|
11148
|
+
// src/openai/containers.ts
|
|
11149
|
+
var import_openai4 = require("openai");
|
|
11150
|
+
function toOpenAiContainerNetworkPolicy(policy) {
|
|
11151
|
+
if (!policy) {
|
|
11152
|
+
return void 0;
|
|
11153
|
+
}
|
|
11154
|
+
if (policy.type === "disabled") {
|
|
11155
|
+
return { type: "disabled" };
|
|
11156
|
+
}
|
|
11157
|
+
return {
|
|
11158
|
+
type: "allowlist",
|
|
11159
|
+
allowed_domains: Array.from(policy.allowedDomains),
|
|
11160
|
+
...policy.domainSecrets ? {
|
|
11161
|
+
domain_secrets: policy.domainSecrets.map((secret) => ({
|
|
11162
|
+
domain: secret.domain,
|
|
11163
|
+
name: secret.name,
|
|
11164
|
+
value: secret.value
|
|
11165
|
+
}))
|
|
11166
|
+
} : {}
|
|
11167
|
+
};
|
|
11168
|
+
}
|
|
11169
|
+
function toContainer(container) {
|
|
11170
|
+
return {
|
|
11171
|
+
id: String(container.id),
|
|
11172
|
+
name: typeof container.name === "string" ? container.name : "",
|
|
11173
|
+
status: typeof container.status === "string" ? container.status : "",
|
|
11174
|
+
...typeof container.created_at === "number" ? { createdAt: container.created_at } : {},
|
|
11175
|
+
...typeof container.last_active_at === "number" ? { lastActiveAt: container.last_active_at } : {},
|
|
11176
|
+
...typeof container.memory_limit === "string" ? { memoryLimit: container.memory_limit } : {}
|
|
11177
|
+
};
|
|
11178
|
+
}
|
|
11179
|
+
function toContainerFile(file) {
|
|
11180
|
+
return {
|
|
11181
|
+
id: String(file.id),
|
|
11182
|
+
containerId: typeof file.container_id === "string" ? file.container_id : "",
|
|
11183
|
+
path: typeof file.path === "string" ? file.path : "",
|
|
11184
|
+
...typeof file.bytes === "number" || file.bytes === null ? { bytes: file.bytes } : {},
|
|
11185
|
+
...typeof file.created_at === "number" ? { createdAt: file.created_at } : {},
|
|
11186
|
+
...typeof file.source === "string" ? { source: file.source } : {}
|
|
11187
|
+
};
|
|
11188
|
+
}
|
|
11189
|
+
async function createOpenAiContainer(options) {
|
|
11190
|
+
const container = await runOpenAiCall(
|
|
11191
|
+
async (client) => await client.containers.create({
|
|
11192
|
+
name: options.name,
|
|
11193
|
+
...options.fileIds ? { file_ids: Array.from(options.fileIds) } : {},
|
|
11194
|
+
...options.memoryLimit ? { memory_limit: options.memoryLimit } : {},
|
|
11195
|
+
...options.networkPolicy ? { network_policy: toOpenAiContainerNetworkPolicy(options.networkPolicy) } : {},
|
|
11196
|
+
...options.expiresAfterMinutes ? {
|
|
11197
|
+
expires_after: {
|
|
11198
|
+
anchor: "last_active_at",
|
|
11199
|
+
minutes: options.expiresAfterMinutes
|
|
11200
|
+
}
|
|
11201
|
+
} : {}
|
|
11202
|
+
}),
|
|
11203
|
+
"openai-containers"
|
|
11204
|
+
);
|
|
11205
|
+
return toContainer(container);
|
|
11206
|
+
}
|
|
11207
|
+
async function deleteOpenAiContainer(containerId) {
|
|
11208
|
+
await runOpenAiCall(
|
|
11209
|
+
async (client) => await client.containers.delete(containerId),
|
|
11210
|
+
"openai-containers"
|
|
11211
|
+
);
|
|
11212
|
+
}
|
|
11213
|
+
async function listOpenAiContainerFiles(containerId) {
|
|
11214
|
+
const files2 = [];
|
|
11215
|
+
await runOpenAiCall(async (client) => {
|
|
11216
|
+
for await (const file of client.containers.files.list(containerId)) {
|
|
11217
|
+
files2.push(toContainerFile(file));
|
|
11218
|
+
}
|
|
11219
|
+
}, "openai-containers");
|
|
11220
|
+
return files2;
|
|
11221
|
+
}
|
|
11222
|
+
async function uploadOpenAiContainerFile(upload) {
|
|
11223
|
+
const file = await (0, import_openai4.toFile)(upload.data, upload.filename, {
|
|
11224
|
+
...upload.mimeType ? { type: upload.mimeType } : {}
|
|
11225
|
+
});
|
|
11226
|
+
const created = await runOpenAiCall(
|
|
11227
|
+
async (client) => await client.containers.files.create(upload.containerId, { file }),
|
|
11228
|
+
"openai-containers"
|
|
11229
|
+
);
|
|
11230
|
+
return toContainerFile(created);
|
|
11231
|
+
}
|
|
11232
|
+
async function downloadOpenAiContainerFile(params) {
|
|
11233
|
+
const response = await runOpenAiCall(
|
|
11234
|
+
async (client) => await client.containers.files.content.retrieve(params.fileId, {
|
|
11235
|
+
container_id: params.containerId
|
|
11236
|
+
}),
|
|
11237
|
+
"openai-containers"
|
|
11238
|
+
);
|
|
11239
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
11240
|
+
}
|
|
11241
|
+
async function downloadOpenAiContainerFileText(params) {
|
|
11242
|
+
const bytes = await downloadOpenAiContainerFile(params);
|
|
11243
|
+
return new TextDecoder().decode(bytes);
|
|
11244
|
+
}
|
|
11245
|
+
|
|
11094
11246
|
// src/agent.ts
|
|
11095
11247
|
var import_node_crypto4 = require("crypto");
|
|
11096
11248
|
var import_node_path9 = __toESM(require("path"), 1);
|
|
@@ -14891,12 +15043,16 @@ async function runCandidateEvolution(options) {
|
|
|
14891
15043
|
createListDirectoryTool,
|
|
14892
15044
|
createModelAgnosticFilesystemToolSet,
|
|
14893
15045
|
createNodeAgentFilesystem,
|
|
15046
|
+
createOpenAiContainer,
|
|
14894
15047
|
createReplaceTool,
|
|
14895
15048
|
createRgSearchTool,
|
|
14896
15049
|
createToolLoopSteeringChannel,
|
|
14897
15050
|
createViewImageTool,
|
|
14898
15051
|
createWriteFileTool,
|
|
14899
15052
|
customTool,
|
|
15053
|
+
deleteOpenAiContainer,
|
|
15054
|
+
downloadOpenAiContainerFile,
|
|
15055
|
+
downloadOpenAiContainerFileText,
|
|
14900
15056
|
emptyFileUploadMetrics,
|
|
14901
15057
|
encodeChatGptAuthJson,
|
|
14902
15058
|
encodeChatGptAuthJsonB64,
|
|
@@ -14921,6 +15077,7 @@ async function runCandidateEvolution(options) {
|
|
|
14921
15077
|
isLlmTextModelId,
|
|
14922
15078
|
isOpenAiImageModelId,
|
|
14923
15079
|
isOpenAiModelId,
|
|
15080
|
+
listOpenAiContainerFiles,
|
|
14924
15081
|
loadEnvFromFile,
|
|
14925
15082
|
loadLocalEnv,
|
|
14926
15083
|
parseJsonFromLlmText,
|
|
@@ -14941,6 +15098,7 @@ async function runCandidateEvolution(options) {
|
|
|
14941
15098
|
stripCodexCitationMarkers,
|
|
14942
15099
|
toGeminiJsonSchema,
|
|
14943
15100
|
tool,
|
|
15101
|
+
uploadOpenAiContainerFile,
|
|
14944
15102
|
validateOpenAiGptImage2Resolution
|
|
14945
15103
|
});
|
|
14946
15104
|
//# sourceMappingURL=index.cjs.map
|