zuplo 7.6.6 → 7.6.8

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.
@@ -171,8 +171,9 @@ options exactly.
171
171
 
172
172
  ## Configure credentials
173
173
 
174
- If a policy needs a credential—say it calls an external moderation API—set it in
175
- the declaration's options, and let chain entries inherit it:
174
+ If a policy needs a credential—say it calls an external moderation API—store it
175
+ as an [environment variable](../articles/environment-variables.mdx) and
176
+ reference it with `$env(...)` in the declaration's options:
176
177
 
177
178
  ```json title="config/policies.json"
178
179
  {
@@ -182,14 +183,17 @@ the declaration's options, and let chain entries inherit it:
182
183
  "export": "default",
183
184
  "module": "$import(./modules/my-moderation-policy)",
184
185
  "options": {
185
- "apiKey": "your-moderation-api-key"
186
+ "apiKey": "$env(MODERATION_API_KEY)"
186
187
  }
187
188
  }
188
189
  }
189
190
  ```
190
191
 
191
192
  Leave the chain entry's options out so it inherits the declaration's values—an
192
- entry that sets its own options replaces them completely.
193
+ entry that sets its own options replaces them completely. An entry that does set
194
+ its own options can use `$env(...)` references too, so one declared policy can
195
+ read a different credential or setting per app. See
196
+ [Options and secrets](./policy-chains.mdx#options-and-secrets).
193
197
 
194
198
  ## Beyond filtering
195
199
 
@@ -90,8 +90,27 @@ an entry with empty options replaces the declared options with an empty object,
90
90
  which breaks a policy that has required settings. Omit options entirely to
91
91
  inherit.
92
92
 
93
- Keep credentials in the declaration's options and let entries inherit them, so
94
- the gateway's repository—not app configuration—holds them. See
93
+ Entry options may reference
94
+ [environment variables](../articles/environment-variables.mdx) with
95
+ `$env(VAR_NAME)`, exactly as in `policies.json`. The gateway resolves each
96
+ reference when the chain runs, so a per-app entry can carry its own
97
+ environment-backed value:
98
+
99
+ ```json
100
+ {
101
+ "name": "my-moderation-policy",
102
+ "options": {
103
+ "apiKey": "$env(MODERATION_API_KEY)",
104
+ "threshold": 0.8
105
+ }
106
+ }
107
+ ```
108
+
109
+ A reference to an unset variable fails the request with a configuration error
110
+ naming the variable—it never silently resolves to an empty string.
111
+
112
+ Alternatively, keep credentials in the declaration's options and let entries
113
+ inherit them, so the gateway's repository—not app configuration—holds them. See
95
114
  [Configure credentials](./custom-policies.mdx#configure-credentials).
96
115
 
97
116
  ## Recommended order
@@ -118,13 +118,13 @@ at $80, block at $100. The warn amount has to be the lower of the two.
118
118
  The **Overview** tab charts daily and monthly usage only. Hourly and weekly rows
119
119
  are enforced, but no meter on that tab tracks them.
120
120
 
121
- :::note
121
+ :::note{title="Budget rule periods follow the UTC calendar"}
122
122
 
123
- Periods are anchored to your gateway, not the calendar. Every period rolls over
124
- relative to the time (UTC) the gateway was created, so a daily period resets at
125
- that hour rather than at midnight, and a monthly one on that day of the month.
126
- Teams and apps created later use the same anchor. Changing a limit mid-period
127
- doesn't reset the period's usage.
123
+ Hourly periods reset at the top of each hour, daily at 00:00 UTC, weekly on
124
+ Monday at 00:00 UTC, and monthly on the first of the month. A rule added
125
+ mid-period gets the full allowance for the rest of that period—the limit isn't
126
+ prorated—and resets at the next boundary. Changing a limit mid-period doesn't
127
+ reset the period's usage. Custom anchors aren't configurable.
128
128
 
129
129
  :::
130
130
 
@@ -184,6 +184,56 @@ App rules are stored in `options.budgetRules` on the app's own Budgets and Costs
184
184
  policy entry. For the app rule schema, see the
185
185
  [Budgets and Costs policy reference](../policies/ai-gateway-metering-v2-inbound.mdx).
186
186
 
187
+ This rule set budgets each user, each organization, and the app as a whole:
188
+
189
+ ```json
190
+ {
191
+ "budgetRules": [
192
+ {
193
+ "budgetBy": "expression",
194
+ "expression": "request.headers.get(\"x-user\")",
195
+ "meters": [
196
+ {
197
+ "meter": "tokens",
198
+ "period": "hourly",
199
+ "value": 20000,
200
+ "action": "block"
201
+ }
202
+ ]
203
+ },
204
+ {
205
+ "budgetBy": "expression",
206
+ "expression": "request.headers.get(\"x-organization\")",
207
+ "meters": [
208
+ { "meter": "cost", "period": "daily", "value": 50, "action": "block" }
209
+ ]
210
+ },
211
+ {
212
+ "budgetBy": "app",
213
+ "meters": [
214
+ {
215
+ "meter": "cost",
216
+ "period": "monthly",
217
+ "value": 2000,
218
+ "action": "warn"
219
+ },
220
+ {
221
+ "meter": "cost",
222
+ "period": "monthly",
223
+ "value": 2500,
224
+ "action": "block"
225
+ }
226
+ ]
227
+ }
228
+ ]
229
+ }
230
+ ```
231
+
232
+ Every distinct `x-user` value gets its own 20,000 tokens per hour, resetting at
233
+ the top of the hour. Every distinct `x-organization` value gets its own $50 per
234
+ day, resetting at 00:00 UTC. The `app` rule caps the whole app at $2,500 per
235
+ month, warning at $2,000, resetting on the first of the month.
236
+
187
237
  ## Setting team and gateway limits
188
238
 
189
239
  Team and gateway limits cover the node's own usage and all descendant usage.
@@ -535,9 +535,33 @@ From a chain policy you can:
535
535
 
536
536
  ## Store secrets safely
537
537
 
538
- Keep credentials and other environment-backed values in the pre-declared
539
- policy's `handler.options`, then omit `options` from the application chain entry
540
- to inherit them:
538
+ Application chain options can reference project environment variables. Use a
539
+ standalone reference when the complete option value comes from one variable, or
540
+ embed one or more references in a larger string:
541
+
542
+ ```json
543
+ {
544
+ "inboundPolicyChain": [
545
+ {
546
+ "name": "my-ai-guardrail",
547
+ "options": {
548
+ "apiKey": "$env(MY_GUARDRAIL_API_KEY)",
549
+ "authorization": "Bearer $env(MY_GUARDRAIL_API_KEY)"
550
+ }
551
+ }
552
+ ]
553
+ }
554
+ ```
555
+
556
+ The executor resolves `$env(NAME)` references when it instantiates an enabled
557
+ chain entry. Resolution visits string values recursively through nested objects
558
+ and arrays. Object keys remain literal. If a referenced variable is missing or
559
+ restricted, the executor rejects the configuration with an error that identifies
560
+ the variable and the chain entry; it never substitutes an empty string.
561
+
562
+ To share the same environment-backed options across applications, keep them in
563
+ the pre-declared policy's `handler.options`, then omit `options` from the
564
+ application chain entry to inherit them:
541
565
 
542
566
  ```json
543
567
  {
@@ -563,9 +587,9 @@ to inherit them:
563
587
  }
564
588
  ```
565
589
 
566
- Do not place `$env(...)` expressions in application configuration. Environment
567
- references are resolved when gateway configuration is built, while application
568
- chains are evaluated when a request arrives.
590
+ Declared `handler.options` use the normal build-time environment resolution.
591
+ Application entry options are resolved at runtime and replace the declaration's
592
+ complete options object; the two objects are not merged.
569
593
 
570
594
  ## Chain entry reference
571
595
 
@@ -578,8 +602,8 @@ Every chain entry supports:
578
602
  without running it. Omitted or `true` entries run normally.
579
603
 
580
604
  Disabled entries are still validated. They must be well-formed, name a declared
581
- policy, contain no literal `$env(...)` value, and cannot select the
582
- configuration loader or executor.
605
+ policy, and cannot select the configuration loader or executor. Their options
606
+ are not instantiated, so their environment references are not resolved.
583
607
 
584
608
  The executor permits repeated entries and cannot infer the behavior of custom or
585
609
  wrapper policies. Configuration authors are responsible for avoiding repeated
@@ -606,7 +630,9 @@ Before deploying:
606
630
  1. Declare every selectable policy in `config/policies.json`.
607
631
  2. Configure application and team policy templates with the policies each app
608
632
  may edit or remove.
609
- 3. Put environment-backed values in declared policy options.
633
+ 3. Put shared environment-backed values in declared policy options, or use
634
+ `$env(...)` in application entry option values when each application needs
635
+ its own complete options object.
610
636
  4. Place the configuration loader before the executor on every AI Gateway route
611
637
  (or the executor alone when you prefer the combined path). Add AI Gateway
612
638
  Authentication to an application's chain for that app only, or before the
@@ -24,6 +24,8 @@ invalid options fail open: the original request is forwarded.
24
24
  - `classifierAppApiKey` — bearer token for that app. Use
25
25
  `$env(CLASSIFIER_APP_API_KEY)`.
26
26
  - `classifierModel` — `providerName/model` sent on the classifier request.
27
+ - `modelsByComplexity` — `providerName/model` for each of `low`, `medium`, and
28
+ `high`. Used for routing when `smartRoutingEnabled` is true.
27
29
 
28
30
  Omit `intents` and `classifierPrompt` to use the built-in taxonomy (code,
29
31
  summarization, translation, qa, conversation, classification, creative_writing,
@@ -38,7 +38,8 @@
38
38
  "required": [
39
39
  "classifierAppID",
40
40
  "classifierAppApiKey",
41
- "classifierModel"
41
+ "classifierModel",
42
+ "modelsByComplexity"
42
43
  ],
43
44
  "examples": [
44
45
  {
@@ -82,8 +83,9 @@
82
83
  "modelsByComplexity": {
83
84
  "type": "object",
84
85
  "title": "Models By Complexity",
85
- "description": "Optional `providerName/model` routing by classified complexity. Used only when `smartRoutingEnabled` is true.",
86
+ "description": "`providerName/model` routing by classified complexity. All of `low`, `medium`, and `high` are required. Used only when `smartRoutingEnabled` is true.",
86
87
  "additionalProperties": false,
88
+ "required": ["low", "medium", "high"],
87
89
  "properties": {
88
90
  "low": {
89
91
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "7.6.6",
3
+ "version": "7.6.8",
4
4
  "type": "module",
5
5
  "description": "The official Zuplo CLI for local development and platform management",
6
6
  "homepage": "https://zuplo.com/docs/cli/overview",
@@ -32,9 +32,9 @@
32
32
  "zuplo": "zuplo.js"
33
33
  },
34
34
  "dependencies": {
35
- "@zuplo/cli": "7.6.6",
36
- "@zuplo/core": "7.6.6",
37
- "@zuplo/runtime": "7.6.6",
38
- "@zuplo/test": "7.6.6"
35
+ "@zuplo/cli": "7.6.8",
36
+ "@zuplo/core": "7.6.8",
37
+ "@zuplo/runtime": "7.6.8",
38
+ "@zuplo/test": "7.6.8"
39
39
  }
40
40
  }