Skip to content

LLM configuration (GraphEngine({ llm }))

Pass provider name, API key, and model/region when you construct GraphEngine. Credentials are merged into each node's data.settings at run time — you do not need to put secrets in pipeline JSON or globalSettings files.

Quick example (Bedrock)

typescript
import {
  GraphEngine,
  loadFlowFromFile,
  createBuiltinNodeExecutor,
} from "arc-dag";

const flow = await loadFlowFromFile("./pipeline.json");

const engine = new GraphEngine({
  flow,
  llm: {
    provider: "bedrock",
    apiKey: process.env.BEDROCK_API_KEY!,
    modelId: "us.anthropic.claude-sonnet-4-6",
    region: "us-east-1",
  },
  nodeExecutor: createBuiltinNodeExecutor(),
});

await engine.run();

Quick example (OpenAI-compatible)

typescript
const engine = new GraphEngine({
  flow,
  llm: {
    provider: "openai",
    apiKey: process.env.LLM_API_KEY!,
    baseUrl: "https://api.openai.com/v1",
    model: "gpt-4o",
    systemPrompt: "You are a helpful assistant",
    temperature: 0.5,
  },
  nodeExecutor: createBuiltinNodeExecutor(),
});

LlmConfig shape

FieldProvidersDescription
providerrequired"bedrock" or "openai"
apiKeybothShorthand API key
modelIdbedrockBedrock model id (e.g. us.anthropic.claude-sonnet-4-6)
regionbedrockAWS region (default us-east-1 in handler)
timeoutMsbedrockRequest timeout
baseUrlopenaiChat completions root (e.g. https://api.openai.com/v1)
modelopenaiModel name
temperatureopenaiSampling temperature
maxOutputTokensopenaiMax tokens
systemPromptopenaiSystem message
bedrockbedrockNested { apiKey, modelId, region, timeoutMs, userId }
openaiopenaiNested { apiKey, baseUrl, model, … }

Use shorthand or nested — not both required:

typescript
// Shorthand
{ provider: "bedrock", apiKey: "…", modelId: "…", region: "us-east-1" }

// Nested
{ provider: "bedrock", bedrock: { apiKey: "…", modelId: "…" } }

What the engine merges

GraphEngine calls mergeLlmConfigIntoGlobalSettings(llm, globalSettings) and exposes the result via getGlobalSettings().

Each node receives merged settings on node.data.settings:

Setting keySourceUsed by
llmProviderllm.providergenText routing
bedrockApiKeyllm.apiKey / llm.bedrock.apiKeyBedrock Converse
modelIdbedrock configBedrock model
regionbedrock configBedrock endpoint
llmApiKeyopenai configOpenAI-compatible API
llmApiBaseopenai baseUrlOpenAI-compatible API
modelopenai configChat model
temperature, systemPrompt, …openai / globalSettingsChat options

Merge order: llm defaults first, then globalSettings overrides (e.g. per-run temperature without touching the API key).

typescript
const engine = new GraphEngine({
  flow,
  llm: { provider: "bedrock", apiKey: secret, region: "us-east-1" },
  globalSettings: { temperature: 0.2 }, // overrides only; key stays from llm
});

Per-node data.settings in pipeline JSON still overrides both for that node only.

Built-in executor

createBuiltinNodeExecutor() handles ArcPX core types (genText, LLM, pipeNode, text, …) and reads credentials from node.data.settings.

Example runners add extension handlers (webpage, community node types) on top. See Extending the builtin executor.

typescript
import { createBuiltinNodeExecutor } from "arc-dag";
import { createNodeExecutor } from "./examples/lib/handlers/index.mjs"; // builtins + webpage + community

const engine = new GraphEngine({
  flow,
  llm: { provider: "bedrock", apiKey: "…", modelId: "…" },
  nodeExecutor: createNodeExecutor(),
});

Local development (.env)

Example scripts load .env / .env.bedrock and map env vars to llm:

bash
cp .env.bedrock.template .env.bedrock
# BEDROCK_API_KEY=…
npm run run:output-chaining

Helper: examples/lib/resolve-llm-from-env.mjs — same mapping for your own runners.

Env variableMaps to
BEDROCK_API_KEYllm.provider: "bedrock", apiKey
BEDROCK_REGIONregion
BEDROCK_MODEL_IDmodelId
LLM_API_KEY + LLM_API_BASEllm.provider: "openai", apiKey, baseUrl
LLM_MODELmodel

Bedrock env wins when BEDROCK_API_KEY is set.

genText prompt placeholders

resolveGenTextQuery() (exported from arc-dag) substitutes upstream data into data.nodeData:

PlaceholderMeaning
{$upstream}All fan-in sources joined
{$source_1}, {$source_2}By dependency order
{$ontario_gov}Upstream outputTarget: "$ontario_gov"

See Output chaining.

Custom executor

If you use your own nodeExecutor, read merged settings from each node:

typescript
nodeExecutor: async (node) => {
  const settings = node.data?.settings ?? {};
  const apiKey = settings.bedrockApiKey as string;
  const modelId = settings.modelId as string;
  // call your LLM
};

Or call mergeLlmConfigIntoGlobalSettings() yourself when building settings outside GraphEngine.

Security

  • Pass llm.apiKey from env vars or a secret manager in application code.
  • Do not commit API keys into pipeline JSON or checked-in globalSettings files.
  • See Security policy.

MIT Licensed