@ljoukov/llm 4.0.2 → 4.0.4

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 CHANGED
@@ -333,13 +333,15 @@ Use a `chatgpt-` prefix:
333
333
  import { generateText } from "@ljoukov/llm";
334
334
 
335
335
  const result = await generateText({
336
- model: "chatgpt-gpt-5.1-codex-mini",
336
+ model: "chatgpt-gpt-5.4",
337
337
  input: "Return exactly: OK",
338
338
  });
339
339
 
340
340
  console.log(result.text);
341
341
  ```
342
342
 
343
+ `chatgpt-gpt-5.4-fast` is also supported as a convenience alias for ChatGPT-authenticated `gpt-5.4` with priority processing enabled (`service_tier="priority"`), matching Codex `/fast` semantics.
344
+
343
345
  ## JSON outputs
344
346
 
345
347
  `generateJson()` validates the output with Zod and returns the parsed value.
@@ -681,7 +683,7 @@ See `docs/agent-telemetry.md` for event schema, design rationale, and backend ad
681
683
 
682
684
  - console lines,
683
685
  - `<workspace>/agent.log`,
684
- - per-call artifacts under a sibling logs directory: `<workspace-parent>/logs/<timestamp>-<n>/<model-id>/`.
686
+ - per-call artifacts under `<workspace>/llm_calls/<timestamp>-<n>/<model-id>/` by default.
685
687
 
686
688
  Each LLM call writes:
687
689
 
@@ -692,6 +694,7 @@ Each LLM call writes:
692
694
  `image_url` data URLs are redacted in text/metadata logs (`data:...,...`) so base64 payloads are not printed inline.
693
695
 
694
696
  ```ts
697
+ import path from "node:path";
695
698
  import { runAgentLoop } from "@ljoukov/llm";
696
699
 
697
700
  await runAgentLoop({
@@ -699,7 +702,8 @@ await runAgentLoop({
699
702
  input: "Do the task",
700
703
  filesystemTool: true,
701
704
  logging: {
702
- workspaceDir: process.cwd(), // optional; defaults to filesystem cwd or process.cwd()
705
+ workspaceDir: path.join(process.cwd(), "logs", "agent"), // optional; defaults to filesystem cwd or process.cwd()
706
+ callLogsDir: "llm_calls", // optional; relative paths resolve from workspaceDir
703
707
  mirrorToConsole: false, // useful for CLI UIs that already render stream events
704
708
  sink: {
705
709
  append: (line) => {
package/dist/index.cjs CHANGED
@@ -317,6 +317,16 @@ var OPENAI_GPT_52_PRICING = {
317
317
  cachedRate: 0.175 / 1e6,
318
318
  outputRate: 14 / 1e6
319
319
  };
320
+ var OPENAI_GPT_54_PRICING = {
321
+ inputRate: 2.5 / 1e6,
322
+ cachedRate: 0.25 / 1e6,
323
+ outputRate: 15 / 1e6
324
+ };
325
+ var OPENAI_GPT_54_PRIORITY_PRICING = {
326
+ inputRate: 5 / 1e6,
327
+ cachedRate: 0.5 / 1e6,
328
+ outputRate: 30 / 1e6
329
+ };
320
330
  var OPENAI_GPT_53_CODEX_PRICING = {
321
331
  inputRate: 1.25 / 1e6,
322
332
  cachedRate: 0.125 / 1e6,
@@ -328,6 +338,12 @@ var OPENAI_GPT_5_MINI_PRICING = {
328
338
  outputRate: 2 / 1e6
329
339
  };
330
340
  function getOpenAiPricing(modelId) {
341
+ if (modelId.includes("gpt-5.4-fast")) {
342
+ return OPENAI_GPT_54_PRIORITY_PRICING;
343
+ }
344
+ if (modelId.includes("gpt-5.4")) {
345
+ return OPENAI_GPT_54_PRICING;
346
+ }
331
347
  if (modelId.includes("gpt-5.3-codex-spark")) {
332
348
  return OPENAI_GPT_5_MINI_PRICING;
333
349
  }
@@ -2738,11 +2754,18 @@ async function runOpenAiCall(fn, modelId, runOptions) {
2738
2754
  }
2739
2755
 
2740
2756
  // src/openai/models.ts
2741
- var OPENAI_MODEL_IDS = ["gpt-5.3-codex", "gpt-5.2", "gpt-5.1-codex-mini"];
2757
+ var OPENAI_MODEL_IDS = [
2758
+ "gpt-5.4",
2759
+ "gpt-5.3-codex",
2760
+ "gpt-5.2",
2761
+ "gpt-5.1-codex-mini"
2762
+ ];
2742
2763
  function isOpenAiModelId(value) {
2743
2764
  return OPENAI_MODEL_IDS.includes(value);
2744
2765
  }
2745
2766
  var CHATGPT_MODEL_IDS = [
2767
+ "chatgpt-gpt-5.4",
2768
+ "chatgpt-gpt-5.4-fast",
2746
2769
  "chatgpt-gpt-5.3-codex",
2747
2770
  "chatgpt-gpt-5.3-codex-spark",
2748
2771
  "chatgpt-gpt-5.2",
@@ -2754,6 +2777,17 @@ function isChatGptModelId(value) {
2754
2777
  function stripChatGptPrefix(model) {
2755
2778
  return model.slice("chatgpt-".length);
2756
2779
  }
2780
+ function resolveChatGptProviderModel(model) {
2781
+ switch (model) {
2782
+ case "chatgpt-gpt-5.4-fast":
2783
+ return "gpt-5.4";
2784
+ default:
2785
+ return stripChatGptPrefix(model);
2786
+ }
2787
+ }
2788
+ function resolveChatGptServiceTier(model) {
2789
+ return model === "chatgpt-gpt-5.4-fast" ? "priority" : void 0;
2790
+ }
2757
2791
 
2758
2792
  // src/agentLogging.ts
2759
2793
  var import_node_async_hooks = require("async_hooks");
@@ -2935,7 +2969,8 @@ var AgentLoggingSessionImpl = class {
2935
2969
  callCounter = 0;
2936
2970
  constructor(config) {
2937
2971
  this.workspaceDir = import_node_path3.default.resolve(config.workspaceDir ?? process.cwd());
2938
- this.logsRootDir = import_node_path3.default.join(import_node_path3.default.dirname(this.workspaceDir), "logs");
2972
+ const configuredCallLogsDir = typeof config.callLogsDir === "string" ? config.callLogsDir.trim() : "";
2973
+ this.logsRootDir = configuredCallLogsDir.length > 0 ? import_node_path3.default.resolve(this.workspaceDir, configuredCallLogsDir) : import_node_path3.default.join(this.workspaceDir, "llm_calls");
2939
2974
  this.mirrorToConsole = config.mirrorToConsole !== false;
2940
2975
  this.sink = config.sink;
2941
2976
  this.agentLogPath = import_node_path3.default.join(this.workspaceDir, "agent.log");
@@ -3502,7 +3537,11 @@ function convertLlmContentToGeminiContent(content) {
3502
3537
  }
3503
3538
  function resolveProvider(model) {
3504
3539
  if (isChatGptModelId(model)) {
3505
- return { provider: "chatgpt", model: stripChatGptPrefix(model) };
3540
+ return {
3541
+ provider: "chatgpt",
3542
+ model: resolveChatGptProviderModel(model),
3543
+ serviceTier: resolveChatGptServiceTier(model)
3544
+ };
3506
3545
  }
3507
3546
  if (isGeminiTextModelId(model) || isGeminiImageModelId(model)) {
3508
3547
  return { provider: "gemini", model };
@@ -5213,6 +5252,7 @@ async function runTextCall(params) {
5213
5252
  model: modelForProvider,
5214
5253
  store: false,
5215
5254
  stream: true,
5255
+ ...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
5216
5256
  instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
5217
5257
  input: chatGptInput.input,
5218
5258
  include: ["reasoning.encrypted_content"],
@@ -5247,7 +5287,7 @@ async function runTextCall(params) {
5247
5287
  queue.push({ type: "blocked" });
5248
5288
  }
5249
5289
  if (result.model) {
5250
- modelVersion = `chatgpt-${result.model}`;
5290
+ modelVersion = providerInfo.serviceTier ? request.model : `chatgpt-${result.model}`;
5251
5291
  queue.push({ type: "model", modelVersion });
5252
5292
  }
5253
5293
  latestUsage = extractChatGptUsageTokens(result.usage);
@@ -6209,6 +6249,7 @@ async function runToolLoop(request) {
6209
6249
  model: providerInfo.model,
6210
6250
  store: false,
6211
6251
  stream: true,
6252
+ ...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
6212
6253
  instructions: toolLoopInput.instructions ?? "You are a helpful assistant.",
6213
6254
  input,
6214
6255
  prompt_cache_key: promptCacheKey,
@@ -6249,7 +6290,7 @@ async function runToolLoop(request) {
6249
6290
  }
6250
6291
  });
6251
6292
  const modelCompletedAtMs = Date.now();
6252
- modelVersion = response.model ? `chatgpt-${response.model}` : request.model;
6293
+ modelVersion = response.model && !providerInfo.serviceTier ? `chatgpt-${response.model}` : request.model;
6253
6294
  usageTokens = extractChatGptUsageTokens(response.usage);
6254
6295
  const stepCostUsd = estimateCallCostUsd({
6255
6296
  modelId: modelVersion,
@@ -10374,9 +10415,10 @@ function createRootAgentLoggingSession(request) {
10374
10415
  if (!selected) {
10375
10416
  return void 0;
10376
10417
  }
10418
+ const workspaceDir = typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ? import_node_path7.default.resolve(selected.workspaceDir) : resolveWorkspaceDirForLogging(request);
10377
10419
  return createAgentLoggingSession({
10378
10420
  ...selected,
10379
- workspaceDir: typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ? import_node_path7.default.resolve(selected.workspaceDir) : resolveWorkspaceDirForLogging(request),
10421
+ workspaceDir,
10380
10422
  mirrorToConsole: selected.mirrorToConsole !== false
10381
10423
  });
10382
10424
  }