@ingram-cloud/eve
v2.0.0
Published
eve adapter for Ingram Cloud — run an Ingram smith as an eve agent's model over the OpenAI Responses API, attach an Ingram-hosted deployment's tools as an eve MCP connection, and resolve human-in-the-loop approvals. Standards-first; no proprietary protoco
Maintainers
Readme
@ingram-cloud/eve
Wire an Ingram Cloud smith into an eve agent. A thin, idiomatic extension of eve: run a smith as your agent's model, attach Ingram-hosted tools as an MCP connection, and resolve approvals — each over an industry-standard surface, no bespoke protocol.
Philosophy: stand on the standard
This package adds no proprietary client. The model rides Ingram Cloud's
Responses API as a plain
AI SDK LanguageModel (eve takes one directly) — the smith's server-executed
tool calls arrive as standard tool-call/tool-result parts; tools ride
MCP through eve's own connection system;
approvals ride the AI SDK's standard approval channel. A smith still runs
the agent loop server-side — memory, tools, approvals, isolation — but to eve it
looks like any model.
Install
npm install @ingram-cloud/eveeve and ai are peer dependencies — you already have them in an eve
project.
Model: a smith as your agent's model
eve's model takes an AI SDK LanguageModel, so a smith drops straight into
agent/agent.ts:
// agent/agent.ts
import { defineAgent } from "eve";
import { ingramCloudModel } from "@ingram-cloud/eve";
// A per-smith token names exactly one smith; the agent is the one that smith runs.
export default defineAgent({
model: ingramCloudModel({ apiKey: process.env.IC_SMITH_TOKEN! }),
});eve routes this as an external provider — it bypasses the AI Gateway and talks to Ingram Cloud directly.
The model id is the LLM, not the agent
The agent a smith runs — its instructions, tools, and memory — is resolved from
the smith, never from the model id. modelId is the upstream inference LLM
for the turn: omit it to use the smith's configured model, or name one to
override it (ingramCloudModel({ apiKey, modelId: "gpt-5.5" })).
Opt into Ingram Cloud's server-side memory with threadId. Server-side with a
tenant-admin token instead of a smith token? Name the smith with smithId:
ingramCloudModel({ apiKey: process.env.IC_TENANT_TOKEN!, smithId: "smt_…" });Never ship a tenant-admin token to the browser.
Tools: Ingram-hosted MCP as an eve connection
Expose an Ingram Cloud deployment of kind: "mcp" as an eve connection. The
filename is the connection name:
// agent/connections/ingram.ts
import { defineIngramMcpConnection } from "@ingram-cloud/eve";
export default defineIngramMcpConnection({
apiKey: process.env.IC_SMITH_TOKEN!,
deploymentId: "dep_…",
description: "Ingram-hosted tools for this smith.",
});eve discovers the deployment's tools, brokers auth, and hands them to the model —
the token never reaches the model. Gate them with eve's own per-connection
approval (never() / once() / always() from eve/tools/approval) or filter
with tools: { allow: [...] }.
This is distinct from ingramCloudModel: there a smith runs its own server-side
tools as the model; here an eve agent calls Ingram-hosted tools directly over MCP.
Approvals (human-in-the-loop)
A smith tool marked destructiveHint pauses its run for approval. The pause
arrives as a standard tool-approval-request content part whose approvalId is
"<run_id>::<tool_call_id>". The helpers are pure and also live at
@ingram-cloud/eve/approvals:
import {
getApprovalRequests,
approvalResponseMessage,
} from "@ingram-cloud/eve";
// `content` from the model result (composite approval ids are Ingram's).
const approvals = getApprovalRequests(result.content);
for (const a of approvals) {
const decision = (await askTheHuman(a)) ? "approve" : "reject";
// Append this message and run the next turn to resume the paused run.
messages.push(approvalResponseMessage(a, decision));
}On approve, Ingram Cloud executes the tool itself and continues; on reject,
the run completes with stop_reason: "approval_rejected" and nothing runs. These
are the smith's server-side approvals — distinct from eve's per-connection
approval gate above.
Identity & tokens
| Token | Use | How the smith is chosen |
|---|---|---|
| Smith token (sub = "<tenant>:<smith>") | browser-safe; the default | the token is the smith |
| Tenant-admin token | server-side only | pass smithId (sent as IC-Smith-Id) |
Notes
- ESM-only, ships as
dist/. Build withnpm run build(plaintsc). - Built on
@ingram-cloud/ai-sdk(the model seam) — for the same product over the raw Vercel AI SDK or Flue (@ingram-cloud/flue), reach for those. - Independent of the API's api/web checks, like the
pulumi/,ai-sdk/, andflue/packages. Keep it in step when the Responses / MCP surfaces it wraps change.
