@oxygen-agent/cli 1.987.20 → 1.1003.12
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/admin-primary-providers-render.d.ts +0 -2
- package/dist/admin-primary-providers-render.js +1 -1
- package/dist/browser-login.js +1 -4
- package/dist/command-manifest.d.ts +3 -2
- package/dist/command-manifest.js +10 -0
- package/dist/credentials.d.ts +1 -1
- package/dist/functions-commands.js +6 -2
- package/dist/help.d.ts +8 -0
- package/dist/help.js +46 -0
- package/dist/index.js +1569 -123
- package/dist/knowledge-mirror.d.ts +2 -2
- package/dist/runtime.d.ts +0 -15
- package/dist/runtime.js +1 -1
- package/dist/session.d.ts +4 -3
- package/dist/skills.d.ts +8 -7
- package/dist/skills.js +24 -10
- package/dist/transcript.d.ts +2 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.js +1 -3
- package/node_modules/@oxygen/formula/dist/coerce.d.ts +10 -0
- package/node_modules/@oxygen/formula/dist/coerce.js +10 -0
- package/node_modules/@oxygen/formula/dist/formula-functions.js +65 -0
- package/node_modules/@oxygen/formula/dist/hash.d.ts +19 -0
- package/node_modules/@oxygen/formula/dist/hash.js +199 -0
- package/node_modules/@oxygen/formula/dist/value-cleaners.d.ts +6 -1
- package/node_modules/@oxygen/formula/dist/value-cleaners.js +10 -26
- package/node_modules/@oxygen/shared/dist/array-utils.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/array-utils.js +11 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +78 -22
- package/node_modules/@oxygen/shared/dist/billing.js +150 -40
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +89 -16
- package/node_modules/@oxygen/shared/dist/column-autofill.d.ts +52 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.js +80 -0
- package/node_modules/@oxygen/shared/dist/column-output-fields.js +2 -6
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.d.ts +108 -0
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.js +545 -0
- 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/deploy-env.d.ts +74 -0
- package/node_modules/@oxygen/shared/dist/deploy-env.js +82 -0
- package/node_modules/@oxygen/shared/dist/dnc-rules.d.ts +130 -0
- package/node_modules/@oxygen/shared/dist/dnc-rules.js +221 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.d.ts +103 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +819 -0
- package/node_modules/@oxygen/shared/dist/error-message.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/error-message.js +3 -0
- package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -3
- package/node_modules/@oxygen/shared/dist/external-write-policy.d.ts +33 -0
- package/node_modules/@oxygen/shared/dist/external-write-policy.js +68 -0
- package/node_modules/@oxygen/shared/dist/format-percent.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/format-percent.js +13 -0
- package/node_modules/@oxygen/shared/dist/freemail-domains.d.ts +81 -0
- package/node_modules/@oxygen/shared/dist/freemail-domains.js +157 -0
- package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.js +1 -1
- package/node_modules/@oxygen/shared/dist/index.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/index.js +13 -0
- package/node_modules/@oxygen/shared/dist/json-path.js +1 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bases.js +1 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +2 -2
- package/node_modules/@oxygen/shared/dist/langfuse.js +9 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +32 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.js +359 -0
- package/node_modules/@oxygen/shared/dist/log-sink-selector.d.ts +39 -0
- package/node_modules/@oxygen/shared/dist/log-sink-selector.js +56 -0
- package/node_modules/@oxygen/shared/dist/log.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/log.js +6 -1
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +21 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +54 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +213 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +1 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +23 -22
- package/node_modules/@oxygen/shared/dist/plan-limits.js +45 -18
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +48 -41
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +36 -25
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +22 -22
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +40 -34
- package/node_modules/@oxygen/shared/dist/product-analytics-environment.js +9 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +15 -0
- package/node_modules/@oxygen/shared/dist/rate-window.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/rate-window.js +8 -0
- package/node_modules/@oxygen/shared/dist/research-output-contract.js +1 -3
- package/node_modules/@oxygen/shared/dist/search-vocab.js +4 -5
- package/node_modules/@oxygen/shared/dist/select-options.js +6 -1
- package/node_modules/@oxygen/shared/dist/sequence-failures.js +1 -5
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +23 -0
- package/node_modules/@oxygen/shared/dist/sequences.js +110 -4
- package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +22 -10
- package/node_modules/@oxygen/shared/dist/spend-safety.js +15 -21
- package/node_modules/@oxygen/shared/dist/sql-rows.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/sql-rows.js +3 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +9 -1
- package/node_modules/@oxygen/shared/dist/type-guards.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/type-guards.js +35 -0
- package/node_modules/@oxygen/shared/dist/value-readers.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/value-readers.js +59 -0
- package/node_modules/@oxygen/shared/dist/version.js +1 -1
- package/node_modules/@oxygen/shared/package.json +50 -0
- package/node_modules/@oxygen/workflows/dist/graph/expression.js +2 -5
- package/node_modules/@oxygen/workflows/dist/graph/params.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
const DEFAULT_BATCH_SIZE = 500;
|
|
2
|
+
const DEFAULT_FLUSH_INTERVAL_MS = 2_000;
|
|
3
|
+
const DEFAULT_MAX_QUEUE = 10_000;
|
|
4
|
+
const EXPORT_TIMEOUT_MS = 10_000;
|
|
5
|
+
const NO_TIMER_REPORT_WINDOW_MS = 60_000;
|
|
6
|
+
const MAX_ERROR_BODY = 300;
|
|
7
|
+
// OTLP severity numbers (logs data model): the base of each 4-value band.
|
|
8
|
+
const SEVERITY_NUMBERS = { debug: 5, info: 9, warn: 13, error: 17 };
|
|
9
|
+
// Set by log() on every record; they become the OTLP record's own fields rather
|
|
10
|
+
// than attributes, so carrying them twice would just inflate every batch.
|
|
11
|
+
const RECORD_FIELDS_NOT_ATTRIBUTES = new Set(["ts", "level", "msg"]);
|
|
12
|
+
/**
|
|
13
|
+
* `k=v,k=v` — the same shape as `OTEL_EXPORTER_OTLP_HEADERS`, so an operator who
|
|
14
|
+
* knows the OTel variable can set ours without learning a second syntax. A pair
|
|
15
|
+
* with no `=`, or an empty key, is skipped rather than throwing: this is parsed
|
|
16
|
+
* at process start, and a malformed telemetry header must not stop a boot. The
|
|
17
|
+
* value keeps every `=` after the first (tokens contain them).
|
|
18
|
+
*/
|
|
19
|
+
export function parseOtlpHeaders(raw) {
|
|
20
|
+
const headers = {};
|
|
21
|
+
if (!raw)
|
|
22
|
+
return headers;
|
|
23
|
+
for (const pair of raw.split(",")) {
|
|
24
|
+
const separator = pair.indexOf("=");
|
|
25
|
+
if (separator <= 0)
|
|
26
|
+
continue;
|
|
27
|
+
const key = pair.slice(0, separator).trim();
|
|
28
|
+
const value = pair.slice(separator + 1).trim();
|
|
29
|
+
if (!key)
|
|
30
|
+
continue;
|
|
31
|
+
headers[key] = value;
|
|
32
|
+
}
|
|
33
|
+
return headers;
|
|
34
|
+
}
|
|
35
|
+
function toAnyValue(value) {
|
|
36
|
+
if (typeof value === "string")
|
|
37
|
+
return { stringValue: value };
|
|
38
|
+
if (typeof value === "boolean")
|
|
39
|
+
return { boolValue: value };
|
|
40
|
+
if (typeof value === "number") {
|
|
41
|
+
if (!Number.isFinite(value))
|
|
42
|
+
return { stringValue: String(value) };
|
|
43
|
+
// OTLP/JSON encodes int64 as a STRING (proto3 JSON mapping); a bare number
|
|
44
|
+
// there is what makes a collector reject an otherwise valid record.
|
|
45
|
+
return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
46
|
+
}
|
|
47
|
+
if (value === null || value === undefined)
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
return { stringValue: JSON.stringify(value) ?? String(value) };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return { stringValue: "[unserializable]" };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function toAttributes(source, skip) {
|
|
57
|
+
const attributes = [];
|
|
58
|
+
for (const [key, value] of Object.entries(source)) {
|
|
59
|
+
if (skip?.has(key))
|
|
60
|
+
continue;
|
|
61
|
+
const anyValue = toAnyValue(value);
|
|
62
|
+
if (!anyValue)
|
|
63
|
+
continue;
|
|
64
|
+
attributes.push({ key, value: anyValue });
|
|
65
|
+
}
|
|
66
|
+
return attributes;
|
|
67
|
+
}
|
|
68
|
+
function timeUnixNano(ts) {
|
|
69
|
+
const parsed = typeof ts === "string" ? Date.parse(ts) : Number.NaN;
|
|
70
|
+
const millis = Number.isFinite(parsed) ? parsed : Date.now();
|
|
71
|
+
// Decimal string, not a number: nanoseconds since the epoch exceed 2^53.
|
|
72
|
+
return `${millis}000000`;
|
|
73
|
+
}
|
|
74
|
+
function toLogRecord(record) {
|
|
75
|
+
const level = typeof record.level === "string" && record.level in SEVERITY_NUMBERS
|
|
76
|
+
? record.level
|
|
77
|
+
: "info";
|
|
78
|
+
return {
|
|
79
|
+
timeUnixNano: timeUnixNano(record.ts),
|
|
80
|
+
severityNumber: SEVERITY_NUMBERS[level],
|
|
81
|
+
severityText: level.toUpperCase(),
|
|
82
|
+
body: { stringValue: typeof record.msg === "string" ? record.msg : String(record.msg ?? "") },
|
|
83
|
+
attributes: toAttributes(record, RECORD_FIELDS_NOT_ATTRIBUTES),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function createOtlpLogSink(options) {
|
|
87
|
+
const batchSize = options.batchSize && options.batchSize > 0 ? options.batchSize : DEFAULT_BATCH_SIZE;
|
|
88
|
+
const maxQueue = options.maxQueue && options.maxQueue > 0 ? options.maxQueue : DEFAULT_MAX_QUEUE;
|
|
89
|
+
const flushIntervalMs = options.flushIntervalMs === undefined
|
|
90
|
+
? DEFAULT_FLUSH_INTERVAL_MS
|
|
91
|
+
: options.flushIntervalMs;
|
|
92
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
93
|
+
const reportWindowMs = flushIntervalMs > 0 ? flushIntervalMs : NO_TIMER_REPORT_WINDOW_MS;
|
|
94
|
+
// A null/undefined override is dropped rather than applied, so a caller that
|
|
95
|
+
// resolves its own environment and comes back empty-handed falls back to the
|
|
96
|
+
// default here instead of shipping records with no `deployment.environment`.
|
|
97
|
+
const resourceOverrides = Object.fromEntries(Object.entries(options.resource ?? {}).filter(([, value]) => value !== null && value !== undefined));
|
|
98
|
+
const resourceAttributes = toAttributes({
|
|
99
|
+
"service.name": options.serviceName,
|
|
100
|
+
"deployment.environment": process.env.OXYGEN_DEPLOY_ENV
|
|
101
|
+
?? process.env.VERCEL_ENV
|
|
102
|
+
?? process.env.NODE_ENV
|
|
103
|
+
?? null,
|
|
104
|
+
...resourceOverrides,
|
|
105
|
+
});
|
|
106
|
+
const queue = [];
|
|
107
|
+
let inFlight = null;
|
|
108
|
+
let stopped = false;
|
|
109
|
+
let lastReportAt = 0;
|
|
110
|
+
// Never through log(): this module IS the sink log() calls, so a log() here
|
|
111
|
+
// would enqueue its own failure and re-fail on the next flush forever. stderr
|
|
112
|
+
// is the one destination that cannot re-enter, and the write is guarded
|
|
113
|
+
// because a closed/full stderr must not throw into the flush path either.
|
|
114
|
+
const report = (fields) => {
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
if (now - lastReportAt < reportWindowMs)
|
|
117
|
+
return;
|
|
118
|
+
lastReportAt = now;
|
|
119
|
+
try {
|
|
120
|
+
process.stderr.write(`${JSON.stringify({
|
|
121
|
+
level: "error",
|
|
122
|
+
msg: "otlp_log_sink.export_failed",
|
|
123
|
+
endpoint: options.endpoint,
|
|
124
|
+
...fields,
|
|
125
|
+
})}\n`);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// A telemetry failure that cannot even be reported is still not a fault
|
|
129
|
+
// of the code being observed.
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const sink = (record) => {
|
|
133
|
+
if (stopped)
|
|
134
|
+
return;
|
|
135
|
+
// Drop the OLDEST record and keep this one: under sustained backpressure the
|
|
136
|
+
// newest lines are the ones describing the incident being debugged.
|
|
137
|
+
while (queue.length >= maxQueue) {
|
|
138
|
+
queue.shift();
|
|
139
|
+
}
|
|
140
|
+
queue.push(record);
|
|
141
|
+
};
|
|
142
|
+
const flush = async () => {
|
|
143
|
+
if (inFlight)
|
|
144
|
+
return inFlight;
|
|
145
|
+
if (queue.length === 0)
|
|
146
|
+
return undefined;
|
|
147
|
+
const batch = queue.splice(0, batchSize);
|
|
148
|
+
const payload = JSON.stringify({
|
|
149
|
+
resourceLogs: [
|
|
150
|
+
{
|
|
151
|
+
resource: { attributes: resourceAttributes },
|
|
152
|
+
scopeLogs: [
|
|
153
|
+
{
|
|
154
|
+
scope: { name: "oxygen" },
|
|
155
|
+
logRecords: batch.map(toLogRecord),
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
const run = (async () => {
|
|
162
|
+
try {
|
|
163
|
+
const response = await doFetch(options.endpoint, {
|
|
164
|
+
method: "POST",
|
|
165
|
+
headers: { "Content-Type": "application/json", ...options.headers },
|
|
166
|
+
body: payload,
|
|
167
|
+
signal: AbortSignal.timeout(EXPORT_TIMEOUT_MS),
|
|
168
|
+
});
|
|
169
|
+
if (response.ok)
|
|
170
|
+
return;
|
|
171
|
+
let body = "";
|
|
172
|
+
try {
|
|
173
|
+
body = (await response.text()).slice(0, MAX_ERROR_BODY);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// An unreadable body is no worse than a status-only report.
|
|
177
|
+
}
|
|
178
|
+
// The batch is gone deliberately: retrying into an unhealthy collector
|
|
179
|
+
// is how a telemetry path turns an ingest blip into memory pressure.
|
|
180
|
+
report({ status: response.status, dropped_events: batch.length, response_body: body });
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
report({
|
|
184
|
+
dropped_events: batch.length,
|
|
185
|
+
error_message: error instanceof Error ? error.message : String(error),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
})();
|
|
189
|
+
inFlight = run.finally(() => {
|
|
190
|
+
inFlight = null;
|
|
191
|
+
});
|
|
192
|
+
return inFlight;
|
|
193
|
+
};
|
|
194
|
+
const timer = flushIntervalMs > 0
|
|
195
|
+
? setInterval(() => {
|
|
196
|
+
void flush();
|
|
197
|
+
}, flushIntervalMs)
|
|
198
|
+
: null;
|
|
199
|
+
// Never hold the process open on the telemetry timer.
|
|
200
|
+
timer?.unref?.();
|
|
201
|
+
const stop = async () => {
|
|
202
|
+
stopped = true;
|
|
203
|
+
if (timer)
|
|
204
|
+
clearInterval(timer);
|
|
205
|
+
// Drain rather than flush once: a shutdown's final lines are usually the
|
|
206
|
+
// interesting ones, and one flush ships only the oldest `batchSize`.
|
|
207
|
+
while (queue.length > 0) {
|
|
208
|
+
await flush();
|
|
209
|
+
}
|
|
210
|
+
await inFlight;
|
|
211
|
+
};
|
|
212
|
+
return { sink, flush, stop };
|
|
213
|
+
}
|
|
@@ -185,14 +185,14 @@ export declare const PLAN_LIMITS: {
|
|
|
185
185
|
readonly maxDirectCsvBodyBytes: 10000000;
|
|
186
186
|
};
|
|
187
187
|
readonly agents: {
|
|
188
|
-
readonly maxTotalCredits:
|
|
189
|
-
readonly maxInferenceCredits:
|
|
188
|
+
readonly maxTotalCredits: 250;
|
|
189
|
+
readonly maxInferenceCredits: 150;
|
|
190
190
|
readonly maxUpstreamCostUsd: 10;
|
|
191
191
|
readonly maxUpstreamCostUsdByok: 10;
|
|
192
192
|
};
|
|
193
193
|
readonly copilot: {
|
|
194
|
-
readonly maxSessionBudgetCredits:
|
|
195
|
-
readonly defaultPerTurnCreditCeiling:
|
|
194
|
+
readonly maxSessionBudgetCredits: 500;
|
|
195
|
+
readonly defaultPerTurnCreditCeiling: 150;
|
|
196
196
|
};
|
|
197
197
|
readonly signals: {
|
|
198
198
|
readonly maxEvents: 100;
|
|
@@ -295,14 +295,14 @@ export declare const PLAN_LIMITS: {
|
|
|
295
295
|
readonly maxDirectCsvBodyBytes: 10000000;
|
|
296
296
|
};
|
|
297
297
|
readonly agents: {
|
|
298
|
-
readonly maxTotalCredits:
|
|
299
|
-
readonly maxInferenceCredits:
|
|
298
|
+
readonly maxTotalCredits: 1000;
|
|
299
|
+
readonly maxInferenceCredits: 500;
|
|
300
300
|
readonly maxUpstreamCostUsd: 10;
|
|
301
301
|
readonly maxUpstreamCostUsdByok: 250;
|
|
302
302
|
};
|
|
303
303
|
readonly copilot: {
|
|
304
|
-
readonly maxSessionBudgetCredits:
|
|
305
|
-
readonly defaultPerTurnCreditCeiling:
|
|
304
|
+
readonly maxSessionBudgetCredits: 500;
|
|
305
|
+
readonly defaultPerTurnCreditCeiling: 150;
|
|
306
306
|
};
|
|
307
307
|
readonly signals: {
|
|
308
308
|
readonly maxEvents: 200;
|
|
@@ -405,14 +405,14 @@ export declare const PLAN_LIMITS: {
|
|
|
405
405
|
readonly maxDirectCsvBodyBytes: 10000000;
|
|
406
406
|
};
|
|
407
407
|
readonly agents: {
|
|
408
|
-
readonly maxTotalCredits:
|
|
409
|
-
readonly maxInferenceCredits:
|
|
408
|
+
readonly maxTotalCredits: 2500;
|
|
409
|
+
readonly maxInferenceCredits: 1250;
|
|
410
410
|
readonly maxUpstreamCostUsd: 25;
|
|
411
411
|
readonly maxUpstreamCostUsdByok: 250;
|
|
412
412
|
};
|
|
413
413
|
readonly copilot: {
|
|
414
|
-
readonly maxSessionBudgetCredits:
|
|
415
|
-
readonly defaultPerTurnCreditCeiling:
|
|
414
|
+
readonly maxSessionBudgetCredits: 1000;
|
|
415
|
+
readonly defaultPerTurnCreditCeiling: 250;
|
|
416
416
|
};
|
|
417
417
|
readonly signals: {
|
|
418
418
|
readonly maxEvents: 200;
|
|
@@ -515,14 +515,14 @@ export declare const PLAN_LIMITS: {
|
|
|
515
515
|
readonly maxDirectCsvBodyBytes: 10000000;
|
|
516
516
|
};
|
|
517
517
|
readonly agents: {
|
|
518
|
-
readonly maxTotalCredits:
|
|
519
|
-
readonly maxInferenceCredits:
|
|
518
|
+
readonly maxTotalCredits: 5000;
|
|
519
|
+
readonly maxInferenceCredits: 2500;
|
|
520
520
|
readonly maxUpstreamCostUsd: 50;
|
|
521
521
|
readonly maxUpstreamCostUsdByok: 250;
|
|
522
522
|
};
|
|
523
523
|
readonly copilot: {
|
|
524
|
-
readonly maxSessionBudgetCredits:
|
|
525
|
-
readonly defaultPerTurnCreditCeiling:
|
|
524
|
+
readonly maxSessionBudgetCredits: 2000;
|
|
525
|
+
readonly defaultPerTurnCreditCeiling: 500;
|
|
526
526
|
};
|
|
527
527
|
readonly signals: {
|
|
528
528
|
readonly maxEvents: 200;
|
|
@@ -625,14 +625,14 @@ export declare const PLAN_LIMITS: {
|
|
|
625
625
|
readonly maxDirectCsvBodyBytes: 10000000;
|
|
626
626
|
};
|
|
627
627
|
readonly agents: {
|
|
628
|
-
readonly maxTotalCredits:
|
|
629
|
-
readonly maxInferenceCredits:
|
|
628
|
+
readonly maxTotalCredits: 10000;
|
|
629
|
+
readonly maxInferenceCredits: 5000;
|
|
630
630
|
readonly maxUpstreamCostUsd: 100;
|
|
631
631
|
readonly maxUpstreamCostUsdByok: 250;
|
|
632
632
|
};
|
|
633
633
|
readonly copilot: {
|
|
634
|
-
readonly maxSessionBudgetCredits:
|
|
635
|
-
readonly defaultPerTurnCreditCeiling:
|
|
634
|
+
readonly maxSessionBudgetCredits: 5000;
|
|
635
|
+
readonly defaultPerTurnCreditCeiling: 1000;
|
|
636
636
|
};
|
|
637
637
|
readonly signals: {
|
|
638
638
|
readonly maxEvents: 200;
|
|
@@ -645,8 +645,9 @@ export declare const PLAN_LIMITS: {
|
|
|
645
645
|
};
|
|
646
646
|
/**
|
|
647
647
|
* Map a raw plan-tier string (subscription `tier`, metadata tier, legacy plan
|
|
648
|
-
* key like `growth_250
|
|
649
|
-
* on the unentitled "free" rung;
|
|
648
|
+
* key like `growth_250`, or an Oxygen rung key like `oxygen_499`) onto its
|
|
649
|
+
* enforcement rung. Unknown/absent tiers land on the unentitled "free" rung;
|
|
650
|
+
* enterprise shares "scale".
|
|
650
651
|
*/
|
|
651
652
|
export declare function limitsTierForPlanTier(tier: string | null | undefined): LimitsTier;
|
|
652
653
|
export declare function planLimitsForTier(tier: LimitsTier): PlanLimits;
|
|
@@ -70,8 +70,8 @@ export const PLAN_LIMITS = {
|
|
|
70
70
|
// is bounded by its balance, not by these. The intent is only that no single
|
|
71
71
|
// run can silently eat a first impression.
|
|
72
72
|
agents: {
|
|
73
|
-
maxTotalCredits:
|
|
74
|
-
maxInferenceCredits:
|
|
73
|
+
maxTotalCredits: 250,
|
|
74
|
+
maxInferenceCredits: 150,
|
|
75
75
|
maxUpstreamCostUsd: 10,
|
|
76
76
|
maxUpstreamCostUsdByok: 10,
|
|
77
77
|
},
|
|
@@ -80,7 +80,7 @@ export const PLAN_LIMITS = {
|
|
|
80
80
|
// path over the CLI must be able to complete one real session on the base
|
|
81
81
|
// grant alone. Lowering this would re-create the dead-on-arrival Copilot the
|
|
82
82
|
// split grant exists to prevent.
|
|
83
|
-
copilot: { maxSessionBudgetCredits:
|
|
83
|
+
copilot: { maxSessionBudgetCredits: 500, defaultPerTurnCreditCeiling: 150 },
|
|
84
84
|
signals: { maxEvents: 100, maxWindowDays: 30 },
|
|
85
85
|
tableActions: { maxActionsPerRun: 10 },
|
|
86
86
|
},
|
|
@@ -108,12 +108,12 @@ export const PLAN_LIMITS = {
|
|
|
108
108
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
109
109
|
},
|
|
110
110
|
agents: {
|
|
111
|
-
maxTotalCredits:
|
|
112
|
-
maxInferenceCredits:
|
|
111
|
+
maxTotalCredits: 1_000,
|
|
112
|
+
maxInferenceCredits: 500,
|
|
113
113
|
maxUpstreamCostUsd: 10,
|
|
114
114
|
maxUpstreamCostUsdByok: 250,
|
|
115
115
|
},
|
|
116
|
-
copilot: { maxSessionBudgetCredits:
|
|
116
|
+
copilot: { maxSessionBudgetCredits: 500, defaultPerTurnCreditCeiling: 150 },
|
|
117
117
|
signals: { maxEvents: 200, maxWindowDays: 90 },
|
|
118
118
|
tableActions: { maxActionsPerRun: 25 },
|
|
119
119
|
},
|
|
@@ -141,12 +141,12 @@ export const PLAN_LIMITS = {
|
|
|
141
141
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
142
142
|
},
|
|
143
143
|
agents: {
|
|
144
|
-
maxTotalCredits:
|
|
145
|
-
maxInferenceCredits:
|
|
144
|
+
maxTotalCredits: 2_500,
|
|
145
|
+
maxInferenceCredits: 1_250,
|
|
146
146
|
maxUpstreamCostUsd: 25,
|
|
147
147
|
maxUpstreamCostUsdByok: 250,
|
|
148
148
|
},
|
|
149
|
-
copilot: { maxSessionBudgetCredits:
|
|
149
|
+
copilot: { maxSessionBudgetCredits: 1_000, defaultPerTurnCreditCeiling: 250 },
|
|
150
150
|
signals: { maxEvents: 200, maxWindowDays: 180 },
|
|
151
151
|
tableActions: { maxActionsPerRun: 25 },
|
|
152
152
|
},
|
|
@@ -174,12 +174,12 @@ export const PLAN_LIMITS = {
|
|
|
174
174
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
175
175
|
},
|
|
176
176
|
agents: {
|
|
177
|
-
maxTotalCredits:
|
|
178
|
-
maxInferenceCredits:
|
|
177
|
+
maxTotalCredits: 5_000,
|
|
178
|
+
maxInferenceCredits: 2_500,
|
|
179
179
|
maxUpstreamCostUsd: 50,
|
|
180
180
|
maxUpstreamCostUsdByok: 250,
|
|
181
181
|
},
|
|
182
|
-
copilot: { maxSessionBudgetCredits:
|
|
182
|
+
copilot: { maxSessionBudgetCredits: 2_000, defaultPerTurnCreditCeiling: 500 },
|
|
183
183
|
signals: { maxEvents: 200, maxWindowDays: 365 },
|
|
184
184
|
tableActions: { maxActionsPerRun: 25 },
|
|
185
185
|
},
|
|
@@ -207,27 +207,54 @@ export const PLAN_LIMITS = {
|
|
|
207
207
|
maxDirectCsvBodyBytes: 10_000_000,
|
|
208
208
|
},
|
|
209
209
|
agents: {
|
|
210
|
-
maxTotalCredits:
|
|
211
|
-
maxInferenceCredits:
|
|
210
|
+
maxTotalCredits: 10_000,
|
|
211
|
+
maxInferenceCredits: 5_000,
|
|
212
212
|
maxUpstreamCostUsd: 100,
|
|
213
213
|
maxUpstreamCostUsdByok: 250,
|
|
214
214
|
},
|
|
215
|
-
copilot: { maxSessionBudgetCredits:
|
|
215
|
+
copilot: { maxSessionBudgetCredits: 5_000, defaultPerTurnCreditCeiling: 1_000 },
|
|
216
216
|
signals: { maxEvents: 200, maxWindowDays: 365 },
|
|
217
217
|
tableActions: { maxActionsPerRun: 25 },
|
|
218
218
|
},
|
|
219
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* Which enforcement rung a rung of the six-rung Oxygen plan lands on.
|
|
222
|
+
*
|
|
223
|
+
* The rungs share one `oxygen` tier, so the ladder has to be re-derived from
|
|
224
|
+
* price. Deliberately scoped to `oxygen` rather than applied to every plan: a
|
|
225
|
+
* blanket price band would regress the grandfathered plans, demoting `pro_149`
|
|
226
|
+
* ($149) to "starter" and `team_399` ($399) to "pro".
|
|
227
|
+
*/
|
|
228
|
+
function oxygenRungLimitsTier(monthlyPriceCents) {
|
|
229
|
+
if (monthlyPriceCents === null)
|
|
230
|
+
return "starter";
|
|
231
|
+
// Thresholds track the ladder these rungs replaced, so nobody's enforcement
|
|
232
|
+
// rung moves for a price they were already paying: Starter was $99, Pro $249,
|
|
233
|
+
// Team $749. A rung sits on the rung of the old plan at or below its price —
|
|
234
|
+
// $499 is below the old Team, so it enforces as "pro".
|
|
235
|
+
if (monthlyPriceCents >= 199_900)
|
|
236
|
+
return "scale";
|
|
237
|
+
if (monthlyPriceCents >= 99_900)
|
|
238
|
+
return "team";
|
|
239
|
+
if (monthlyPriceCents >= 19_900)
|
|
240
|
+
return "pro";
|
|
241
|
+
return "starter";
|
|
242
|
+
}
|
|
220
243
|
/**
|
|
221
244
|
* Map a raw plan-tier string (subscription `tier`, metadata tier, legacy plan
|
|
222
|
-
* key like `growth_250
|
|
223
|
-
* on the unentitled "free" rung;
|
|
245
|
+
* key like `growth_250`, or an Oxygen rung key like `oxygen_499`) onto its
|
|
246
|
+
* enforcement rung. Unknown/absent tiers land on the unentitled "free" rung;
|
|
247
|
+
* enterprise shares "scale".
|
|
224
248
|
*/
|
|
225
249
|
export function limitsTierForPlanTier(tier) {
|
|
226
|
-
const
|
|
250
|
+
const plan = resolveBasePricingPlan(tier);
|
|
251
|
+
const base = plan?.tier;
|
|
227
252
|
if (!base || base === "free")
|
|
228
253
|
return "free";
|
|
229
254
|
if (base === "enterprise")
|
|
230
255
|
return "scale";
|
|
256
|
+
if (base === "oxygen")
|
|
257
|
+
return oxygenRungLimitsTier(plan?.monthlyPriceCents ?? null);
|
|
231
258
|
return base;
|
|
232
259
|
}
|
|
233
260
|
export function planLimitsForTier(tier) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* page's "what credits buy" table, the pricing calculator, and docs.
|
|
4
4
|
*
|
|
5
5
|
* Pricing Model 2.0 (founder-ratified 2026-07-14): ONE credit pool pays for
|
|
6
|
-
* everything; 1 USD =
|
|
6
|
+
* everything; 1 USD = 100 credits.
|
|
7
7
|
*
|
|
8
8
|
* THIS FILE NO LONGER DECLARES PRICES. It used to carry hand-copied literals
|
|
9
9
|
* under a comment asking the next person to remember to update them — which is
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
*/
|
|
37
37
|
export { creditsToUsd, usdToCredits } from "./pricing-snapshot.generated.js";
|
|
38
38
|
export declare const PRICING_SHEET_VERIFIED = "2026-07";
|
|
39
|
-
export declare const PRICING_CREDITS_PER_USD =
|
|
40
|
-
/** On-demand top-up price per
|
|
41
|
-
export declare const
|
|
39
|
+
export declare const PRICING_CREDITS_PER_USD = 100;
|
|
40
|
+
/** On-demand top-up price per 100 credits (USD); subscriptions pay $1.00. */
|
|
41
|
+
export declare const TOPUP_USD_PER_100 = 1.25;
|
|
42
42
|
export declare const SENDING_SEAT_USD_CENTS: {
|
|
43
43
|
readonly linkedin: 3000;
|
|
44
44
|
readonly whatsapp: 3000;
|
|
@@ -47,7 +47,7 @@ export declare const SENDING_SEAT_USD_CENTS: {
|
|
|
47
47
|
};
|
|
48
48
|
export declare const MANAGED_INBOX_USD_CENTS = 400;
|
|
49
49
|
export declare const SENDING_DOMAIN_USD_CENTS = 1250;
|
|
50
|
-
export declare const
|
|
50
|
+
export declare const SUBSCRIPTION_USD_PER_100 = 1;
|
|
51
51
|
/**
|
|
52
52
|
* AI column runs, honest 5× of modeled tier COGS.
|
|
53
53
|
*
|
|
@@ -58,28 +58,35 @@ export declare const SUBSCRIPTION_USD_PER_1K = 1;
|
|
|
58
58
|
* quietly mispricing the page.
|
|
59
59
|
*/
|
|
60
60
|
export declare const AI_COLUMN_CREDITS: {
|
|
61
|
-
readonly low:
|
|
62
|
-
readonly medium:
|
|
63
|
-
readonly high:
|
|
61
|
+
readonly low: 1.5;
|
|
62
|
+
readonly medium: 7.5;
|
|
63
|
+
readonly high: 25;
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
66
|
-
* Web-search grounding, billed per
|
|
66
|
+
* Web-search grounding, billed per PROVIDER CALL on top of the model — not a flat
|
|
67
|
+
* adder.
|
|
67
68
|
*
|
|
68
|
-
* This
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* the managed provider's own per-search charge (cogs-rates.ts): exa 35, parallel
|
|
73
|
-
* 5, firecrawl 80 at the default 5 results. The default column runs exa primary
|
|
74
|
-
* with parallel as its one fallback (WEB_SEARCH_ENGINES), so a row costs 35 when
|
|
75
|
-
* the primary answers and reserves 40 for the case where both lanes fire.
|
|
69
|
+
* This replaced `AI_COLUMN_WEB_SEARCH_SURCHARGE_CREDITS = 25`, a real under-quote on
|
|
70
|
+
* a public surface: a leftover from the bundled `*_with_web_search` model tiers that
|
|
71
|
+
* were removed when grounding moved onto native providers, which the billing path
|
|
72
|
+
* never read.
|
|
76
73
|
*
|
|
77
|
-
*
|
|
74
|
+
* The figures below describe the DEFAULT research column, which since D53 discovers
|
|
75
|
+
* then reads: `serper.search` (0.5) finds the URLs, then one additive
|
|
76
|
+
* `exa.contents` read (0.5) turns the top result's ~160-char SERP teaser into real
|
|
77
|
+
* page text. So a typical row spends 1 and a preview reserves 4.5, because the
|
|
78
|
+
* ceiling must also cover the `exa.search` fallback (3.5) firing when serper finds
|
|
79
|
+
* nothing. The read carries no fallback of its own — a read miss leaves the row
|
|
80
|
+
* grounded on the snippets it already has.
|
|
81
|
+
*
|
|
82
|
+
* Both numbers are RESOLVER-DERIVED and pinned by pricing-sheet-conformance.test.ts
|
|
83
|
+
* against the shipped default, so a re-price or a lane change fails a test rather
|
|
84
|
+
* than quietly mispricing this page. Do not hand-edit them.
|
|
78
85
|
*/
|
|
79
|
-
export declare const AI_COLUMN_WEB_SEARCH_TYPICAL_CREDITS =
|
|
80
|
-
export declare const AI_COLUMN_WEB_SEARCH_RESERVED_CREDITS =
|
|
86
|
+
export declare const AI_COLUMN_WEB_SEARCH_TYPICAL_CREDITS = 1;
|
|
87
|
+
export declare const AI_COLUMN_WEB_SEARCH_RESERVED_CREDITS = 4.5;
|
|
81
88
|
/** Workflow/automation actions (steps, tool calls, row writes) — capacity guard. */
|
|
82
|
-
export declare const AUTOMATION_ACTION_CREDITS = 0.
|
|
89
|
+
export declare const AUTOMATION_ACTION_CREDITS = 0.001;
|
|
83
90
|
/**
|
|
84
91
|
* Managed email inboxes: founder-ratified flat price (2026-07-25), superseding
|
|
85
92
|
* the earlier dynamic vendor-COGS × 1.25 range. Kept as an object (min/typical/max
|
|
@@ -88,9 +95,9 @@ export declare const AUTOMATION_ACTION_CREDITS = 0.01;
|
|
|
88
95
|
*/
|
|
89
96
|
export declare const MANAGED_INBOX_MARKUP = 1.25;
|
|
90
97
|
export declare const MANAGED_INBOX_CREDITS_PER_MONTH: {
|
|
91
|
-
readonly min:
|
|
92
|
-
readonly typical:
|
|
93
|
-
readonly max:
|
|
98
|
+
readonly min: 300;
|
|
99
|
+
readonly typical: 300;
|
|
100
|
+
readonly max: 300;
|
|
94
101
|
};
|
|
95
102
|
/**
|
|
96
103
|
* VOICE (the call channel). Marked up 5×, not the 1.25× infra rule the inbox and
|
|
@@ -106,12 +113,12 @@ export declare const MANAGED_INBOX_CREDITS_PER_MONTH: {
|
|
|
106
113
|
* Costing only the outbound leg undercharges every call by 29%.
|
|
107
114
|
*/
|
|
108
115
|
export declare const VOICE_MARKUP = 5;
|
|
109
|
-
export declare const VOICE_NUMBER_CREDITS_PER_MONTH =
|
|
110
|
-
export declare const VOICE_CREDITS_PER_MINUTE =
|
|
111
|
-
export declare const VOICE_CREDITS_PER_AMD_CALL =
|
|
116
|
+
export declare const VOICE_NUMBER_CREDITS_PER_MONTH = 500;
|
|
117
|
+
export declare const VOICE_CREDITS_PER_MINUTE = 9;
|
|
118
|
+
export declare const VOICE_CREDITS_PER_AMD_CALL = 3.8;
|
|
112
119
|
/** Managed domains: registrar at-cost × 1.25 (≈ a $10.44 .com → ~13,050 credits/yr). */
|
|
113
120
|
export declare const MANAGED_DOMAIN_MARKUP = 1.25;
|
|
114
|
-
export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL =
|
|
121
|
+
export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 1305;
|
|
115
122
|
/**
|
|
116
123
|
* Inbox deliverability (EmailGuard placement seat). A flat monthly price per
|
|
117
124
|
* SUBSCRIBED inbox covering continuous deliverability monitoring (blacklist,
|
|
@@ -126,9 +133,9 @@ export declare const MANAGED_DOMAIN_CREDITS_PER_YEAR_TYPICAL = 13050;
|
|
|
126
133
|
* revenue — a ~73% margin — and everything past them bills
|
|
127
134
|
* PLACEMENT_TEST_OVERAGE_CREDITS. Orgs on their own EmailGuard key (BYOK) pay 0.
|
|
128
135
|
*/
|
|
129
|
-
export declare const DELIVERABILITY_SEAT_CREDITS_PER_MONTH =
|
|
136
|
+
export declare const DELIVERABILITY_SEAT_CREDITS_PER_MONTH = 100;
|
|
130
137
|
export declare const DELIVERABILITY_INCLUDED_TESTS_PER_INBOX = 2;
|
|
131
|
-
export declare const PLACEMENT_TEST_OVERAGE_CREDITS =
|
|
138
|
+
export declare const PLACEMENT_TEST_OVERAGE_CREDITS = 16.6;
|
|
132
139
|
/**
|
|
133
140
|
* LinkedIn accounts: founder decision (2026-07-25) — a PURE seat model. The
|
|
134
141
|
* flat monthly connection fee per connected account is the WHOLE LinkedIn
|
|
@@ -136,7 +143,7 @@ export declare const PLACEMENT_TEST_OVERAGE_CREDITS = 166;
|
|
|
136
143
|
* stay 0 too — but a connected WhatsApp NUMBER carries its own monthly
|
|
137
144
|
* connection fee, see WHATSAPP_ACCOUNT_CREDITS_PER_MONTH.
|
|
138
145
|
*/
|
|
139
|
-
export declare const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH =
|
|
146
|
+
export declare const LINKEDIN_ACCOUNT_CREDITS_PER_MONTH = 1000;
|
|
140
147
|
export declare const LINKEDIN_ACTION_CREDITS: {
|
|
141
148
|
readonly visit_profile: 0;
|
|
142
149
|
readonly invite: 0;
|
|
@@ -153,9 +160,9 @@ export declare const LINKEDIN_TYPICAL_ACTIONS_CREDITS_PER_MONTH = 0;
|
|
|
153
160
|
* part-way through a month still bills the full cycle. WhatsApp message sends
|
|
154
161
|
* themselves remain 0 credits.
|
|
155
162
|
*/
|
|
156
|
-
export declare const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH =
|
|
163
|
+
export declare const WHATSAPP_ACCOUNT_CREDITS_PER_MONTH = 1000;
|
|
157
164
|
/** Dedicated egress IP add-on. */
|
|
158
|
-
export declare const EGRESS_IP_CREDITS_PER_MONTH =
|
|
165
|
+
export declare const EGRESS_IP_CREDITS_PER_MONTH = 2500;
|
|
159
166
|
/**
|
|
160
167
|
* Email + WhatsApp sends cost nothing per message — the pool pays for inboxes and
|
|
161
168
|
* connected accounts, not for sends.
|
|
@@ -170,13 +177,13 @@ export declare const SEND_CREDITS = 0;
|
|
|
170
177
|
* pricing seed.
|
|
171
178
|
*/
|
|
172
179
|
export declare const ENRICHMENT_CREDITS: {
|
|
173
|
-
readonly email_verify:
|
|
174
|
-
readonly email_find_typical:
|
|
175
|
-
readonly phone_find_typical:
|
|
176
|
-
readonly company_enrich_typical:
|
|
177
|
-
readonly web_search: 5;
|
|
178
|
-
readonly page_scrape:
|
|
179
|
-
readonly linkedin_profile_scrape:
|
|
180
|
+
readonly email_verify: 0.225;
|
|
181
|
+
readonly email_find_typical: 8.5;
|
|
182
|
+
readonly phone_find_typical: 99;
|
|
183
|
+
readonly company_enrich_typical: 9.9;
|
|
184
|
+
readonly web_search: 0.5;
|
|
185
|
+
readonly page_scrape: 4;
|
|
186
|
+
readonly linkedin_profile_scrape: 1;
|
|
180
187
|
};
|
|
181
188
|
/** Editable calculator default: blended credits per fully-enriched row. */
|
|
182
|
-
export declare const ENRICHMENT_CREDITS_PER_ROW_TYPICAL =
|
|
189
|
+
export declare const ENRICHMENT_CREDITS_PER_ROW_TYPICAL = 10;
|