@oxygen-agent/cli 1.1010.721 → 1.1010.905
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 +1 -1
- package/dist/auto-update.d.ts +129 -0
- package/dist/auto-update.js +392 -0
- package/dist/command-manifest.js +14 -0
- package/dist/credentials.d.ts +2 -0
- package/dist/credentials.js +6 -3
- package/dist/functions-commands.js +1 -1
- package/dist/http-client.js +28 -4
- package/dist/index.js +583 -145
- package/dist/run-wait.d.ts +3 -1
- package/dist/run-wait.js +19 -5
- package/dist/streamed-file-import.d.ts +58 -0
- package/dist/streamed-file-import.js +115 -0
- package/dist/update.d.ts +29 -0
- package/dist/update.js +62 -16
- package/dist/workflow-plan-limit-notices.d.ts +8 -0
- package/dist/workflow-plan-limit-notices.js +28 -0
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +3 -3
- package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/billing-anchors.js +27 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +191 -35
- package/node_modules/@oxygen/shared/dist/billing.js +333 -42
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +55 -5
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +2 -2
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate-view.js +90 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +167 -0
- package/node_modules/@oxygen/shared/dist/cost-estimate.js +361 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/credit-gate.js +65 -0
- package/node_modules/@oxygen/shared/dist/email-deliverability-policy.d.ts +51 -0
- package/node_modules/@oxygen/shared/dist/email-deliverability-policy.js +101 -0
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.d.ts +3 -1
- package/node_modules/@oxygen/shared/dist/email-hard-bounce.js +3 -3
- package/node_modules/@oxygen/shared/dist/error-redaction.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -1
- package/node_modules/@oxygen/shared/dist/feature-gates.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/feature-gates.js +5 -0
- package/node_modules/@oxygen/shared/dist/file-import.d.ts +13 -1
- package/node_modules/@oxygen/shared/dist/file-import.js +33 -6
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +73 -3
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +246 -24
- package/node_modules/@oxygen/shared/dist/import-limits.d.ts +25 -1
- package/node_modules/@oxygen/shared/dist/import-limits.js +35 -2
- package/node_modules/@oxygen/shared/dist/index.d.ts +2 -22
- package/node_modules/@oxygen/shared/dist/index.js +2 -42
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +9 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +17 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.js +55 -0
- package/node_modules/@oxygen/shared/dist/plan-band.d.ts +117 -1
- package/node_modules/@oxygen/shared/dist/plan-band.js +175 -10
- package/node_modules/@oxygen/shared/dist/plan-capabilities.d.ts +77 -7
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +87 -7
- package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +219 -0
- package/node_modules/@oxygen/shared/dist/plan-limits-view.js +330 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +204 -6
- package/node_modules/@oxygen/shared/dist/plan-limits.js +197 -15
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +80 -36
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +80 -31
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +38 -20
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +47 -34
- package/node_modules/@oxygen/shared/dist/provider-http-error.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/provider-http-error.js +27 -0
- package/node_modules/@oxygen/shared/dist/repricing.d.ts +127 -0
- package/node_modules/@oxygen/shared/dist/repricing.js +407 -6
- package/node_modules/@oxygen/shared/dist/semver.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/semver.js +41 -0
- package/node_modules/@oxygen/shared/dist/sending-limits.d.ts +5 -7
- package/node_modules/@oxygen/shared/dist/sending-limits.js +10 -16
- package/node_modules/@oxygen/shared/dist/sending-seats.d.ts +18 -15
- package/node_modules/@oxygen/shared/dist/sending-seats.js +22 -17
- package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +57 -8
- package/node_modules/@oxygen/shared/dist/spend-safety.js +64 -11
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.d.ts +15 -7
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +18 -5
- package/node_modules/@oxygen/shared/dist/table-capacity.d.ts +34 -5
- package/node_modules/@oxygen/shared/dist/table-capacity.js +25 -8
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +13 -5
- package/node_modules/@oxygen/shared/dist/telemetry-resource.d.ts +40 -0
- package/node_modules/@oxygen/shared/dist/telemetry-resource.js +35 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +5 -0
- package/node_modules/@oxygen/shared/dist/ugc.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/ugc.js +29 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -3
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +14 -27
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +5 -0
- package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +3 -3
- package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +15 -1
- package/node_modules/@oxygen/workflows/dist/graph/types.js +15 -1
- package/node_modules/@oxygen/workflows/dist/index.d.ts +45 -0
- package/node_modules/@oxygen/workflows/dist/index.js +152 -2
- package/node_modules/@oxygen/workflows/dist/usage-estimate.d.ts +10 -1
- package/node_modules/@oxygen/workflows/dist/usage-estimate.js +33 -29
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RepricingOptions } from "./repricing.js";
|
|
1
2
|
/**
|
|
2
3
|
* The five enforcement rungs of the per-plan limits ladder. Every PlanTier maps
|
|
3
4
|
* onto exactly one rung: "free" doubles as the unentitled fallback (no live
|
|
@@ -8,6 +9,12 @@
|
|
|
8
9
|
* Credits are the billing meter; these limits are abuse/runaway guards. They
|
|
9
10
|
* are sized so legitimate interactive use never hits them and scale with plan
|
|
10
11
|
* price so worst-case burn stays proportional to what the org pays.
|
|
12
|
+
*
|
|
13
|
+
* Org-scope unit budgets (`orgUnits`) bound row-weighted bulk volume only: a
|
|
14
|
+
* call whose normalized amount is 1 is counted against the budget but never
|
|
15
|
+
* refused by it, so single-item work is bounded by `requestsPerMinute` and the
|
|
16
|
+
* global `cli` buckets. A budget accumulated under a higher rung keeps refusing
|
|
17
|
+
* bulk calls until its window resets after a downgrade; there is no rebase.
|
|
11
18
|
*/
|
|
12
19
|
export type LimitsTier = "free" | "starter" | "pro" | "team" | "scale";
|
|
13
20
|
export declare const LIMITS_TIER_ORDER: readonly LimitsTier[];
|
|
@@ -16,7 +23,10 @@ export type OrgWindowLimit = {
|
|
|
16
23
|
limit: number;
|
|
17
24
|
windowSeconds: number;
|
|
18
25
|
};
|
|
19
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Request bucket (per api-key / web-user scope) + org-scope unit budget. The
|
|
28
|
+
* unit budget never refuses a 1-unit call (rate-limits.ts `orgUnitBudget`).
|
|
29
|
+
*/
|
|
20
30
|
export type UnitPolicyLimits = {
|
|
21
31
|
requestsPerMinute: number;
|
|
22
32
|
orgUnits: OrgWindowLimit;
|
|
@@ -53,6 +63,11 @@ export type PlanLimits = {
|
|
|
53
63
|
maxDirectCsvBodyBytes: number;
|
|
54
64
|
};
|
|
55
65
|
agents: {
|
|
66
|
+
/**
|
|
67
|
+
* The pre-2026-09-repricing default Agent run ceilings. Read the value in
|
|
68
|
+
* force with `resolvePlanAgentCreditLimits`: team and scale drop at the
|
|
69
|
+
* repricing instant.
|
|
70
|
+
*/
|
|
56
71
|
maxTotalCredits: number;
|
|
57
72
|
maxInferenceCredits: number;
|
|
58
73
|
maxUpstreamCostUsd: number;
|
|
@@ -69,6 +84,15 @@ export type PlanLimits = {
|
|
|
69
84
|
tableActions: {
|
|
70
85
|
maxActionsPerRun: number;
|
|
71
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* `cronMinIntervalMinutes` is the fastest cron cadence a workflow or Agent
|
|
89
|
+
* trigger may be scheduled at (repricing 2026-09, decision L4.2). It is the
|
|
90
|
+
* ratified value; read the value in force with `resolveCronMinIntervalMinutes`,
|
|
91
|
+
* because the free rung's cut waits for the repricing switch.
|
|
92
|
+
*/
|
|
93
|
+
workflows: {
|
|
94
|
+
cronMinIntervalMinutes: number;
|
|
95
|
+
};
|
|
72
96
|
};
|
|
73
97
|
/**
|
|
74
98
|
* The per-rung Table import ceiling this matrix reports: today's envelope. The
|
|
@@ -88,6 +112,66 @@ export { VERCEL_REQUEST_BODY_LIMIT_BYTES } from "./import-limits.js";
|
|
|
88
112
|
* in the CLI alone — an older server would still 413 at the old number.
|
|
89
113
|
*/
|
|
90
114
|
export declare const MAX_CLI_JSON_BODY_BYTES = 2000000;
|
|
115
|
+
/**
|
|
116
|
+
* Derived plan-scaled limits (repricing 2026-09 decision L6, spec § 4.7):
|
|
117
|
+
* import file size, columns per action run or standing auto-run and the signals
|
|
118
|
+
* feed. Each only rises against the pre-repricing ladder, so no paid customer
|
|
119
|
+
* loses a limit and nothing here waits for the effective-date switch. Rows per
|
|
120
|
+
* write request stay 5,000 free / 50,000 paid: the 2 MB request body
|
|
121
|
+
* (`MAX_CLI_JSON_BODY_BYTES`) binds first.
|
|
122
|
+
*
|
|
123
|
+
* `importFileBytes` is ratified (decision F.8, Philipp 2026-09-27): free 500 MiB,
|
|
124
|
+
* $49–$99 1 GiB, $199–$499 2 GiB, $999–$1,999 5 GiB. It is live on every plan
|
|
125
|
+
* and no longer waits for the per-Table capacity test: rows per Table still cap
|
|
126
|
+
* what one import can load, so a bigger file never buys more rows. 5 GiB is also
|
|
127
|
+
* the largest single PUT an S3-compatible store accepts
|
|
128
|
+
* (`IMPORT_OBJECT_SINGLE_PUT_MAX_BYTES`), which is the one upload a staged
|
|
129
|
+
* import makes.
|
|
130
|
+
*/
|
|
131
|
+
export declare const DERIVED_PLAN_LIMIT_TARGETS: {
|
|
132
|
+
readonly free: {
|
|
133
|
+
readonly importFileBytes: number;
|
|
134
|
+
readonly maxActionsPerRun: 10;
|
|
135
|
+
readonly signals: {
|
|
136
|
+
readonly maxEvents: 100;
|
|
137
|
+
readonly maxWindowDays: 30;
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
readonly starter: {
|
|
141
|
+
readonly importFileBytes: number;
|
|
142
|
+
readonly maxActionsPerRun: 25;
|
|
143
|
+
readonly signals: {
|
|
144
|
+
readonly maxEvents: 200;
|
|
145
|
+
readonly maxWindowDays: 90;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
readonly pro: {
|
|
149
|
+
readonly importFileBytes: number;
|
|
150
|
+
readonly maxActionsPerRun: 25;
|
|
151
|
+
readonly signals: {
|
|
152
|
+
readonly maxEvents: 500;
|
|
153
|
+
readonly maxWindowDays: 180;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
readonly team: {
|
|
157
|
+
readonly importFileBytes: number;
|
|
158
|
+
readonly maxActionsPerRun: 50;
|
|
159
|
+
readonly signals: {
|
|
160
|
+
readonly maxEvents: 1000;
|
|
161
|
+
readonly maxWindowDays: 365;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
readonly scale: {
|
|
165
|
+
readonly importFileBytes: number;
|
|
166
|
+
readonly maxActionsPerRun: 50;
|
|
167
|
+
readonly signals: {
|
|
168
|
+
readonly maxEvents: 1000;
|
|
169
|
+
readonly maxWindowDays: 365;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
/** The import file size a rung enforces (see `DERIVED_PLAN_LIMIT_TARGETS`). */
|
|
174
|
+
export declare function importMaxFileBytesForTier(tier: LimitsTier): number;
|
|
91
175
|
/**
|
|
92
176
|
* The per-rung limit matrix. `ai_live` deliberately equals `tool_live` at every
|
|
93
177
|
* rung — one "live actions" mental model; the per-call cost asymmetry between
|
|
@@ -212,6 +296,9 @@ export declare const PLAN_LIMITS: {
|
|
|
212
296
|
readonly tableActions: {
|
|
213
297
|
readonly maxActionsPerRun: 10;
|
|
214
298
|
};
|
|
299
|
+
readonly workflows: {
|
|
300
|
+
readonly cronMinIntervalMinutes: 15;
|
|
301
|
+
};
|
|
215
302
|
};
|
|
216
303
|
readonly starter: {
|
|
217
304
|
readonly cli: {
|
|
@@ -322,6 +409,9 @@ export declare const PLAN_LIMITS: {
|
|
|
322
409
|
readonly tableActions: {
|
|
323
410
|
readonly maxActionsPerRun: 25;
|
|
324
411
|
};
|
|
412
|
+
readonly workflows: {
|
|
413
|
+
readonly cronMinIntervalMinutes: 1;
|
|
414
|
+
};
|
|
325
415
|
};
|
|
326
416
|
readonly pro: {
|
|
327
417
|
readonly cli: {
|
|
@@ -426,12 +516,15 @@ export declare const PLAN_LIMITS: {
|
|
|
426
516
|
readonly defaultPerTurnCreditCeiling: 250;
|
|
427
517
|
};
|
|
428
518
|
readonly signals: {
|
|
429
|
-
readonly maxEvents:
|
|
519
|
+
readonly maxEvents: 500;
|
|
430
520
|
readonly maxWindowDays: 180;
|
|
431
521
|
};
|
|
432
522
|
readonly tableActions: {
|
|
433
523
|
readonly maxActionsPerRun: 25;
|
|
434
524
|
};
|
|
525
|
+
readonly workflows: {
|
|
526
|
+
readonly cronMinIntervalMinutes: 1;
|
|
527
|
+
};
|
|
435
528
|
};
|
|
436
529
|
readonly team: {
|
|
437
530
|
readonly cli: {
|
|
@@ -536,11 +629,14 @@ export declare const PLAN_LIMITS: {
|
|
|
536
629
|
readonly defaultPerTurnCreditCeiling: 500;
|
|
537
630
|
};
|
|
538
631
|
readonly signals: {
|
|
539
|
-
readonly maxEvents:
|
|
632
|
+
readonly maxEvents: 1000;
|
|
540
633
|
readonly maxWindowDays: 365;
|
|
541
634
|
};
|
|
542
635
|
readonly tableActions: {
|
|
543
|
-
readonly maxActionsPerRun:
|
|
636
|
+
readonly maxActionsPerRun: 50;
|
|
637
|
+
};
|
|
638
|
+
readonly workflows: {
|
|
639
|
+
readonly cronMinIntervalMinutes: 1;
|
|
544
640
|
};
|
|
545
641
|
};
|
|
546
642
|
readonly scale: {
|
|
@@ -646,14 +742,30 @@ export declare const PLAN_LIMITS: {
|
|
|
646
742
|
readonly defaultPerTurnCreditCeiling: 1000;
|
|
647
743
|
};
|
|
648
744
|
readonly signals: {
|
|
649
|
-
readonly maxEvents:
|
|
745
|
+
readonly maxEvents: 1000;
|
|
650
746
|
readonly maxWindowDays: 365;
|
|
651
747
|
};
|
|
652
748
|
readonly tableActions: {
|
|
653
|
-
readonly maxActionsPerRun:
|
|
749
|
+
readonly maxActionsPerRun: 50;
|
|
750
|
+
};
|
|
751
|
+
readonly workflows: {
|
|
752
|
+
readonly cronMinIntervalMinutes: 1;
|
|
654
753
|
};
|
|
655
754
|
};
|
|
656
755
|
};
|
|
756
|
+
/**
|
|
757
|
+
* The fastest cron cadence, in minutes, a rung may schedule right now. The free
|
|
758
|
+
* rung's cut from every minute to every 15 (decision L4.2) is a tightening, so
|
|
759
|
+
* it resolves through the 2026-09 repricing switch: every minute until the
|
|
760
|
+
* effective instant, `PLAN_LIMITS.free.workflows.cronMinIntervalMinutes` from it.
|
|
761
|
+
*/
|
|
762
|
+
export declare function resolveCronMinIntervalMinutes(tier: LimitsTier, options?: RepricingOptions): number;
|
|
763
|
+
/**
|
|
764
|
+
* The largest minimum cron interval any rung enforces right now. A schedule
|
|
765
|
+
* whose fires are never closer than this fits every plan, so a caller can skip
|
|
766
|
+
* the plan lookup for it.
|
|
767
|
+
*/
|
|
768
|
+
export declare function highestCronMinIntervalMinutes(options?: RepricingOptions): number;
|
|
657
769
|
/**
|
|
658
770
|
* Map a raw plan-tier string (subscription `tier`, metadata tier, legacy plan
|
|
659
771
|
* key like `growth_250`, or an Oxygen rung key like `oxygen_499`) onto its
|
|
@@ -662,3 +774,89 @@ export declare const PLAN_LIMITS: {
|
|
|
662
774
|
*/
|
|
663
775
|
export declare function limitsTierForPlanTier(tier: string | null | undefined): LimitsTier;
|
|
664
776
|
export declare function planLimitsForTier(tier: LimitsTier): PlanLimits;
|
|
777
|
+
/** The default credit ceilings of one Agent run on a rung. */
|
|
778
|
+
export type PlanAgentCreditLimits = {
|
|
779
|
+
maxTotalCredits: number;
|
|
780
|
+
maxInferenceCredits: number;
|
|
781
|
+
};
|
|
782
|
+
/**
|
|
783
|
+
* The default credit ceilings of one Agent run in force on a rung right now.
|
|
784
|
+
*
|
|
785
|
+
* `PLAN_LIMITS[tier].agents` holds the values each rung read before the 2026-09
|
|
786
|
+
* repricing. The team and scale rungs drop to 2,500 total / 1,250 inference
|
|
787
|
+
* (decision L5.4, inference half PROPOSED P-56), and a cut waits for the
|
|
788
|
+
* effective-date switch (`agents.<tier>.*` in `REPRICING_2026_09_SCHEDULE`).
|
|
789
|
+
* Every Agent budget check reads this, never the table, so the cut lands
|
|
790
|
+
* everywhere at the same instant.
|
|
791
|
+
*/
|
|
792
|
+
export declare function resolvePlanAgentCreditLimits(tier: LimitsTier, options?: RepricingOptions): PlanAgentCreditLimits;
|
|
793
|
+
/**
|
|
794
|
+
* The platform's hard backstop on one Agent run's approved credit ceiling
|
|
795
|
+
* (decision F.4, ratified 2026-09-27).
|
|
796
|
+
*
|
|
797
|
+
* The plan's Agent run ceiling is a DEFAULT: a run or trigger whose approved
|
|
798
|
+
* `max_credits` fits under it needs only the usual approval. Going above it
|
|
799
|
+
* takes a second, explicit per-run (or per-trigger) approval, and even that
|
|
800
|
+
* approval stops here. 25,000 credits ($250) is the largest standing
|
|
801
|
+
* per-delivery default any plan has carried (the pre-2026-09 scale trigger
|
|
802
|
+
* default), so an approved Agent run never outspends one delivery of the
|
|
803
|
+
* largest plan's own automation. The other backstops stay in force whatever is
|
|
804
|
+
* approved: the plan's upstream-USD clamp, the iteration, tool-call and
|
|
805
|
+
* active-minute bounds, the balance check on every reservation and the org
|
|
806
|
+
* daily spend guard.
|
|
807
|
+
*/
|
|
808
|
+
export declare const AGENT_RUN_APPROVED_CEILING_MAX_CREDITS = 25000;
|
|
809
|
+
/** Where an org's default Agent run ceiling came from. */
|
|
810
|
+
export type AgentRunDefaultCeilingSource = "plan" | "enterprise_contract";
|
|
811
|
+
/** The Agent run ceilings an org's runs are held to without a further approval. */
|
|
812
|
+
export type AgentRunDefaultCeilings = PlanAgentCreditLimits & {
|
|
813
|
+
source: AgentRunDefaultCeilingSource;
|
|
814
|
+
};
|
|
815
|
+
/**
|
|
816
|
+
* The default Agent run ceilings for an org: its plan rung's, unless an
|
|
817
|
+
* enterprise contract names its own default (decision F.4). The contract value
|
|
818
|
+
* replaces the rung's total and model calls take half of it, as on every paid
|
|
819
|
+
* rung. A contract value is clamped to the platform backstop; an unusable one
|
|
820
|
+
* (absent, non-numeric, not positive) is ignored.
|
|
821
|
+
*/
|
|
822
|
+
export declare function resolveAgentRunDefaultCeilings(input: {
|
|
823
|
+
tier: LimitsTier;
|
|
824
|
+
enterpriseDefaultCredits?: number | null;
|
|
825
|
+
options?: RepricingOptions;
|
|
826
|
+
}): AgentRunDefaultCeilings;
|
|
827
|
+
/** `details.approval_kind` on the refusal below, so every surface can render its own approval card. */
|
|
828
|
+
export declare const AGENT_CEILING_ABOVE_DEFAULT_APPROVAL_KIND = "agent_ceiling_above_default";
|
|
829
|
+
/**
|
|
830
|
+
* Check one run's (or one trigger's per-delivery) approved ceiling against the
|
|
831
|
+
* org's default before anything is created.
|
|
832
|
+
*
|
|
833
|
+
* - At or under the default: nothing more to approve.
|
|
834
|
+
* - Above it: refused with `approval_required` unless the caller also passed the
|
|
835
|
+
* explicit above-default approval. The details carry the numbers and the flag
|
|
836
|
+
* each surface re-sends, so the refusal is the approval card.
|
|
837
|
+
* - Above the platform backstop: refused outright; no approval raises it.
|
|
838
|
+
*
|
|
839
|
+
* Returns whether the approved ceiling is above the default; the caller persists
|
|
840
|
+
* that as the run's or trigger's above-default approval.
|
|
841
|
+
*/
|
|
842
|
+
export declare function assertAgentRunCeilingApproval(input: {
|
|
843
|
+
maxCredits: number;
|
|
844
|
+
defaults: AgentRunDefaultCeilings;
|
|
845
|
+
approveAboveDefault: boolean;
|
|
846
|
+
/** "run" for one run, "trigger" for a trigger's per-delivery ceiling. */
|
|
847
|
+
scope: "run" | "trigger";
|
|
848
|
+
}): {
|
|
849
|
+
aboveDefault: boolean;
|
|
850
|
+
};
|
|
851
|
+
/**
|
|
852
|
+
* The ceilings one run is held to, for the worker and every budget check that
|
|
853
|
+
* reads a run's authority. A run with a recorded above-default approval is
|
|
854
|
+
* bounded by its own approved `max_credits` (applied by the caller as a user
|
|
855
|
+
* limit) under the platform backstop. Every other run is bounded by the default,
|
|
856
|
+
* so a ceiling approved without the second approval — including every one
|
|
857
|
+
* approved before this rule — still binds at the default exactly as before.
|
|
858
|
+
*/
|
|
859
|
+
export declare function agentRunEnforcedCeilings(input: {
|
|
860
|
+
defaults: PlanAgentCreditLimits;
|
|
861
|
+
aboveDefaultApproved: boolean;
|
|
862
|
+
}): PlanAgentCreditLimits;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { resolveBasePricingPlan } from "./billing.js";
|
|
2
|
+
import { OxygenError } from "./cli-result.js";
|
|
2
3
|
import { WORKSPACE_TABLE_CAPACITY } from "./table-capacity.js";
|
|
4
|
+
import { findRepricedValue, repricedValue } from "./repricing.js";
|
|
3
5
|
export const LIMITS_TIER_ORDER = [
|
|
4
6
|
"free",
|
|
5
7
|
"starter",
|
|
@@ -31,6 +33,33 @@ export { VERCEL_REQUEST_BODY_LIMIT_BYTES } from "./import-limits.js";
|
|
|
31
33
|
* in the CLI alone — an older server would still 413 at the old number.
|
|
32
34
|
*/
|
|
33
35
|
export const MAX_CLI_JSON_BODY_BYTES = 2_000_000;
|
|
36
|
+
/**
|
|
37
|
+
* Derived plan-scaled limits (repricing 2026-09 decision L6, spec § 4.7):
|
|
38
|
+
* import file size, columns per action run or standing auto-run and the signals
|
|
39
|
+
* feed. Each only rises against the pre-repricing ladder, so no paid customer
|
|
40
|
+
* loses a limit and nothing here waits for the effective-date switch. Rows per
|
|
41
|
+
* write request stay 5,000 free / 50,000 paid: the 2 MB request body
|
|
42
|
+
* (`MAX_CLI_JSON_BODY_BYTES`) binds first.
|
|
43
|
+
*
|
|
44
|
+
* `importFileBytes` is ratified (decision F.8, Philipp 2026-09-27): free 500 MiB,
|
|
45
|
+
* $49–$99 1 GiB, $199–$499 2 GiB, $999–$1,999 5 GiB. It is live on every plan
|
|
46
|
+
* and no longer waits for the per-Table capacity test: rows per Table still cap
|
|
47
|
+
* what one import can load, so a bigger file never buys more rows. 5 GiB is also
|
|
48
|
+
* the largest single PUT an S3-compatible store accepts
|
|
49
|
+
* (`IMPORT_OBJECT_SINGLE_PUT_MAX_BYTES`), which is the one upload a staged
|
|
50
|
+
* import makes.
|
|
51
|
+
*/
|
|
52
|
+
export const DERIVED_PLAN_LIMIT_TARGETS = {
|
|
53
|
+
free: { importFileBytes: 500 * MIB, maxActionsPerRun: 10, signals: { maxEvents: 100, maxWindowDays: 30 } },
|
|
54
|
+
starter: { importFileBytes: 1_024 * MIB, maxActionsPerRun: 25, signals: { maxEvents: 200, maxWindowDays: 90 } },
|
|
55
|
+
pro: { importFileBytes: 2_048 * MIB, maxActionsPerRun: 25, signals: { maxEvents: 500, maxWindowDays: 180 } },
|
|
56
|
+
team: { importFileBytes: 5_120 * MIB, maxActionsPerRun: 50, signals: { maxEvents: 1_000, maxWindowDays: 365 } },
|
|
57
|
+
scale: { importFileBytes: 5_120 * MIB, maxActionsPerRun: 50, signals: { maxEvents: 1_000, maxWindowDays: 365 } },
|
|
58
|
+
};
|
|
59
|
+
/** The import file size a rung enforces (see `DERIVED_PLAN_LIMIT_TARGETS`). */
|
|
60
|
+
export function importMaxFileBytesForTier(tier) {
|
|
61
|
+
return DERIVED_PLAN_LIMIT_TARGETS[tier].importFileBytes;
|
|
62
|
+
}
|
|
34
63
|
/**
|
|
35
64
|
* The per-rung limit matrix. `ai_live` deliberately equals `tool_live` at every
|
|
36
65
|
* rung — one "live actions" mental model; the per-call cost asymmetry between
|
|
@@ -66,7 +95,7 @@ export const PLAN_LIMITS = {
|
|
|
66
95
|
},
|
|
67
96
|
import: {
|
|
68
97
|
maxRowsPerFile: TABLE_IMPORT_ROW_LIMIT,
|
|
69
|
-
maxFileBytes:
|
|
98
|
+
maxFileBytes: importMaxFileBytesForTier("free"),
|
|
70
99
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
71
100
|
},
|
|
72
101
|
// Sized against the free tier's actual funding (OXP-10.2.4, 2026-08-17): one
|
|
@@ -90,8 +119,13 @@ export const PLAN_LIMITS = {
|
|
|
90
119
|
// to complete one real Copilot session on the 1,000-credit signup grant
|
|
91
120
|
// alone. Lowering this would re-create a dead-on-arrival Copilot.
|
|
92
121
|
copilot: { maxSessionBudgetCredits: 500, defaultPerTurnCreditCeiling: 150 },
|
|
93
|
-
signals:
|
|
94
|
-
tableActions: { maxActionsPerRun:
|
|
122
|
+
signals: DERIVED_PLAN_LIMIT_TARGETS.free.signals,
|
|
123
|
+
tableActions: { maxActionsPerRun: DERIVED_PLAN_LIMIT_TARGETS.free.maxActionsPerRun },
|
|
124
|
+
// Decision L4.2 (ratified 2026-09-26): a free workspace schedules at most
|
|
125
|
+
// every 15 minutes, paid plans every minute. Dark until the repricing switch
|
|
126
|
+
// (FREE_CRON_MIN_INTERVAL_REPRICING); a faster schedule already armed is
|
|
127
|
+
// slowed to this interval at fire time, never deleted (proposal P-47).
|
|
128
|
+
workflows: { cronMinIntervalMinutes: 15 },
|
|
95
129
|
},
|
|
96
130
|
starter: {
|
|
97
131
|
cli: {
|
|
@@ -113,7 +147,7 @@ export const PLAN_LIMITS = {
|
|
|
113
147
|
},
|
|
114
148
|
import: {
|
|
115
149
|
maxRowsPerFile: TABLE_IMPORT_ROW_LIMIT,
|
|
116
|
-
maxFileBytes:
|
|
150
|
+
maxFileBytes: importMaxFileBytesForTier("starter"),
|
|
117
151
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
118
152
|
},
|
|
119
153
|
agents: {
|
|
@@ -123,8 +157,9 @@ export const PLAN_LIMITS = {
|
|
|
123
157
|
maxUpstreamCostUsdByok: 250,
|
|
124
158
|
},
|
|
125
159
|
copilot: { maxSessionBudgetCredits: 500, defaultPerTurnCreditCeiling: 150 },
|
|
126
|
-
signals:
|
|
127
|
-
tableActions: { maxActionsPerRun:
|
|
160
|
+
signals: DERIVED_PLAN_LIMIT_TARGETS.starter.signals,
|
|
161
|
+
tableActions: { maxActionsPerRun: DERIVED_PLAN_LIMIT_TARGETS.starter.maxActionsPerRun },
|
|
162
|
+
workflows: { cronMinIntervalMinutes: 1 },
|
|
128
163
|
},
|
|
129
164
|
pro: {
|
|
130
165
|
cli: {
|
|
@@ -146,7 +181,7 @@ export const PLAN_LIMITS = {
|
|
|
146
181
|
},
|
|
147
182
|
import: {
|
|
148
183
|
maxRowsPerFile: TABLE_IMPORT_ROW_LIMIT,
|
|
149
|
-
maxFileBytes:
|
|
184
|
+
maxFileBytes: importMaxFileBytesForTier("pro"),
|
|
150
185
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
151
186
|
},
|
|
152
187
|
agents: {
|
|
@@ -156,8 +191,9 @@ export const PLAN_LIMITS = {
|
|
|
156
191
|
maxUpstreamCostUsdByok: 250,
|
|
157
192
|
},
|
|
158
193
|
copilot: { maxSessionBudgetCredits: 1_000, defaultPerTurnCreditCeiling: 250 },
|
|
159
|
-
signals:
|
|
160
|
-
tableActions: { maxActionsPerRun:
|
|
194
|
+
signals: DERIVED_PLAN_LIMIT_TARGETS.pro.signals,
|
|
195
|
+
tableActions: { maxActionsPerRun: DERIVED_PLAN_LIMIT_TARGETS.pro.maxActionsPerRun },
|
|
196
|
+
workflows: { cronMinIntervalMinutes: 1 },
|
|
161
197
|
},
|
|
162
198
|
team: {
|
|
163
199
|
cli: {
|
|
@@ -179,7 +215,7 @@ export const PLAN_LIMITS = {
|
|
|
179
215
|
},
|
|
180
216
|
import: {
|
|
181
217
|
maxRowsPerFile: TABLE_IMPORT_ROW_LIMIT,
|
|
182
|
-
maxFileBytes:
|
|
218
|
+
maxFileBytes: importMaxFileBytesForTier("team"),
|
|
183
219
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
184
220
|
},
|
|
185
221
|
agents: {
|
|
@@ -189,8 +225,9 @@ export const PLAN_LIMITS = {
|
|
|
189
225
|
maxUpstreamCostUsdByok: 250,
|
|
190
226
|
},
|
|
191
227
|
copilot: { maxSessionBudgetCredits: 2_000, defaultPerTurnCreditCeiling: 500 },
|
|
192
|
-
signals:
|
|
193
|
-
tableActions: { maxActionsPerRun:
|
|
228
|
+
signals: DERIVED_PLAN_LIMIT_TARGETS.team.signals,
|
|
229
|
+
tableActions: { maxActionsPerRun: DERIVED_PLAN_LIMIT_TARGETS.team.maxActionsPerRun },
|
|
230
|
+
workflows: { cronMinIntervalMinutes: 1 },
|
|
194
231
|
},
|
|
195
232
|
scale: {
|
|
196
233
|
cli: {
|
|
@@ -212,7 +249,7 @@ export const PLAN_LIMITS = {
|
|
|
212
249
|
},
|
|
213
250
|
import: {
|
|
214
251
|
maxRowsPerFile: TABLE_IMPORT_ROW_LIMIT,
|
|
215
|
-
maxFileBytes:
|
|
252
|
+
maxFileBytes: importMaxFileBytesForTier("scale"),
|
|
216
253
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
217
254
|
},
|
|
218
255
|
agents: {
|
|
@@ -222,10 +259,32 @@ export const PLAN_LIMITS = {
|
|
|
222
259
|
maxUpstreamCostUsdByok: 250,
|
|
223
260
|
},
|
|
224
261
|
copilot: { maxSessionBudgetCredits: 5_000, defaultPerTurnCreditCeiling: 1_000 },
|
|
225
|
-
signals:
|
|
226
|
-
tableActions: { maxActionsPerRun:
|
|
262
|
+
signals: DERIVED_PLAN_LIMIT_TARGETS.scale.signals,
|
|
263
|
+
tableActions: { maxActionsPerRun: DERIVED_PLAN_LIMIT_TARGETS.scale.maxActionsPerRun },
|
|
264
|
+
workflows: { cronMinIntervalMinutes: 1 },
|
|
227
265
|
},
|
|
228
266
|
};
|
|
267
|
+
/**
|
|
268
|
+
* The fastest cron cadence, in minutes, a rung may schedule right now. The free
|
|
269
|
+
* rung's cut from every minute to every 15 (decision L4.2) is a tightening, so
|
|
270
|
+
* it resolves through the 2026-09 repricing switch: every minute until the
|
|
271
|
+
* effective instant, `PLAN_LIMITS.free.workflows.cronMinIntervalMinutes` from it.
|
|
272
|
+
*/
|
|
273
|
+
export function resolveCronMinIntervalMinutes(tier, options = {}) {
|
|
274
|
+
const scheduled = findRepricedValue(`workflows.${tier}.cron_min_interval_minutes`);
|
|
275
|
+
if (scheduled && typeof scheduled.before === "number" && typeof scheduled.after === "number") {
|
|
276
|
+
return repricedValue({ before: scheduled.before, after: scheduled.after }, options);
|
|
277
|
+
}
|
|
278
|
+
return PLAN_LIMITS[tier].workflows.cronMinIntervalMinutes;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The largest minimum cron interval any rung enforces right now. A schedule
|
|
282
|
+
* whose fires are never closer than this fits every plan, so a caller can skip
|
|
283
|
+
* the plan lookup for it.
|
|
284
|
+
*/
|
|
285
|
+
export function highestCronMinIntervalMinutes(options = {}) {
|
|
286
|
+
return Math.max(...LIMITS_TIER_ORDER.map((tier) => resolveCronMinIntervalMinutes(tier, options)));
|
|
287
|
+
}
|
|
229
288
|
/**
|
|
230
289
|
* Which enforcement rung a rung of the six-rung Oxygen plan lands on.
|
|
231
290
|
*
|
|
@@ -269,3 +328,126 @@ export function limitsTierForPlanTier(tier) {
|
|
|
269
328
|
export function planLimitsForTier(tier) {
|
|
270
329
|
return PLAN_LIMITS[tier];
|
|
271
330
|
}
|
|
331
|
+
/**
|
|
332
|
+
* The default credit ceilings of one Agent run in force on a rung right now.
|
|
333
|
+
*
|
|
334
|
+
* `PLAN_LIMITS[tier].agents` holds the values each rung read before the 2026-09
|
|
335
|
+
* repricing. The team and scale rungs drop to 2,500 total / 1,250 inference
|
|
336
|
+
* (decision L5.4, inference half PROPOSED P-56), and a cut waits for the
|
|
337
|
+
* effective-date switch (`agents.<tier>.*` in `REPRICING_2026_09_SCHEDULE`).
|
|
338
|
+
* Every Agent budget check reads this, never the table, so the cut lands
|
|
339
|
+
* everywhere at the same instant.
|
|
340
|
+
*/
|
|
341
|
+
export function resolvePlanAgentCreditLimits(tier, options = {}) {
|
|
342
|
+
const agents = PLAN_LIMITS[tier].agents;
|
|
343
|
+
const resolve = (field, fallback) => {
|
|
344
|
+
const scheduled = findRepricedValue(`agents.${tier}.${field}`);
|
|
345
|
+
return scheduled && typeof scheduled.before === "number" && typeof scheduled.after === "number"
|
|
346
|
+
? repricedValue({ before: scheduled.before, after: scheduled.after }, options)
|
|
347
|
+
: fallback;
|
|
348
|
+
};
|
|
349
|
+
return {
|
|
350
|
+
maxTotalCredits: resolve("max_total_credits", agents.maxTotalCredits),
|
|
351
|
+
maxInferenceCredits: resolve("max_inference_credits", agents.maxInferenceCredits),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* The platform's hard backstop on one Agent run's approved credit ceiling
|
|
356
|
+
* (decision F.4, ratified 2026-09-27).
|
|
357
|
+
*
|
|
358
|
+
* The plan's Agent run ceiling is a DEFAULT: a run or trigger whose approved
|
|
359
|
+
* `max_credits` fits under it needs only the usual approval. Going above it
|
|
360
|
+
* takes a second, explicit per-run (or per-trigger) approval, and even that
|
|
361
|
+
* approval stops here. 25,000 credits ($250) is the largest standing
|
|
362
|
+
* per-delivery default any plan has carried (the pre-2026-09 scale trigger
|
|
363
|
+
* default), so an approved Agent run never outspends one delivery of the
|
|
364
|
+
* largest plan's own automation. The other backstops stay in force whatever is
|
|
365
|
+
* approved: the plan's upstream-USD clamp, the iteration, tool-call and
|
|
366
|
+
* active-minute bounds, the balance check on every reservation and the org
|
|
367
|
+
* daily spend guard.
|
|
368
|
+
*/
|
|
369
|
+
export const AGENT_RUN_APPROVED_CEILING_MAX_CREDITS = 25_000;
|
|
370
|
+
/**
|
|
371
|
+
* The default Agent run ceilings for an org: its plan rung's, unless an
|
|
372
|
+
* enterprise contract names its own default (decision F.4). The contract value
|
|
373
|
+
* replaces the rung's total and model calls take half of it, as on every paid
|
|
374
|
+
* rung. A contract value is clamped to the platform backstop; an unusable one
|
|
375
|
+
* (absent, non-numeric, not positive) is ignored.
|
|
376
|
+
*/
|
|
377
|
+
export function resolveAgentRunDefaultCeilings(input) {
|
|
378
|
+
const contract = input.enterpriseDefaultCredits;
|
|
379
|
+
if (typeof contract === "number" && Number.isFinite(contract) && contract >= 1) {
|
|
380
|
+
const total = Math.min(Math.floor(contract), AGENT_RUN_APPROVED_CEILING_MAX_CREDITS);
|
|
381
|
+
return {
|
|
382
|
+
maxTotalCredits: total,
|
|
383
|
+
maxInferenceCredits: Math.max(1, Math.floor(total / 2)),
|
|
384
|
+
source: "enterprise_contract",
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return { ...resolvePlanAgentCreditLimits(input.tier, input.options), source: "plan" };
|
|
388
|
+
}
|
|
389
|
+
/** `details.approval_kind` on the refusal below, so every surface can render its own approval card. */
|
|
390
|
+
export const AGENT_CEILING_ABOVE_DEFAULT_APPROVAL_KIND = "agent_ceiling_above_default";
|
|
391
|
+
/**
|
|
392
|
+
* Check one run's (or one trigger's per-delivery) approved ceiling against the
|
|
393
|
+
* org's default before anything is created.
|
|
394
|
+
*
|
|
395
|
+
* - At or under the default: nothing more to approve.
|
|
396
|
+
* - Above it: refused with `approval_required` unless the caller also passed the
|
|
397
|
+
* explicit above-default approval. The details carry the numbers and the flag
|
|
398
|
+
* each surface re-sends, so the refusal is the approval card.
|
|
399
|
+
* - Above the platform backstop: refused outright; no approval raises it.
|
|
400
|
+
*
|
|
401
|
+
* Returns whether the approved ceiling is above the default; the caller persists
|
|
402
|
+
* that as the run's or trigger's above-default approval.
|
|
403
|
+
*/
|
|
404
|
+
export function assertAgentRunCeilingApproval(input) {
|
|
405
|
+
const defaultMax = input.defaults.maxTotalCredits;
|
|
406
|
+
const subject = input.scope === "trigger" ? "each delivery of this trigger" : "this run";
|
|
407
|
+
if (input.maxCredits > AGENT_RUN_APPROVED_CEILING_MAX_CREDITS) {
|
|
408
|
+
throw new OxygenError("invalid_request", `max_credits ${input.maxCredits} is above the platform maximum of ${AGENT_RUN_APPROVED_CEILING_MAX_CREDITS} credits for ${subject}.`, {
|
|
409
|
+
exitCode: 2,
|
|
410
|
+
details: {
|
|
411
|
+
requested_max_credits: input.maxCredits,
|
|
412
|
+
default_max_credits: defaultMax,
|
|
413
|
+
platform_max_credits: AGENT_RUN_APPROVED_CEILING_MAX_CREDITS,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (input.maxCredits <= defaultMax)
|
|
418
|
+
return { aboveDefault: false };
|
|
419
|
+
if (input.approveAboveDefault)
|
|
420
|
+
return { aboveDefault: true };
|
|
421
|
+
throw new OxygenError("approval_required", `max_credits ${input.maxCredits} is above your default Agent run ceiling of ${defaultMax} credits. Approve the higher ceiling for ${subject} with approve_above_default=true, or lower max_credits to ${defaultMax} or less.`, {
|
|
422
|
+
exitCode: 7,
|
|
423
|
+
details: {
|
|
424
|
+
approval_kind: AGENT_CEILING_ABOVE_DEFAULT_APPROVAL_KIND,
|
|
425
|
+
scope: input.scope,
|
|
426
|
+
requested_max_credits: input.maxCredits,
|
|
427
|
+
default_max_credits: defaultMax,
|
|
428
|
+
default_source: input.defaults.source,
|
|
429
|
+
platform_max_credits: AGENT_RUN_APPROVED_CEILING_MAX_CREDITS,
|
|
430
|
+
next_step: `Re-send with approve_above_default=true (CLI: --approve-above-default) to approve up to ${input.maxCredits} credits for ${subject}.`,
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* The ceilings one run is held to, for the worker and every budget check that
|
|
436
|
+
* reads a run's authority. A run with a recorded above-default approval is
|
|
437
|
+
* bounded by its own approved `max_credits` (applied by the caller as a user
|
|
438
|
+
* limit) under the platform backstop. Every other run is bounded by the default,
|
|
439
|
+
* so a ceiling approved without the second approval — including every one
|
|
440
|
+
* approved before this rule — still binds at the default exactly as before.
|
|
441
|
+
*/
|
|
442
|
+
export function agentRunEnforcedCeilings(input) {
|
|
443
|
+
if (!input.aboveDefaultApproved) {
|
|
444
|
+
return {
|
|
445
|
+
maxTotalCredits: input.defaults.maxTotalCredits,
|
|
446
|
+
maxInferenceCredits: input.defaults.maxInferenceCredits,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
maxTotalCredits: AGENT_RUN_APPROVED_CEILING_MAX_CREDITS,
|
|
451
|
+
maxInferenceCredits: AGENT_RUN_APPROVED_CEILING_MAX_CREDITS,
|
|
452
|
+
};
|
|
453
|
+
}
|