@oxygen-agent/cli 1.987.20 → 1.1010.1
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/column-decision-options.d.ts +20 -0
- package/dist/column-decision-options.js +54 -0
- package/dist/command-manifest.d.ts +3 -2
- package/dist/command-manifest.js +25 -2
- package/dist/credentials.d.ts +1 -1
- package/dist/functions-commands.js +13 -9
- package/dist/help.d.ts +8 -0
- package/dist/help.js +46 -0
- package/dist/index.js +2751 -242
- package/dist/knowledge-mirror.d.ts +2 -2
- package/dist/runtime.d.ts +0 -15
- package/dist/runtime.js +1 -1
- package/dist/search-ai-filter-notice.d.ts +17 -0
- package/dist/search-ai-filter-notice.js +38 -0
- package/dist/session.d.ts +4 -3
- package/dist/skills.d.ts +8 -7
- package/dist/skills.js +58 -20
- package/dist/transcript.d.ts +2 -1
- package/dist/util.d.ts +10 -1
- package/dist/util.js +14 -2
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +296 -140
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.d.ts +9 -0
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.js +34 -0
- 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/recipe-sdk/dist/index.d.ts +13 -0
- 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 +99 -22
- package/node_modules/@oxygen/shared/dist/billing.js +195 -40
- package/node_modules/@oxygen/shared/dist/byok-connect.js +5 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +27 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +311 -28
- package/node_modules/@oxygen/shared/dist/cli-http-error.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/cli-http-error.js +8 -0
- package/node_modules/@oxygen/shared/dist/cli-result.js +1 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.d.ts +52 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.js +62 -0
- package/node_modules/@oxygen/shared/dist/column-decision.d.ts +50 -0
- package/node_modules/@oxygen/shared/dist/column-decision.js +228 -0
- package/node_modules/@oxygen/shared/dist/column-output-fields.js +2 -6
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.d.ts +113 -0
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.js +548 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +6 -6
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +6 -6
- package/node_modules/@oxygen/shared/dist/cutover-freeze.d.ts +26 -0
- package/node_modules/@oxygen/shared/dist/cutover-freeze.js +52 -0
- package/node_modules/@oxygen/shared/dist/data-suppliers.d.ts +57 -0
- package/node_modules/@oxygen/shared/dist/data-suppliers.js +59 -0
- 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 +107 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +809 -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/hosted-ai.d.ts +60 -4
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +125 -10
- package/node_modules/@oxygen/shared/dist/index.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/index.js +15 -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.d.ts +44 -1
- package/node_modules/@oxygen/shared/dist/langfuse.js +416 -14
- package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +33 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.js +361 -0
- package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/linkedin-country-timezones.js +276 -0
- package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/linkedin-message-deletion.js +5 -0
- package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.d.ts +44 -0
- package/node_modules/@oxygen/shared/dist/linkedin-post-keywords.js +116 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +96 -0
- package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +123 -0
- package/node_modules/@oxygen/shared/dist/llm-durable-capture.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/llm-durable-capture.js +89 -0
- package/node_modules/@oxygen/shared/dist/llm-prompts.d.ts +75 -0
- package/node_modules/@oxygen/shared/dist/llm-prompts.js +161 -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/mailbox-egress-ownership.d.ts +90 -0
- package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.js +130 -0
- 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/operational-telemetry.d.ts +24 -0
- package/node_modules/@oxygen/shared/dist/operational-telemetry.js +73 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +79 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +366 -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 +36 -2
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +36 -1
- 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/redaction.js +4 -1
- package/node_modules/@oxygen/shared/dist/research-output-contract.js +1 -3
- package/node_modules/@oxygen/shared/dist/scraper-lane-credential.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/scraper-lane-credential.js +23 -0
- 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 +115 -5
- package/node_modules/@oxygen/shared/dist/signup-lead-payload.d.ts +80 -0
- package/node_modules/@oxygen/shared/dist/signup-lead-payload.js +198 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/social-capabilities.js +25 -16
- package/node_modules/@oxygen/shared/dist/social-post-metrics-core.d.ts +32 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-core.js +32 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.d.ts +31 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-linkedin.js +103 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-series.d.ts +96 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-series.js +213 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-x.d.ts +13 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics-x.js +78 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/social-post-metrics.js +51 -0
- 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/stripe-price-catalog.d.ts +36 -0
- package/node_modules/@oxygen/shared/dist/stripe-price-catalog.js +184 -0
- package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.d.ts +41 -0
- package/node_modules/@oxygen/shared/dist/stripe-subscription-kind.js +44 -0
- package/node_modules/@oxygen/shared/dist/table-limits.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/table-limits.js +3 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.d.ts +94 -0
- package/node_modules/@oxygen/shared/dist/telemetry-export-observer.js +298 -0
- package/node_modules/@oxygen/shared/dist/telemetry.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +28 -2
- 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/ugc.d.ts +22 -11
- package/node_modules/@oxygen/shared/dist/ugc.js +10 -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.generated.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/version.generated.js +2 -0
- package/node_modules/@oxygen/shared/dist/version.js +8 -1
- package/node_modules/@oxygen/shared/dist/workspace-event-catalog.js +0 -23
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +29 -0
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +31 -0
- package/node_modules/@oxygen/shared/package.json +59 -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 +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function errorMessage(error: unknown): string;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
// idempotent, never throws, and never widens a message.
|
|
21
21
|
import { redactSecretsInString } from "./redaction.js";
|
|
22
22
|
import { isRetryableConcurrencyError, redactSqlParameters } from "./sql-error.js";
|
|
23
|
+
import { isRecord } from "./type-guards.js";
|
|
23
24
|
// Whole fields whose NAME marks them secret. Unchanged from the operation-event
|
|
24
25
|
// writer this was extracted from; substring credentials (Bearer/sk-/DB URLs) are
|
|
25
26
|
// scrubbed separately by redactSecretsInString.
|
|
@@ -306,6 +307,3 @@ export function summarizeProviderBody(body) {
|
|
|
306
307
|
function truncate(value, maxLength) {
|
|
307
308
|
return value.length > maxLength ? `${value.slice(0, maxLength - 3)}...` : value;
|
|
308
309
|
}
|
|
309
|
-
function isRecord(value) {
|
|
310
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
311
|
-
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type ExternalWritePolicy = "allow" | "deny";
|
|
2
|
+
/** The error code every refusal carries, on every surface. */
|
|
3
|
+
export declare const EXTERNAL_WRITES_DENIED_CODE = "external_writes_denied";
|
|
4
|
+
export declare const EXTERNAL_WRITES_ENV_VAR = "OXYGEN_EXTERNAL_WRITES";
|
|
5
|
+
type PolicyEnv = {
|
|
6
|
+
[key: string]: string | undefined;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* `deny` when `OXYGEN_EXTERNAL_WRITES` is exactly `deny` (trimmed,
|
|
10
|
+
* case-insensitive), `allow` for anything else including unset.
|
|
11
|
+
*
|
|
12
|
+
* Read per call rather than memoized at module load: the value is read on paths
|
|
13
|
+
* a test needs to drive both ways, and a process-static snapshot would make the
|
|
14
|
+
* denial untestable in exactly the suite that has to prove it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveExternalWritePolicy(env?: PolicyEnv): ExternalWritePolicy;
|
|
17
|
+
/** Convenience predicate for callers that only branch. */
|
|
18
|
+
export declare function externalWritesDenied(env?: PolicyEnv): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Refuse `action` when this environment denies external writes.
|
|
21
|
+
*
|
|
22
|
+
* Throws `OxygenError` with code `external_writes_denied` so the refusal travels
|
|
23
|
+
* the CLI/MCP envelope, the run record and the worker's job failure the same way
|
|
24
|
+
* every other refusal does — a shadow that swallows the denial into a generic
|
|
25
|
+
* failure teaches its operator nothing.
|
|
26
|
+
*
|
|
27
|
+
* Logged at `warn`, not `error`: a refusal here is the control WORKING, and the
|
|
28
|
+
* shadow's soak is expected to produce a stream of them. The message names both
|
|
29
|
+
* the action and the variable, because the person reading it in Axiom is usually
|
|
30
|
+
* asking "why did nothing send" and the answer is a configuration they set.
|
|
31
|
+
*/
|
|
32
|
+
export declare function assertExternalWritesAllowed(action: string, env?: PolicyEnv): void;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// The environment-level external-write denial, and the one place that reads
|
|
2
|
+
// `OXYGEN_EXTERNAL_WRITES`.
|
|
3
|
+
//
|
|
4
|
+
// WHY THIS EXISTS AND WHY IT IS NOT A CLASSIFIER. A production *shadow* holds a
|
|
5
|
+
// restored copy of production: real mailbox OAuth tokens, real provider
|
|
6
|
+
// credentials, real customer records — while managed production is still live
|
|
7
|
+
// and doing the same work. The restore script scrubs those columns, but a scrub
|
|
8
|
+
// is data hygiene, not a guarantee: one un-nulled column is one real send, to a
|
|
9
|
+
// real prospect, twice. So the shadow also fails closed at the platform
|
|
10
|
+
// boundary (`.agents/skills/oxygen-self-host-cutover`, Part 1 Control 3).
|
|
11
|
+
//
|
|
12
|
+
// THE ORDERING IS THE SAFETY PROPERTY, and it is the same lesson
|
|
13
|
+
// `EXTERNAL_REACH_CAPABILITY_NAMES` (packages/copilot/src/policy.ts) was written
|
|
14
|
+
// to record: `capabilityLooksPaid` read ARGUMENT NAMES, so a write-capable tool
|
|
15
|
+
// declaring `max_credits` classified `paid` and could never reach the
|
|
16
|
+
// `external_write` branch — which made a real outbound launch waivable by an
|
|
17
|
+
// approval-free spend budget on a declared ceiling of one credit. A denial that
|
|
18
|
+
// runs anywhere except FIRST inherits exactly that defect. Every caller here
|
|
19
|
+
// asks this before it classifies, before it evaluates an allowance, an approval
|
|
20
|
+
// or a policy rule, and before it constructs a provider client.
|
|
21
|
+
//
|
|
22
|
+
// UNSET MEANS ALLOW, deliberately and permanently. Managed production must be
|
|
23
|
+
// byte-identical to the day before this module landed; only a shadow sets the
|
|
24
|
+
// variable. `deny` is the only recognised denial value — a typo (`denied`,
|
|
25
|
+
// `true`, `1`) allows, which is the fail-OPEN direction and is the right one
|
|
26
|
+
// here: a variable nobody set must never take production off the air, and the
|
|
27
|
+
// shadow's operator proves the denial by ATTEMPTING a send and observing the
|
|
28
|
+
// refusal rather than by trusting the configuration (same skill, "Proving it,
|
|
29
|
+
// rather than believing it").
|
|
30
|
+
import { OxygenError } from "./cli-result.js";
|
|
31
|
+
import { log } from "./log.js";
|
|
32
|
+
/** The error code every refusal carries, on every surface. */
|
|
33
|
+
export const EXTERNAL_WRITES_DENIED_CODE = "external_writes_denied";
|
|
34
|
+
export const EXTERNAL_WRITES_ENV_VAR = "OXYGEN_EXTERNAL_WRITES";
|
|
35
|
+
/**
|
|
36
|
+
* `deny` when `OXYGEN_EXTERNAL_WRITES` is exactly `deny` (trimmed,
|
|
37
|
+
* case-insensitive), `allow` for anything else including unset.
|
|
38
|
+
*
|
|
39
|
+
* Read per call rather than memoized at module load: the value is read on paths
|
|
40
|
+
* a test needs to drive both ways, and a process-static snapshot would make the
|
|
41
|
+
* denial untestable in exactly the suite that has to prove it.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveExternalWritePolicy(env = process.env) {
|
|
44
|
+
return env[EXTERNAL_WRITES_ENV_VAR]?.trim().toLowerCase() === "deny" ? "deny" : "allow";
|
|
45
|
+
}
|
|
46
|
+
/** Convenience predicate for callers that only branch. */
|
|
47
|
+
export function externalWritesDenied(env = process.env) {
|
|
48
|
+
return resolveExternalWritePolicy(env) === "deny";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Refuse `action` when this environment denies external writes.
|
|
52
|
+
*
|
|
53
|
+
* Throws `OxygenError` with code `external_writes_denied` so the refusal travels
|
|
54
|
+
* the CLI/MCP envelope, the run record and the worker's job failure the same way
|
|
55
|
+
* every other refusal does — a shadow that swallows the denial into a generic
|
|
56
|
+
* failure teaches its operator nothing.
|
|
57
|
+
*
|
|
58
|
+
* Logged at `warn`, not `error`: a refusal here is the control WORKING, and the
|
|
59
|
+
* shadow's soak is expected to produce a stream of them. The message names both
|
|
60
|
+
* the action and the variable, because the person reading it in Axiom is usually
|
|
61
|
+
* asking "why did nothing send" and the answer is a configuration they set.
|
|
62
|
+
*/
|
|
63
|
+
export function assertExternalWritesAllowed(action, env = process.env) {
|
|
64
|
+
if (resolveExternalWritePolicy(env) !== "deny")
|
|
65
|
+
return;
|
|
66
|
+
log("warn", "external_writes.denied", { action });
|
|
67
|
+
throw new OxygenError(EXTERNAL_WRITES_DENIED_CODE, `External writes are denied in this environment (${EXTERNAL_WRITES_ENV_VAR}=deny), so "${action}" cannot run.`, { details: { action, env_var: EXTERNAL_WRITES_ENV_VAR } });
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical percentage formatting shared by the web app and MCP surfaces.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format a 0..1 ratio as an en-US percentage with at most one decimal; `null`
|
|
6
|
+
* renders as an em dash. The locale is pinned so web and MCP cannot drift.
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatPercent(value: number | null): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical percentage formatting shared by the web app and MCP surfaces.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format a 0..1 ratio as an en-US percentage with at most one decimal; `null`
|
|
6
|
+
* renders as an em dash. The locale is pinned so web and MCP cannot drift.
|
|
7
|
+
*/
|
|
8
|
+
export function formatPercent(value) {
|
|
9
|
+
return value === null ? "—" : new Intl.NumberFormat("en-US", {
|
|
10
|
+
style: "percent",
|
|
11
|
+
maximumFractionDigits: 1,
|
|
12
|
+
}).format(value);
|
|
13
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer / freemail mail hosts — the ONE list, in two deliberate tiers.
|
|
3
|
+
*
|
|
4
|
+
* EIGHT call sites used to carry their own hand-typed copy of this concept — 101, 34, 34,
|
|
5
|
+
* 25, 22, 18, 13 and 12 entries — none importing another, none covered by a test
|
|
6
|
+
* asserting they agreed, and two of them byte-identical forks that nothing kept in sync.
|
|
7
|
+
* The same address resolved differently depending on which copy a code path happened to
|
|
8
|
+
* reach. This module is the single source of truth; `packages/shared` is the only leaf
|
|
9
|
+
* package all eight can reach without inverting a dependency edge.
|
|
10
|
+
*
|
|
11
|
+
* WHY TWO TIERS, and why they must not be collapsed into one:
|
|
12
|
+
*
|
|
13
|
+
* The callers are not asking the same question, and the cost of a wrong answer is
|
|
14
|
+
* asymmetric in opposite directions.
|
|
15
|
+
*
|
|
16
|
+
* - `FREEMAIL_DOMAINS` (core) answers "may I treat this domain as a shared EMPLOYER?"
|
|
17
|
+
* Two consumers ride on that answer, and they fail in OPPOSITE directions, which is
|
|
18
|
+
* why this tier is conservative rather than generous:
|
|
19
|
+
*
|
|
20
|
+
* 1. The company-scope reply stop (`settings.stop_on_reply_scope = "company_domain"`)
|
|
21
|
+
* terminalizes an enrollment's colleagues by matching domain. A host wrongly IN
|
|
22
|
+
* this tier is harmless here; a host wrongly OUT of it stops strangers who merely
|
|
23
|
+
* share a mail host — real, customer-visible damage.
|
|
24
|
+
* 2. Company derivation from a person's email domain
|
|
25
|
+
* (`deriveCompanyDomainFromEmail`, `packages/tenant-db/src/table-link-plan.ts`)
|
|
26
|
+
* drops freemail before offering a domain as a company join key. Here the
|
|
27
|
+
* polarity REVERSES: a host wrongly OUT of this tier makes OXYGEN mint a company
|
|
28
|
+
* record for a mail provider, so every @<host> person collapses onto one fake
|
|
29
|
+
* account. Where that derivation is wired into record creation, removing a host
|
|
30
|
+
* from this tier silently starts creating accounts for it.
|
|
31
|
+
*
|
|
32
|
+
* So a host must be in this tier to be safe for BOTH, and the safe direction for an
|
|
33
|
+
* edit is to ADD, never to remove or relocate to the broad tier. Extend it only with
|
|
34
|
+
* hosts that are unambiguously consumer mailboxes — and note the ORDER caveat in
|
|
35
|
+
* `packages/tenant-db/src/freemail-domains.ts`, because a core-tier edit also changes
|
|
36
|
+
* a formula string already persisted in every tenant's column definitions.
|
|
37
|
+
*
|
|
38
|
+
* - `PERSONAL_EMAIL_DOMAINS` (broad) answers "is this domain a poor stand-in for a
|
|
39
|
+
* COMPANY identity?" — used to skip fetching a workspace icon, to reject a personal
|
|
40
|
+
* host typed into the marketing hero form, to avoid picking a personal address as a
|
|
41
|
+
* person's work email, and to avoid treating a meeting participant's mail host as their
|
|
42
|
+
* employer. Here a false positive costs nothing (we simply decline to guess a company)
|
|
43
|
+
* while a miss produces a junk company/icon. So this tier is the superset, including
|
|
44
|
+
* regional and privacy-focused providers.
|
|
45
|
+
*
|
|
46
|
+
* The broad tier is a strict superset of the core tier by construction below, so a host
|
|
47
|
+
* can never be "freemail but not personal" — exactly the incoherence the forks had
|
|
48
|
+
* developed (the old core list carried `t-online.de`; several broad lists did not).
|
|
49
|
+
*
|
|
50
|
+
* The broad tier is the union of all eight former lists. Most of its bulk comes from the
|
|
51
|
+
* old `packages/formula` copy, which was by far the best maintained and is the only one
|
|
52
|
+
* that covered country-specific variants (`yahoo.co.uk`, `hotmail.fr`, `orange.fr`,
|
|
53
|
+
* `wp.pl`, `uol.com.br` …) and ISP mailboxes (`comcast.net`, `btinternet.com`). Every
|
|
54
|
+
* other caller was silently missing those.
|
|
55
|
+
*/
|
|
56
|
+
/** Tier 1 — see the module note. Small on purpose. */
|
|
57
|
+
export declare const FREEMAIL_DOMAINS: ReadonlySet<string>;
|
|
58
|
+
/** Tier 2 — a strict superset of {@link FREEMAIL_DOMAINS}. */
|
|
59
|
+
export declare const PERSONAL_EMAIL_DOMAINS: ReadonlySet<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Reduce an address or a bare domain to a comparable mail host: lowercased, trimmed,
|
|
62
|
+
* everything before the last '@' dropped, and a trailing FQDN dot removed. Returns null
|
|
63
|
+
* for junk/empty/nullish input so callers can distinguish "not a host" from "not in the
|
|
64
|
+
* set". Previously each fork normalized differently — one did full address handling, two
|
|
65
|
+
* only lowercased a bare domain — so the same input could resolve differently depending
|
|
66
|
+
* on which copy you happened to call.
|
|
67
|
+
*/
|
|
68
|
+
export declare function normalizeMailHost(value: string | null | undefined): string | null;
|
|
69
|
+
/**
|
|
70
|
+
* True when the host is a tier-1 consumer mailbox, i.e. it NEVER identifies a shared
|
|
71
|
+
* employer. Accepts a bare domain or a full address. Unknown input returns false: an
|
|
72
|
+
* unrecognized domain is treated as a company domain, which keeps the company-scope
|
|
73
|
+
* stop's safe default identical to lead-scope.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isFreemailDomain(domain: string | null | undefined): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* True when the host is a personal mailbox of any kind (tier 2). Use this for "should I
|
|
78
|
+
* infer a company from this domain?"; use {@link isFreemailDomain} when a false positive
|
|
79
|
+
* would wrongly group unrelated people as colleagues.
|
|
80
|
+
*/
|
|
81
|
+
export declare function isPersonalEmailDomain(domain: string | null | undefined): boolean;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumer / freemail mail hosts — the ONE list, in two deliberate tiers.
|
|
3
|
+
*
|
|
4
|
+
* EIGHT call sites used to carry their own hand-typed copy of this concept — 101, 34, 34,
|
|
5
|
+
* 25, 22, 18, 13 and 12 entries — none importing another, none covered by a test
|
|
6
|
+
* asserting they agreed, and two of them byte-identical forks that nothing kept in sync.
|
|
7
|
+
* The same address resolved differently depending on which copy a code path happened to
|
|
8
|
+
* reach. This module is the single source of truth; `packages/shared` is the only leaf
|
|
9
|
+
* package all eight can reach without inverting a dependency edge.
|
|
10
|
+
*
|
|
11
|
+
* WHY TWO TIERS, and why they must not be collapsed into one:
|
|
12
|
+
*
|
|
13
|
+
* The callers are not asking the same question, and the cost of a wrong answer is
|
|
14
|
+
* asymmetric in opposite directions.
|
|
15
|
+
*
|
|
16
|
+
* - `FREEMAIL_DOMAINS` (core) answers "may I treat this domain as a shared EMPLOYER?"
|
|
17
|
+
* Two consumers ride on that answer, and they fail in OPPOSITE directions, which is
|
|
18
|
+
* why this tier is conservative rather than generous:
|
|
19
|
+
*
|
|
20
|
+
* 1. The company-scope reply stop (`settings.stop_on_reply_scope = "company_domain"`)
|
|
21
|
+
* terminalizes an enrollment's colleagues by matching domain. A host wrongly IN
|
|
22
|
+
* this tier is harmless here; a host wrongly OUT of it stops strangers who merely
|
|
23
|
+
* share a mail host — real, customer-visible damage.
|
|
24
|
+
* 2. Company derivation from a person's email domain
|
|
25
|
+
* (`deriveCompanyDomainFromEmail`, `packages/tenant-db/src/table-link-plan.ts`)
|
|
26
|
+
* drops freemail before offering a domain as a company join key. Here the
|
|
27
|
+
* polarity REVERSES: a host wrongly OUT of this tier makes OXYGEN mint a company
|
|
28
|
+
* record for a mail provider, so every @<host> person collapses onto one fake
|
|
29
|
+
* account. Where that derivation is wired into record creation, removing a host
|
|
30
|
+
* from this tier silently starts creating accounts for it.
|
|
31
|
+
*
|
|
32
|
+
* So a host must be in this tier to be safe for BOTH, and the safe direction for an
|
|
33
|
+
* edit is to ADD, never to remove or relocate to the broad tier. Extend it only with
|
|
34
|
+
* hosts that are unambiguously consumer mailboxes — and note the ORDER caveat in
|
|
35
|
+
* `packages/tenant-db/src/freemail-domains.ts`, because a core-tier edit also changes
|
|
36
|
+
* a formula string already persisted in every tenant's column definitions.
|
|
37
|
+
*
|
|
38
|
+
* - `PERSONAL_EMAIL_DOMAINS` (broad) answers "is this domain a poor stand-in for a
|
|
39
|
+
* COMPANY identity?" — used to skip fetching a workspace icon, to reject a personal
|
|
40
|
+
* host typed into the marketing hero form, to avoid picking a personal address as a
|
|
41
|
+
* person's work email, and to avoid treating a meeting participant's mail host as their
|
|
42
|
+
* employer. Here a false positive costs nothing (we simply decline to guess a company)
|
|
43
|
+
* while a miss produces a junk company/icon. So this tier is the superset, including
|
|
44
|
+
* regional and privacy-focused providers.
|
|
45
|
+
*
|
|
46
|
+
* The broad tier is a strict superset of the core tier by construction below, so a host
|
|
47
|
+
* can never be "freemail but not personal" — exactly the incoherence the forks had
|
|
48
|
+
* developed (the old core list carried `t-online.de`; several broad lists did not).
|
|
49
|
+
*
|
|
50
|
+
* The broad tier is the union of all eight former lists. Most of its bulk comes from the
|
|
51
|
+
* old `packages/formula` copy, which was by far the best maintained and is the only one
|
|
52
|
+
* that covered country-specific variants (`yahoo.co.uk`, `hotmail.fr`, `orange.fr`,
|
|
53
|
+
* `wp.pl`, `uol.com.br` …) and ISP mailboxes (`comcast.net`, `btinternet.com`). Every
|
|
54
|
+
* other caller was silently missing those.
|
|
55
|
+
*/
|
|
56
|
+
// Tier 1. Unambiguous global consumer mailboxes. Load-bearing for the company-scope
|
|
57
|
+
// reply stop — read the note above before adding anything here.
|
|
58
|
+
const CORE_FREEMAIL_DOMAINS = [
|
|
59
|
+
"gmail.com",
|
|
60
|
+
"googlemail.com",
|
|
61
|
+
"outlook.com",
|
|
62
|
+
"hotmail.com",
|
|
63
|
+
"live.com",
|
|
64
|
+
"msn.com",
|
|
65
|
+
"yahoo.com",
|
|
66
|
+
"ymail.com",
|
|
67
|
+
"icloud.com",
|
|
68
|
+
"me.com",
|
|
69
|
+
"aol.com",
|
|
70
|
+
"gmx.com",
|
|
71
|
+
"gmx.net",
|
|
72
|
+
"gmx.de",
|
|
73
|
+
"web.de",
|
|
74
|
+
"proton.me",
|
|
75
|
+
"protonmail.com",
|
|
76
|
+
"mail.com",
|
|
77
|
+
"zoho.com",
|
|
78
|
+
"yandex.com",
|
|
79
|
+
"yandex.ru",
|
|
80
|
+
"t-online.de",
|
|
81
|
+
];
|
|
82
|
+
// Tier 2 additions: country variants of the global providers, regional hosts (qq.com,
|
|
83
|
+
// naver.com, wp.pl, libero.it, uol.com.br), ISP mailboxes (comcast.net, btinternet.com,
|
|
84
|
+
// telenet.be), privacy hosts (pm.me, tutanota.com, duck.com) and prosumer ones
|
|
85
|
+
// (fastmail, hey.com, mac.com). Confident enough to refuse to call any of them a
|
|
86
|
+
// company; NOT confident enough to let them drive a reply-stop decision — an ISP or
|
|
87
|
+
// country-TLD host is exactly where a "shared employer" guess goes wrong.
|
|
88
|
+
// Sorted, because this list is long enough that grouping by theme would rot.
|
|
89
|
+
const ADDITIONAL_PERSONAL_EMAIL_DOMAINS = [
|
|
90
|
+
"126.com", "163.com", "att.net", "bellsouth.net",
|
|
91
|
+
"bigpond.com", "bluewin.ch", "blueyonder.co.uk", "bol.com.br",
|
|
92
|
+
"btinternet.com", "charter.net", "comcast.net", "cox.net",
|
|
93
|
+
"daum.net", "duck.com", "earthlink.net", "fastmail.com",
|
|
94
|
+
"fastmail.fm", "free.fr", "freenet.de", "gmx.at",
|
|
95
|
+
"gmx.ch", "hanmail.net", "hey.com", "home.nl",
|
|
96
|
+
"hotmail.co.uk", "hotmail.de", "hotmail.es", "hotmail.fr",
|
|
97
|
+
"hotmail.it", "interia.pl", "kpnmail.nl", "laposte.net",
|
|
98
|
+
"libero.it", "live.co.uk", "live.de", "live.fr",
|
|
99
|
+
"mac.com", "mail.ru", "naver.com", "o2.pl",
|
|
100
|
+
"onet.pl", "optusnet.com.au", "orange.fr", "outlook.co.uk",
|
|
101
|
+
"outlook.de", "outlook.es", "outlook.fr", "pm.me",
|
|
102
|
+
"qq.com", "rediffmail.com", "rocketmail.com", "rogers.com",
|
|
103
|
+
"sbcglobal.net", "seznam.cz", "sfr.fr", "shaw.ca",
|
|
104
|
+
"sina.com", "sky.com", "skynet.be", "sympatico.ca",
|
|
105
|
+
"talktalk.net", "telenet.be", "telus.net", "terra.com.br",
|
|
106
|
+
"tuta.io", "tutanota.com", "uol.com.br", "verizon.net",
|
|
107
|
+
"virgilio.it", "virginmedia.com", "wanadoo.fr", "wp.pl",
|
|
108
|
+
"yahoo.ca", "yahoo.co.jp", "yahoo.co.uk", "yahoo.com.au",
|
|
109
|
+
"yahoo.de", "yahoo.es", "yahoo.fr", "yahoo.it",
|
|
110
|
+
"ziggo.nl",
|
|
111
|
+
];
|
|
112
|
+
/** Tier 1 — see the module note. Small on purpose. */
|
|
113
|
+
export const FREEMAIL_DOMAINS = new Set(CORE_FREEMAIL_DOMAINS);
|
|
114
|
+
/** Tier 2 — a strict superset of {@link FREEMAIL_DOMAINS}. */
|
|
115
|
+
export const PERSONAL_EMAIL_DOMAINS = new Set([
|
|
116
|
+
...CORE_FREEMAIL_DOMAINS,
|
|
117
|
+
...ADDITIONAL_PERSONAL_EMAIL_DOMAINS,
|
|
118
|
+
]);
|
|
119
|
+
/**
|
|
120
|
+
* Reduce an address or a bare domain to a comparable mail host: lowercased, trimmed,
|
|
121
|
+
* everything before the last '@' dropped, and a trailing FQDN dot removed. Returns null
|
|
122
|
+
* for junk/empty/nullish input so callers can distinguish "not a host" from "not in the
|
|
123
|
+
* set". Previously each fork normalized differently — one did full address handling, two
|
|
124
|
+
* only lowercased a bare domain — so the same input could resolve differently depending
|
|
125
|
+
* on which copy you happened to call.
|
|
126
|
+
*/
|
|
127
|
+
export function normalizeMailHost(value) {
|
|
128
|
+
if (typeof value !== "string")
|
|
129
|
+
return null;
|
|
130
|
+
let host = value.trim().toLowerCase();
|
|
131
|
+
if (!host)
|
|
132
|
+
return null;
|
|
133
|
+
const at = host.lastIndexOf("@");
|
|
134
|
+
if (at >= 0)
|
|
135
|
+
host = host.slice(at + 1);
|
|
136
|
+
host = host.replace(/\.+$/, "");
|
|
137
|
+
return host || null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* True when the host is a tier-1 consumer mailbox, i.e. it NEVER identifies a shared
|
|
141
|
+
* employer. Accepts a bare domain or a full address. Unknown input returns false: an
|
|
142
|
+
* unrecognized domain is treated as a company domain, which keeps the company-scope
|
|
143
|
+
* stop's safe default identical to lead-scope.
|
|
144
|
+
*/
|
|
145
|
+
export function isFreemailDomain(domain) {
|
|
146
|
+
const host = normalizeMailHost(domain);
|
|
147
|
+
return host !== null && FREEMAIL_DOMAINS.has(host);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* True when the host is a personal mailbox of any kind (tier 2). Use this for "should I
|
|
151
|
+
* infer a company from this domain?"; use {@link isFreemailDomain} when a false positive
|
|
152
|
+
* would wrongly group unrelated people as colleagues.
|
|
153
|
+
*/
|
|
154
|
+
export function isPersonalEmailDomain(domain) {
|
|
155
|
+
const host = normalizeMailHost(domain);
|
|
156
|
+
return host !== null && PERSONAL_EMAIL_DOMAINS.has(host);
|
|
157
|
+
}
|
|
@@ -423,3 +423,4 @@ export declare function normalizeFutureSignupLifecycleProjectionEnvelope(value:
|
|
|
423
423
|
export declare function normalizeFutureSignupLifecycleProjectionV2Envelope(value: unknown): NormalizedFutureSignupLifecycleProjectionV2Envelope;
|
|
424
424
|
export declare function normalizeFutureSignupLifecycleProjectionDestinationApplyOptions(value: unknown): NormalizedFutureSignupLifecycleProjectionDestinationApplyOptions;
|
|
425
425
|
export declare function normalizeFutureSignupLifecycleProjectionV2DestinationApplyOptions(value: unknown): NormalizedFutureSignupLifecycleProjectionV2DestinationApplyOptions;
|
|
426
|
+
export declare function codeUnitCompare(left: string, right: string): number;
|
|
@@ -1336,7 +1336,7 @@ function canonicalize(value) {
|
|
|
1336
1336
|
}
|
|
1337
1337
|
return value;
|
|
1338
1338
|
}
|
|
1339
|
-
function codeUnitCompare(left, right) {
|
|
1339
|
+
export function codeUnitCompare(left, right) {
|
|
1340
1340
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
1341
1341
|
}
|
|
1342
1342
|
function invalid(path, rule) {
|
|
@@ -22,6 +22,17 @@
|
|
|
22
22
|
*/
|
|
23
23
|
export type HostedAiLevel = "low" | "medium" | "high";
|
|
24
24
|
export type HostedAiUseCase = "ai_column" | "copilot" | "agent";
|
|
25
|
+
/**
|
|
26
|
+
* The Copilot's own level set. `auto` is the only tier a customer can land on
|
|
27
|
+
* since 2026-09-21 ("Oxygen Auto"); low/medium/high survive because sessions
|
|
28
|
+
* created before that release carry them in `copilot_sessions.reasoning_level`
|
|
29
|
+
* and must keep resolving to the model they were priced against.
|
|
30
|
+
*
|
|
31
|
+
* Deliberately NOT folded into `HostedAiLevel`: that type is shared with
|
|
32
|
+
* `AiReasoningLevel` and with the ai_column/agent registries, neither of which
|
|
33
|
+
* has an `auto` entry, so widening it would force two fictional rows.
|
|
34
|
+
*/
|
|
35
|
+
export type CopilotAiLevel = HostedAiLevel | "auto";
|
|
25
36
|
export type HostedAiModelSpec = {
|
|
26
37
|
/** OpenRouter model id, e.g. "deepseek/deepseek-v4-flash". */
|
|
27
38
|
model: string;
|
|
@@ -44,7 +55,11 @@ export type HostedAiModelSpec = {
|
|
|
44
55
|
/** Upper bound on completion tokens requested for this tier. */
|
|
45
56
|
maxOutputTokens: number;
|
|
46
57
|
};
|
|
47
|
-
export declare const HOSTED_AI_MODEL_REGISTRY:
|
|
58
|
+
export declare const HOSTED_AI_MODEL_REGISTRY: {
|
|
59
|
+
ai_column: Record<HostedAiLevel, HostedAiModelSpec>;
|
|
60
|
+
copilot: Record<CopilotAiLevel, HostedAiModelSpec>;
|
|
61
|
+
agent: Record<HostedAiLevel, HostedAiModelSpec>;
|
|
62
|
+
};
|
|
48
63
|
/**
|
|
49
64
|
* What a MANAGED AI column's reasoning tier is called in front of a customer.
|
|
50
65
|
*
|
|
@@ -60,8 +75,49 @@ export declare const HOSTED_AI_MODEL_REGISTRY: Record<HostedAiUseCase, Record<Ho
|
|
|
60
75
|
* their own key, so the real model id is the correct thing to show.
|
|
61
76
|
*/
|
|
62
77
|
export declare const MANAGED_AI_TIER_LABELS: Record<HostedAiLevel, string>;
|
|
63
|
-
/**
|
|
64
|
-
|
|
78
|
+
/**
|
|
79
|
+
* What the Copilot calls its tiers.
|
|
80
|
+
*
|
|
81
|
+
* Separate from MANAGED_AI_TIER_LABELS rather than folded into it because the
|
|
82
|
+
* Copilot's level set is not the AI column's: only the Copilot has `auto`, and
|
|
83
|
+
* only the Copilot has stopped offering a choice. AI columns and Agents still
|
|
84
|
+
* sell Fast/Balanced/Max and still mean it.
|
|
85
|
+
*
|
|
86
|
+
* Every current session reads "Oxygen Auto". The other three exist so a session
|
|
87
|
+
* created before 2026-09-21 still renders as the thing its owner picked, rather
|
|
88
|
+
* than being relabelled under them.
|
|
89
|
+
*/
|
|
90
|
+
export declare const COPILOT_TIER_LABELS: Record<CopilotAiLevel, string>;
|
|
91
|
+
/**
|
|
92
|
+
* The tier every new Copilot session gets. There is no longer a picker: "Oxygen
|
|
93
|
+
* Auto" is the whole customer-facing choice (Philipp, 2026-09-21).
|
|
94
|
+
*
|
|
95
|
+
* It was `high` until then, which is why 83% of production sessions ran the most
|
|
96
|
+
* expensive tier -- 110 of 132 sessions across 69 of 81 tenants -- while the
|
|
97
|
+
* composer's own dropdown told the user that medium was "The default for most
|
|
98
|
+
* GTM work". Nobody chose that; we defaulted them into it.
|
|
99
|
+
*/
|
|
100
|
+
export declare const COPILOT_DEFAULT_LEVEL: CopilotAiLevel;
|
|
101
|
+
/**
|
|
102
|
+
* The tier the Copilot's ERRANDS run at: sub-agent children, compaction
|
|
103
|
+
* summaries, and auto-titles.
|
|
104
|
+
*
|
|
105
|
+
* This is the only place a model may differ from the session's own, and it is
|
|
106
|
+
* safe for one reason: each of those builds a FRESH context rather than
|
|
107
|
+
* continuing the main transcript -- a child constructs its own Agent and
|
|
108
|
+
* messages (`packages/agent-runtime/src/subagents.ts`), and the summarizer sends
|
|
109
|
+
* a two-message prompt with no tools
|
|
110
|
+
* (`packages/agent-runtime/src/strands-runtime.ts` summarizeForCompaction). A
|
|
111
|
+
* cold context has no prompt cache to lose and no transcript to corrupt, so the
|
|
112
|
+
* switch costs nothing. Switching the main thread would cost both.
|
|
113
|
+
*
|
|
114
|
+
* It matters because delegation is habitual and currently doubles the price of a
|
|
115
|
+
* turn: measured over 30 days to 2026-09-21, the 26% of turns that fired
|
|
116
|
+
* `subagent_run` produced 45% of all Copilot credit burn (1,805 credits/turn
|
|
117
|
+
* against 786), because every child inherited the parent's model through the
|
|
118
|
+
* parent's own `callModel`.
|
|
119
|
+
*/
|
|
120
|
+
export declare const COPILOT_ERRAND_LEVEL: CopilotAiLevel;
|
|
65
121
|
export declare const AGENT_DEFAULT_LEVEL: HostedAiLevel;
|
|
66
122
|
/**
|
|
67
123
|
* Resolve the model spec for a hosted-AI use case + reasoning level.
|
|
@@ -87,7 +143,7 @@ export declare const AGENT_DEFAULT_LEVEL: HostedAiLevel;
|
|
|
87
143
|
export declare function findHostedAiModelSpec(model: string, preferredUseCase?: HostedAiUseCase): HostedAiModelSpec | null;
|
|
88
144
|
export declare function resolveHostedAiModel(input: {
|
|
89
145
|
useCase: HostedAiUseCase;
|
|
90
|
-
level:
|
|
146
|
+
level: CopilotAiLevel;
|
|
91
147
|
env?: Record<string, string | undefined>;
|
|
92
148
|
}): HostedAiModelSpec;
|
|
93
149
|
/**
|