tollgate-skill 1.0.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.
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "tollgate",
3
+ "owner": { "name": "Tollgate", "url": "https://tollgateai.com" },
4
+ "plugins": [
5
+ {
6
+ "name": "tollgate",
7
+ "description": "Real-time gross-margin observability for AI agents. Wraps any LLM provider with cost + margin tracking in 2 lines.",
8
+ "category": "development",
9
+ "source": {
10
+ "source": "git",
11
+ "url": "https://github.com/Tollgateai/tollgate-skill.git",
12
+ "ref": "main"
13
+ },
14
+ "skills": ["./claude-code"],
15
+ "homepage": "https://github.com/Tollgateai/tollgate-skill"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "tollgate",
3
+ "description": "Real-time gross-margin observability for AI agents. Wraps any LLM provider with cost + margin tracking in 2 lines.",
4
+ "version": "1.0.0",
5
+ "author": { "name": "Tollgate", "url": "https://tollgateai.com" },
6
+ "keywords": ["ai", "cost", "margin", "observability", "llm", "agents"],
7
+ "homepage": "https://github.com/Tollgateai/tollgate-skill"
8
+ }
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # tollgate-skill
2
+
3
+ > AI coding tool instructions for integrating [Tollgate](https://www.tollgateai.dev) — real-time gross-margin observability for AI products.
4
+
5
+ Works with **Claude Code**, **Cursor**, **GitHub Copilot**, **Windsurf**, and **Codex**. One install, your AI coding assistant knows how to wire up Tollgate correctly.
6
+
7
+ ---
8
+
9
+ ## What this does
10
+
11
+ Once installed, your AI coding assistant can:
12
+ - Wrap any LLM provider client (Anthropic, OpenAI, Gemini, Bedrock, OpenRouter…) with Tollgate tracking in 2 lines
13
+ - Set `idempotencyKey`, `reasoningTokens`, `cachedTokens` correctly
14
+ - Handle multi-step agents and run outcomes
15
+ - Configure streaming correctly for each provider
16
+ - Keep prompt content out of the tracking payload
17
+
18
+ ---
19
+
20
+ ## Install
21
+
22
+ ### Claude Code
23
+
24
+ ```bash
25
+ curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | bash -s -- --tool claude
26
+ ```
27
+
28
+ Installs to `~/.claude/skills/tollgate/SKILL.md`. Restart Claude Code, then type `/tollgate` to activate.
29
+
30
+ ### Cursor
31
+
32
+ ```bash
33
+ curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | bash -s -- --tool cursor
34
+ ```
35
+
36
+ Installs to `.cursor/rules/tollgate.mdc` in your project. Cursor picks it up automatically when relevant.
37
+
38
+ ### GitHub Copilot
39
+
40
+ ```bash
41
+ curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | bash -s -- --tool copilot
42
+ ```
43
+
44
+ Appends to (or creates) `.github/copilot-instructions.md` in your project.
45
+
46
+ ### Windsurf
47
+
48
+ ```bash
49
+ curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | bash -s -- --tool windsurf
50
+ ```
51
+
52
+ Installs to `.windsurf/rules/tollgate.md` in your project.
53
+
54
+ ### Codex
55
+
56
+ ```bash
57
+ curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | bash -s -- --tool codex
58
+ ```
59
+
60
+ Appends to (or creates) `AGENTS.md` in your project.
61
+
62
+ ### All tools at once
63
+
64
+ ```bash
65
+ curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | bash -s -- --tool all
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Manual install
71
+
72
+ | Tool | Copy this file to... |
73
+ |---|---|
74
+ | Claude Code | `~/.claude/skills/tollgate/SKILL.md` |
75
+ | Cursor | `.cursor/rules/tollgate.mdc` |
76
+ | GitHub Copilot | `.github/copilot-instructions.md` |
77
+ | Windsurf | `.windsurf/rules/tollgate.md` |
78
+ | Codex | `AGENTS.md` (project root) |
79
+
80
+ ---
81
+
82
+ ## What you'll need
83
+
84
+ - A Tollgate account — [sign up at tollgateai](https://www.tollgateai.dev)
85
+ - An API key from **Settings → API Keys** (prefix: `tg_live_…`)
86
+ - The Tollgate SDK: `npm install @tollgateai/sdk` or `pip install tollgateai`
87
+
88
+ ---
89
+
90
+ ## Repo structure
91
+
92
+ ```
93
+ tollgate-skill/
94
+ claude-code/
95
+ SKILL.md Claude Code skill (YAML frontmatter + full integration guide)
96
+ cursor/
97
+ tollgate.mdc Cursor rule (.mdc format with glob config)
98
+ copilot/
99
+ copilot-instructions.md GitHub Copilot workspace instructions
100
+ windsurf/
101
+ tollgate.md Windsurf rule
102
+ codex/
103
+ AGENTS.md OpenAI Codex agent instructions
104
+ install.sh One-liner installer for all tools
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Links
110
+
111
+ - [Tollgate Dashboard](https://www.tollgateai.dev/dashboard)
112
+ - [SDK — @tollgateai/sdk](https://www.npmjs.com/package/@tollgateai/sdk) · [source](https://github.com/Tollgateai/tollgate-sdk/tree/main/packages/tollgate-sdk-ts)
113
+ - [Python SDK — tollgateai](https://pypi.org/project/tollgateai/) · [source](https://github.com/Tollgateai/tollgate-sdk/tree/main/packages/tollgate-sdk-python)
114
+ - [Docs](https://www.tollgateai.dev/docs)
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const args = process.argv.slice(2);
8
+ const toolFlagIndex = args.indexOf('--tool');
9
+ const tool = toolFlagIndex !== -1 ? args[toolFlagIndex + 1] : (args[0] || '');
10
+
11
+ const ROOT = path.join(__dirname, '..');
12
+
13
+ function copyFile(src, dest) {
14
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
15
+ fs.copyFileSync(src, dest);
16
+ }
17
+
18
+ function appendOrCreate(src, dest) {
19
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
20
+ const content = fs.readFileSync(src, 'utf8');
21
+ if (fs.existsSync(dest)) {
22
+ fs.appendFileSync(dest, '\n' + content);
23
+ return 'appended to';
24
+ }
25
+ fs.writeFileSync(dest, content);
26
+ return 'created at';
27
+ }
28
+
29
+ function installClaude() {
30
+ const dest = path.join(os.homedir(), '.claude', 'skills', 'tollgate', 'SKILL.md');
31
+ copyFile(path.join(ROOT, 'claude-code', 'SKILL.md'), dest);
32
+ console.log(`Claude Code: skill installed at ${dest}`);
33
+ console.log(' Restart Claude Code, then use /tollgate to activate.');
34
+ }
35
+
36
+ function installCursor() {
37
+ const dest = path.join(process.cwd(), '.cursor', 'rules', 'tollgate.mdc');
38
+ copyFile(path.join(ROOT, 'cursor', 'tollgate.mdc'), dest);
39
+ console.log(`Cursor: rule installed at ${dest}`);
40
+ }
41
+
42
+ function installCopilot() {
43
+ const dest = path.join(process.cwd(), '.github', 'copilot-instructions.md');
44
+ const action = appendOrCreate(path.join(ROOT, 'copilot', 'copilot-instructions.md'), dest);
45
+ console.log(`Copilot: instructions ${action} ${dest}`);
46
+ }
47
+
48
+ function installWindsurf() {
49
+ const dest = path.join(process.cwd(), '.windsurf', 'rules', 'tollgate.md');
50
+ copyFile(path.join(ROOT, 'windsurf', 'tollgate.md'), dest);
51
+ console.log(`Windsurf: rule installed at ${dest}`);
52
+ }
53
+
54
+ function installCodex() {
55
+ const dest = path.join(process.cwd(), 'AGENTS.md');
56
+ const action = appendOrCreate(path.join(ROOT, 'codex', 'AGENTS.md'), dest);
57
+ console.log(`Codex: AGENTS.md ${action} ${dest}`);
58
+ }
59
+
60
+ function usage() {
61
+ console.log('Tollgate skill installer\n');
62
+ console.log('Usage:');
63
+ console.log(' npx tollgate-skill --tool claude # Claude Code (~/.claude/skills/tollgate/)');
64
+ console.log(' npx tollgate-skill --tool cursor # Cursor (.cursor/rules/tollgate.mdc)');
65
+ console.log(' npx tollgate-skill --tool copilot # GitHub Copilot (.github/copilot-instructions.md)');
66
+ console.log(' npx tollgate-skill --tool windsurf # Windsurf (.windsurf/rules/tollgate.md)');
67
+ console.log(' npx tollgate-skill --tool codex # Codex (AGENTS.md)');
68
+ console.log(' npx tollgate-skill --tool all # All of the above');
69
+ }
70
+
71
+ switch (tool) {
72
+ case 'claude': installClaude(); break;
73
+ case 'cursor': installCursor(); break;
74
+ case 'copilot': installCopilot(); break;
75
+ case 'windsurf': installWindsurf(); break;
76
+ case 'codex': installCodex(); break;
77
+ case 'all':
78
+ installClaude();
79
+ installCursor();
80
+ installCopilot();
81
+ installWindsurf();
82
+ installCodex();
83
+ break;
84
+ default:
85
+ usage();
86
+ console.log('\nDefaulting to Claude Code:');
87
+ installClaude();
88
+ }
@@ -0,0 +1,331 @@
1
+ ---
2
+ name: tollgate
3
+ description: Integrate Tollgate to track LLM costs per customer and monitor gross margin in real time. Use when the user wants to add Tollgate to their AI product.
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Tollgate Integration Skill
8
+
9
+ Tollgate is a **real-time gross-margin observability** layer for AI products. It joins LLM provider costs with your revenue config to show per-customer, per-agent, per-run margins — so you know which customers are profitable and which are not.
10
+
11
+ > "Stripe/Orb tells you what to charge. Tollgate tells you if you're making money."
12
+
13
+ ## When to use this skill
14
+
15
+ Trigger on phrases like:
16
+ - "integrate Tollgate", "add Tollgate tracking", "set up cost tracking"
17
+ - "track LLM costs per customer", "monitor gross margin"
18
+ - "instrument my AI agent with Tollgate"
19
+
20
+ ---
21
+
22
+ ## What Tollgate tracks
23
+
24
+ Each call to `POST /api/track` records one **usage event** — a single LLM call, tool call, or retrieval step — attributed to a customer and run. Tollgate:
25
+
26
+ 1. Writes the raw event to DynamoDB (idempotent, ~1 ms hot path)
27
+ 2. Looks up the provider rate card to compute cost in cents
28
+ 3. Looks up the customer's plan to compute recognized revenue
29
+ 4. Rolls up `costCents`, `revenueCents`, `marginCents`, `marginPct` per customer/day/run
30
+
31
+ The dashboard shows live per-customer gross margin, margin-leak flags, and trend charts.
32
+
33
+ ---
34
+
35
+ ## Quick start (3 steps)
36
+
37
+ ### Step 1 — Get an API key
38
+
39
+ Generate a key in **Settings → API Keys** (prefix: `tg_live_…`). Set it as an environment variable:
40
+
41
+ ```bash
42
+ TOLLGATE_API_KEY=tg_live_your_key_here
43
+ ```
44
+
45
+ ### Step 2 — Install the SDK
46
+
47
+ ```bash
48
+ # TypeScript / Node.js
49
+ npm install @tollgateai/sdk
50
+ # or: pnpm add @tollgateai/sdk | yarn add @tollgateai/sdk
51
+
52
+ # Python
53
+ pip install tollgateai
54
+ ```
55
+
56
+ ### Step 3 — Wrap your provider client
57
+
58
+ Pick the snippet for your provider. Tollgate intercepts the response, extracts token counts, and fires `POST /api/track` in the background.
59
+
60
+ ---
61
+
62
+ ## Provider integration examples
63
+
64
+ ### Anthropic (TypeScript)
65
+
66
+ ```typescript
67
+ import Anthropic from '@anthropic-ai/sdk';
68
+ import { createTollgateClient, wrapAnthropic } from '@tollgateai/sdk';
69
+
70
+ const tollgate = createTollgateClient(); // reads TOLLGATE_API_KEY
71
+ const anthropic = wrapAnthropic(new Anthropic(), tollgate, {
72
+ customerId: 'cust_acme', // your external customer id — required
73
+ runId: 'ticket_8842', // your run/session id — recommended
74
+ agentId: 'support-agent', // optional: which agent within the run
75
+ });
76
+
77
+ // Use anthropic exactly as before — no changes needed below this line.
78
+ const msg = await anthropic.messages.create({
79
+ model: 'claude-opus-4-8',
80
+ max_tokens: 1024,
81
+ messages: [{ role: 'user', content: 'Hello' }],
82
+ });
83
+ ```
84
+
85
+ ### OpenAI (TypeScript)
86
+
87
+ ```typescript
88
+ import OpenAI from 'openai';
89
+ import { createTollgateClient, wrapOpenAI } from '@tollgateai/sdk';
90
+
91
+ const tollgate = createTollgateClient();
92
+ const openai = wrapOpenAI(new OpenAI(), tollgate, {
93
+ customerId: 'cust_acme',
94
+ runId: 'ticket_8842',
95
+ });
96
+ ```
97
+
98
+ ### OpenAI-compatible gateways (Groq, OpenRouter, Vercel AI Gateway, vLLM, Together, Fireworks)
99
+
100
+ ```typescript
101
+ import OpenAI from 'openai';
102
+ import { createTollgateClient, wrapOpenAI } from '@tollgateai/sdk';
103
+
104
+ const tollgate = createTollgateClient();
105
+ const groq = wrapOpenAI(
106
+ new OpenAI({ baseURL: 'https://api.groq.com/openai/v1', apiKey: process.env.GROQ_API_KEY }),
107
+ tollgate,
108
+ { customerId: 'cust_acme', runId: 'ticket_8842', provider: 'openai_compatible' },
109
+ );
110
+ ```
111
+
112
+ ### Google Gemini (TypeScript)
113
+
114
+ ```typescript
115
+ import { GoogleGenAI } from '@google/genai';
116
+ import { createTollgateClient, wrapGemini } from '@tollgateai/sdk';
117
+
118
+ const tollgate = createTollgateClient();
119
+ const gemini = wrapGemini(new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY }), tollgate, {
120
+ customerId: 'cust_acme',
121
+ runId: 'ticket_8842',
122
+ });
123
+ ```
124
+
125
+ ### AWS Bedrock (TypeScript)
126
+
127
+ ```typescript
128
+ import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
129
+ import { createTollgateClient, wrapBedrock } from '@tollgateai/sdk';
130
+
131
+ const tollgate = createTollgateClient();
132
+ const bedrock = wrapBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }), tollgate, {
133
+ customerId: 'cust_acme',
134
+ runId: 'ticket_8842',
135
+ });
136
+ ```
137
+
138
+ ### Anthropic (Python)
139
+
140
+ ```python
141
+ import anthropic
142
+ from tollgate import create_tollgate_client, wrap_anthropic
143
+
144
+ tollgate = create_tollgate_client() # reads TOLLGATE_API_KEY
145
+ client = wrap_anthropic(
146
+ anthropic.Anthropic(), tollgate,
147
+ customer_id="cust_acme",
148
+ run_id="ticket_8842",
149
+ )
150
+ ```
151
+
152
+ ### OpenAI (Python)
153
+
154
+ ```python
155
+ from openai import OpenAI
156
+ from tollgate import create_tollgate_client, wrap_openai
157
+
158
+ tollgate = create_tollgate_client()
159
+ client = wrap_openai(OpenAI(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Streaming
165
+
166
+ The wrapper handles streaming automatically. **OpenAI / OpenAI-compatible only:** add `stream_options: { include_usage: true }` or token counts won't be captured.
167
+
168
+ ```typescript
169
+ const stream = await openai.chat.completions.create({
170
+ model: 'gpt-4o',
171
+ messages: [{ role: 'user', content: 'Hello' }],
172
+ stream: true,
173
+ stream_options: { include_usage: true }, // required for Tollgate
174
+ });
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Multi-step agents — closing a run
180
+
181
+ A **run** (`runId`) groups all LLM calls for one end-to-end task. Set `outcome` on the final step to close the run and gate outcome-priced revenue.
182
+
183
+ ```typescript
184
+ await tollgate.resolve({
185
+ runId: 'ticket_8842',
186
+ customerId: 'cust_acme',
187
+ outcome: 'resolved', // 'resolved' | 'escalated' | 'failed'
188
+ revenueUnitCents: 50, // $0.50 per resolved ticket
189
+ });
190
+ ```
191
+
192
+ - `resolved` — task done; outcome-priced revenue is recognized.
193
+ - `escalated` / `failed` — no activity revenue recognized, but all costs are tracked. Makes unprofitable runs visible.
194
+ - Omitting `outcome` on a single-call run treats it as `resolved`.
195
+
196
+ ---
197
+
198
+ ## Manual tracking (no wrapper)
199
+
200
+ ```typescript
201
+ await tollgate.track({
202
+ customerId: 'cust_acme',
203
+ runId: 'ticket_8842',
204
+ provider: 'anthropic', // 'anthropic' | 'openai' | 'openai_compatible' | 'bedrock' | 'google'
205
+ model: 'claude-opus-4-8',
206
+ tokensIn: response.usage.input_tokens,
207
+ tokensOut: response.usage.output_tokens,
208
+ reasoningTokens: response.usage.cache_creation_input_tokens ?? 0,
209
+ cachedTokens: response.usage.cache_read_input_tokens ?? 0,
210
+ idempotencyKey: `${runId}#step_1`, // stable, unique per event
211
+ latencyMs: Date.now() - startTime,
212
+ });
213
+ ```
214
+
215
+ ### REST
216
+
217
+ ```bash
218
+ curl -X POST https://www.tollgateai.dev/api/track \
219
+ -H "Authorization: Bearer tg_live_your_key" \
220
+ -H "Content-Type: application/json" \
221
+ -d '{
222
+ "customerId": "cust_acme",
223
+ "runId": "ticket_8842",
224
+ "provider": "anthropic",
225
+ "model": "claude-opus-4-8",
226
+ "tokensIn": 1200,
227
+ "tokensOut": 340,
228
+ "idempotencyKey": "ticket_8842#step_1"
229
+ }'
230
+ ```
231
+
232
+ Response: `{ "status": "created", "eventId": "..." }` or `{ "status": "duplicate" }` (safe to ignore).
233
+
234
+ ---
235
+
236
+ ## Full field reference
237
+
238
+ | Field | Type | Required | Description |
239
+ |---|---|---|---|
240
+ | `customerId` | string | ✅ | Your external customer id. |
241
+ | `runId` | string | ✅ | Groups all LLM calls for one task/session. |
242
+ | `provider` | string | ✅ | `anthropic` `openai` `openai_compatible` `bedrock` `google` |
243
+ | `model` | string | ✅ | Model name as returned by provider. |
244
+ | `idempotencyKey` | string | ✅ | Unique per event — prevents double-counting on retries. Pattern: `runId#step_N`. |
245
+ | `agentId` | string | — | Which agent within the run. |
246
+ | `type` | string | — | `llm` (default) `tool` `retrieval` |
247
+ | `tokensIn` | int | — | Standard (non-cached) input tokens. |
248
+ | `tokensOut` | int | — | Output tokens. |
249
+ | `reasoningTokens` | int | — | Thinking/reasoning tokens — billed at output rate. |
250
+ | `cachedTokens` | int | — | Cache-read input tokens — billed at reduced rate. |
251
+ | `cacheWrite5mTokens` | int | — | Cache-write tokens, 5-min TTL. |
252
+ | `cacheWrite1hTokens` | int | — | Cache-write tokens, 1-hour TTL. |
253
+ | `toolCalls` | int | — | Number of tool calls. |
254
+ | `toolName` | string | — | Tool name for per-tool breakdown. |
255
+ | `audioTokensIn` | int | — | Audio input tokens (OpenAI Realtime). |
256
+ | `audioTokensOut` | int | — | Audio output tokens. |
257
+ | `imageTokensIn` | int | — | Image/vision input tokens. |
258
+ | `imageTokensOut` | int | — | Image generation output tokens. |
259
+ | `videoTokensIn` | int | — | Video input tokens (Gemini). |
260
+ | `webSearchRequests` | int | — | Web search calls (Anthropic/Gemini grounding). |
261
+ | `latencyMs` | int | — | Request latency in milliseconds. |
262
+ | `externalCostCents` | float | — | Cost of external tools used (image gen APIs, sandboxes). Added directly to cost. |
263
+ | `providerCostCents` | float | — | Exact cost from provider/gateway — skips rate-card lookup. |
264
+ | `outcome` | string | — | `resolved` `escalated` `failed` — set only on the closing event. |
265
+ | `revenueUnitCents` | int | — | Per-run revenue in cents. Overrides plan default. |
266
+ | `ts` | ISO string | — | Event timestamp. Defaults to server receive time. |
267
+
268
+ > **Privacy:** Never send prompt content. Fields like `prompt`, `messages`, `content`, `input`, `output` are rejected with HTTP 400.
269
+
270
+ ---
271
+
272
+ ## Error codes
273
+
274
+ | Status | Meaning |
275
+ |---|---|
276
+ | 201 created | Event ingested. |
277
+ | 200 duplicate | Same `idempotencyKey` already stored — ignore. |
278
+ | 400 | Validation error or prompt content detected. |
279
+ | 401 | Invalid or missing API key. |
280
+ | 402 | Monthly event quota reached. |
281
+ | 429 | Rate limit exceeded — check `Retry-After` header. |
282
+ | 500 | Internal error — event may not have been stored. |
283
+
284
+ ---
285
+
286
+ ## Register a customer before first usage (optional but recommended)
287
+
288
+ Call `upsertCustomer()` before sending any usage events so the plan is ready and revenue is recognized from event one. This is especially important for `usage_based` pricing, where revenue is computed at ingest time.
289
+
290
+ ```typescript
291
+ await tollgate.upsertCustomer({
292
+ externalId: 'cust_acme', // must match the customerId used in track/wrap
293
+ name: 'Acme Corp',
294
+ plan: {
295
+ name: 'Growth',
296
+ pricingModel: 'per_unit', // 'per_unit' | 'per_resolution' | 'usage_based' | 'per_seat' | 'flat' | 'hybrid'
297
+ unitRevenueCents: 50, // $0.50 per resolved ticket
298
+ baseRevenueCents: 0,
299
+ },
300
+ });
301
+ ```
302
+
303
+ ---
304
+
305
+ ## Integration checklist
306
+
307
+ - [ ] `TOLLGATE_API_KEY` set in environment (never commit it)
308
+ - [ ] Provider client wrapped (or `tollgate.track()` called after each LLM call)
309
+ - [ ] `customerId` matches real customer ids in your system
310
+ - [ ] `runId` consistently identifies one end-to-end task
311
+ - [ ] `idempotencyKey` is stable and unique per event
312
+ - [ ] `reasoningTokens` included for extended thinking models (Claude 3.7+, o1, o3)
313
+ - [ ] `cachedTokens` included if using prompt caching
314
+ - [ ] `outcome` set on the closing event for per_unit / hybrid plans
315
+ - [ ] No prompt content in any field
316
+
317
+ ---
318
+
319
+ ## Implementation approach
320
+
321
+ When helping a user integrate Tollgate:
322
+
323
+ 1. Ask which provider(s) they use (Anthropic / OpenAI / Gemini / Bedrock / gateway).
324
+ 2. Ask which language (TypeScript / Python / other).
325
+ 3. Find where they create the provider client — show the 2-line wrap.
326
+ 4. If they have multi-step agents, identify the final step and add `resolve()`.
327
+ 5. If they use OpenAI streaming, add `stream_options: { include_usage: true }`.
328
+ 6. Confirm `customerId` maps to real customer ids in their system.
329
+ 7. Remind them to add `TOLLGATE_API_KEY` to `.env` and `.gitignore`.
330
+
331
+ The wrapper never modifies the response the user's code sees, never blocks on Tollgate errors, and always passes through to the original provider.
@@ -0,0 +1,150 @@
1
+ # Tollgate Integration
2
+
3
+ When asked to integrate Tollgate, add LLM cost tracking, or set up gross-margin observability, follow these instructions.
4
+
5
+ Tollgate tracks LLM provider costs per customer in real time and joins them with revenue config to show gross margin per customer, agent, and run.
6
+
7
+ ## Setup
8
+
9
+ Set the API key (get it from Settings → API Keys on the Tollgate dashboard):
10
+
11
+ ```
12
+ TOLLGATE_API_KEY=tg_live_your_key_here
13
+ ```
14
+
15
+ Install the SDK:
16
+
17
+ ```bash
18
+ npm install @tollgateai/sdk # TypeScript / Node.js
19
+ pip install tollgateai # Python
20
+ ```
21
+
22
+ ## Wrap the provider client
23
+
24
+ Find where the user creates their provider client. Replace the client with a wrapped version. The wrapper is transparent — it never changes the response shape or blocks on errors.
25
+
26
+ **Anthropic (TypeScript):**
27
+ ```typescript
28
+ import Anthropic from '@anthropic-ai/sdk';
29
+ import { createTollgateClient, wrapAnthropic } from '@tollgateai/sdk';
30
+
31
+ const tollgate = createTollgateClient();
32
+ const anthropic = wrapAnthropic(new Anthropic(), tollgate, {
33
+ customerId: 'cust_acme',
34
+ runId: 'ticket_8842',
35
+ });
36
+ ```
37
+
38
+ **OpenAI (TypeScript):**
39
+ ```typescript
40
+ import OpenAI from 'openai';
41
+ import { createTollgateClient, wrapOpenAI } from '@tollgateai/sdk';
42
+
43
+ const tollgate = createTollgateClient();
44
+ const openai = wrapOpenAI(new OpenAI(), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
45
+ ```
46
+
47
+ **OpenAI-compatible (Groq, OpenRouter, vLLM, Together, Fireworks):**
48
+ ```typescript
49
+ const client = wrapOpenAI(
50
+ new OpenAI({ baseURL: 'https://api.groq.com/openai/v1', apiKey: process.env.GROQ_API_KEY }),
51
+ tollgate,
52
+ { customerId: 'cust_acme', runId: 'ticket_8842', provider: 'openai_compatible' },
53
+ );
54
+ ```
55
+
56
+ **Google Gemini (TypeScript):**
57
+ ```typescript
58
+ import { GoogleGenAI } from '@google/genai';
59
+ import { createTollgateClient, wrapGemini } from '@tollgateai/sdk';
60
+ const gemini = wrapGemini(new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
61
+ ```
62
+
63
+ **AWS Bedrock (TypeScript):**
64
+ ```typescript
65
+ import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
66
+ import { createTollgateClient, wrapBedrock } from '@tollgateai/sdk';
67
+ const bedrock = wrapBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
68
+ ```
69
+
70
+ **Anthropic (Python):**
71
+ ```python
72
+ import anthropic
73
+ from tollgate import create_tollgate_client, wrap_anthropic
74
+
75
+ tollgate = create_tollgate_client()
76
+ client = wrap_anthropic(anthropic.Anthropic(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
77
+ ```
78
+
79
+ **OpenAI (Python):**
80
+ ```python
81
+ from openai import OpenAI
82
+ from tollgate import create_tollgate_client, wrap_openai
83
+
84
+ tollgate = create_tollgate_client()
85
+ client = wrap_openai(OpenAI(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
86
+ ```
87
+
88
+ ## Streaming (OpenAI and OpenAI-compatible only)
89
+
90
+ Add `stream_options: { include_usage: true }` — otherwise Tollgate cannot see token counts during streaming.
91
+
92
+ ```typescript
93
+ const stream = await openai.chat.completions.create({
94
+ model: 'gpt-4o',
95
+ messages: [...],
96
+ stream: true,
97
+ stream_options: { include_usage: true },
98
+ });
99
+ ```
100
+
101
+ ## Closing a multi-step run
102
+
103
+ When a run has multiple LLM calls, call `resolve()` after the final step:
104
+
105
+ ```typescript
106
+ await tollgate.resolve({
107
+ runId: 'ticket_8842',
108
+ customerId: 'cust_acme',
109
+ outcome: 'resolved', // 'resolved' | 'escalated' | 'failed'
110
+ revenueUnitCents: 50, // $0.50 per resolved ticket
111
+ });
112
+ ```
113
+
114
+ Use `escalated` or `failed` when the task did not complete successfully. Tollgate still tracks the cost but suppresses activity revenue, making the margin drag visible.
115
+
116
+ ## Manual tracking (no wrapper available)
117
+
118
+ ```typescript
119
+ await tollgate.track({
120
+ customerId: 'cust_acme',
121
+ runId: 'ticket_8842',
122
+ provider: 'anthropic',
123
+ model: 'claude-opus-4-8',
124
+ tokensIn: 1200,
125
+ tokensOut: 340,
126
+ reasoningTokens: 0,
127
+ cachedTokens: 0,
128
+ idempotencyKey: `ticket_8842#step_1`,
129
+ latencyMs: 820,
130
+ });
131
+ ```
132
+
133
+ ## Rules to follow
134
+
135
+ - `idempotencyKey` must be stable and unique per event. Use `runId#step_N`. Duplicates are safely dropped.
136
+ - Never include prompt content in any field. Fields like `messages`, `content`, `input`, `output` are rejected with HTTP 400.
137
+ - Pass `reasoningTokens` separately — they bill at the output token rate.
138
+ - Pass `cachedTokens` separately — they bill at a reduced rate.
139
+ - Set `outcome` only on the closing event of a run.
140
+
141
+ ## Error codes
142
+
143
+ - 201: event stored
144
+ - 200 duplicate: already stored, ignore
145
+ - 400: validation error or prompt content detected
146
+ - 401: bad API key
147
+ - 402: quota reached
148
+ - 429: rate limited — check Retry-After header
149
+
150
+ Full docs: https://www.tollgateai.dev/docs
@@ -0,0 +1,137 @@
1
+ # Tollgate Integration Instructions
2
+
3
+ When asked to integrate Tollgate, track LLM costs per customer, or add gross-margin observability, follow these instructions.
4
+
5
+ ## What Tollgate does
6
+
7
+ Tollgate wraps your LLM provider client and tracks every API call — tokens in, tokens out, reasoning tokens, latency — and attributes them to a customer and run. It joins cost (from provider rate cards) with revenue (from your plan config) to show real-time gross margin per customer in a dashboard.
8
+
9
+ ## Required setup
10
+
11
+ Get an API key from the Tollgate dashboard (Settings → API Keys). Add it to the environment:
12
+
13
+ ```
14
+ TOLLGATE_API_KEY=tg_live_your_key_here
15
+ ```
16
+
17
+ Install:
18
+
19
+ ```bash
20
+ npm install @tollgateai/sdk # TypeScript
21
+ pip install tollgateai # Python
22
+ ```
23
+
24
+ ## Wrap the provider client — TypeScript
25
+
26
+ **Anthropic:**
27
+ ```typescript
28
+ import Anthropic from '@anthropic-ai/sdk';
29
+ import { createTollgateClient, wrapAnthropic } from '@tollgateai/sdk';
30
+
31
+ const tollgate = createTollgateClient();
32
+ const anthropic = wrapAnthropic(new Anthropic(), tollgate, {
33
+ customerId: 'cust_acme', // your external customer id — required
34
+ runId: 'ticket_8842', // groups all LLM calls for one task
35
+ });
36
+ // Use anthropic normally — tracking is automatic.
37
+ ```
38
+
39
+ **OpenAI:**
40
+ ```typescript
41
+ import OpenAI from 'openai';
42
+ import { createTollgateClient, wrapOpenAI } from '@tollgateai/sdk';
43
+
44
+ const tollgate = createTollgateClient();
45
+ const openai = wrapOpenAI(new OpenAI(), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
46
+ ```
47
+
48
+ **OpenAI-compatible (Groq, OpenRouter, vLLM, Together, Fireworks):**
49
+ ```typescript
50
+ const client = wrapOpenAI(
51
+ new OpenAI({ baseURL: 'https://api.groq.com/openai/v1', apiKey: process.env.GROQ_API_KEY }),
52
+ tollgate,
53
+ { customerId: 'cust_acme', runId: 'ticket_8842', provider: 'openai_compatible' },
54
+ );
55
+ ```
56
+
57
+ **Google Gemini:**
58
+ ```typescript
59
+ import { GoogleGenAI } from '@google/genai';
60
+ import { createTollgateClient, wrapGemini } from '@tollgateai/sdk';
61
+ const gemini = wrapGemini(new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
62
+ ```
63
+
64
+ **AWS Bedrock:**
65
+ ```typescript
66
+ import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
67
+ import { createTollgateClient, wrapBedrock } from '@tollgateai/sdk';
68
+ const bedrock = wrapBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
69
+ ```
70
+
71
+ ## Wrap the provider client — Python
72
+
73
+ ```python
74
+ from tollgate import create_tollgate_client, wrap_anthropic, wrap_openai
75
+
76
+ tollgate = create_tollgate_client()
77
+
78
+ # Anthropic
79
+ import anthropic
80
+ client = wrap_anthropic(anthropic.Anthropic(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
81
+
82
+ # OpenAI
83
+ from openai import OpenAI
84
+ client = wrap_openai(OpenAI(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
85
+ ```
86
+
87
+ ## OpenAI streaming — required flag
88
+
89
+ ```typescript
90
+ const stream = await openai.chat.completions.create({
91
+ model: 'gpt-4o',
92
+ messages: [...],
93
+ stream: true,
94
+ stream_options: { include_usage: true }, // required — Tollgate won't see tokens without this
95
+ });
96
+ ```
97
+
98
+ ## Closing a multi-step run
99
+
100
+ After the final LLM call in a task, call resolve():
101
+
102
+ ```typescript
103
+ await tollgate.resolve({
104
+ runId: 'ticket_8842',
105
+ customerId: 'cust_acme',
106
+ outcome: 'resolved', // 'resolved' | 'escalated' | 'failed'
107
+ revenueUnitCents: 50, // cents — $0.50 per resolved ticket
108
+ });
109
+ ```
110
+
111
+ ## Important rules
112
+
113
+ - `idempotencyKey` must be unique per event (pattern: `runId#step_N`). Duplicates are safely ignored.
114
+ - Never send prompt content. Fields like `messages`, `content`, `input`, `output` are rejected.
115
+ - `reasoningTokens` (thinking/extended-thinking) bills at output rate — always pass separately.
116
+ - `cachedTokens` bills at reduced rate — always pass separately.
117
+ - `outcome` goes only on the final event of a run.
118
+
119
+ ## Direct API call (any language)
120
+
121
+ ```
122
+ POST https://www.tollgateai.dev/api/track
123
+ Authorization: Bearer tg_live_…
124
+ Content-Type: application/json
125
+
126
+ {
127
+ "customerId": "cust_acme",
128
+ "runId": "ticket_8842",
129
+ "provider": "anthropic",
130
+ "model": "claude-opus-4-8",
131
+ "tokensIn": 1200,
132
+ "tokensOut": 340,
133
+ "idempotencyKey": "ticket_8842#step_1"
134
+ }
135
+ ```
136
+
137
+ Full reference: https://www.tollgateai.dev/docs
@@ -0,0 +1,141 @@
1
+ ---
2
+ description: Instructions for integrating Tollgate LLM cost tracking and gross-margin observability into AI products. Apply when the user asks to add Tollgate, track LLM costs per customer, or monitor gross margin.
3
+ globs: []
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Tollgate Integration
8
+
9
+ Tollgate tracks LLM provider costs per customer and joins them with revenue to show real-time gross margin. One wrap of your provider client is all it takes.
10
+
11
+ ## Setup
12
+
13
+ ```bash
14
+ TOLLGATE_API_KEY=tg_live_your_key_here
15
+ ```
16
+
17
+ ```bash
18
+ npm install @tollgateai/sdk # TypeScript
19
+ pip install tollgateai # Python
20
+ ```
21
+
22
+ ## Wrap your provider (TypeScript)
23
+
24
+ **Anthropic:**
25
+ ```typescript
26
+ import Anthropic from '@anthropic-ai/sdk';
27
+ import { createTollgateClient, wrapAnthropic } from '@tollgateai/sdk';
28
+
29
+ const tollgate = createTollgateClient();
30
+ const anthropic = wrapAnthropic(new Anthropic(), tollgate, {
31
+ customerId: 'cust_acme', // required — your external customer id
32
+ runId: 'ticket_8842', // groups all calls for one task
33
+ });
34
+ // Use anthropic normally — Tollgate tracks in the background.
35
+ ```
36
+
37
+ **OpenAI:**
38
+ ```typescript
39
+ import OpenAI from 'openai';
40
+ import { createTollgateClient, wrapOpenAI } from '@tollgateai/sdk';
41
+
42
+ const tollgate = createTollgateClient();
43
+ const openai = wrapOpenAI(new OpenAI(), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
44
+ ```
45
+
46
+ **OpenAI-compatible gateways (Groq, OpenRouter, vLLM, Together):**
47
+ ```typescript
48
+ const client = wrapOpenAI(
49
+ new OpenAI({ baseURL: 'https://api.groq.com/openai/v1', apiKey: process.env.GROQ_API_KEY }),
50
+ tollgate,
51
+ { customerId: 'cust_acme', runId: 'ticket_8842', provider: 'openai_compatible' },
52
+ );
53
+ ```
54
+
55
+ **Google Gemini:**
56
+ ```typescript
57
+ import { GoogleGenAI } from '@google/genai';
58
+ import { createTollgateClient, wrapGemini } from '@tollgateai/sdk';
59
+ const gemini = wrapGemini(new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
60
+ ```
61
+
62
+ **AWS Bedrock:**
63
+ ```typescript
64
+ import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
65
+ import { createTollgateClient, wrapBedrock } from '@tollgateai/sdk';
66
+ const bedrock = wrapBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
67
+ ```
68
+
69
+ ## Wrap your provider (Python)
70
+
71
+ ```python
72
+ from tollgate import create_tollgate_client, wrap_anthropic, wrap_openai
73
+
74
+ tollgate = create_tollgate_client()
75
+
76
+ # Anthropic
77
+ import anthropic
78
+ client = wrap_anthropic(anthropic.Anthropic(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
79
+
80
+ # OpenAI
81
+ from openai import OpenAI
82
+ client = wrap_openai(OpenAI(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
83
+ ```
84
+
85
+ ## Streaming (OpenAI only — required)
86
+
87
+ ```typescript
88
+ const stream = await openai.chat.completions.create({
89
+ model: 'gpt-4o',
90
+ messages: [...],
91
+ stream: true,
92
+ stream_options: { include_usage: true }, // required for Tollgate to see token counts
93
+ });
94
+ ```
95
+
96
+ ## Close a multi-step run with outcome
97
+
98
+ ```typescript
99
+ await tollgate.resolve({
100
+ runId: 'ticket_8842',
101
+ customerId: 'cust_acme',
102
+ outcome: 'resolved', // 'resolved' | 'escalated' | 'failed'
103
+ revenueUnitCents: 50, // $0.50 per resolved ticket
104
+ });
105
+ ```
106
+
107
+ `escalated`/`failed` suppresses activity revenue but still tracks cost — making unprofitable runs visible on the dashboard.
108
+
109
+ ## Manual tracking (no wrapper)
110
+
111
+ ```typescript
112
+ await tollgate.track({
113
+ customerId: 'cust_acme',
114
+ runId: 'ticket_8842',
115
+ provider: 'anthropic', // 'anthropic' | 'openai' | 'openai_compatible' | 'bedrock' | 'google'
116
+ model: 'claude-opus-4-8',
117
+ tokensIn: 1200,
118
+ tokensOut: 340,
119
+ reasoningTokens: 0, // thinking tokens — bill at output rate
120
+ cachedTokens: 0, // cache-read tokens — reduced rate
121
+ idempotencyKey: `${runId}#step_1`, // stable, unique per event
122
+ latencyMs: 820,
123
+ });
124
+ ```
125
+
126
+ ## Key rules
127
+
128
+ - `idempotencyKey` must be stable and unique per event (e.g. `runId#step_N`). Duplicates are silently dropped.
129
+ - Never send prompt content (`messages`, `content`, `input`, `output` etc.) — rejected with HTTP 400.
130
+ - `reasoningTokens` and `cachedTokens` must be passed separately — they bill at different rates.
131
+ - `outcome` goes only on the **closing** event of a run.
132
+
133
+ ## REST endpoint
134
+
135
+ ```
136
+ POST https://www.tollgateai.dev/api/track
137
+ Authorization: Bearer tg_live_…
138
+ Content-Type: application/json
139
+ ```
140
+
141
+ Full field reference: https://www.tollgateai.dev/docs
package/install.sh ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ # Tollgate skill installer
3
+ # Usage: curl -fsSL https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main/install.sh | sh
4
+ # Or: bash install.sh [--tool claude|cursor|copilot|windsurf|codex|all]
5
+
6
+ set -e
7
+
8
+ REPO_URL="https://raw.githubusercontent.com/Tollgateai/tollgate-skill/main"
9
+ TOOL="${1:-}"
10
+
11
+ # Parse --tool flag
12
+ if [ "$1" = "--tool" ]; then
13
+ TOOL="$2"
14
+ fi
15
+
16
+ install_claude_code() {
17
+ SKILL_DIR="${HOME}/.claude/skills/tollgate"
18
+ mkdir -p "$SKILL_DIR"
19
+ curl -fsSL "${REPO_URL}/claude-code/SKILL.md" -o "${SKILL_DIR}/SKILL.md"
20
+ echo "Claude Code: skill installed at ${SKILL_DIR}/SKILL.md"
21
+ echo " Restart Claude Code, then use /tollgate to activate the skill."
22
+ }
23
+
24
+ install_cursor() {
25
+ mkdir -p ".cursor/rules"
26
+ curl -fsSL "${REPO_URL}/cursor/tollgate.mdc" -o ".cursor/rules/tollgate.mdc"
27
+ echo "Cursor: rule installed at .cursor/rules/tollgate.mdc"
28
+ }
29
+
30
+ install_copilot() {
31
+ mkdir -p ".github"
32
+ if [ -f ".github/copilot-instructions.md" ]; then
33
+ echo "" >> ".github/copilot-instructions.md"
34
+ curl -fsSL "${REPO_URL}/copilot/copilot-instructions.md" >> ".github/copilot-instructions.md"
35
+ echo "Copilot: appended to .github/copilot-instructions.md"
36
+ else
37
+ curl -fsSL "${REPO_URL}/copilot/copilot-instructions.md" -o ".github/copilot-instructions.md"
38
+ echo "Copilot: instructions created at .github/copilot-instructions.md"
39
+ fi
40
+ }
41
+
42
+ install_windsurf() {
43
+ mkdir -p ".windsurf/rules"
44
+ curl -fsSL "${REPO_URL}/windsurf/tollgate.md" -o ".windsurf/rules/tollgate.md"
45
+ echo "Windsurf: rule installed at .windsurf/rules/tollgate.md"
46
+ }
47
+
48
+ install_codex() {
49
+ if [ -f "AGENTS.md" ]; then
50
+ echo "" >> "AGENTS.md"
51
+ curl -fsSL "${REPO_URL}/codex/AGENTS.md" >> "AGENTS.md"
52
+ echo "Codex: appended to AGENTS.md"
53
+ else
54
+ curl -fsSL "${REPO_URL}/codex/AGENTS.md" -o "AGENTS.md"
55
+ echo "Codex: AGENTS.md created"
56
+ fi
57
+ }
58
+
59
+ case "$TOOL" in
60
+ claude) install_claude_code ;;
61
+ cursor) install_cursor ;;
62
+ copilot) install_copilot ;;
63
+ windsurf) install_windsurf ;;
64
+ codex) install_codex ;;
65
+ all)
66
+ install_claude_code
67
+ install_cursor
68
+ install_copilot
69
+ install_windsurf
70
+ install_codex
71
+ ;;
72
+ *)
73
+ echo "Tollgate skill installer"
74
+ echo ""
75
+ echo "Usage:"
76
+ echo " bash install.sh --tool claude # Claude Code (~/.claude/skills/tollgate/)"
77
+ echo " bash install.sh --tool cursor # Cursor (.cursor/rules/tollgate.mdc)"
78
+ echo " bash install.sh --tool copilot # GitHub Copilot (.github/copilot-instructions.md)"
79
+ echo " bash install.sh --tool windsurf # Windsurf (.windsurf/rules/tollgate.md)"
80
+ echo " bash install.sh --tool codex # Codex (AGENTS.md)"
81
+ echo " bash install.sh --tool all # All of the above"
82
+ echo ""
83
+ echo "Or install for Claude Code (most common):"
84
+ install_claude_code
85
+ ;;
86
+ esac
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "tollgate-skill",
3
+ "version": "1.0.0",
4
+ "description": "AI coding tool instructions for Tollgate — real-time gross-margin observability for AI agents",
5
+ "bin": {
6
+ "tollgate-skill": "./bin/tollgate-skill.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "claude-code/",
11
+ "cursor/",
12
+ "copilot/",
13
+ "windsurf/",
14
+ "codex/",
15
+ "install.sh",
16
+ ".claude-plugin/"
17
+ ],
18
+ "keywords": [
19
+ "tollgate",
20
+ "llm",
21
+ "ai",
22
+ "cost",
23
+ "margin",
24
+ "observability",
25
+ "claude",
26
+ "cursor",
27
+ "copilot",
28
+ "windsurf",
29
+ "codex",
30
+ "agents"
31
+ ],
32
+ "author": "Tollgate <hello@tollgateai.com>",
33
+ "license": "MIT",
34
+ "homepage": "https://github.com/Tollgateai/tollgate-skill",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/Tollgateai/tollgate-skill.git"
38
+ },
39
+ "engines": {
40
+ "node": ">=16"
41
+ }
42
+ }
@@ -0,0 +1,123 @@
1
+ # Tollgate Integration
2
+
3
+ When the user asks to integrate Tollgate, add LLM cost tracking, or set up gross-margin observability, follow these instructions.
4
+
5
+ Tollgate wraps your LLM provider client and tracks every API call — attributing cost to a customer and run, then joining it with revenue to show real-time gross margin per customer.
6
+
7
+ ## Setup
8
+
9
+ Add to environment:
10
+ ```
11
+ TOLLGATE_API_KEY=tg_live_your_key_here
12
+ ```
13
+
14
+ Install:
15
+ ```bash
16
+ npm install @tollgateai/sdk # TypeScript
17
+ pip install tollgateai # Python
18
+ ```
19
+
20
+ ## Wrap the provider (TypeScript)
21
+
22
+ Anthropic:
23
+ ```typescript
24
+ import Anthropic from '@anthropic-ai/sdk';
25
+ import { createTollgateClient, wrapAnthropic } from '@tollgateai/sdk';
26
+
27
+ const tollgate = createTollgateClient();
28
+ const anthropic = wrapAnthropic(new Anthropic(), tollgate, {
29
+ customerId: 'cust_acme',
30
+ runId: 'ticket_8842',
31
+ });
32
+ ```
33
+
34
+ OpenAI:
35
+ ```typescript
36
+ import OpenAI from 'openai';
37
+ import { createTollgateClient, wrapOpenAI } from '@tollgateai/sdk';
38
+
39
+ const tollgate = createTollgateClient();
40
+ const openai = wrapOpenAI(new OpenAI(), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
41
+ ```
42
+
43
+ OpenAI-compatible (Groq, OpenRouter, vLLM, Together):
44
+ ```typescript
45
+ const client = wrapOpenAI(
46
+ new OpenAI({ baseURL: 'https://api.groq.com/openai/v1', apiKey: process.env.GROQ_API_KEY }),
47
+ tollgate,
48
+ { customerId: 'cust_acme', runId: 'ticket_8842', provider: 'openai_compatible' },
49
+ );
50
+ ```
51
+
52
+ Google Gemini:
53
+ ```typescript
54
+ import { GoogleGenAI } from '@google/genai';
55
+ import { createTollgateClient, wrapGemini } from '@tollgateai/sdk';
56
+ const gemini = wrapGemini(new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
57
+ ```
58
+
59
+ AWS Bedrock:
60
+ ```typescript
61
+ import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime';
62
+ import { createTollgateClient, wrapBedrock } from '@tollgateai/sdk';
63
+ const bedrock = wrapBedrock(new BedrockRuntimeClient({ region: 'us-east-1' }), tollgate, { customerId: 'cust_acme', runId: 'ticket_8842' });
64
+ ```
65
+
66
+ ## Wrap the provider (Python)
67
+
68
+ ```python
69
+ from tollgate import create_tollgate_client, wrap_anthropic, wrap_openai
70
+
71
+ tollgate = create_tollgate_client()
72
+
73
+ import anthropic
74
+ client = wrap_anthropic(anthropic.Anthropic(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
75
+
76
+ from openai import OpenAI
77
+ client = wrap_openai(OpenAI(), tollgate, customer_id="cust_acme", run_id="ticket_8842")
78
+ ```
79
+
80
+ ## OpenAI streaming
81
+
82
+ Add stream_options or token counts won't be captured:
83
+ ```typescript
84
+ const stream = await openai.chat.completions.create({
85
+ model: 'gpt-4o',
86
+ messages: [...],
87
+ stream: true,
88
+ stream_options: { include_usage: true },
89
+ });
90
+ ```
91
+
92
+ ## Close a multi-step run
93
+
94
+ ```typescript
95
+ await tollgate.resolve({
96
+ runId: 'ticket_8842',
97
+ customerId: 'cust_acme',
98
+ outcome: 'resolved', // 'resolved' | 'escalated' | 'failed'
99
+ revenueUnitCents: 50,
100
+ });
101
+ ```
102
+
103
+ ## Rules
104
+
105
+ - idempotencyKey must be unique per event — use runId#step_N pattern
106
+ - Never send prompt content (messages, content, input, output fields are rejected)
107
+ - reasoningTokens bills at output rate — pass separately
108
+ - cachedTokens bills at reduced rate — pass separately
109
+ - outcome only on the closing event of a run
110
+
111
+ ## Direct REST API
112
+
113
+ ```
114
+ POST https://tollgateai.dev/api/track
115
+ Authorization: Bearer tg_live_…
116
+ Content-Type: application/json
117
+
118
+ { "customerId": "cust_acme", "runId": "ticket_8842", "provider": "anthropic",
119
+ "model": "claude-opus-4-8", "tokensIn": 1200, "tokensOut": 340,
120
+ "idempotencyKey": "ticket_8842#step_1" }
121
+ ```
122
+
123
+ Full docs: https://www.tollgateai.dev/docs