@zuora/agent-toolkit 0.0.1-alpha.0 → 0.1.0-alpha.0
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 +264 -62
- package/dist/{async-jobs-Dd8Jafv0.d.ts → async-jobs-DJ_GygII.d.ts} +8 -16
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/langchain/index.d.ts +52 -1
- package/dist/langchain/index.js +4963 -0
- package/dist/langchain/index.js.map +1 -1
- package/dist/openai/index.d.ts +3 -3
- package/dist/openai/index.js +36 -128
- package/dist/openai/index.js.map +1 -1
- package/dist/openai-agents/index.d.ts +3 -3
- package/dist/openai-agents/index.js +36 -128
- package/dist/openai-agents/index.js.map +1 -1
- package/dist/shared/toolkit-core.d.ts +1 -1
- package/dist/shared/toolkit-core.js +31 -84
- package/dist/shared/toolkit-core.js.map +1 -1
- package/dist/{toolkit-CafRZuAV.d.ts → toolkit-Bjw46goJ.d.ts} +1 -1
- package/dist/vercel-ai/index.d.ts +64 -1
- package/dist/vercel-ai/index.js +4997 -0
- package/dist/vercel-ai/index.js.map +1 -1
- package/package.json +18 -17
package/README.md
CHANGED
|
@@ -6,18 +6,38 @@ Zuora billing operations as callable tools for AI agent frameworks.
|
|
|
6
6
|
|
|
7
7
|
Built on the [Zuora MCP server](https://developer.zuora.com). Tool inventory is discovered at runtime from your tenant's MCP endpoint — it is not hardcoded in this package.
|
|
8
8
|
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Agent, run } from "@openai/agents";
|
|
13
|
+
import { createZuoraOpenAIAgentsToolkit } from "@zuora/agent-toolkit/openai-agents";
|
|
14
|
+
|
|
15
|
+
const toolkit = await createZuoraOpenAIAgentsToolkit({ env: true });
|
|
16
|
+
try {
|
|
17
|
+
const agent = new Agent({ name: "Billing Agent", tools: await toolkit.getTools() });
|
|
18
|
+
const result = await run(agent, "How many active accounts do we have?");
|
|
19
|
+
console.log(result.finalOutput);
|
|
20
|
+
} finally {
|
|
21
|
+
await toolkit.close();
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Set `ZUORA_BASE_URL`, `ZUORA_CLIENT_ID`, and `ZUORA_CLIENT_SECRET` in your environment. See [Credentials](#credentials) for other auth options.
|
|
26
|
+
|
|
9
27
|
## Adapter status
|
|
10
28
|
|
|
11
29
|
| Subpath | Factory | Status |
|
|
12
30
|
|---|---|---|
|
|
13
31
|
| `@zuora/agent-toolkit/openai` | `createZuoraOpenAIAgentToolkit` | ✅ Implemented |
|
|
14
32
|
| `@zuora/agent-toolkit/openai-agents` | `createZuoraOpenAIAgentsToolkit` | ✅ Implemented |
|
|
15
|
-
| `@zuora/agent-toolkit/langchain` |
|
|
16
|
-
| `@zuora/agent-toolkit/vercel-ai` |
|
|
33
|
+
| `@zuora/agent-toolkit/langchain` | `createZuoraLangChainToolkit` | ✅ Implemented |
|
|
34
|
+
| `@zuora/agent-toolkit/vercel-ai` | `createZuoraVercelAIToolkit` | ✅ Implemented |
|
|
17
35
|
| `@zuora/agent-toolkit/mcp` | — | 🚧 Coming soon |
|
|
18
36
|
|
|
19
37
|
## Installation
|
|
20
38
|
|
|
39
|
+
Requires **Node.js 18** or later.
|
|
40
|
+
|
|
21
41
|
```bash
|
|
22
42
|
npm install @zuora/agent-toolkit
|
|
23
43
|
```
|
|
@@ -25,52 +45,165 @@ npm install @zuora/agent-toolkit
|
|
|
25
45
|
Framework packages are peer dependencies — install only what you use:
|
|
26
46
|
|
|
27
47
|
```bash
|
|
28
|
-
# OpenAI Chat Completions
|
|
48
|
+
# OpenAI Chat Completions (requires openai >=4)
|
|
29
49
|
npm install openai
|
|
30
50
|
|
|
31
|
-
# OpenAI Agents SDK
|
|
51
|
+
# OpenAI Agents SDK (requires @openai/agents >=0.13)
|
|
32
52
|
npm install @openai/agents
|
|
53
|
+
|
|
54
|
+
# LangChain (requires @langchain/core >=1.2.1)
|
|
55
|
+
npm install @langchain/core @langchain/langgraph @langchain/openai
|
|
56
|
+
|
|
57
|
+
# Vercel AI SDK (requires ai >=7 — v7 is a breaking rewrite from v6)
|
|
58
|
+
npm install ai @ai-sdk/openai
|
|
33
59
|
```
|
|
34
60
|
|
|
61
|
+
> **Version notes**
|
|
62
|
+
> - **Vercel AI SDK** — `ai >=7` is required. v7 introduced `ToolSet`, `isStepCount`, and `jsonSchema()`, which this adapter depends on. v6 is **not** compatible.
|
|
63
|
+
> - **LangChain** — `@langchain/core >=1.2.1` is required for `DynamicStructuredTool` and JSON Schema parameter support.
|
|
64
|
+
> - `@langchain/langgraph` and `@langchain/openai` are not direct peer dependencies but are needed to run the agent (see examples).
|
|
65
|
+
|
|
35
66
|
## Credentials
|
|
36
67
|
|
|
37
|
-
|
|
68
|
+
Pass `env: true` to read credentials from the environment automatically:
|
|
69
|
+
|
|
70
|
+
| Variable | Purpose |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `ZUORA_BASE_URL` | Tenant REST API endpoint (required) |
|
|
73
|
+
| `ZUORA_CLIENT_ID` / `ZUORA_CLIENT_SECRET` | OAuth credentials (required) |
|
|
74
|
+
| `ZUORA_TOOLKIT_MODE` | `readOnly` (default) or `writeEnabled` |
|
|
75
|
+
|
|
76
|
+
`ZUORA_TOOLKIT_MODE` is only read when `env: true` is set, and is overridden by an explicit `configuration.mode`.
|
|
77
|
+
|
|
78
|
+
You can also pass credentials explicitly:
|
|
38
79
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
80
|
+
```ts
|
|
81
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
82
|
+
|
|
83
|
+
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
84
|
+
baseUrl: process.env.ZUORA_BASE_URL!,
|
|
85
|
+
auth: {
|
|
86
|
+
clientId: process.env.ZUORA_CLIENT_ID!,
|
|
87
|
+
clientSecret: process.env.ZUORA_CLIENT_SECRET!,
|
|
88
|
+
},
|
|
89
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`env: true` reads only credentials and base URL from the environment — all other config fields (`configuration`, `approvalPolicy`, `observability`, etc.) can still be set explicitly alongside it.
|
|
42
94
|
|
|
43
95
|
**Use a client scoped to the minimum permissions your agent needs.** Never use admin credentials.
|
|
44
96
|
|
|
45
97
|
## Usage
|
|
46
98
|
|
|
99
|
+
> **Which OpenAI adapter should I use?**
|
|
100
|
+
> - Use `@zuora/agent-toolkit/openai-agents` + `createZuoraOpenAIAgentsToolkit` if you are building with the **`@openai/agents` library** (the higher-level agent runtime).
|
|
101
|
+
> - Use `@zuora/agent-toolkit/openai` + `createZuoraOpenAIAgentToolkit` if you are using the **raw `openai` Chat Completions API** and managing the tool-call loop yourself.
|
|
102
|
+
|
|
47
103
|
### OpenAI Agents SDK
|
|
48
104
|
|
|
49
105
|
```ts
|
|
50
106
|
import { Agent, run } from "@openai/agents";
|
|
107
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
51
108
|
import { createZuoraOpenAIAgentsToolkit } from "@zuora/agent-toolkit/openai-agents";
|
|
52
109
|
|
|
53
110
|
const toolkit = await createZuoraOpenAIAgentsToolkit({
|
|
54
111
|
env: true,
|
|
55
|
-
configuration: { mode:
|
|
112
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
56
113
|
});
|
|
57
114
|
|
|
58
|
-
|
|
115
|
+
// Scope to specific bundles and cap tool count — improves model accuracy
|
|
116
|
+
const tools = (await toolkit.getTools({ bundles: ["accounts", "query"] })).slice(0, 50);
|
|
59
117
|
const agent = new Agent({ name: "Billing Agent", tools });
|
|
60
118
|
const result = await run(agent, "How many active billing accounts do we have?");
|
|
61
119
|
|
|
62
120
|
await toolkit.close();
|
|
63
121
|
```
|
|
64
122
|
|
|
65
|
-
If you already have a
|
|
123
|
+
If you already have a `ZuoraOpenAIAgentToolkit` instance (for example, shared across multiple agents or reused from an existing integration), you can convert its tools to Agents SDK format without opening a second MCP connection:
|
|
66
124
|
|
|
67
125
|
```ts
|
|
68
126
|
import { buildAgentsTools } from "@zuora/agent-toolkit/openai-agents";
|
|
69
|
-
import { createZuoraOpenAIAgentToolkit } from "@zuora/agent-toolkit/openai";
|
|
70
127
|
import { tool } from "@openai/agents";
|
|
71
128
|
|
|
72
|
-
|
|
129
|
+
// `tool` is passed in rather than imported directly so @openai/agents stays
|
|
130
|
+
// an optional peer dependency and the module loads without it installed.
|
|
73
131
|
const tools = await buildAgentsTools(tool, chatToolkit, { bundles: ["query"] });
|
|
132
|
+
const agent = new Agent({ name: "Billing Agent", tools });
|
|
133
|
+
await run(agent, "...");
|
|
134
|
+
// chatToolkit must stay open while tools are in use — close it when done
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> If you are starting fresh (no existing toolkit), prefer `createZuoraOpenAIAgentsToolkit` directly — it handles the connection internally.
|
|
138
|
+
|
|
139
|
+
### LangChain
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
143
|
+
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
|
144
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
145
|
+
import { createZuoraLangChainToolkit } from "@zuora/agent-toolkit/langchain";
|
|
146
|
+
|
|
147
|
+
const toolkit = await createZuoraLangChainToolkit({
|
|
148
|
+
env: true,
|
|
149
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Scope to specific bundles and cap tool count — improves model accuracy
|
|
153
|
+
const tools = (await toolkit.getTools({ bundles: ["accounts", "query"] })).slice(0, 50);
|
|
154
|
+
|
|
155
|
+
const agent = createReactAgent({
|
|
156
|
+
llm: new ChatOpenAI({ model: "gpt-4o" }),
|
|
157
|
+
tools,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// LangChain owns the tool-call loop — no manual dispatch needed
|
|
161
|
+
const result = await agent.invoke({
|
|
162
|
+
messages: [{ role: "user", content: "List 3 active accounts" }],
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const answer = result.messages.at(-1)?.content;
|
|
166
|
+
console.log(typeof answer === "string" ? answer : JSON.stringify(answer));
|
|
167
|
+
|
|
168
|
+
await toolkit.close();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Vercel AI SDK
|
|
172
|
+
|
|
173
|
+
> `getToolSet()` returns a `ToolSet` (`Record<string, Tool>`) — the format `streamText` and `generateText` require. All other adapters use `getTools()` which returns an array.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { openai } from "@ai-sdk/openai";
|
|
177
|
+
import { streamText, isStepCount } from "ai";
|
|
178
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
179
|
+
import { createZuoraVercelAIToolkit } from "@zuora/agent-toolkit/vercel-ai";
|
|
180
|
+
|
|
181
|
+
const toolkit = await createZuoraVercelAIToolkit({
|
|
182
|
+
env: true,
|
|
183
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// `getToolSet()` returns a ToolSet (`Record<string, Tool>`) rather than an array,
|
|
187
|
+
// so `.slice()` is not available — the second argument is the only way to cap tool count.
|
|
188
|
+
// Omit it to return all matching tools.
|
|
189
|
+
const tools = await toolkit.getToolSet(
|
|
190
|
+
{ bundles: ["accounts", "query"] },
|
|
191
|
+
50,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const { textStream } = streamText({
|
|
195
|
+
model: openai("gpt-4o"),
|
|
196
|
+
tools,
|
|
197
|
+
stopWhen: isStepCount(20), // SDK drives the tool-call loop — no manual dispatch needed
|
|
198
|
+
messages: [{ role: "user", content: "List 3 active accounts" }],
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
for await (const chunk of textStream) {
|
|
202
|
+
process.stdout.write(chunk);
|
|
203
|
+
}
|
|
204
|
+
console.log();
|
|
205
|
+
|
|
206
|
+
await toolkit.close();
|
|
74
207
|
```
|
|
75
208
|
|
|
76
209
|
### OpenAI Chat Completions
|
|
@@ -81,10 +214,11 @@ import {
|
|
|
81
214
|
createZuoraOpenAIAgentToolkit,
|
|
82
215
|
handleToolCalls,
|
|
83
216
|
} from "@zuora/agent-toolkit/openai";
|
|
217
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
84
218
|
|
|
85
219
|
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
86
220
|
env: true,
|
|
87
|
-
configuration: { mode:
|
|
221
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
88
222
|
});
|
|
89
223
|
|
|
90
224
|
const client = new OpenAI();
|
|
@@ -105,6 +239,8 @@ for (let step = 0; step < 20; step++) {
|
|
|
105
239
|
messages.push(choice.message);
|
|
106
240
|
|
|
107
241
|
if (choice.finish_reason === "tool_calls") {
|
|
242
|
+
// handleToolCalls returns { messages, abortTurn, requireToolOnNextStep, followUpToolNames }.
|
|
243
|
+
// For basic loops, only `messages` is needed. See examples/openai/hitl.ts for advanced usage.
|
|
108
244
|
const { messages: toolMessages } = await handleToolCalls({ toolkit, response });
|
|
109
245
|
messages.push(...toolMessages);
|
|
110
246
|
continue;
|
|
@@ -119,13 +255,33 @@ await toolkit.close();
|
|
|
119
255
|
|
|
120
256
|
## Configuration
|
|
121
257
|
|
|
258
|
+
Top-level config shape — all fields except credentials are optional:
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
{
|
|
262
|
+
env: true, // reads ZUORA_BASE_URL, ZUORA_CLIENT_ID, ZUORA_CLIENT_SECRET
|
|
263
|
+
configuration: { // tool filtering, safety, and routing
|
|
264
|
+
mode: SafetyMode.ReadOnly,
|
|
265
|
+
bundles: { accounts: true },
|
|
266
|
+
context: { // scopes operations to the specified entity / org
|
|
267
|
+
entityIds: "entity-1", // → Zuora-Entity-Ids header
|
|
268
|
+
orgIds: "org-1", // → Zuora-Org-Ids header
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
// approvalPolicy: … // see "Approval policy" section below
|
|
272
|
+
observability: { // optional: events and logging
|
|
273
|
+
onEvent: (event) => { … },
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
122
278
|
### Safety modes
|
|
123
279
|
|
|
124
280
|
```ts
|
|
125
281
|
configuration: {
|
|
126
|
-
mode:
|
|
282
|
+
mode: SafetyMode.ReadOnly, // only read operations (default)
|
|
127
283
|
// or
|
|
128
|
-
mode:
|
|
284
|
+
mode: SafetyMode.WriteEnabled, // read + write operations
|
|
129
285
|
}
|
|
130
286
|
```
|
|
131
287
|
|
|
@@ -143,96 +299,125 @@ configuration: {
|
|
|
143
299
|
}
|
|
144
300
|
```
|
|
145
301
|
|
|
146
|
-
Available bundles: `accounts`, `catalog`, `subscriptions`, `orders`, `billing`, `payments`, `usage`, `revenue`, `finance`, `workflows`, `query`, `admin`, `files`.
|
|
302
|
+
Available bundles: `accounts`, `catalog`, `subscriptions`, `orders`, `billing`, `payments`, `usage`, `revenue`, `finance`, `workflows`, `query`, `admin`, `files`. Which bundles are available depends on your Zuora tenant's MCP endpoint.
|
|
303
|
+
|
|
304
|
+
You can also filter at call time via `getTools()`. Note that `configuration.bundles` uses an object (`{ accounts: true }`) and is fixed at toolkit creation time; `getTools({ bundles: [...] })` uses an array and filters the already-loaded catalog at call time.
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
// Filter by bundle
|
|
308
|
+
toolkit.getTools({ bundles: ["accounts", "query"] })
|
|
147
309
|
|
|
148
|
-
|
|
310
|
+
// Include or exclude specific tools by exact name
|
|
311
|
+
toolkit.getTools({ include: ["get_account", "list_accounts"] })
|
|
312
|
+
toolkit.getTools({ exclude: ["delete_account"] })
|
|
313
|
+
|
|
314
|
+
// Narrow to write-enabled tools for this call only (per-call mode overrides global config)
|
|
315
|
+
toolkit.getTools({ mode: SafetyMode.WriteEnabled })
|
|
316
|
+
```
|
|
149
317
|
|
|
150
318
|
### Exclude / include specific tools
|
|
151
319
|
|
|
320
|
+
`configuration.bundles.billing.exclude` is evaluated once at toolkit creation and applies permanently to that bundle. `getTools({ exclude })` filters the already-loaded catalog on each call and works across all bundles.
|
|
321
|
+
|
|
322
|
+
`include` and `exclude` can be combined: `include` acts as an allowlist first, then `exclude` removes from that set. A tool passes if it matches `include` (when set) **and** is not in `exclude`.
|
|
323
|
+
|
|
152
324
|
```ts
|
|
153
325
|
configuration: {
|
|
154
326
|
bundles: {
|
|
155
327
|
billing: {
|
|
156
328
|
exclude: ["create_invoice", "delete_invoice"],
|
|
157
|
-
// or include: ["list_invoices"]
|
|
329
|
+
// or use include to allowlist specific tools: include: ["list_invoices"]
|
|
330
|
+
// or combine both: include: ["run_reports", "list_invoices"], exclude: ["delete_billing_run"]
|
|
158
331
|
},
|
|
159
332
|
},
|
|
160
333
|
}
|
|
161
334
|
```
|
|
162
335
|
|
|
163
|
-
###
|
|
336
|
+
### Enabling or disabling individual tools
|
|
337
|
+
|
|
338
|
+
To enable or disable specific tools without affecting their entire bundle:
|
|
164
339
|
|
|
165
|
-
|
|
340
|
+
```ts
|
|
341
|
+
configuration: {
|
|
342
|
+
tools: {
|
|
343
|
+
"delete_invoice": false, // disable one tool
|
|
344
|
+
"run_reports": true, // explicitly enable (useful when a bundle is partially restricted)
|
|
345
|
+
},
|
|
346
|
+
}
|
|
347
|
+
```
|
|
166
348
|
|
|
167
349
|
### Approval policy
|
|
168
350
|
|
|
169
351
|
Gate write / high-risk operations before they reach Zuora. `approvalPolicy` is a **top-level** config field (not inside `configuration`):
|
|
170
352
|
|
|
171
353
|
```ts
|
|
172
|
-
import { ApprovalPolicyPreset } from "@zuora/agent-toolkit";
|
|
354
|
+
import { ApprovalPolicyPreset, SafetyMode } from "@zuora/agent-toolkit";
|
|
173
355
|
|
|
174
356
|
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
175
357
|
env: true,
|
|
176
|
-
configuration: { mode:
|
|
358
|
+
configuration: { mode: SafetyMode.WriteEnabled },
|
|
177
359
|
approvalPolicy: ApprovalPolicyPreset.HighRisk,
|
|
178
360
|
// or a custom handler:
|
|
179
361
|
// approvalPolicy: async (request) => {
|
|
180
362
|
// if (request.tool.meta.riskLevel === "high") return "deny";
|
|
181
|
-
// return "
|
|
363
|
+
// return "allow";
|
|
182
364
|
// },
|
|
183
365
|
});
|
|
184
366
|
```
|
|
185
367
|
|
|
186
368
|
Presets: `Off`, `AllWrites`, `HighRisk`, `ProductionWrites`, `ProductionHighRisk`.
|
|
187
369
|
|
|
188
|
-
|
|
370
|
+
Custom handler return values: `"allow"` (proceed) · `"deny"` (block) · `{ decision: "allow" | "deny", reason?: string }` (with an explanation added to the rejection error).
|
|
371
|
+
|
|
372
|
+
### Context
|
|
189
373
|
|
|
190
|
-
Pass
|
|
374
|
+
Pass routing and observability identifiers via `configuration.context`. All values are strings — use comma-separation for multiple IDs:
|
|
375
|
+
|
|
376
|
+
| Key | Effect |
|
|
377
|
+
|---|---|
|
|
378
|
+
| `entityIds` | Forwarded as `Zuora-Entity-Ids` to scope operations to the specified entity |
|
|
379
|
+
| `orgIds` | Forwarded as `Zuora-Org-Ids` to scope operations to the specified org |
|
|
191
380
|
|
|
192
381
|
```ts
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
382
|
+
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
383
|
+
env: true,
|
|
384
|
+
configuration: {
|
|
385
|
+
mode: SafetyMode.WriteEnabled,
|
|
386
|
+
context: {
|
|
387
|
+
entityIds: "entity-1,entity-2", // comma-separated for multiple
|
|
388
|
+
orgIds: "org-1",
|
|
389
|
+
},
|
|
196
390
|
},
|
|
197
|
-
}
|
|
198
|
-
connection: {
|
|
199
|
-
entityIds: ["entity-1"],
|
|
200
|
-
orgIds: ["org-1"],
|
|
201
|
-
},
|
|
391
|
+
});
|
|
202
392
|
```
|
|
203
393
|
|
|
204
394
|
### Observability
|
|
205
395
|
|
|
206
396
|
```ts
|
|
207
397
|
observability: {
|
|
208
|
-
onEvent: (event) => { /*
|
|
398
|
+
onEvent: (event) => { /* synchronous observer */ },
|
|
399
|
+
emit: async (event) => { /* async sink — await is respected */ },
|
|
209
400
|
logger: { info: console.info, warn: console.warn, error: console.error },
|
|
210
|
-
includePayloads: false, // default; set true to include
|
|
401
|
+
includePayloads: false, // default; set true to include tool input keys and
|
|
402
|
+
// truncated values in events — secrets are redacted
|
|
211
403
|
}
|
|
212
404
|
```
|
|
213
405
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
Pass `env: true` to read credentials from the environment automatically:
|
|
406
|
+
Emitted event names:
|
|
217
407
|
|
|
218
|
-
|
|
219
|
-
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
220
|
-
env: true,
|
|
221
|
-
configuration: { mode: "readOnly" },
|
|
222
|
-
});
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
| Variable | Purpose |
|
|
408
|
+
| Event | When |
|
|
226
409
|
|---|---|
|
|
227
|
-
| `
|
|
228
|
-
| `
|
|
229
|
-
| `
|
|
230
|
-
|
|
231
|
-
|
|
410
|
+
| `tool.called` | Tool invocation starts |
|
|
411
|
+
| `tool.completed` | Tool returns successfully |
|
|
412
|
+
| `tool.failed` | Tool throws or returns an error |
|
|
413
|
+
| `approval.requested` | Approval policy triggers before execution |
|
|
414
|
+
| `approval.decided` | Approval decision recorded (approved / denied) |
|
|
415
|
+
| `metadata.loaded` | Tool catalog fetched from MCP on `initialize()` |
|
|
416
|
+
| `async.poll.checked` | A polling iteration completed for an async job |
|
|
232
417
|
|
|
233
418
|
## Lifecycle
|
|
234
419
|
|
|
235
|
-
Always call `close()` when done:
|
|
420
|
+
Always call `close()` when done — it closes the underlying MCP connection and allows the process to exit cleanly:
|
|
236
421
|
|
|
237
422
|
```ts
|
|
238
423
|
const toolkit = await createZuoraOpenAIAgentToolkit({ env: true });
|
|
@@ -245,19 +430,19 @@ try {
|
|
|
245
430
|
|
|
246
431
|
## Discovery and execution
|
|
247
432
|
|
|
433
|
+
> `listTools()` returns `ZuoraToolDefinition[]` — framework-agnostic metadata for inspection and logging.
|
|
434
|
+
> `getTools()` returns framework-native tool objects (e.g. `ChatCompletionTool[]`) ready to pass directly to the LLM.
|
|
435
|
+
|
|
248
436
|
```ts
|
|
249
437
|
const tools = await toolkit.listTools(); // ZuoraToolDefinition[]
|
|
250
|
-
const def = await toolkit.describeTool("get_account");
|
|
251
|
-
const bundles = await toolkit.listBundles();
|
|
252
|
-
const bundle = await toolkit.describeBundle("subscriptions");
|
|
438
|
+
const def = await toolkit.describeTool("get_account"); // ZuoraToolDefinition
|
|
439
|
+
const bundles = await toolkit.listBundles(); // ZuoraBundleName[]
|
|
440
|
+
const bundle = await toolkit.describeBundle("subscriptions"); // { name, description, toolCount, tools: ZuoraToolDefinition[] }
|
|
253
441
|
|
|
254
442
|
const result = await toolkit.callTool("get_account", { accountKey: "…" });
|
|
255
|
-
// For async tools: await toolkit.waitForJob(toolName, asyncResult, options?)
|
|
256
443
|
```
|
|
257
444
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
When the `query` bundle is enabled, the SDK may expose local helpers such as `download_query_result` and `read_downloaded_file` so agents can fetch and preview Data Query artifacts. Artifacts default to `~/.zuora-agent-artifacts`.
|
|
445
|
+
For tools that start async jobs (e.g. Data Query), the tool result automatically includes a follow-up instruction telling the model which tool to call next — the model drives polling on subsequent steps without any extra code.
|
|
261
446
|
|
|
262
447
|
## Errors
|
|
263
448
|
|
|
@@ -277,7 +462,7 @@ All SDK errors are `ZuoraAgentToolkitError` with a typed `code`:
|
|
|
277
462
|
import { ZuoraAgentToolkitError } from "@zuora/agent-toolkit";
|
|
278
463
|
|
|
279
464
|
try {
|
|
280
|
-
await
|
|
465
|
+
await toolkit.callTool("create_invoice", { accountId: "A-1" });
|
|
281
466
|
} catch (err) {
|
|
282
467
|
if (err instanceof ZuoraAgentToolkitError && err.code === "APPROVAL_REJECTED") {
|
|
283
468
|
// handle rejection
|
|
@@ -285,6 +470,21 @@ try {
|
|
|
285
470
|
}
|
|
286
471
|
```
|
|
287
472
|
|
|
473
|
+
When using framework adapters, `ZuoraAgentToolkitError` surfaces from `handleToolCalls()` (OpenAI Chat Completions), `run()` (OpenAI Agents SDK), `agent.invoke()` (LangChain), or during stream consumption with `generateText()` / `streamText()` (Vercel AI SDK).
|
|
474
|
+
|
|
475
|
+
## Key exported types
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
import type {
|
|
479
|
+
ZuoraToolDefinition, // full tool descriptor: name, description, inputSchema, meta
|
|
480
|
+
ZuoraBundleName, // union of all valid bundle name strings
|
|
481
|
+
ToolSelection, // filter shape passed to getTools() / listTools() — { bundles?, include?, exclude?, mode? }
|
|
482
|
+
ZuoraToolkitEvent, // observability event payload
|
|
483
|
+
ApprovalPolicy, // type for the approvalPolicy config field
|
|
484
|
+
} from "@zuora/agent-toolkit";
|
|
485
|
+
import { ZuoraAgentToolkitError, ApprovalPolicyPreset, SafetyMode } from "@zuora/agent-toolkit";
|
|
486
|
+
```
|
|
487
|
+
|
|
288
488
|
## Examples
|
|
289
489
|
|
|
290
490
|
Working examples are available in the source repository:
|
|
@@ -293,6 +493,8 @@ Working examples are available in the source repository:
|
|
|
293
493
|
|---|---|
|
|
294
494
|
| `examples/openai/index.ts` | Minimal Chat Completions agent loop |
|
|
295
495
|
| `examples/openai/advanced.ts` | Observability, hooks, async jobs, discovery |
|
|
296
|
-
| `examples/openai/hitl.ts` | Human-in-the-loop
|
|
496
|
+
| `examples/openai/hitl.ts` | Human-in-the-loop (HITL) approval |
|
|
297
497
|
| `examples/openai-agents/index.ts` | OpenAI Agents SDK agent |
|
|
298
498
|
| `examples/openai-agents-cli/` | Interactive CLI agent + planner |
|
|
499
|
+
| `examples/langchain/index.ts` | LangChain ReactAgent with Zuora tools |
|
|
500
|
+
| `examples/vercel-ai/index.ts` | Vercel AI SDK `streamText` agent |
|
|
@@ -30,7 +30,11 @@ type EventSanitizerLimits = {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
type ZuoraEnvironment = "sandbox" | "production";
|
|
33
|
-
|
|
33
|
+
declare const SafetyMode: {
|
|
34
|
+
readonly ReadOnly: "readOnly";
|
|
35
|
+
readonly WriteEnabled: "writeEnabled";
|
|
36
|
+
};
|
|
37
|
+
type ZuoraSafetyMode = (typeof SafetyMode)[keyof typeof SafetyMode];
|
|
34
38
|
type ZuoraToolOperation = "read" | "write";
|
|
35
39
|
type ZuoraRiskLevel = "low" | "medium" | "high";
|
|
36
40
|
/**
|
|
@@ -164,13 +168,8 @@ type JsonSchema = {
|
|
|
164
168
|
[key: string]: unknown;
|
|
165
169
|
};
|
|
166
170
|
type ZuoraAuthConfig = {
|
|
167
|
-
type: "oauthClientCredentials";
|
|
168
171
|
clientId: string;
|
|
169
172
|
clientSecret: string;
|
|
170
|
-
scope?: string;
|
|
171
|
-
} | {
|
|
172
|
-
type: "accessToken";
|
|
173
|
-
accessToken: string;
|
|
174
173
|
};
|
|
175
174
|
type ZuoraTenantAuthConfig = {
|
|
176
175
|
enabled: true;
|
|
@@ -226,8 +225,6 @@ type ZuoraMcpClient = {
|
|
|
226
225
|
close?: () => Promise<void>;
|
|
227
226
|
};
|
|
228
227
|
type ZuoraConnectionConfigBase = {
|
|
229
|
-
tokenEndpoint?: string;
|
|
230
|
-
tokenAuthMethod?: "client_secret_post" | "client_secret_basic";
|
|
231
228
|
headers?: Record<string, string | undefined>;
|
|
232
229
|
entityIds?: string | string[];
|
|
233
230
|
orgIds?: string | string[];
|
|
@@ -237,10 +234,6 @@ type ZuoraConnectionConfigBase = {
|
|
|
237
234
|
type ZuoraTenantAuthConnectionConfig = ZuoraConnectionConfigBase & {
|
|
238
235
|
tenantAuth: EnabledZuoraTenantAuthConfig;
|
|
239
236
|
};
|
|
240
|
-
type ZuoraStandardConnectionConfig = ZuoraConnectionConfigBase & {
|
|
241
|
-
tenantAuth?: Exclude<ZuoraTenantAuthConfig, EnabledZuoraTenantAuthConfig>;
|
|
242
|
-
};
|
|
243
|
-
type ZuoraConnectionConfig = ZuoraStandardConnectionConfig | ZuoraTenantAuthConnectionConfig;
|
|
244
237
|
declare const ApprovalPolicyPreset: {
|
|
245
238
|
readonly Off: "off";
|
|
246
239
|
readonly AllWrites: "all_writes";
|
|
@@ -249,8 +242,8 @@ declare const ApprovalPolicyPreset: {
|
|
|
249
242
|
readonly ProductionHighRisk: "production_high_risk";
|
|
250
243
|
};
|
|
251
244
|
type ApprovalPolicyPresetValue = (typeof ApprovalPolicyPreset)[keyof typeof ApprovalPolicyPreset];
|
|
252
|
-
type ApprovalPolicyResult = "
|
|
253
|
-
decision: "
|
|
245
|
+
type ApprovalPolicyResult = "allow" | "deny" | {
|
|
246
|
+
decision: "allow" | "deny";
|
|
254
247
|
reason?: string;
|
|
255
248
|
};
|
|
256
249
|
type ApprovalPolicyHandler = (request: ApprovalRequest) => ApprovalPolicyResult | Promise<ApprovalPolicyResult>;
|
|
@@ -362,7 +355,6 @@ type ZuoraAgentToolkitEnvConfig = Omit<ZuoraAgentToolkitConfigBase, "baseUrl"> &
|
|
|
362
355
|
};
|
|
363
356
|
type ZuoraAgentToolkitConfig = (ZuoraAgentToolkitConfigBase & {
|
|
364
357
|
auth: ZuoraAuthConfig;
|
|
365
|
-
connection?: ZuoraConnectionConfig;
|
|
366
358
|
}) | (ZuoraAgentToolkitConfigBase & {
|
|
367
359
|
auth?: ZuoraAuthConfig;
|
|
368
360
|
connection: ZuoraTenantAuthConnectionConfig;
|
|
@@ -529,4 +521,4 @@ declare function resolveAsyncJobPollingToolName(result: ZuoraAsyncJobResult | Zu
|
|
|
529
521
|
*/
|
|
530
522
|
declare function resolveAsyncJobStatusDetails(result: ZuoraToolExecutionResult, statusPath: string, terminalStatuses: ZuoraAsyncJobTerminalStatuses): ZuoraAsyncJobStatusResolution;
|
|
531
523
|
|
|
532
|
-
export { type ApprovalPolicy as A, resolveAsyncJobId as B, resolveAsyncJobPollingToolName as C, DEFAULT_ASYNC_JOB_TERMINAL_STATUSES as D, resolveAsyncJobStatus as E, resolveAsyncJobStatusDetails as F, resolveAsyncJobTerminalState as G, type NativeFileApprovalMetadata as N, type ToolSelection as T, type ZuoraToolDefinition as Z, type ZuoraAgentToolkitConfigInput as a, type ZuoraToolExecutionResult as b, type ZuoraAsyncJobResult as c, type ZuoraToolkitEvent as d, type ZuoraAgentToolkitConfig as e, type ZuoraMcpClient as f, type ZuoraBundleDefinition as g, type ZuoraBundleName as h, type ZuoraWaitForJobOptions as i, ApprovalPolicyPreset as j, type ApprovalPolicyPresetValue as k, type ApprovalRequest as l, type NativeFileToolsConfig as m, type NativeToolApprovalMetadata as n, type NativeToolMetadataConfig as o, type ToolkitBundleName as p, type ZuoraAsyncJobStatusResolution as q, type ZuoraAsyncJobTerminalState as r, type ZuoraAsyncJobTerminalStatuses as s, type ZuoraSafetyMode as t, type ZuoraToolkitConfiguration as u, type ZuoraToolkitLogger as v, buildAsyncJobResult as w, isAsyncJobResult as x, isAsyncJobTerminal as y, matchesAsyncJobTerminalStatus as z };
|
|
524
|
+
export { type ApprovalPolicy as A, resolveAsyncJobId as B, resolveAsyncJobPollingToolName as C, DEFAULT_ASYNC_JOB_TERMINAL_STATUSES as D, resolveAsyncJobStatus as E, resolveAsyncJobStatusDetails as F, resolveAsyncJobTerminalState as G, type NativeFileApprovalMetadata as N, SafetyMode as S, type ToolSelection as T, type ZuoraToolDefinition as Z, type ZuoraAgentToolkitConfigInput as a, type ZuoraToolExecutionResult as b, type ZuoraAsyncJobResult as c, type ZuoraToolkitEvent as d, type ZuoraAgentToolkitConfig as e, type ZuoraMcpClient as f, type ZuoraBundleDefinition as g, type ZuoraBundleName as h, type ZuoraWaitForJobOptions as i, ApprovalPolicyPreset as j, type ApprovalPolicyPresetValue as k, type ApprovalRequest as l, type NativeFileToolsConfig as m, type NativeToolApprovalMetadata as n, type NativeToolMetadataConfig as o, type ToolkitBundleName as p, type ZuoraAsyncJobStatusResolution as q, type ZuoraAsyncJobTerminalState as r, type ZuoraAsyncJobTerminalStatuses as s, type ZuoraSafetyMode as t, type ZuoraToolkitConfiguration as u, type ZuoraToolkitLogger as v, buildAsyncJobResult as w, isAsyncJobResult as x, isAsyncJobTerminal as y, matchesAsyncJobTerminalStatus as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as ZuoraToolExecutionResult, h as ZuoraBundleName } from './async-jobs-
|
|
2
|
-
export { A as ApprovalPolicy, j as ApprovalPolicyPreset, k as ApprovalPolicyPresetValue, l as ApprovalRequest, D as DEFAULT_ASYNC_JOB_TERMINAL_STATUSES, N as NativeFileApprovalMetadata, m as NativeFileToolsConfig, n as NativeToolApprovalMetadata, o as NativeToolMetadataConfig, T as ToolSelection, p as ToolkitBundleName, e as ZuoraAgentToolkitConfig, a as ZuoraAgentToolkitConfigInput, c as ZuoraAsyncJobResult, q as ZuoraAsyncJobStatusResolution, r as ZuoraAsyncJobTerminalState, s as ZuoraAsyncJobTerminalStatuses, g as ZuoraBundleDefinition, t as ZuoraSafetyMode, Z as ZuoraToolDefinition, u as ZuoraToolkitConfiguration, d as ZuoraToolkitEvent, v as ZuoraToolkitLogger, i as ZuoraWaitForJobOptions, w as buildAsyncJobResult, x as isAsyncJobResult, y as isAsyncJobTerminal, z as matchesAsyncJobTerminalStatus, B as resolveAsyncJobId, C as resolveAsyncJobPollingToolName, E as resolveAsyncJobStatus, F as resolveAsyncJobStatusDetails, G as resolveAsyncJobTerminalState } from './async-jobs-
|
|
1
|
+
import { b as ZuoraToolExecutionResult, h as ZuoraBundleName } from './async-jobs-DJ_GygII.js';
|
|
2
|
+
export { A as ApprovalPolicy, j as ApprovalPolicyPreset, k as ApprovalPolicyPresetValue, l as ApprovalRequest, D as DEFAULT_ASYNC_JOB_TERMINAL_STATUSES, N as NativeFileApprovalMetadata, m as NativeFileToolsConfig, n as NativeToolApprovalMetadata, o as NativeToolMetadataConfig, S as SafetyMode, T as ToolSelection, p as ToolkitBundleName, e as ZuoraAgentToolkitConfig, a as ZuoraAgentToolkitConfigInput, c as ZuoraAsyncJobResult, q as ZuoraAsyncJobStatusResolution, r as ZuoraAsyncJobTerminalState, s as ZuoraAsyncJobTerminalStatuses, g as ZuoraBundleDefinition, t as ZuoraSafetyMode, Z as ZuoraToolDefinition, u as ZuoraToolkitConfiguration, d as ZuoraToolkitEvent, v as ZuoraToolkitLogger, i as ZuoraWaitForJobOptions, w as buildAsyncJobResult, x as isAsyncJobResult, y as isAsyncJobTerminal, z as matchesAsyncJobTerminalStatus, B as resolveAsyncJobId, C as resolveAsyncJobPollingToolName, E as resolveAsyncJobStatus, F as resolveAsyncJobStatusDetails, G as resolveAsyncJobTerminalState } from './async-jobs-DJ_GygII.js';
|
|
3
3
|
|
|
4
4
|
type ZuoraAgentToolkitP0ErrorCode = "TOOL_EXECUTION_ERROR" | "TOOL_NOT_FOUND" | "BUNDLE_NOT_FOUND" | "APPROVAL_REJECTED" | "MALFORMED_METADATA" | "OAUTH_TOKEN_ERROR" | "ASYNC_JOB_TIMEOUT";
|
|
5
5
|
type ZuoraAgentToolkitErrorCode = ZuoraAgentToolkitP0ErrorCode | (string & {});
|
package/dist/index.js
CHANGED
|
@@ -236,6 +236,10 @@ var readNonEmptyString = (value) => {
|
|
|
236
236
|
};
|
|
237
237
|
|
|
238
238
|
// src/shared/types.ts
|
|
239
|
+
var SafetyMode = {
|
|
240
|
+
ReadOnly: "readOnly",
|
|
241
|
+
WriteEnabled: "writeEnabled"
|
|
242
|
+
};
|
|
239
243
|
var ApprovalPolicyPreset = {
|
|
240
244
|
Off: "off",
|
|
241
245
|
AllWrites: "all_writes",
|
|
@@ -479,6 +483,7 @@ var ZUORA_BUNDLE_NAME_SET = new Set(ZUORA_BUNDLE_NAMES);
|
|
|
479
483
|
export {
|
|
480
484
|
ApprovalPolicyPreset,
|
|
481
485
|
DEFAULT_ASYNC_JOB_TERMINAL_STATUSES,
|
|
486
|
+
SafetyMode,
|
|
482
487
|
ZUORA_BUNDLE_NAME_SET,
|
|
483
488
|
ZuoraAgentToolkitError,
|
|
484
489
|
buildAsyncJobResult,
|