@zuora/agent-toolkit 0.0.1-alpha.0 → 0.1.0-alpha.1
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 +279 -63
- 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 +4972 -0
- package/dist/langchain/index.js.map +1 -1
- package/dist/openai/index.d.ts +3 -3
- package/dist/openai/index.js +52 -135
- package/dist/openai/index.js.map +1 -1
- package/dist/openai-agents/index.d.ts +32 -3
- package/dist/openai-agents/index.js +126 -135
- package/dist/openai-agents/index.js.map +1 -1
- package/dist/shared/toolkit-core.d.ts +1 -1
- package/dist/shared/toolkit-core.js +47 -91
- 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 +5006 -0
- package/dist/vercel-ai/index.js.map +1 -1
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -6,18 +6,51 @@ 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
|
|
|
37
|
+
## Changelog
|
|
38
|
+
|
|
39
|
+
### [0.1.0-alpha.1]
|
|
40
|
+
|
|
41
|
+
- Fixed HITL approval policy handling with correct `request.environment` usage
|
|
42
|
+
- Improved tool name resolution
|
|
43
|
+
- Removed deprecated `CLI_AGENT_SPLIT_OPERATIONS` references
|
|
44
|
+
- Test and documentation updates
|
|
45
|
+
|
|
46
|
+
### [0.1.0-alpha.0]
|
|
47
|
+
|
|
48
|
+
Initial alpha release.
|
|
49
|
+
|
|
19
50
|
## Installation
|
|
20
51
|
|
|
52
|
+
Requires **Node.js 18** or later.
|
|
53
|
+
|
|
21
54
|
```bash
|
|
22
55
|
npm install @zuora/agent-toolkit
|
|
23
56
|
```
|
|
@@ -25,52 +58,165 @@ npm install @zuora/agent-toolkit
|
|
|
25
58
|
Framework packages are peer dependencies — install only what you use:
|
|
26
59
|
|
|
27
60
|
```bash
|
|
28
|
-
# OpenAI Chat Completions
|
|
61
|
+
# OpenAI Chat Completions (requires openai >=4)
|
|
29
62
|
npm install openai
|
|
30
63
|
|
|
31
|
-
# OpenAI Agents SDK
|
|
64
|
+
# OpenAI Agents SDK (requires @openai/agents >=0.13)
|
|
32
65
|
npm install @openai/agents
|
|
66
|
+
|
|
67
|
+
# LangChain (requires @langchain/core >=1.2.1)
|
|
68
|
+
npm install @langchain/core @langchain/langgraph @langchain/openai
|
|
69
|
+
|
|
70
|
+
# Vercel AI SDK (requires ai >=7 — v7 is a breaking rewrite from v6)
|
|
71
|
+
npm install ai @ai-sdk/openai
|
|
33
72
|
```
|
|
34
73
|
|
|
74
|
+
> **Version notes**
|
|
75
|
+
> - **Vercel AI SDK** — `ai >=7` is required. v7 introduced `ToolSet`, `isStepCount`, and `jsonSchema()`, which this adapter depends on. v6 is **not** compatible.
|
|
76
|
+
> - **LangChain** — `@langchain/core >=1.2.1` is required for `DynamicStructuredTool` and JSON Schema parameter support.
|
|
77
|
+
> - `@langchain/langgraph` and `@langchain/openai` are not direct peer dependencies but are needed to run the agent (see examples).
|
|
78
|
+
|
|
35
79
|
## Credentials
|
|
36
80
|
|
|
37
|
-
|
|
81
|
+
Pass `env: true` to read credentials from the environment automatically:
|
|
82
|
+
|
|
83
|
+
| Variable | Purpose |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `ZUORA_BASE_URL` | Tenant REST API endpoint (required) |
|
|
86
|
+
| `ZUORA_CLIENT_ID` / `ZUORA_CLIENT_SECRET` | OAuth credentials (required) |
|
|
87
|
+
| `ZUORA_TOOLKIT_MODE` | `readOnly` (default) or `writeEnabled` |
|
|
38
88
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
89
|
+
`ZUORA_TOOLKIT_MODE` is only read when `env: true` is set, and is overridden by an explicit `configuration.mode`.
|
|
90
|
+
|
|
91
|
+
You can also pass credentials explicitly:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
95
|
+
|
|
96
|
+
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
97
|
+
baseUrl: process.env.ZUORA_BASE_URL!,
|
|
98
|
+
auth: {
|
|
99
|
+
clientId: process.env.ZUORA_CLIENT_ID!,
|
|
100
|
+
clientSecret: process.env.ZUORA_CLIENT_SECRET!,
|
|
101
|
+
},
|
|
102
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`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
107
|
|
|
43
108
|
**Use a client scoped to the minimum permissions your agent needs.** Never use admin credentials.
|
|
44
109
|
|
|
45
110
|
## Usage
|
|
46
111
|
|
|
112
|
+
> **Which OpenAI adapter should I use?**
|
|
113
|
+
> - Use `@zuora/agent-toolkit/openai-agents` + `createZuoraOpenAIAgentsToolkit` if you are building with the **`@openai/agents` library** (the higher-level agent runtime).
|
|
114
|
+
> - Use `@zuora/agent-toolkit/openai` + `createZuoraOpenAIAgentToolkit` if you are using the **raw `openai` Chat Completions API** and managing the tool-call loop yourself.
|
|
115
|
+
|
|
47
116
|
### OpenAI Agents SDK
|
|
48
117
|
|
|
49
118
|
```ts
|
|
50
119
|
import { Agent, run } from "@openai/agents";
|
|
120
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
51
121
|
import { createZuoraOpenAIAgentsToolkit } from "@zuora/agent-toolkit/openai-agents";
|
|
52
122
|
|
|
53
123
|
const toolkit = await createZuoraOpenAIAgentsToolkit({
|
|
54
124
|
env: true,
|
|
55
|
-
configuration: { mode:
|
|
125
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
56
126
|
});
|
|
57
127
|
|
|
58
|
-
|
|
128
|
+
// Scope to specific bundles and cap tool count — improves model accuracy
|
|
129
|
+
const tools = (await toolkit.getTools({ bundles: ["accounts", "query"] })).slice(0, 50);
|
|
59
130
|
const agent = new Agent({ name: "Billing Agent", tools });
|
|
60
131
|
const result = await run(agent, "How many active billing accounts do we have?");
|
|
61
132
|
|
|
62
133
|
await toolkit.close();
|
|
63
134
|
```
|
|
64
135
|
|
|
65
|
-
If you already have a
|
|
136
|
+
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
137
|
|
|
67
138
|
```ts
|
|
68
139
|
import { buildAgentsTools } from "@zuora/agent-toolkit/openai-agents";
|
|
69
|
-
import { createZuoraOpenAIAgentToolkit } from "@zuora/agent-toolkit/openai";
|
|
70
140
|
import { tool } from "@openai/agents";
|
|
71
141
|
|
|
72
|
-
|
|
142
|
+
// `tool` is passed in rather than imported directly so @openai/agents stays
|
|
143
|
+
// an optional peer dependency and the module loads without it installed.
|
|
73
144
|
const tools = await buildAgentsTools(tool, chatToolkit, { bundles: ["query"] });
|
|
145
|
+
const agent = new Agent({ name: "Billing Agent", tools });
|
|
146
|
+
await run(agent, "...");
|
|
147
|
+
// chatToolkit must stay open while tools are in use — close it when done
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
> If you are starting fresh (no existing toolkit), prefer `createZuoraOpenAIAgentsToolkit` directly — it handles the connection internally.
|
|
151
|
+
|
|
152
|
+
### LangChain
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
156
|
+
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
|
157
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
158
|
+
import { createZuoraLangChainToolkit } from "@zuora/agent-toolkit/langchain";
|
|
159
|
+
|
|
160
|
+
const toolkit = await createZuoraLangChainToolkit({
|
|
161
|
+
env: true,
|
|
162
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Scope to specific bundles and cap tool count — improves model accuracy
|
|
166
|
+
const tools = (await toolkit.getTools({ bundles: ["accounts", "query"] })).slice(0, 50);
|
|
167
|
+
|
|
168
|
+
const agent = createReactAgent({
|
|
169
|
+
llm: new ChatOpenAI({ model: "gpt-4o" }),
|
|
170
|
+
tools,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// LangChain owns the tool-call loop — no manual dispatch needed
|
|
174
|
+
const result = await agent.invoke({
|
|
175
|
+
messages: [{ role: "user", content: "List 3 active accounts" }],
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const answer = result.messages.at(-1)?.content;
|
|
179
|
+
console.log(typeof answer === "string" ? answer : JSON.stringify(answer));
|
|
180
|
+
|
|
181
|
+
await toolkit.close();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Vercel AI SDK
|
|
185
|
+
|
|
186
|
+
> `getToolSet()` returns a `ToolSet` (`Record<string, Tool>`) — the format `streamText` and `generateText` require. All other adapters use `getTools()` which returns an array.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { openai } from "@ai-sdk/openai";
|
|
190
|
+
import { streamText, isStepCount } from "ai";
|
|
191
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
192
|
+
import { createZuoraVercelAIToolkit } from "@zuora/agent-toolkit/vercel-ai";
|
|
193
|
+
|
|
194
|
+
const toolkit = await createZuoraVercelAIToolkit({
|
|
195
|
+
env: true,
|
|
196
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// `getToolSet()` returns a ToolSet (`Record<string, Tool>`) rather than an array,
|
|
200
|
+
// so `.slice()` is not available — the second argument is the only way to cap tool count.
|
|
201
|
+
// Omit it to return all matching tools.
|
|
202
|
+
const tools = await toolkit.getToolSet(
|
|
203
|
+
{ bundles: ["accounts", "query"] },
|
|
204
|
+
50,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const { textStream } = streamText({
|
|
208
|
+
model: openai("gpt-4o"),
|
|
209
|
+
tools,
|
|
210
|
+
stopWhen: isStepCount(20), // SDK drives the tool-call loop — no manual dispatch needed
|
|
211
|
+
messages: [{ role: "user", content: "List 3 active accounts" }],
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
for await (const chunk of textStream) {
|
|
215
|
+
process.stdout.write(chunk);
|
|
216
|
+
}
|
|
217
|
+
console.log();
|
|
218
|
+
|
|
219
|
+
await toolkit.close();
|
|
74
220
|
```
|
|
75
221
|
|
|
76
222
|
### OpenAI Chat Completions
|
|
@@ -81,10 +227,11 @@ import {
|
|
|
81
227
|
createZuoraOpenAIAgentToolkit,
|
|
82
228
|
handleToolCalls,
|
|
83
229
|
} from "@zuora/agent-toolkit/openai";
|
|
230
|
+
import { SafetyMode } from "@zuora/agent-toolkit";
|
|
84
231
|
|
|
85
232
|
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
86
233
|
env: true,
|
|
87
|
-
configuration: { mode:
|
|
234
|
+
configuration: { mode: SafetyMode.ReadOnly },
|
|
88
235
|
});
|
|
89
236
|
|
|
90
237
|
const client = new OpenAI();
|
|
@@ -105,6 +252,8 @@ for (let step = 0; step < 20; step++) {
|
|
|
105
252
|
messages.push(choice.message);
|
|
106
253
|
|
|
107
254
|
if (choice.finish_reason === "tool_calls") {
|
|
255
|
+
// handleToolCalls returns { messages, abortTurn, requireToolOnNextStep, followUpToolNames }.
|
|
256
|
+
// For basic loops, only `messages` is needed. See examples/openai/hitl.ts for advanced usage.
|
|
108
257
|
const { messages: toolMessages } = await handleToolCalls({ toolkit, response });
|
|
109
258
|
messages.push(...toolMessages);
|
|
110
259
|
continue;
|
|
@@ -119,13 +268,33 @@ await toolkit.close();
|
|
|
119
268
|
|
|
120
269
|
## Configuration
|
|
121
270
|
|
|
271
|
+
Top-level config shape — all fields except credentials are optional:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
{
|
|
275
|
+
env: true, // reads ZUORA_BASE_URL, ZUORA_CLIENT_ID, ZUORA_CLIENT_SECRET
|
|
276
|
+
configuration: { // tool filtering, safety, and routing
|
|
277
|
+
mode: SafetyMode.ReadOnly,
|
|
278
|
+
bundles: { accounts: true },
|
|
279
|
+
context: { // scopes operations to the specified entity / org
|
|
280
|
+
entityIds: "entity-1", // → Zuora-Entity-Ids header
|
|
281
|
+
orgIds: "org-1", // → Zuora-Org-Ids header
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
// approvalPolicy: … // see "Approval policy" section below
|
|
285
|
+
observability: { // optional: events and logging
|
|
286
|
+
onEvent: (event) => { … },
|
|
287
|
+
},
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
122
291
|
### Safety modes
|
|
123
292
|
|
|
124
293
|
```ts
|
|
125
294
|
configuration: {
|
|
126
|
-
mode:
|
|
295
|
+
mode: SafetyMode.ReadOnly, // only read operations (default)
|
|
127
296
|
// or
|
|
128
|
-
mode:
|
|
297
|
+
mode: SafetyMode.WriteEnabled, // read + write operations
|
|
129
298
|
}
|
|
130
299
|
```
|
|
131
300
|
|
|
@@ -143,96 +312,125 @@ configuration: {
|
|
|
143
312
|
}
|
|
144
313
|
```
|
|
145
314
|
|
|
146
|
-
Available bundles: `accounts`, `catalog`, `subscriptions`, `orders`, `billing`, `payments`, `usage`, `revenue`, `finance`, `workflows`, `query`, `admin`, `files`.
|
|
315
|
+
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.
|
|
316
|
+
|
|
317
|
+
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.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
// Filter by bundle
|
|
321
|
+
toolkit.getTools({ bundles: ["accounts", "query"] })
|
|
322
|
+
|
|
323
|
+
// Include or exclude specific tools by exact name
|
|
324
|
+
toolkit.getTools({ include: ["get_account", "list_accounts"] })
|
|
325
|
+
toolkit.getTools({ exclude: ["delete_account"] })
|
|
147
326
|
|
|
148
|
-
|
|
327
|
+
// Narrow to write-enabled tools for this call only (per-call mode overrides global config)
|
|
328
|
+
toolkit.getTools({ mode: SafetyMode.WriteEnabled })
|
|
329
|
+
```
|
|
149
330
|
|
|
150
331
|
### Exclude / include specific tools
|
|
151
332
|
|
|
333
|
+
`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.
|
|
334
|
+
|
|
335
|
+
`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`.
|
|
336
|
+
|
|
152
337
|
```ts
|
|
153
338
|
configuration: {
|
|
154
339
|
bundles: {
|
|
155
340
|
billing: {
|
|
156
341
|
exclude: ["create_invoice", "delete_invoice"],
|
|
157
|
-
// or include: ["list_invoices"]
|
|
342
|
+
// or use include to allowlist specific tools: include: ["list_invoices"]
|
|
343
|
+
// or combine both: include: ["run_reports", "list_invoices"], exclude: ["delete_billing_run"]
|
|
158
344
|
},
|
|
159
345
|
},
|
|
160
346
|
}
|
|
161
347
|
```
|
|
162
348
|
|
|
163
|
-
###
|
|
349
|
+
### Enabling or disabling individual tools
|
|
164
350
|
|
|
165
|
-
|
|
351
|
+
To enable or disable specific tools without affecting their entire bundle:
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
configuration: {
|
|
355
|
+
tools: {
|
|
356
|
+
"delete_invoice": false, // disable one tool
|
|
357
|
+
"run_reports": true, // explicitly enable (useful when a bundle is partially restricted)
|
|
358
|
+
},
|
|
359
|
+
}
|
|
360
|
+
```
|
|
166
361
|
|
|
167
362
|
### Approval policy
|
|
168
363
|
|
|
169
364
|
Gate write / high-risk operations before they reach Zuora. `approvalPolicy` is a **top-level** config field (not inside `configuration`):
|
|
170
365
|
|
|
171
366
|
```ts
|
|
172
|
-
import { ApprovalPolicyPreset } from "@zuora/agent-toolkit";
|
|
367
|
+
import { ApprovalPolicyPreset, SafetyMode } from "@zuora/agent-toolkit";
|
|
173
368
|
|
|
174
369
|
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
175
370
|
env: true,
|
|
176
|
-
configuration: { mode:
|
|
371
|
+
configuration: { mode: SafetyMode.WriteEnabled },
|
|
177
372
|
approvalPolicy: ApprovalPolicyPreset.HighRisk,
|
|
178
373
|
// or a custom handler:
|
|
179
374
|
// approvalPolicy: async (request) => {
|
|
180
375
|
// if (request.tool.meta.riskLevel === "high") return "deny";
|
|
181
|
-
// return "
|
|
376
|
+
// return "allow";
|
|
182
377
|
// },
|
|
183
378
|
});
|
|
184
379
|
```
|
|
185
380
|
|
|
186
381
|
Presets: `Off`, `AllWrites`, `HighRisk`, `ProductionWrites`, `ProductionHighRisk`.
|
|
187
382
|
|
|
188
|
-
|
|
383
|
+
Custom handler return values: `"allow"` (proceed) · `"deny"` (block) · `{ decision: "allow" | "deny", reason?: string }` (with an explanation added to the rejection error).
|
|
189
384
|
|
|
190
|
-
|
|
385
|
+
### Context
|
|
386
|
+
|
|
387
|
+
Pass routing and observability identifiers via `configuration.context`. All values are strings — use comma-separation for multiple IDs:
|
|
388
|
+
|
|
389
|
+
| Key | Effect |
|
|
390
|
+
|---|---|
|
|
391
|
+
| `entityIds` | Forwarded as `Zuora-Entity-Ids` to scope operations to the specified entity |
|
|
392
|
+
| `orgIds` | Forwarded as `Zuora-Org-Ids` to scope operations to the specified org |
|
|
191
393
|
|
|
192
394
|
```ts
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
395
|
+
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
396
|
+
env: true,
|
|
397
|
+
configuration: {
|
|
398
|
+
mode: SafetyMode.WriteEnabled,
|
|
399
|
+
context: {
|
|
400
|
+
entityIds: "entity-1,entity-2", // comma-separated for multiple
|
|
401
|
+
orgIds: "org-1",
|
|
402
|
+
},
|
|
196
403
|
},
|
|
197
|
-
}
|
|
198
|
-
connection: {
|
|
199
|
-
entityIds: ["entity-1"],
|
|
200
|
-
orgIds: ["org-1"],
|
|
201
|
-
},
|
|
404
|
+
});
|
|
202
405
|
```
|
|
203
406
|
|
|
204
407
|
### Observability
|
|
205
408
|
|
|
206
409
|
```ts
|
|
207
410
|
observability: {
|
|
208
|
-
onEvent: (event) => { /*
|
|
411
|
+
onEvent: (event) => { /* synchronous observer */ },
|
|
412
|
+
emit: async (event) => { /* async sink — await is respected */ },
|
|
209
413
|
logger: { info: console.info, warn: console.warn, error: console.error },
|
|
210
|
-
includePayloads: false, // default; set true to include
|
|
414
|
+
includePayloads: false, // default; set true to include tool input keys and
|
|
415
|
+
// truncated values in events — secrets are redacted
|
|
211
416
|
}
|
|
212
417
|
```
|
|
213
418
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
Pass `env: true` to read credentials from the environment automatically:
|
|
217
|
-
|
|
218
|
-
```ts
|
|
219
|
-
const toolkit = await createZuoraOpenAIAgentToolkit({
|
|
220
|
-
env: true,
|
|
221
|
-
configuration: { mode: "readOnly" },
|
|
222
|
-
});
|
|
223
|
-
```
|
|
419
|
+
Emitted event names:
|
|
224
420
|
|
|
225
|
-
|
|
|
421
|
+
| Event | When |
|
|
226
422
|
|---|---|
|
|
227
|
-
| `
|
|
228
|
-
| `
|
|
229
|
-
| `
|
|
230
|
-
|
|
231
|
-
|
|
423
|
+
| `tool.called` | Tool invocation starts |
|
|
424
|
+
| `tool.completed` | Tool returns successfully |
|
|
425
|
+
| `tool.failed` | Tool throws or returns an error |
|
|
426
|
+
| `approval.requested` | Approval policy triggers before execution |
|
|
427
|
+
| `approval.decided` | Approval decision recorded (approved / denied) |
|
|
428
|
+
| `metadata.loaded` | Tool catalog fetched from MCP on `initialize()` |
|
|
429
|
+
| `async.poll.checked` | A polling iteration completed for an async job |
|
|
232
430
|
|
|
233
431
|
## Lifecycle
|
|
234
432
|
|
|
235
|
-
Always call `close()` when done:
|
|
433
|
+
Always call `close()` when done — it closes the underlying MCP connection and allows the process to exit cleanly:
|
|
236
434
|
|
|
237
435
|
```ts
|
|
238
436
|
const toolkit = await createZuoraOpenAIAgentToolkit({ env: true });
|
|
@@ -245,19 +443,19 @@ try {
|
|
|
245
443
|
|
|
246
444
|
## Discovery and execution
|
|
247
445
|
|
|
446
|
+
> `listTools()` returns `ZuoraToolDefinition[]` — framework-agnostic metadata for inspection and logging.
|
|
447
|
+
> `getTools()` returns framework-native tool objects (e.g. `ChatCompletionTool[]`) ready to pass directly to the LLM.
|
|
448
|
+
|
|
248
449
|
```ts
|
|
249
450
|
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");
|
|
451
|
+
const def = await toolkit.describeTool("get_account"); // ZuoraToolDefinition
|
|
452
|
+
const bundles = await toolkit.listBundles(); // ZuoraBundleName[]
|
|
453
|
+
const bundle = await toolkit.describeBundle("subscriptions"); // { name, description, toolCount, tools: ZuoraToolDefinition[] }
|
|
253
454
|
|
|
254
455
|
const result = await toolkit.callTool("get_account", { accountKey: "…" });
|
|
255
|
-
// For async tools: await toolkit.waitForJob(toolName, asyncResult, options?)
|
|
256
456
|
```
|
|
257
457
|
|
|
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`.
|
|
458
|
+
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
459
|
|
|
262
460
|
## Errors
|
|
263
461
|
|
|
@@ -277,7 +475,7 @@ All SDK errors are `ZuoraAgentToolkitError` with a typed `code`:
|
|
|
277
475
|
import { ZuoraAgentToolkitError } from "@zuora/agent-toolkit";
|
|
278
476
|
|
|
279
477
|
try {
|
|
280
|
-
await
|
|
478
|
+
await toolkit.callTool("create_invoice", { accountId: "A-1" });
|
|
281
479
|
} catch (err) {
|
|
282
480
|
if (err instanceof ZuoraAgentToolkitError && err.code === "APPROVAL_REJECTED") {
|
|
283
481
|
// handle rejection
|
|
@@ -285,6 +483,21 @@ try {
|
|
|
285
483
|
}
|
|
286
484
|
```
|
|
287
485
|
|
|
486
|
+
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).
|
|
487
|
+
|
|
488
|
+
## Key exported types
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
import type {
|
|
492
|
+
ZuoraToolDefinition, // full tool descriptor: name, description, inputSchema, meta
|
|
493
|
+
ZuoraBundleName, // union of all valid bundle name strings
|
|
494
|
+
ToolSelection, // filter shape passed to getTools() / listTools() — { bundles?, include?, exclude?, mode? }
|
|
495
|
+
ZuoraToolkitEvent, // observability event payload
|
|
496
|
+
ApprovalPolicy, // type for the approvalPolicy config field
|
|
497
|
+
} from "@zuora/agent-toolkit";
|
|
498
|
+
import { ZuoraAgentToolkitError, ApprovalPolicyPreset, SafetyMode } from "@zuora/agent-toolkit";
|
|
499
|
+
```
|
|
500
|
+
|
|
288
501
|
## Examples
|
|
289
502
|
|
|
290
503
|
Working examples are available in the source repository:
|
|
@@ -293,6 +506,9 @@ Working examples are available in the source repository:
|
|
|
293
506
|
|---|---|
|
|
294
507
|
| `examples/openai/index.ts` | Minimal Chat Completions agent loop |
|
|
295
508
|
| `examples/openai/advanced.ts` | Observability, hooks, async jobs, discovery |
|
|
296
|
-
| `examples/openai/hitl.ts` | Human-in-the-loop
|
|
509
|
+
| `examples/openai/hitl.ts` | Human-in-the-loop (HITL) approval |
|
|
297
510
|
| `examples/openai-agents/index.ts` | OpenAI Agents SDK agent |
|
|
298
|
-
| `examples/openai-agents-cli/` | Interactive CLI agent + planner |
|
|
511
|
+
| `examples/openai-agents-cli/` | Interactive CLI agent + planner + dual-layer approval (HITL + toolkit) |
|
|
512
|
+
| `examples/langchain-agents-cli/` | Interactive LangChain CLI agent + planner + dual-layer approval (HITL + toolkit) |
|
|
513
|
+
| `examples/langchain/index.ts` | LangChain ReactAgent with Zuora tools |
|
|
514
|
+
| `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,
|