@oxygen-agent/cli 1.354.0 → 1.365.3
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/command-manifest.js +12 -1
- package/dist/help.js +6 -5
- package/dist/index.js +321 -145
- package/node_modules/@oxygen/shared/dist/billing.d.ts +32 -10
- package/node_modules/@oxygen/shared/dist/billing.js +79 -11
- package/node_modules/@oxygen/shared/dist/copilot-journeys.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/copilot-journeys.js +36 -0
- package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +89 -0
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +182 -0
- package/node_modules/@oxygen/shared/dist/index.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/index.js +3 -0
- package/node_modules/@oxygen/shared/dist/linkedin-mentions.d.ts +37 -0
- package/node_modules/@oxygen/shared/dist/linkedin-mentions.js +157 -0
- package/node_modules/@oxygen/shared/dist/tags.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/tags.js +1 -0
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -28,6 +28,12 @@ export type PricingPlanMetadata = Record<string, unknown> | null | undefined;
|
|
|
28
28
|
export declare const CONTACT_SALES_URL = "https://cal.com/tim-scheuer-mxbib9/45";
|
|
29
29
|
export declare const CREDITS_PER_USD = 1000;
|
|
30
30
|
export declare const TOPUP_USD_CENTS_PER_1K_CREDITS = 125;
|
|
31
|
+
export declare const CREDIT_TOPUP_MIN_CREDITS = 8000;
|
|
32
|
+
export declare const CREDIT_TOPUP_MAX_CREDITS = 200000;
|
|
33
|
+
export declare const CREDIT_TOPUP_STEP_CREDITS = 1000;
|
|
34
|
+
export declare const CREDIT_TOPUP_DEFAULT_CREDITS = 20000;
|
|
35
|
+
export declare function isValidCreditTopupCredits(credits: number): boolean;
|
|
36
|
+
export declare function creditTopupUsdCents(credits: number): number | null;
|
|
31
37
|
export declare const AUTOMATION_ACTION_CREDITS = 0.01;
|
|
32
38
|
export declare const CREDIT_TOPUP_PACKS: readonly [{
|
|
33
39
|
readonly id: "10";
|
|
@@ -57,7 +63,7 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
57
63
|
readonly name: "Free";
|
|
58
64
|
readonly monthlyPriceCents: 0;
|
|
59
65
|
readonly monthlyCredits: 10000;
|
|
60
|
-
readonly weeklyCreditsLimit:
|
|
66
|
+
readonly weeklyCreditsLimit: null;
|
|
61
67
|
readonly rolloverCap: 10000;
|
|
62
68
|
readonly monthlyAutomationActions: null;
|
|
63
69
|
readonly automationOverageCentsPerMillion: null;
|
|
@@ -65,14 +71,14 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
65
71
|
readonly byokEnabled: false;
|
|
66
72
|
readonly description: "Get $10 in credits on us every month — try OXYGEN with managed email, phone enrichment, and AI credits.";
|
|
67
73
|
readonly ctaLabel: "Start free";
|
|
68
|
-
readonly features: readonly ["$10 in credits every month", "
|
|
74
|
+
readonly features: readonly ["$10 in credits every month", "All integrations", "Workflows", "No card required"];
|
|
69
75
|
};
|
|
70
76
|
readonly starter: {
|
|
71
77
|
readonly tier: "starter";
|
|
72
78
|
readonly name: "Starter";
|
|
73
79
|
readonly monthlyPriceCents: 9900;
|
|
74
80
|
readonly monthlyCredits: 99000;
|
|
75
|
-
readonly weeklyCreditsLimit:
|
|
81
|
+
readonly weeklyCreditsLimit: null;
|
|
76
82
|
readonly rolloverCap: 99000;
|
|
77
83
|
readonly monthlyAutomationActions: null;
|
|
78
84
|
readonly automationOverageCentsPerMillion: null;
|
|
@@ -80,14 +86,14 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
80
86
|
readonly byokEnabled: true;
|
|
81
87
|
readonly description: "For founders running focused managed enrichment and AI columns.";
|
|
82
88
|
readonly ctaLabel: "Choose Starter";
|
|
83
|
-
readonly features: readonly ["99,000 credits every month", "All integrations", "Workflows
|
|
89
|
+
readonly features: readonly ["99,000 credits every month", "All integrations", "Workflows", "Bring your own keys", "Standard support"];
|
|
84
90
|
};
|
|
85
91
|
readonly pro: {
|
|
86
92
|
readonly tier: "pro";
|
|
87
93
|
readonly name: "Pro";
|
|
88
94
|
readonly monthlyPriceCents: 24900;
|
|
89
95
|
readonly monthlyCredits: 249000;
|
|
90
|
-
readonly weeklyCreditsLimit:
|
|
96
|
+
readonly weeklyCreditsLimit: null;
|
|
91
97
|
readonly rolloverCap: 249000;
|
|
92
98
|
readonly monthlyAutomationActions: null;
|
|
93
99
|
readonly automationOverageCentsPerMillion: null;
|
|
@@ -97,14 +103,14 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
97
103
|
readonly badge: "Most popular";
|
|
98
104
|
readonly highlighted: true;
|
|
99
105
|
readonly ctaLabel: "Choose Pro";
|
|
100
|
-
readonly features: readonly ["249,000 credits every month", "All integrations", "Workflows
|
|
106
|
+
readonly features: readonly ["249,000 credits every month", "All integrations", "Workflows", "Bring your own keys", "Standard support"];
|
|
101
107
|
};
|
|
102
108
|
readonly team: {
|
|
103
109
|
readonly tier: "team";
|
|
104
110
|
readonly name: "Team";
|
|
105
111
|
readonly monthlyPriceCents: 74900;
|
|
106
112
|
readonly monthlyCredits: 749000;
|
|
107
|
-
readonly weeklyCreditsLimit:
|
|
113
|
+
readonly weeklyCreditsLimit: null;
|
|
108
114
|
readonly rolloverCap: 749000;
|
|
109
115
|
readonly monthlyAutomationActions: null;
|
|
110
116
|
readonly automationOverageCentsPerMillion: null;
|
|
@@ -112,14 +118,14 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
112
118
|
readonly byokEnabled: true;
|
|
113
119
|
readonly description: "For small GTM teams and agencies running shared workflows with their own AI keys.";
|
|
114
120
|
readonly ctaLabel: "Choose Team";
|
|
115
|
-
readonly features: readonly ["749,000 credits every month", "All integrations", "Workflows
|
|
121
|
+
readonly features: readonly ["749,000 credits every month", "All integrations", "Workflows", "Bring your own keys", "Premium support"];
|
|
116
122
|
};
|
|
117
123
|
readonly scale: {
|
|
118
124
|
readonly tier: "scale";
|
|
119
125
|
readonly name: "Scale";
|
|
120
126
|
readonly monthlyPriceCents: null;
|
|
121
127
|
readonly monthlyCredits: 10000000;
|
|
122
|
-
readonly weeklyCreditsLimit:
|
|
128
|
+
readonly weeklyCreditsLimit: null;
|
|
123
129
|
readonly rolloverCap: 10000000;
|
|
124
130
|
readonly monthlyAutomationActions: null;
|
|
125
131
|
readonly automationOverageCentsPerMillion: null;
|
|
@@ -128,7 +134,7 @@ export declare const BASE_PRICING_PLANS: {
|
|
|
128
134
|
readonly description: "For high-volume GTM teams that need custom limits and rollout support.";
|
|
129
135
|
readonly ctaLabel: "Contact sales";
|
|
130
136
|
readonly contactHref: "https://cal.com/tim-scheuer-mxbib9/45";
|
|
131
|
-
readonly features: readonly ["10,000,000+ managed credits / month", "
|
|
137
|
+
readonly features: readonly ["10,000,000+ managed credits / month", "Workflows", "Phone number enrichment on managed credits", "Custom provider routing and BYOK policies", "Dedicated onboarding"];
|
|
132
138
|
};
|
|
133
139
|
readonly enterprise: {
|
|
134
140
|
readonly tier: "enterprise";
|
|
@@ -152,6 +158,22 @@ export declare const SELF_SERVE_PLAN_TIERS: readonly SelfServePlanTier[];
|
|
|
152
158
|
export declare const CONTACT_SALES_PLAN_TIERS: readonly ContactSalesPlanTier[];
|
|
153
159
|
export declare const ACTIVE_SUBSCRIPTION_STATUSES: readonly ["active", "trialing", "past_due"];
|
|
154
160
|
export type ActiveSubscriptionStatus = (typeof ACTIVE_SUBSCRIPTION_STATUSES)[number];
|
|
161
|
+
export declare const BILLING_VISIBLE_SUBSCRIPTION_STATUSES: readonly ["active", "trialing", "past_due", "unpaid", "paused", "incomplete"];
|
|
162
|
+
export type BillingVisibleSubscriptionStatus = (typeof BILLING_VISIBLE_SUBSCRIPTION_STATUSES)[number];
|
|
163
|
+
export declare const PAST_DUE_GRACE_DAYS = 7;
|
|
164
|
+
export type SubscriptionEntitlementReason = "active" | "trialing" | "past_due_grace" | "past_due_grace_expired" | "missing_past_due_period_start" | "trial_expired" | "missing_trial_end" | "unpaid" | "paused" | "incomplete" | "canceled" | "incomplete_expired" | "missing_subscription";
|
|
165
|
+
export type SubscriptionEntitlement = {
|
|
166
|
+
entitled: boolean;
|
|
167
|
+
reason: SubscriptionEntitlementReason;
|
|
168
|
+
graceEndsAt: Date | null;
|
|
169
|
+
};
|
|
170
|
+
export declare function resolveSubscriptionEntitlement(input: {
|
|
171
|
+
status: string | null | undefined;
|
|
172
|
+
currentPeriodStart?: Date | null;
|
|
173
|
+
currentPeriodEnd?: Date | null;
|
|
174
|
+
trialEnd?: Date | null;
|
|
175
|
+
now?: Date;
|
|
176
|
+
}): SubscriptionEntitlement;
|
|
155
177
|
export type ResolvedPricingPlan = PricingPlanDefinition;
|
|
156
178
|
export declare function resolveBasePricingPlan(tier: string | null | undefined): ResolvedPricingPlan | null;
|
|
157
179
|
export declare function applyPricingPlanMetadataOverrides(// skipcq: JS-R1005
|
|
@@ -9,6 +9,23 @@ export const CONTACT_SALES_URL = "https://cal.com/tim-scheuer-mxbib9/45";
|
|
|
9
9
|
// credits bought on demand.
|
|
10
10
|
export const CREDITS_PER_USD = 1_000;
|
|
11
11
|
export const TOPUP_USD_CENTS_PER_1K_CREDITS = 125;
|
|
12
|
+
// Keep on-demand purchases inside the same $10-$250 spend envelope as the
|
|
13
|
+
// original fixed packs, but let customers choose any 1,000-credit increment.
|
|
14
|
+
export const CREDIT_TOPUP_MIN_CREDITS = 8_000;
|
|
15
|
+
export const CREDIT_TOPUP_MAX_CREDITS = 200_000;
|
|
16
|
+
export const CREDIT_TOPUP_STEP_CREDITS = 1_000;
|
|
17
|
+
export const CREDIT_TOPUP_DEFAULT_CREDITS = 20_000;
|
|
18
|
+
export function isValidCreditTopupCredits(credits) {
|
|
19
|
+
return Number.isInteger(credits)
|
|
20
|
+
&& credits >= CREDIT_TOPUP_MIN_CREDITS
|
|
21
|
+
&& credits <= CREDIT_TOPUP_MAX_CREDITS
|
|
22
|
+
&& credits % CREDIT_TOPUP_STEP_CREDITS === 0;
|
|
23
|
+
}
|
|
24
|
+
export function creditTopupUsdCents(credits) {
|
|
25
|
+
if (!isValidCreditTopupCredits(credits))
|
|
26
|
+
return null;
|
|
27
|
+
return (credits / 1_000) * TOPUP_USD_CENTS_PER_1K_CREDITS;
|
|
28
|
+
}
|
|
12
29
|
// Workflow/automation actions (steps, tool calls, row writes, retries) draw
|
|
13
30
|
// from the same credit pool at a flat capacity-guard rate — the old separate
|
|
14
31
|
// monthly action allowance + USD overage meter economy is retired (2026-07-14).
|
|
@@ -36,7 +53,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
36
53
|
name: "Free",
|
|
37
54
|
monthlyPriceCents: 0,
|
|
38
55
|
monthlyCredits: 10_000,
|
|
39
|
-
weeklyCreditsLimit:
|
|
56
|
+
weeklyCreditsLimit: null,
|
|
40
57
|
rolloverCap: 10_000,
|
|
41
58
|
monthlyAutomationActions: null,
|
|
42
59
|
automationOverageCentsPerMillion: null,
|
|
@@ -46,7 +63,6 @@ export const BASE_PRICING_PLANS = {
|
|
|
46
63
|
ctaLabel: "Start free",
|
|
47
64
|
features: [
|
|
48
65
|
"$10 in credits every month",
|
|
49
|
-
"Automation actions at 0.01 credits each",
|
|
50
66
|
"All integrations",
|
|
51
67
|
"Workflows",
|
|
52
68
|
"No card required",
|
|
@@ -57,7 +73,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
57
73
|
name: "Starter",
|
|
58
74
|
monthlyPriceCents: 9_900,
|
|
59
75
|
monthlyCredits: 99_000,
|
|
60
|
-
weeklyCreditsLimit:
|
|
76
|
+
weeklyCreditsLimit: null,
|
|
61
77
|
rolloverCap: 99_000,
|
|
62
78
|
monthlyAutomationActions: null,
|
|
63
79
|
automationOverageCentsPerMillion: null,
|
|
@@ -68,7 +84,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
68
84
|
features: [
|
|
69
85
|
"99,000 credits every month",
|
|
70
86
|
"All integrations",
|
|
71
|
-
"Workflows
|
|
87
|
+
"Workflows",
|
|
72
88
|
"Bring your own keys",
|
|
73
89
|
"Standard support",
|
|
74
90
|
],
|
|
@@ -78,7 +94,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
78
94
|
name: "Pro",
|
|
79
95
|
monthlyPriceCents: 24_900,
|
|
80
96
|
monthlyCredits: 249_000,
|
|
81
|
-
weeklyCreditsLimit:
|
|
97
|
+
weeklyCreditsLimit: null,
|
|
82
98
|
rolloverCap: 249_000,
|
|
83
99
|
monthlyAutomationActions: null,
|
|
84
100
|
automationOverageCentsPerMillion: null,
|
|
@@ -91,7 +107,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
91
107
|
features: [
|
|
92
108
|
"249,000 credits every month",
|
|
93
109
|
"All integrations",
|
|
94
|
-
"Workflows
|
|
110
|
+
"Workflows",
|
|
95
111
|
"Bring your own keys",
|
|
96
112
|
"Standard support",
|
|
97
113
|
],
|
|
@@ -101,7 +117,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
101
117
|
name: "Team",
|
|
102
118
|
monthlyPriceCents: 74_900,
|
|
103
119
|
monthlyCredits: 749_000,
|
|
104
|
-
weeklyCreditsLimit:
|
|
120
|
+
weeklyCreditsLimit: null,
|
|
105
121
|
rolloverCap: 749_000,
|
|
106
122
|
monthlyAutomationActions: null,
|
|
107
123
|
automationOverageCentsPerMillion: null,
|
|
@@ -112,7 +128,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
112
128
|
features: [
|
|
113
129
|
"749,000 credits every month",
|
|
114
130
|
"All integrations",
|
|
115
|
-
"Workflows
|
|
131
|
+
"Workflows",
|
|
116
132
|
"Bring your own keys",
|
|
117
133
|
"Premium support",
|
|
118
134
|
],
|
|
@@ -122,7 +138,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
122
138
|
name: "Scale",
|
|
123
139
|
monthlyPriceCents: null,
|
|
124
140
|
monthlyCredits: 10_000_000,
|
|
125
|
-
weeklyCreditsLimit:
|
|
141
|
+
weeklyCreditsLimit: null,
|
|
126
142
|
rolloverCap: 10_000_000,
|
|
127
143
|
monthlyAutomationActions: null,
|
|
128
144
|
automationOverageCentsPerMillion: null,
|
|
@@ -133,7 +149,7 @@ export const BASE_PRICING_PLANS = {
|
|
|
133
149
|
contactHref: CONTACT_SALES_URL,
|
|
134
150
|
features: [
|
|
135
151
|
"10,000,000+ managed credits / month",
|
|
136
|
-
"
|
|
152
|
+
"Workflows",
|
|
137
153
|
"Phone number enrichment on managed credits",
|
|
138
154
|
"Custom provider routing and BYOK policies",
|
|
139
155
|
"Dedicated onboarding",
|
|
@@ -181,6 +197,52 @@ export const ACTIVE_SUBSCRIPTION_STATUSES = [
|
|
|
181
197
|
"trialing",
|
|
182
198
|
"past_due",
|
|
183
199
|
];
|
|
200
|
+
export const BILLING_VISIBLE_SUBSCRIPTION_STATUSES = [
|
|
201
|
+
...ACTIVE_SUBSCRIPTION_STATUSES,
|
|
202
|
+
"unpaid",
|
|
203
|
+
"paused",
|
|
204
|
+
"incomplete",
|
|
205
|
+
];
|
|
206
|
+
export const PAST_DUE_GRACE_DAYS = 7;
|
|
207
|
+
export function resolveSubscriptionEntitlement(input) {
|
|
208
|
+
const now = input.now ?? new Date();
|
|
209
|
+
if (!input.status) {
|
|
210
|
+
return { entitled: false, reason: "missing_subscription", graceEndsAt: null };
|
|
211
|
+
}
|
|
212
|
+
if (input.status === "active") {
|
|
213
|
+
return { entitled: true, reason: "active", graceEndsAt: null };
|
|
214
|
+
}
|
|
215
|
+
if (input.status === "trialing") {
|
|
216
|
+
const trialEnd = input.trialEnd ?? input.currentPeriodEnd ?? null;
|
|
217
|
+
if (!trialEnd) {
|
|
218
|
+
return { entitled: false, reason: "missing_trial_end", graceEndsAt: null };
|
|
219
|
+
}
|
|
220
|
+
return trialEnd.getTime() <= now.getTime()
|
|
221
|
+
? { entitled: false, reason: "trial_expired", graceEndsAt: null }
|
|
222
|
+
: { entitled: true, reason: "trialing", graceEndsAt: null };
|
|
223
|
+
}
|
|
224
|
+
if (input.status === "past_due") {
|
|
225
|
+
if (!input.currentPeriodStart) {
|
|
226
|
+
return {
|
|
227
|
+
entitled: false,
|
|
228
|
+
reason: "missing_past_due_period_start",
|
|
229
|
+
graceEndsAt: null,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const graceEndsAt = new Date(input.currentPeriodStart.getTime() + PAST_DUE_GRACE_DAYS * 24 * 60 * 60 * 1000);
|
|
233
|
+
return graceEndsAt.getTime() > now.getTime()
|
|
234
|
+
? { entitled: true, reason: "past_due_grace", graceEndsAt }
|
|
235
|
+
: { entitled: false, reason: "past_due_grace_expired", graceEndsAt };
|
|
236
|
+
}
|
|
237
|
+
if (input.status === "unpaid"
|
|
238
|
+
|| input.status === "paused"
|
|
239
|
+
|| input.status === "incomplete"
|
|
240
|
+
|| input.status === "canceled"
|
|
241
|
+
|| input.status === "incomplete_expired") {
|
|
242
|
+
return { entitled: false, reason: input.status, graceEndsAt: null };
|
|
243
|
+
}
|
|
244
|
+
return { entitled: false, reason: "missing_subscription", graceEndsAt: null };
|
|
245
|
+
}
|
|
184
246
|
const LEGACY_PRICING_PLAN_OVERRIDES = {
|
|
185
247
|
launch_50: {
|
|
186
248
|
...BASE_PRICING_PLANS.starter,
|
|
@@ -280,6 +342,7 @@ plan, metadata) {
|
|
|
280
342
|
?? readString(record, "custom_plan_description");
|
|
281
343
|
const monthlyCredits = readCreditLimit(config, "monthlyCredits", "monthly_credits", "monthly_credit_limit");
|
|
282
344
|
const weeklyCreditsLimit = readCreditLimit(config, "weeklyCreditsLimit", "weekly_credits_limit", "weekly_credit_limit");
|
|
345
|
+
const weeklyCreditsLimitDisabled = hasExplicitNull(config, "weeklyCreditsLimit", "weekly_credits_limit", "weekly_credit_limit");
|
|
283
346
|
const rolloverCap = readCreditLimit(config, "rolloverCap", "rollover_cap", "rollover_credits");
|
|
284
347
|
const monthlyAutomationActions = readCreditLimit(config, "monthlyAutomationActions", "monthly_automation_actions", "automation_actions", "automation_action_limit");
|
|
285
348
|
const automationOverageCentsPerMillion = readCreditLimit(config, "automationOverageCentsPerMillion", "automation_overage_cents_per_million", "automation_action_overage_cents_per_million");
|
|
@@ -292,7 +355,9 @@ plan, metadata) {
|
|
|
292
355
|
...plan,
|
|
293
356
|
name: name ?? plan.name,
|
|
294
357
|
monthlyCredits: monthlyCredits ?? plan.monthlyCredits,
|
|
295
|
-
weeklyCreditsLimit:
|
|
358
|
+
weeklyCreditsLimit: weeklyCreditsLimitDisabled
|
|
359
|
+
? null
|
|
360
|
+
: weeklyCreditsLimit ?? plan.weeklyCreditsLimit,
|
|
296
361
|
rolloverCap: rolloverCap ?? plan.rolloverCap,
|
|
297
362
|
monthlyAutomationActions: monthlyAutomationActions ?? plan.monthlyAutomationActions,
|
|
298
363
|
automationOverageCentsPerMillion: automationOverageCentsPerMillion ?? plan.automationOverageCentsPerMillion,
|
|
@@ -339,6 +404,9 @@ function readCreditLimit(record, ...keys) {
|
|
|
339
404
|
}
|
|
340
405
|
return null;
|
|
341
406
|
}
|
|
407
|
+
function hasExplicitNull(record, ...keys) {
|
|
408
|
+
return keys.some((key) => Object.hasOwn(record, key) && record[key] === null);
|
|
409
|
+
}
|
|
342
410
|
export function getCurrentFreeTierCycleKey(date = new Date()) {
|
|
343
411
|
const year = date.getUTCFullYear();
|
|
344
412
|
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type CopilotJourney = {
|
|
2
|
+
slug: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
/** Existing catalog recipe slugs this journey leans on (advisory only). */
|
|
6
|
+
recipeSlugs: readonly string[];
|
|
7
|
+
/** The first user message a journey card seeds into a new session. */
|
|
8
|
+
seedMessage: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const COPILOT_JOURNEYS: readonly CopilotJourney[];
|
|
11
|
+
export type CopilotJourneySlug = (typeof COPILOT_JOURNEYS)[number]["slug"];
|
|
12
|
+
export declare function getCopilotJourney(slug: string): CopilotJourney | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Workspace Copilot guided journeys (ADR 0013 §11). One canonical copy shared by
|
|
2
|
+
// the runtime (system-prompt grounding on the named recipes) and the web journey
|
|
3
|
+
// cards (seeding a session's first message) — the data is pure and client-safe.
|
|
4
|
+
// Each journey is a thin descriptor over EXISTING advisory catalog Recipes:
|
|
5
|
+
// journeys add no runtime behavior, and every guardrail (never enroll/send/buy/
|
|
6
|
+
// change DNS without approval) rides those recipes' own approval gates.
|
|
7
|
+
export const COPILOT_JOURNEYS = [
|
|
8
|
+
{
|
|
9
|
+
slug: "inbound-led-outbound",
|
|
10
|
+
title: "Inbound-led outbound",
|
|
11
|
+
description: "Turn LinkedIn engagement, profile views, and replies into a segmented outreach motion.",
|
|
12
|
+
recipeSlugs: [
|
|
13
|
+
"profile-viewer-outreach",
|
|
14
|
+
"daily-warm-lead-queue",
|
|
15
|
+
"reply-to-meeting",
|
|
16
|
+
],
|
|
17
|
+
seedMessage: "Help me turn my recent LinkedIn engagement (profile views, post reactions, replies) into a safe, segmented outreach motion. Start by showing me what signals and connected identities I have.",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
slug: "tam-sourcing",
|
|
21
|
+
title: "Map your market",
|
|
22
|
+
description: "Source and segment your addressable market from your ICP, starting with a bounded sample.",
|
|
23
|
+
recipeSlugs: ["icp-to-account-map", "outbound-pilot-50"],
|
|
24
|
+
seedMessage: "Help me map my total addressable market from my ICP. Ground it in my company profile and website, source a bounded sample first, and show me coverage and credit estimates before expanding.",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
slug: "email-infra-setup",
|
|
28
|
+
title: "Outbound infrastructure",
|
|
29
|
+
description: "Domains, inboxes, warmup, sender posture — reviewed and approved before anything is bought or sent.",
|
|
30
|
+
recipeSlugs: ["email-infra-setup"],
|
|
31
|
+
seedMessage: "Inspect my current sending setup (domains, inboxes, warmup, senders, caps, deliverability) and propose what's missing for a safe cold-email motion. Show quotes and costs — do not buy or change anything without my approval.",
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
export function getCopilotJourney(slug) {
|
|
35
|
+
return COPILOT_JOURNEYS.find((journey) => journey.slug === slug) ?? null;
|
|
36
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical hosted-AI model registry — the single source of truth for which
|
|
3
|
+
* OXYGEN-hosted model backs each reasoning tier of each hosted-AI use case, its
|
|
4
|
+
* human-readable name, its fallback chain, the OpenRouter reasoning effort to
|
|
5
|
+
* request, and the conservative pre-call price estimates used ONLY to size
|
|
6
|
+
* credit reservations (billing always settles on the provider's actual
|
|
7
|
+
* `usage.cost`, never on the numbers here).
|
|
8
|
+
*
|
|
9
|
+
* Two use cases share the registry today:
|
|
10
|
+
* - `ai_column` — managed AI table columns. Its default model ids are
|
|
11
|
+
* re-sourced verbatim by `@oxygen/integrations` (`ai-column-runner.ts`
|
|
12
|
+
* `DEFAULT_REASONING_MODELS`) and `@oxygen/tenant-db` (`ai-models.ts`
|
|
13
|
+
* `DEFAULT_MANAGED_REASONING_MODELS`). Those modules keep owning the
|
|
14
|
+
* `OXYGEN_OPENROUTER_MODEL_*` env-override resolution; this registry only
|
|
15
|
+
* supplies the defaults, so AI-column behavior is byte-for-byte unchanged.
|
|
16
|
+
* - `copilot` — the hosted copilot. Its model + fallback chain accept Doppler
|
|
17
|
+
* overrides (`OXYGEN_COPILOT_MODEL_*` / `OXYGEN_COPILOT_FALLBACK_*`) applied
|
|
18
|
+
* here by `resolveHostedAiModel`.
|
|
19
|
+
*
|
|
20
|
+
* Kept as a leaf module (mirrors ./pricing-sheet.ts): no imports, so any package
|
|
21
|
+
* can re-source the catalog without dragging in the shared barrel.
|
|
22
|
+
*/
|
|
23
|
+
export type HostedAiLevel = "low" | "medium" | "high";
|
|
24
|
+
export type HostedAiUseCase = "ai_column" | "copilot";
|
|
25
|
+
export type HostedAiModelSpec = {
|
|
26
|
+
/** OpenRouter model id, e.g. "deepseek/deepseek-v4-flash". */
|
|
27
|
+
model: string;
|
|
28
|
+
/** Human-readable label for dashboards/UI. */
|
|
29
|
+
displayName: string;
|
|
30
|
+
/** Ordered fallback model ids tried when `model` is unavailable. */
|
|
31
|
+
fallbackModels: readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* OpenRouter reasoning effort to request; omit entirely for models that only
|
|
34
|
+
* support their max mode (Kimi K3) — the request builder sends no reasoning
|
|
35
|
+
* param for those.
|
|
36
|
+
*/
|
|
37
|
+
reasoningEffort?: "low" | "medium" | "high";
|
|
38
|
+
/**
|
|
39
|
+
* Conservative pre-call estimation prices (USD per 1M tokens). Billing settles
|
|
40
|
+
* on actual `usage.cost`; these ONLY size credit reservations.
|
|
41
|
+
*/
|
|
42
|
+
estPromptUsdPerM: number;
|
|
43
|
+
estCompletionUsdPerM: number;
|
|
44
|
+
/** Upper bound on completion tokens requested for this tier. */
|
|
45
|
+
maxOutputTokens: number;
|
|
46
|
+
};
|
|
47
|
+
export declare const HOSTED_AI_MODEL_REGISTRY: Record<HostedAiUseCase, Record<HostedAiLevel, HostedAiModelSpec>>;
|
|
48
|
+
/** The reasoning tier the hosted copilot runs at by default. */
|
|
49
|
+
export declare const COPILOT_DEFAULT_LEVEL: HostedAiLevel;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the model spec for a hosted-AI use case + reasoning level.
|
|
52
|
+
*
|
|
53
|
+
* For `copilot`, Doppler overrides are applied here:
|
|
54
|
+
* - `OXYGEN_COPILOT_MODEL_{LOW,MEDIUM,HIGH}` replaces `.model` (and, since no
|
|
55
|
+
* separate label is supplied, `.displayName` falls back to the model id).
|
|
56
|
+
* - `OXYGEN_COPILOT_FALLBACK_{LOW,MEDIUM,HIGH}` replaces `.fallbackModels`
|
|
57
|
+
* from a comma-separated list.
|
|
58
|
+
*
|
|
59
|
+
* For `ai_column`, NO env handling is applied here: `@oxygen/integrations`
|
|
60
|
+
* `ai-column-runner.ts` (`resolveModel`/`resolveAiColumnTierModels`) and
|
|
61
|
+
* `@oxygen/tenant-db` `ai-models.ts` (`resolveManagedReasoningModels`) remain
|
|
62
|
+
* the sole owners of `OXYGEN_OPENROUTER_MODEL_*` resolution, so the AI-column
|
|
63
|
+
* path is untouched.
|
|
64
|
+
*/
|
|
65
|
+
/**
|
|
66
|
+
* Look a model id up across the priced registry (same-use-case tiers first).
|
|
67
|
+
* A session-level model override must land on a spec that carries ITS OWN
|
|
68
|
+
* pricing/limits — splicing an arbitrary id onto another tier's spec sizes the
|
|
69
|
+
* credit reservation for the wrong model and breaks the spend ceiling.
|
|
70
|
+
*/
|
|
71
|
+
export declare function findHostedAiModelSpec(model: string, preferredUseCase?: HostedAiUseCase): HostedAiModelSpec | null;
|
|
72
|
+
export declare function resolveHostedAiModel(input: {
|
|
73
|
+
useCase: HostedAiUseCase;
|
|
74
|
+
level: HostedAiLevel;
|
|
75
|
+
env?: Record<string, string | undefined>;
|
|
76
|
+
}): HostedAiModelSpec;
|
|
77
|
+
/**
|
|
78
|
+
* Convenience map of each reasoning tier's default `.model` id for a use case.
|
|
79
|
+
* `@oxygen/integrations` and `@oxygen/tenant-db` re-source their AI-column
|
|
80
|
+
* default catalogs from `hostedAiDefaultModels("ai_column")` so the model ids
|
|
81
|
+
* live in exactly one place. Returns a fresh object each call.
|
|
82
|
+
*/
|
|
83
|
+
export declare function hostedAiDefaultModels(useCase: HostedAiUseCase): Record<HostedAiLevel, string>;
|
|
84
|
+
/**
|
|
85
|
+
* Whether the hosted copilot is enabled for this environment. FAIL CLOSED: only
|
|
86
|
+
* the exact strings "1" or "true" (case-insensitive, trimmed) enable it;
|
|
87
|
+
* anything else — unset, "", "0", "false" — leaves it off.
|
|
88
|
+
*/
|
|
89
|
+
export declare function isCopilotEnabled(env?: Record<string, string | undefined>): boolean;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical hosted-AI model registry — the single source of truth for which
|
|
3
|
+
* OXYGEN-hosted model backs each reasoning tier of each hosted-AI use case, its
|
|
4
|
+
* human-readable name, its fallback chain, the OpenRouter reasoning effort to
|
|
5
|
+
* request, and the conservative pre-call price estimates used ONLY to size
|
|
6
|
+
* credit reservations (billing always settles on the provider's actual
|
|
7
|
+
* `usage.cost`, never on the numbers here).
|
|
8
|
+
*
|
|
9
|
+
* Two use cases share the registry today:
|
|
10
|
+
* - `ai_column` — managed AI table columns. Its default model ids are
|
|
11
|
+
* re-sourced verbatim by `@oxygen/integrations` (`ai-column-runner.ts`
|
|
12
|
+
* `DEFAULT_REASONING_MODELS`) and `@oxygen/tenant-db` (`ai-models.ts`
|
|
13
|
+
* `DEFAULT_MANAGED_REASONING_MODELS`). Those modules keep owning the
|
|
14
|
+
* `OXYGEN_OPENROUTER_MODEL_*` env-override resolution; this registry only
|
|
15
|
+
* supplies the defaults, so AI-column behavior is byte-for-byte unchanged.
|
|
16
|
+
* - `copilot` — the hosted copilot. Its model + fallback chain accept Doppler
|
|
17
|
+
* overrides (`OXYGEN_COPILOT_MODEL_*` / `OXYGEN_COPILOT_FALLBACK_*`) applied
|
|
18
|
+
* here by `resolveHostedAiModel`.
|
|
19
|
+
*
|
|
20
|
+
* Kept as a leaf module (mirrors ./pricing-sheet.ts): no imports, so any package
|
|
21
|
+
* can re-source the catalog without dragging in the shared barrel.
|
|
22
|
+
*/
|
|
23
|
+
export const HOSTED_AI_MODEL_REGISTRY = {
|
|
24
|
+
ai_column: {
|
|
25
|
+
low: {
|
|
26
|
+
model: "deepseek/deepseek-v4-flash",
|
|
27
|
+
displayName: "DeepSeek V4 Flash",
|
|
28
|
+
fallbackModels: [],
|
|
29
|
+
estPromptUsdPerM: 0.09,
|
|
30
|
+
estCompletionUsdPerM: 0.18,
|
|
31
|
+
maxOutputTokens: 4096,
|
|
32
|
+
},
|
|
33
|
+
medium: {
|
|
34
|
+
model: "deepseek/deepseek-v4-pro",
|
|
35
|
+
displayName: "DeepSeek V4 Pro",
|
|
36
|
+
fallbackModels: [],
|
|
37
|
+
estPromptUsdPerM: 0.435,
|
|
38
|
+
estCompletionUsdPerM: 0.87,
|
|
39
|
+
maxOutputTokens: 4096,
|
|
40
|
+
},
|
|
41
|
+
high: {
|
|
42
|
+
model: "moonshotai/kimi-k2.6",
|
|
43
|
+
displayName: "Kimi K2.6",
|
|
44
|
+
fallbackModels: [],
|
|
45
|
+
estPromptUsdPerM: 0.66,
|
|
46
|
+
estCompletionUsdPerM: 3.41,
|
|
47
|
+
maxOutputTokens: 4096,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
copilot: {
|
|
51
|
+
low: {
|
|
52
|
+
model: "deepseek/deepseek-v4-flash",
|
|
53
|
+
displayName: "DeepSeek V4 Flash",
|
|
54
|
+
fallbackModels: [],
|
|
55
|
+
reasoningEffort: "medium",
|
|
56
|
+
estPromptUsdPerM: 0.09,
|
|
57
|
+
estCompletionUsdPerM: 0.18,
|
|
58
|
+
maxOutputTokens: 8192,
|
|
59
|
+
},
|
|
60
|
+
medium: {
|
|
61
|
+
model: "deepseek/deepseek-v4-pro",
|
|
62
|
+
displayName: "DeepSeek V4 Pro",
|
|
63
|
+
fallbackModels: [],
|
|
64
|
+
reasoningEffort: "high",
|
|
65
|
+
estPromptUsdPerM: 0.435,
|
|
66
|
+
estCompletionUsdPerM: 0.87,
|
|
67
|
+
maxOutputTokens: 8192,
|
|
68
|
+
},
|
|
69
|
+
high: {
|
|
70
|
+
model: "moonshotai/kimi-k3",
|
|
71
|
+
displayName: "Kimi K3",
|
|
72
|
+
fallbackModels: ["moonshotai/kimi-k2.6"],
|
|
73
|
+
// No reasoningEffort: Kimi K3 is max-only; the request builder omits the
|
|
74
|
+
// reasoning param for this tier.
|
|
75
|
+
estPromptUsdPerM: 3,
|
|
76
|
+
estCompletionUsdPerM: 15,
|
|
77
|
+
maxOutputTokens: 8192,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
/** The reasoning tier the hosted copilot runs at by default. */
|
|
82
|
+
export const COPILOT_DEFAULT_LEVEL = "high";
|
|
83
|
+
const LEVEL_ENV_SUFFIX = {
|
|
84
|
+
low: "LOW",
|
|
85
|
+
medium: "MEDIUM",
|
|
86
|
+
high: "HIGH",
|
|
87
|
+
};
|
|
88
|
+
function readTrimmedEnv(env, key) {
|
|
89
|
+
const raw = env[key];
|
|
90
|
+
if (typeof raw !== "string")
|
|
91
|
+
return undefined;
|
|
92
|
+
const trimmed = raw.trim();
|
|
93
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
94
|
+
}
|
|
95
|
+
function parseFallbackCsv(raw) {
|
|
96
|
+
return raw
|
|
97
|
+
.split(",")
|
|
98
|
+
.map((entry) => entry.trim())
|
|
99
|
+
.filter((entry) => entry.length > 0);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Resolve the model spec for a hosted-AI use case + reasoning level.
|
|
103
|
+
*
|
|
104
|
+
* For `copilot`, Doppler overrides are applied here:
|
|
105
|
+
* - `OXYGEN_COPILOT_MODEL_{LOW,MEDIUM,HIGH}` replaces `.model` (and, since no
|
|
106
|
+
* separate label is supplied, `.displayName` falls back to the model id).
|
|
107
|
+
* - `OXYGEN_COPILOT_FALLBACK_{LOW,MEDIUM,HIGH}` replaces `.fallbackModels`
|
|
108
|
+
* from a comma-separated list.
|
|
109
|
+
*
|
|
110
|
+
* For `ai_column`, NO env handling is applied here: `@oxygen/integrations`
|
|
111
|
+
* `ai-column-runner.ts` (`resolveModel`/`resolveAiColumnTierModels`) and
|
|
112
|
+
* `@oxygen/tenant-db` `ai-models.ts` (`resolveManagedReasoningModels`) remain
|
|
113
|
+
* the sole owners of `OXYGEN_OPENROUTER_MODEL_*` resolution, so the AI-column
|
|
114
|
+
* path is untouched.
|
|
115
|
+
*/
|
|
116
|
+
/**
|
|
117
|
+
* Look a model id up across the priced registry (same-use-case tiers first).
|
|
118
|
+
* A session-level model override must land on a spec that carries ITS OWN
|
|
119
|
+
* pricing/limits — splicing an arbitrary id onto another tier's spec sizes the
|
|
120
|
+
* credit reservation for the wrong model and breaks the spend ceiling.
|
|
121
|
+
*/
|
|
122
|
+
export function findHostedAiModelSpec(model, preferredUseCase) {
|
|
123
|
+
const useCases = Object.keys(HOSTED_AI_MODEL_REGISTRY);
|
|
124
|
+
const ordered = preferredUseCase
|
|
125
|
+
? [preferredUseCase, ...useCases.filter((u) => u !== preferredUseCase)]
|
|
126
|
+
: useCases;
|
|
127
|
+
for (const useCase of ordered) {
|
|
128
|
+
for (const spec of Object.values(HOSTED_AI_MODEL_REGISTRY[useCase])) {
|
|
129
|
+
if (spec.model === model)
|
|
130
|
+
return spec;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
export function resolveHostedAiModel(input) {
|
|
136
|
+
const base = HOSTED_AI_MODEL_REGISTRY[input.useCase][input.level];
|
|
137
|
+
if (input.useCase !== "copilot")
|
|
138
|
+
return base;
|
|
139
|
+
const env = input.env ?? process.env;
|
|
140
|
+
const suffix = LEVEL_ENV_SUFFIX[input.level];
|
|
141
|
+
const modelOverride = readTrimmedEnv(env, `OXYGEN_COPILOT_MODEL_${suffix}`);
|
|
142
|
+
const rawFallback = readTrimmedEnv(env, `OXYGEN_COPILOT_FALLBACK_${suffix}`);
|
|
143
|
+
const fallbackOverride = rawFallback === undefined ? undefined : parseFallbackCsv(rawFallback);
|
|
144
|
+
if (modelOverride === undefined && fallbackOverride === undefined)
|
|
145
|
+
return base;
|
|
146
|
+
// Spread preserves the absence of `reasoningEffort` on max-only tiers.
|
|
147
|
+
const resolved = { ...base };
|
|
148
|
+
if (modelOverride !== undefined) {
|
|
149
|
+
resolved.model = modelOverride;
|
|
150
|
+
resolved.displayName = modelOverride;
|
|
151
|
+
}
|
|
152
|
+
if (fallbackOverride !== undefined) {
|
|
153
|
+
resolved.fallbackModels = fallbackOverride;
|
|
154
|
+
}
|
|
155
|
+
return resolved;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Convenience map of each reasoning tier's default `.model` id for a use case.
|
|
159
|
+
* `@oxygen/integrations` and `@oxygen/tenant-db` re-source their AI-column
|
|
160
|
+
* default catalogs from `hostedAiDefaultModels("ai_column")` so the model ids
|
|
161
|
+
* live in exactly one place. Returns a fresh object each call.
|
|
162
|
+
*/
|
|
163
|
+
export function hostedAiDefaultModels(useCase) {
|
|
164
|
+
const specs = HOSTED_AI_MODEL_REGISTRY[useCase];
|
|
165
|
+
return {
|
|
166
|
+
low: specs.low.model,
|
|
167
|
+
medium: specs.medium.model,
|
|
168
|
+
high: specs.high.model,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Whether the hosted copilot is enabled for this environment. FAIL CLOSED: only
|
|
173
|
+
* the exact strings "1" or "true" (case-insensitive, trimmed) enable it;
|
|
174
|
+
* anything else — unset, "", "0", "false" — leaves it off.
|
|
175
|
+
*/
|
|
176
|
+
export function isCopilotEnabled(env = process.env) {
|
|
177
|
+
const raw = env.OXYGEN_COPILOT_ENABLED;
|
|
178
|
+
if (typeof raw !== "string")
|
|
179
|
+
return false;
|
|
180
|
+
const normalized = raw.trim().toLowerCase();
|
|
181
|
+
return normalized === "1" || normalized === "true";
|
|
182
|
+
}
|
|
@@ -8,16 +8,19 @@ export * from "./cli-envelope.js";
|
|
|
8
8
|
export * from "./cli-login-code.js";
|
|
9
9
|
export * from "./cli-result.js";
|
|
10
10
|
export * from "./column-types.js";
|
|
11
|
+
export * from "./copilot-journeys.js";
|
|
11
12
|
export * from "./credit-guidance.js";
|
|
12
13
|
export * from "./directory.js";
|
|
13
14
|
export * from "./email-tracking-token.js";
|
|
14
15
|
export * from "./email-unsubscribe-token.js";
|
|
15
16
|
export * from "./error-redaction.js";
|
|
17
|
+
export * from "./hosted-ai.js";
|
|
16
18
|
export * from "./identifiers.js";
|
|
17
19
|
export * from "./knowledge-constants.js";
|
|
18
20
|
export * from "./knowledge-links.js";
|
|
19
21
|
export * from "./knowledge-markdown.js";
|
|
20
22
|
export * from "./knowledge-seed-content.js";
|
|
23
|
+
export * from "./linkedin-mentions.js";
|
|
21
24
|
export * from "./linkedin-post-url.js";
|
|
22
25
|
export * from "./linkedin-url.js";
|
|
23
26
|
export * from "./linkedin-sequences.js";
|