@oxygen-agent/cli 1.1011.405 → 1.1011.440
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 +8 -4
- package/dist/connectors-commands.js +3 -0
- package/dist/contract-flags.js +22 -9
- package/dist/customer-operation-commands.d.ts +5 -0
- package/dist/customer-operation-commands.js +101 -0
- package/dist/database-query-flags.d.ts +2 -0
- package/dist/database-query-flags.js +6 -0
- package/dist/help.d.ts +3 -1
- package/dist/help.js +33 -0
- package/dist/http-client.d.ts +2 -0
- package/dist/http-client.js +41 -1
- package/dist/index.js +470 -174
- package/dist/knowledge-repository-commands.js +12 -14
- package/dist/mailbox-ramp-notice.d.ts +11 -0
- package/dist/mailbox-ramp-notice.js +53 -0
- package/dist/settings-commands.js +5 -4
- package/dist/skills.d.ts +5 -4
- package/dist/skills.js +106 -79
- package/dist/tool-catalog-detail-command.d.ts +7 -0
- package/dist/tool-catalog-detail-command.js +19 -0
- package/dist/tool-catalog-search-window.d.ts +6 -0
- package/dist/tool-catalog-search-window.js +12 -0
- package/dist/transcript.js +1 -0
- package/node_modules/@oxygen/shared/dist/bounded-read-result.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/bounded-read-result.js +2 -2
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +17 -1
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +359 -34
- package/node_modules/@oxygen/shared/dist/connection-approval.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/connection-approval.js +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +110 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-attributes.js +39 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.js +15 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +131 -0
- package/node_modules/@oxygen/shared/dist/contracts/database.d.ts +30 -0
- package/node_modules/@oxygen/shared/dist/contracts/database.js +29 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.d.ts +43 -0
- package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.js +20 -0
- package/node_modules/@oxygen/shared/dist/contracts/linkedin-invites-list.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/contracts/linkedin-invites-list.js +8 -0
- package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +48 -2
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +67 -7
- package/node_modules/@oxygen/shared/dist/contracts/table-grid-query.d.ts +4 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-grid-query.js +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.js +27 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-detail.d.ts +19 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-detail.js +10 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-search-window.d.ts +12 -0
- package/node_modules/@oxygen/shared/dist/contracts/tool-catalog-search-window.js +7 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/workspace-pages.js +12 -0
- package/node_modules/@oxygen/shared/dist/email-campaign-ramp.d.ts +104 -0
- package/node_modules/@oxygen/shared/dist/email-campaign-ramp.js +250 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +1 -2
- package/node_modules/@oxygen/shared/dist/plan-limits.js +2 -2
- package/node_modules/@oxygen/shared/dist/provider-input-value.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/provider-input-value.js +10 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/shared/package.json +3 -6
- package/package.json +1 -1
- package/node_modules/@oxygen/shared/dist/copilot-skills.d.ts +0 -15
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +0 -31
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +0 -41
- package/node_modules/@oxygen/shared/dist/copilot-skills.js +0 -6
|
@@ -49,7 +49,7 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
49
49
|
notFor: "Executing GTM work or loading full manifests and schemas before a capability is selected.",
|
|
50
50
|
execution: "Search by outcome, choose the owner, then hydrate one exact command, MCP schema, provider descriptor, or skill. For instance discovery, read the map and then the primitive that owns the row.",
|
|
51
51
|
posture: "read_only",
|
|
52
|
-
gatewayTools: ["oxygen_capabilities_search", "oxygen_tools_search", "oxygen_recipes_list", "oxygen_workspace_map"],
|
|
52
|
+
gatewayTools: ["oxygen_capabilities_search", "oxygen_skills_get", "oxygen_tools_search", "oxygen_recipes_list", "oxygen_workspace_map"],
|
|
53
53
|
gatewayCommands: ["capabilities search", "commands search", "skills search", "tools search", "recipes list", "workspace map"],
|
|
54
54
|
skills: ["oxygen-quickstart", "oxygen-gtm"],
|
|
55
55
|
// `workspace` (the map) belongs here rather than beside `home`: capability
|
|
@@ -73,7 +73,7 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
73
73
|
skills: ["oxygen-onboarding", "oxygen-quickstart", "oxygen-gtm"],
|
|
74
74
|
// `activation` remains an exact legacy API family for saved clients, but it
|
|
75
75
|
// has no recommended gateway and is not an intent term or first-touch path.
|
|
76
|
-
endpointSections: ["activation", "copilot", "home"],
|
|
76
|
+
endpointSections: ["activation", "copilot", "home", "onboarding"],
|
|
77
77
|
// "next step" alone is deliberately absent: it is a phrase every primitive's
|
|
78
78
|
// users say ("next step of this workflow run"), and a 6-point multi-word hit
|
|
79
79
|
// would drag those queries here. The terms kept are the ones only a founder
|
|
@@ -84,15 +84,15 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
84
84
|
id: "billing-and-budgets",
|
|
85
85
|
layer: "Control",
|
|
86
86
|
primitive: null,
|
|
87
|
-
owns: "Credits, plan state, usage receipts, subscriptions, and standing budget policies.",
|
|
87
|
+
owns: "Credits, customer credit prices, plan state, usage receipts, subscriptions, and standing budget policies.",
|
|
88
88
|
notFor: "Authorizing a specific provider call or external write; that action still needs its own preview and approval.",
|
|
89
89
|
execution: "Read billing state or set a hosted budget policy; exact action ceilings remain primitive-owned.",
|
|
90
90
|
posture: "mixed",
|
|
91
|
-
gatewayTools: ["oxygen_billing_balance", "oxygen_billing_usage", "oxygen_billing_estimate", "oxygen_budget_list"],
|
|
92
|
-
gatewayCommands: ["billing balance", "billing usage", "billing estimate", "budget list", "billing invoices"],
|
|
91
|
+
gatewayTools: ["oxygen_billing_balance", "oxygen_billing_usage", "oxygen_billing_estimate", "oxygen_budget_list", "oxygen_customer_credit_prices"],
|
|
92
|
+
gatewayCommands: ["billing balance", "billing usage", "billing estimate", "budget list", "billing invoices", "pricing customer-credit-prices"],
|
|
93
93
|
skills: ["oxygen-gtm", "oxygen-diagnostics"],
|
|
94
|
-
endpointSections: ["billing", "budget", "limits"],
|
|
95
|
-
intentTerms: ["billing", "credits", "credit balance", "usage", "spend", "cost", "cost estimate", "monthly cost", "budget", "subscription", "invoice", "vat", "vat number", "tax id", "cancel plan", "change plan", "upgrade", "downgrade"],
|
|
94
|
+
endpointSections: ["billing", "budget", "limits", "pricing"],
|
|
95
|
+
intentTerms: ["billing", "credits", "credit balance", "customer credit prices", "credit price catalog", "usage", "spend", "cost", "cost estimate", "monthly cost", "budget", "subscription", "invoice", "vat", "vat number", "tax id", "cancel plan", "change plan", "upgrade", "downgrade"],
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
id: "support-and-feedback",
|
|
@@ -112,15 +112,15 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
112
112
|
id: "platform-operations",
|
|
113
113
|
layer: "Control",
|
|
114
114
|
primitive: null,
|
|
115
|
-
owns: "
|
|
116
|
-
notFor: "
|
|
117
|
-
execution: "
|
|
115
|
+
owns: "Workspace queue health, failed jobs, queue recovery, and workspace database status, attach, migrations, read-only SQL and retired cost-policy controls.",
|
|
116
|
+
notFor: "Customer run timelines or approvals (Observability), Table grid queries (Tables), and external Supabase imports (Integrations).",
|
|
117
|
+
execution: "Inspect the active workspace's queue and database status; repair stale queue state or provision its database through the native scoped controls.",
|
|
118
118
|
posture: "mixed",
|
|
119
|
-
gatewayTools: ["oxygen_worker_queue_stats", "oxygen_worker_failures", "
|
|
120
|
-
gatewayCommands: ["worker queue-stats", "worker failures", "db status"],
|
|
119
|
+
gatewayTools: ["oxygen_worker_queue_stats", "oxygen_worker_failures", "oxygen_workspace_queue_repair", "oxygen_workspace_database_status", "oxygen_workspace_database_provision"],
|
|
120
|
+
gatewayCommands: ["worker queue-stats", "worker failures", "worker repair", "db status", "db provision"],
|
|
121
121
|
skills: ["oxygen-diagnostics"],
|
|
122
|
-
endpointSections: ["
|
|
123
|
-
intentTerms: ["
|
|
122
|
+
endpointSections: ["db", "worker"],
|
|
123
|
+
intentTerms: ["worker", "queue", "queue repair", "database", "database hosting", "db status", "stuck jobs", "operations"],
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
// Control-layer interaction state, deliberately NOT a sixteenth primitive
|
|
@@ -256,11 +256,11 @@ export const OXYGEN_CAPABILITY_ROUTES = [
|
|
|
256
256
|
notFor: "Net-new LinkedIn initiation, cadence, enrollment, sender rotation, or reply-stop programs; those belong to Sequences.",
|
|
257
257
|
execution: "Preview and approve a direct email or existing-thread reply; every sent fact stays in the hosted Messages ledger.",
|
|
258
258
|
posture: "external_write",
|
|
259
|
-
gatewayTools: ["oxygen_inbox_send", "oxygen_email_send", "oxygen_messages_query"],
|
|
260
|
-
gatewayCommands: ["inbox send", "email send", "messages query"],
|
|
259
|
+
gatewayTools: ["oxygen_inbox_send", "oxygen_email_send", "oxygen_messages_query", "oxygen_unibox_metadata"],
|
|
260
|
+
gatewayCommands: ["inbox send", "email send", "messages query", "unibox metadata"],
|
|
261
261
|
skills: ["oxygen-unibox"],
|
|
262
|
-
endpointSections: ["email", "inbox", "message-reviews", "messages"],
|
|
263
|
-
intentTerms: ["message", "messages", "reply", "email", "inbox", "conversation", "thread", "direct email", "draft reply", "one off"],
|
|
262
|
+
endpointSections: ["email", "inbox", "message-reviews", "messages", "unibox"],
|
|
263
|
+
intentTerms: ["message", "messages", "reply", "email", "inbox", "unibox", "inbox metadata", "conversation", "thread", "direct email", "draft reply", "one off"],
|
|
264
264
|
},
|
|
265
265
|
{
|
|
266
266
|
id: "posts",
|
|
@@ -646,7 +646,81 @@ export function inferPrimitiveRoute(query) {
|
|
|
646
646
|
return null;
|
|
647
647
|
return route;
|
|
648
648
|
}
|
|
649
|
-
|
|
649
|
+
/** Current hosted instruction audiences, shared by discovery and Agent snapshots. */
|
|
650
|
+
export const OXYGEN_PRODUCT_SKILL_AUDIENCES = Object.freeze({
|
|
651
|
+
"oxygen-onboarding": "workspace",
|
|
652
|
+
"oxygen-gtm": "workspace",
|
|
653
|
+
"oxygen-recipes": "workspace",
|
|
654
|
+
"oxygen-playbooks": "workspace",
|
|
655
|
+
"oxygen-linkedin-marketing": "workspace",
|
|
656
|
+
"oxygen-agency-directory": "agency_partner",
|
|
657
|
+
"oxygen-collaboration": "workspace",
|
|
658
|
+
"oxygen-quickstart": "workspace",
|
|
659
|
+
"oxygen-workflow-authoring": "workspace",
|
|
660
|
+
"oxygen-knowledge": "workspace",
|
|
661
|
+
"oxygen-visual-design": "workspace",
|
|
662
|
+
"oxygen-unibox": "workspace",
|
|
663
|
+
"oxygen-email-infra": "workspace",
|
|
664
|
+
"oxygen-deliverability": "workspace",
|
|
665
|
+
"oxygen-sequencer": "workspace",
|
|
666
|
+
"oxygen-table-tidy": "workspace",
|
|
667
|
+
"oxygen-diagnostics": "workspace",
|
|
668
|
+
"oxygen-feedback": "workspace",
|
|
669
|
+
"oxygen-clay-migration": "workspace",
|
|
670
|
+
"oxygen-ugc": "workspace",
|
|
671
|
+
});
|
|
672
|
+
export function canReadProductSkillInstructions(name, entitlements) {
|
|
673
|
+
if (entitlements.authenticated !== true)
|
|
674
|
+
return false;
|
|
675
|
+
const audience = Object.hasOwn(OXYGEN_PRODUCT_SKILL_AUDIENCES, name)
|
|
676
|
+
? OXYGEN_PRODUCT_SKILL_AUDIENCES[name]
|
|
677
|
+
: undefined;
|
|
678
|
+
return audience === "workspace" || (audience === "agency_partner" && entitlements.agencyPartner);
|
|
679
|
+
}
|
|
680
|
+
/** Identify hosted instruction bodies by native tool lineage, never by user prose. */
|
|
681
|
+
export function readProductSkillInstructionResult(capabilityName, result) {
|
|
682
|
+
if (capabilityName !== "oxygen_skills_get")
|
|
683
|
+
return null;
|
|
684
|
+
const pending = [result];
|
|
685
|
+
for (let i = 0; i < pending.length && i < 24; i += 1) {
|
|
686
|
+
let value = pending[i];
|
|
687
|
+
if (typeof value === "string") {
|
|
688
|
+
try {
|
|
689
|
+
value = JSON.parse(value);
|
|
690
|
+
}
|
|
691
|
+
catch {
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
696
|
+
continue;
|
|
697
|
+
const envelope = value;
|
|
698
|
+
if (envelope.ok === false || envelope.isError === true || envelope.status === "error")
|
|
699
|
+
continue;
|
|
700
|
+
if (typeof envelope.content === "string") {
|
|
701
|
+
const name = typeof envelope.name === "string" ? envelope.name : "";
|
|
702
|
+
return { slug: Object.hasOwn(OXYGEN_PRODUCT_SKILL_AUDIENCES, name) ? name : null };
|
|
703
|
+
}
|
|
704
|
+
for (const key of ["result", "data", "structuredContent", "structured"]) {
|
|
705
|
+
if (envelope[key] !== undefined)
|
|
706
|
+
pending.push(envelope[key]);
|
|
707
|
+
}
|
|
708
|
+
if (Array.isArray(envelope.content)) {
|
|
709
|
+
for (const block of envelope.content) {
|
|
710
|
+
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string")
|
|
711
|
+
pending.push(block.text);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
/** Public action cards never advertise invite-only or unknown skill instructions. */
|
|
718
|
+
export function isPublicCapabilitySkill(name) {
|
|
719
|
+
return Object.hasOwn(OXYGEN_PRODUCT_SKILL_AUDIENCES, name) && OXYGEN_PRODUCT_SKILL_AUDIENCES[name] === "workspace";
|
|
720
|
+
}
|
|
721
|
+
export function serializeCapabilityRoute(route, surfaceOrOptions = "cli", options = {}) {
|
|
722
|
+
const surface = typeof surfaceOrOptions === "string" ? surfaceOrOptions : "cli";
|
|
723
|
+
const visibleSkills = typeof surfaceOrOptions === "string" ? options.visibleSkills : surfaceOrOptions.visibleSkills;
|
|
650
724
|
if (!route)
|
|
651
725
|
return null;
|
|
652
726
|
return {
|
|
@@ -657,7 +731,7 @@ export function serializeCapabilityRoute(route, surface = "cli") {
|
|
|
657
731
|
not_for: route.card.notFor,
|
|
658
732
|
execution: route.card.execution,
|
|
659
733
|
posture: route.card.posture,
|
|
660
|
-
skills: route.card.skills,
|
|
734
|
+
skills: route.card.skills.filter((name) => isPublicCapabilitySkill(name) || visibleSkills?.includes(name)),
|
|
661
735
|
endpoint_sections: route.card.endpointSections,
|
|
662
736
|
recommended_commands: route.recommendedCommands,
|
|
663
737
|
recommended_tools: route.recommendedTools,
|
|
@@ -682,6 +756,8 @@ export function serializeCapabilityRoute(route, surface = "cli") {
|
|
|
682
756
|
hydrate: {
|
|
683
757
|
cli: "oxygen commands get <exact-command> --json",
|
|
684
758
|
mcp: "oxygen_capabilities_schema",
|
|
759
|
+
skill_cli: "oxygen skills get <selected-skill> --json",
|
|
760
|
+
skill_mcp: { tool: "oxygen_skills_get", arguments: { name: "<selected-skill>" } },
|
|
685
761
|
},
|
|
686
762
|
};
|
|
687
763
|
}
|
|
@@ -774,23 +850,75 @@ function routeCardFor(card, query) {
|
|
|
774
850
|
if (card.primitive === "publishing" && isUgcIntent(query))
|
|
775
851
|
return { ...card, ...UGC_ROUTE_VIEW };
|
|
776
852
|
if (card.id === "knowledge-graph" && isWorkspaceVoiceIntent(query))
|
|
777
|
-
|
|
853
|
+
card = { ...card, execution: WORKSPACE_VOICE_EXECUTION };
|
|
778
854
|
if (card.primitive === "workflows" && isRecurringCompanyMonitoringIntent(query))
|
|
779
|
-
|
|
855
|
+
card = {
|
|
780
856
|
...card,
|
|
781
857
|
execution: "Workflows own recurring execution. Inspect oxygen_blueprints_list, describe and preflight before authoring; a matching Blueprint is not guaranteed. Retain canonical company identities and facts in Records, and time-stamped observations in Signals. Use oxygen_crm_objects_list and oxygen_signals_list to inspect those destinations. Do not apply or enable automation before the required approval and credit scope.",
|
|
782
858
|
};
|
|
783
859
|
if (card.primitive === "tables" && isTableCapacityReadIntent(query))
|
|
784
|
-
|
|
860
|
+
card = {
|
|
785
861
|
...card,
|
|
786
862
|
execution: "Read oxygen_limits_show for Tables capacity, largest_table and largest_table_rows. Use that returned table reference with oxygen_tables_query and a small limit to inspect sample rows; no enrichment run is needed.",
|
|
787
863
|
};
|
|
788
864
|
if (card.primitive === "tables" && isFunctionIntent(query))
|
|
789
|
-
|
|
865
|
+
card = {
|
|
790
866
|
...card,
|
|
791
867
|
execution: "List, describe or inspect Function runs without executing. Draft edits are isolated; publish requires the inspected draft hash and changes future invocations. Bind adds a caller column for free; columns run previews cost before a bounded approved run. MCP uses the mixed-effect oxygen_callables_manage through oxygen_capabilities_call, including its read operations.",
|
|
792
868
|
};
|
|
793
|
-
|
|
869
|
+
if (card.primitive === "tables" && isPlainTableIntent(query))
|
|
870
|
+
card = {
|
|
871
|
+
...card,
|
|
872
|
+
execution: "Create a workspace-private Table or inspect its schema and rows. Manual rows, column labels, visibility and member favorites cost 0 credits. Change only the display label with columns update (oxygen_columns_update); columns rename (oxygen_columns_rename) requires a new stable key. Favorite one table or folder with tables favorite (oxygen_tables_favorite), then read tables favorites (oxygen_tables_favorites). For tidy guidance, read oxygen-table-tidy with skills get (oxygen_skills_get); tables tidy-suggest (oxygen_tables_tidy_suggest) analyzes without changes. Read the owning schema, apply the requested scope, then describe or query the Table to verify it.",
|
|
873
|
+
};
|
|
874
|
+
const maintenance = card.primitive === "tables" ? tableMaintenanceRecommendation(query) : null;
|
|
875
|
+
if (maintenance)
|
|
876
|
+
card = { ...card, execution: maintenance.execution };
|
|
877
|
+
const read = card.primitive === "tables" ? tableReadRecommendation(query) : null;
|
|
878
|
+
if (read)
|
|
879
|
+
card = { ...card, execution: read.execution };
|
|
880
|
+
const database = card.id === "platform-operations" ? databaseRecommendation(query) : null;
|
|
881
|
+
if (database)
|
|
882
|
+
card = { ...card,
|
|
883
|
+
owns: "Active-workspace PostgreSQL hosting, attachment, migrations, read-only SQL and retired cost-policy status.",
|
|
884
|
+
notFor: "Provider credentials, enrichment, workspace billing, or staff-wide database operations.",
|
|
885
|
+
execution: database.execution,
|
|
886
|
+
};
|
|
887
|
+
const specializedSkill = preferredSkillForIntent(card, query);
|
|
888
|
+
return specializedSkill ? { ...card, skills: [specializedSkill, ...card.skills.filter((skill) => skill !== specializedSkill)] } : card;
|
|
889
|
+
}
|
|
890
|
+
/** Search surfaces share the selected skill owner; a general router is fallback. */
|
|
891
|
+
function preferredSkillForIntent(card, query) {
|
|
892
|
+
if (card.id === "tables") {
|
|
893
|
+
if (/\bclay\b/.test(query) && /\b(import|export|migrat\w*|mov\w*)\b/.test(query))
|
|
894
|
+
return "oxygen-clay-migration";
|
|
895
|
+
if (isTableMaintenanceIntent(query))
|
|
896
|
+
return "oxygen-table-tidy";
|
|
897
|
+
if (/\b(stuck|failed|failure|trace|provenance|diagnos\w*)\b/.test(query))
|
|
898
|
+
return "oxygen-diagnostics";
|
|
899
|
+
if (isLinkedInProfileWatcherIntent(query))
|
|
900
|
+
return "oxygen-linkedin-marketing";
|
|
901
|
+
}
|
|
902
|
+
if (card.id === "billing-and-budgets" && /\b(explain|why|reduce|increas\w*|burn|spent)\b/.test(query))
|
|
903
|
+
return "oxygen-diagnostics";
|
|
904
|
+
if (card.id === "sending-infrastructure" && /\b(bounc\w*|health|placement|deliverability|spam)\b/.test(query))
|
|
905
|
+
return "oxygen-deliverability";
|
|
906
|
+
if (["signals", "linkedin-public-research"].includes(card.id) && /\blinkedin\b/.test(query))
|
|
907
|
+
return "oxygen-linkedin-marketing";
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
function isTableMaintenanceIntent(query) {
|
|
911
|
+
return /\b(tables?|columns?|folders?)\b/.test(query)
|
|
912
|
+
&& !/\b(functions?|callables?|campaigns?|tags?|workflows?|agents?)\b/.test(query)
|
|
913
|
+
&& (/\b(tidy|tidying|cleanup|clean up|reorder|formatting|duplicates?|favou?rites?|unfavou?rite|star|unstar)\b/.test(query)
|
|
914
|
+
|| (/\bcolumns?\b/.test(query) && /\b(hide|hidden|rename|renaming|label|key)\b/.test(query)));
|
|
915
|
+
}
|
|
916
|
+
function isPlainTableIntent(query) {
|
|
917
|
+
if (isTableCapacityReadIntent(query))
|
|
918
|
+
return false;
|
|
919
|
+
return isTableMaintenanceIntent(query) || (/\btable\b/.test(query)
|
|
920
|
+
&& /\b(create|manual|sample|private)\b/.test(query)
|
|
921
|
+
&& !/\b(enrich\w*|classif\w*|research|prompt|sourc\w*|import|linkedin|function|callable)\b/.test(query));
|
|
794
922
|
}
|
|
795
923
|
function isFunctionIntent(query) {
|
|
796
924
|
return /\b(functions?|callables?)\b/.test(query) && !/\bformula functions?\b/.test(query);
|
|
@@ -909,6 +1037,19 @@ function isSequenceScheduleIntent(query) {
|
|
|
909
1037
|
return /\bsend(?:ing)? (?:schedule|window)s?\b/.test(query)
|
|
910
1038
|
&& !/\b(workflow|automation|automate|webhook|cron)\b/.test(query);
|
|
911
1039
|
}
|
|
1040
|
+
// How much campaign email one inbox may send: its daily campaign limit and the
|
|
1041
|
+
// ramp-up that climbs to it. The 2026-10-01 MCP baseline searched "mailbox
|
|
1042
|
+
// sending settings warmup ramp daily limit" and was routed to Workflows (bare
|
|
1043
|
+
// "daily" reads as a schedule); "ramp up a new inbox" went to Messages. LinkedIn,
|
|
1044
|
+
// WhatsApp and call limits keep their own owners, and provider warm-up without
|
|
1045
|
+
// campaign volume words keeps the card's warm-up path.
|
|
1046
|
+
function isMailboxVolumeIntent(query) {
|
|
1047
|
+
if (/\b(linkedin|whatsapp|calls?|dial\w*|voice)\b/.test(query))
|
|
1048
|
+
return false;
|
|
1049
|
+
const inbox = /\b(mailbox\w*|inbox(?:es)?|email accounts?|sending accounts?|sender accounts?)\b/.test(query);
|
|
1050
|
+
const volume = /\b(ramp\w*|daily (?:campaign )?(?:limit|cap)s?|sending limits?|send limits?|(?:emails?|sends?) (?:per|a) day|volume)\b/.test(query);
|
|
1051
|
+
return inbox && volume;
|
|
1052
|
+
}
|
|
912
1053
|
// The unsubscribe option on a Sequence's emails, not the list of people who
|
|
913
1054
|
// opted out: a list, import or do-not-contact ask stays with suppressions.
|
|
914
1055
|
function isSequenceUnsubscribeIntent(query) {
|
|
@@ -1031,21 +1172,29 @@ function isConnectedAppSpendIntent(query) {
|
|
|
1031
1172
|
* when the pages are wiki, LinkedIn, web, PDF or result pages.
|
|
1032
1173
|
*/
|
|
1033
1174
|
function isWorkspacePagesIntent(query) {
|
|
1034
|
-
//
|
|
1035
|
-
if (/\bsales ?nav/.test(query))
|
|
1175
|
+
// A row, column or cell is content inside a page, and Sales Nav is LinkedIn.
|
|
1176
|
+
if (/\bsales ?nav/.test(query) || /\b(rows?|columns?|cells?|filters?|duplicates?)\b/.test(query))
|
|
1036
1177
|
return false;
|
|
1037
|
-
|
|
1178
|
+
const navigation = /\b(side ?bars?|side ?nav\w*|side ?menus?|nav ?bars?|nav|navigation|left (?:menu|nav\w*|rail|panel)|main menu)\b/.test(query);
|
|
1179
|
+
const visibility = /\b(hid(?:e|es|den|ing)|unhide|visib\w*|invisible)\b/.test(query);
|
|
1180
|
+
const showInNavigation = /\bshow(?:s|n|ing)?\b/.test(query)
|
|
1181
|
+
&& /\b(?:in|on|from|to)\s+(?:the |our |my |this )?(?:side ?bar|side ?nav\w*|navigation|nav|left (?:menu|nav\w*|rail|panel))\b/.test(query);
|
|
1182
|
+
// Explicit sidebar visibility may name the page's primitive: hide Knowledge
|
|
1183
|
+
// from the sidebar or show Tables in navigation still means Customise.
|
|
1184
|
+
if (navigation && (visibility || showInNavigation))
|
|
1038
1185
|
return true;
|
|
1039
|
-
|
|
1040
|
-
|
|
1186
|
+
if (/\bmenu items?\b/.test(query) && /\b(hid(?:e|es|den|ing)|unhide|show(?:s|n|ing)?|visib\w*)\b/.test(query))
|
|
1187
|
+
return true;
|
|
1188
|
+
// Content and navigation within a primitive keep that primitive's owner.
|
|
1189
|
+
// Check this before generic "customize pages" or a navigation noun.
|
|
1190
|
+
if (/\b(wiki|knowledge|linkedin|compan(?:y|ies)|tables?|landing|web ?pages?|websites?|carousels?|pdfs?|paginat\w*|next page|per page|page size|results?|dashboards?)\b/.test(query))
|
|
1191
|
+
return false;
|
|
1192
|
+
if (navigation)
|
|
1041
1193
|
return true;
|
|
1042
1194
|
if (/\bcustomi[sz](?:e|es|ed|ing|ation)\b/.test(query) && /\b(pages?|menus?)\b/.test(query))
|
|
1043
1195
|
return true;
|
|
1044
|
-
// The web page's own name: Settings → Customise.
|
|
1045
1196
|
if (/^customi[sz]e$|\bsettings?\W{1,5}customi[sz]e\b/.test(query))
|
|
1046
1197
|
return true;
|
|
1047
|
-
if (/\b(wiki|linkedin|compan(?:y|ies)|landing|web ?pages?|websites?|carousels?|pdfs?|paginat\w*|next page|per page|page size|results?|dashboards?|rows?|columns?)\b/.test(query))
|
|
1048
|
-
return false;
|
|
1049
1198
|
return /\bpages?\b/.test(query) && /\b(hid(?:e|es|den|ing)|unhide|show(?:s|n|ing)?|visib\w*|invisible)\b/.test(query);
|
|
1050
1199
|
}
|
|
1051
1200
|
/**
|
|
@@ -1073,7 +1222,119 @@ function isCompanySourcingIntent(query) {
|
|
|
1073
1222
|
return /\b(companies|businesses|firms|company search|company sourcing)\b/.test(query)
|
|
1074
1223
|
&& /\b(search|plan|find|source|sourcing|discover|build|tam|prospect)\b/.test(query);
|
|
1075
1224
|
}
|
|
1225
|
+
/** Reads of grid values/state are separate from executing or resolving actions. */
|
|
1226
|
+
function tableReadRecommendation(query) {
|
|
1227
|
+
if (!/\btables?\b/.test(query) || isFunctionIntent(query) || isSecondPartyDecisionIntent(query)
|
|
1228
|
+
|| /\b(workflows?|agents?|actions?|items?|retry|resolve|effects?|imports?|webhooks?|feeds?|enrich\w*|create|add|insert|upsert|update|delete|remove|rename|hide|archive|columns? run)\b/.test(query)
|
|
1229
|
+
|| /\b(run|execute|start|cancel)\s+(?:(?:the|my|these)\s+)?(?:columns?|table|enrichment)\b/.test(query))
|
|
1230
|
+
return null;
|
|
1231
|
+
if (/\bcells?\b/.test(query) && /\b(history|changes?|provenance)\b/.test(query))
|
|
1232
|
+
return {
|
|
1233
|
+
tools: ["oxygen_tables_cell_history", "oxygen_tables_cell_inspect"], commands: ["cells history", "cells inspect"],
|
|
1234
|
+
execution: "Read one cell's recorded value changes with cells history; cells inspect adds its provider attempt timeline. These reads do not run columns or resolve an uncertain external effect.",
|
|
1235
|
+
};
|
|
1236
|
+
if (/\bcells?\b/.test(query) && /\b(provider|attempts?|timeline)\b/.test(query))
|
|
1237
|
+
return {
|
|
1238
|
+
tools: ["oxygen_tables_cell_inspect", "oxygen_tables_cell_history"], commands: ["cells inspect", "cells history"],
|
|
1239
|
+
execution: "Inspect one cell's final value and provider attempt timeline with cells inspect. Cell history reads recorded changes; neither executes a column or records a verified external outcome.",
|
|
1240
|
+
};
|
|
1241
|
+
if (isTableCapacityReadIntent(query) && !/\bgrid\b/.test(query))
|
|
1242
|
+
return null;
|
|
1243
|
+
if (!/\b(grid|preview|raw rows|fill rates?|next page|pagination|cursor)\b/.test(query)
|
|
1244
|
+
&& !(/\b(read|show|inspect|query)\b/.test(query) && /\brows?\b/.test(query)))
|
|
1245
|
+
return null;
|
|
1246
|
+
if (/\b(filtered?|filters?|sorts?|search|crm)\b/.test(query) && /\b(grid|counts?|registry)\b/.test(query))
|
|
1247
|
+
return {
|
|
1248
|
+
tools: ["oxygen_table_rows_page", "oxygen_tables_query", "oxygen_tables_preview"], commands: ["tables rows page", "tables query", "tables preview"],
|
|
1249
|
+
execution: "Read the native rows page for grid filters/sorts/search and count modes. exact counts the matching rows; estimate uses reconciled registry metadata only for an unfiltered scope, otherwise counts exactly. registry never counts and returns no total for a narrowed or unavailable registry scope; skip returns no total. Follow nextCursor with the same table, filters, search, sort and CRM scope; do not substitute an offset. Canonical tables query reads raw values; format=grid refuses those filters/projections.",
|
|
1250
|
+
};
|
|
1251
|
+
if (/\b(preview|fill rates?|without row|summary only|summary_only)\b/.test(query))
|
|
1252
|
+
return {
|
|
1253
|
+
tools: ["oxygen_tables_preview", "oxygen_tables_query", "oxygen_table_fill_progress"], commands: ["tables preview", "tables query", "tables fill-progress"],
|
|
1254
|
+
execution: "Use tables preview for compact rows, optional include_cell_states and whole-table fill stats; summary_only omits row JSON. rowCount is exact, rates may be sampled and summary.statsSampled labels that scope. Follow its nextCursor with the same options. tables query reads raw values or format=grid previews/state. tables fill-progress separately reports ingestion progress/failure; none of these runs columns.",
|
|
1255
|
+
};
|
|
1256
|
+
return {
|
|
1257
|
+
tools: ["oxygen_tables_query", "oxygen_tables_preview", "oxygen_table_rows_page", "oxygen_table_fill_progress"], commands: ["tables query", "tables preview", "tables rows page", "tables fill-progress"],
|
|
1258
|
+
execution: 'Read tables query raw values, or format="grid" for summarized cell previews and per-cell state. Grid defaults to 50 rows and caps at 200; pass grid.nextCursor as cursor with the same table/limit. Grid refuses row_id, fields, filters/filterTree, search, sorts, formula_values and nonzero offset; it is not a snapshot. Its first page uses the reconciled registry count when available, otherwise exact; continuation skips counting (null total), labeled rowCountMode. include_stats adds optional whole-table column stats/count; unavailable stats are omitted. include_fill only adds optional fill state when the first page is empty; later/nonempty pages omit it. tables preview supplies fill-rate summaries; tables fill-progress reads ingestion status. These reads do not execute columns.',
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
/** Native database work outranks generic workspace access and credit billing. */
|
|
1262
|
+
function databaseRecommendation(query) {
|
|
1263
|
+
if (!/\b(databases?|postgres(?:ql)?|db|sql)\b/.test(query)
|
|
1264
|
+
|| /\b(tables?|grid|external|import|workflows?|agents?|enrich\w*|providers?|integrations?|oauth|byok|mailbox\w*|crm|hubspot|salesforce|supabase)\b/.test(query))
|
|
1265
|
+
return null;
|
|
1266
|
+
const actions = [
|
|
1267
|
+
["oxygen_workspace_database_status", "db status"], ["oxygen_database_cost_policy", "db cost-policy"],
|
|
1268
|
+
["oxygen_database_query", "db query"], ["oxygen_database_attach", "db attach"],
|
|
1269
|
+
["oxygen_database_migrate", "db migrate"], ["oxygen_workspace_database_provision", "db provision"],
|
|
1270
|
+
["oxygen_database_cost_policy_reconcile", "db reconcile-cost-policy"],
|
|
1271
|
+
];
|
|
1272
|
+
const first = /\b(migrat\w*|rotate credentials)\b/.test(query) ? 4
|
|
1273
|
+
: /\b(attach|connect|connection)\b/.test(query) ? 3
|
|
1274
|
+
: /\b(query|sql|select|explain)\b/.test(query) ? 2
|
|
1275
|
+
: /\b(provision\w*)\b/.test(query) ? 5
|
|
1276
|
+
: /\breconcile\b/.test(query) ? 6
|
|
1277
|
+
: /\b(cost policy|cost controls?|sleep|suspend|reconcile)\b/.test(query) && !/\bstatus\b/.test(query) ? 1 : 0;
|
|
1278
|
+
const ordered = [actions[first], ...actions.filter((_, index) => index !== first)];
|
|
1279
|
+
return {
|
|
1280
|
+
tools: ordered.map(([tool]) => tool), commands: ordered.map(([, command]) => command),
|
|
1281
|
+
execution: "Inspect db status and db cost-policy for the active workspace. Hosting is included; Neon cost controls are retired, and reconcile-cost-policy is a compatibility no-op, not PostgreSQL sleep control. db query accepts one read-only SELECT/WITH/EXPLAIN statement: request a small max_rows (hard cap 1000). Writes are refused; truncated labels the returned row window, and it has no continuation cursor. Attach (database_url), migrate (optional rotate_credentials) and provision are immediate native writes with no preview or approved field. They preserve workspace identity/access; restricted clients can read status/cost/query but cannot configure. Built-in approval policy is separate from these HTTP fields.",
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
/** Direct Table operations keep their native gateway ahead of general authoring.
|
|
1285
|
+
* Explicit Workflow triggers, mailbox imports and CRM attachments retain their owners. */
|
|
1286
|
+
function tableMaintenanceRecommendation(query) {
|
|
1287
|
+
if (isFunctionIntent(query) || isSecondPartyDecisionIntent(query)
|
|
1288
|
+
|| /\b(workflows?|agents?|campaigns?|tags?|mailbox\w*|crm|attachments?|chatgpt|connected apps?)\b/.test(query)
|
|
1289
|
+
|| (isTableMaintenanceIntent(query) && /\b(skills?|instructions?|guidance)\b/.test(query)))
|
|
1290
|
+
return null;
|
|
1291
|
+
const table = /\btables?\b/.test(query);
|
|
1292
|
+
const result = (tools, commands, execution) => ({ tools, commands, execution });
|
|
1293
|
+
if (/\b(favou?rites?|starred|star|unstar)\b/.test(query) && /\b(tables?|folders?)\b/.test(query)) {
|
|
1294
|
+
const mutate = !/\bstar unstar\b/.test(query) && (/\b(unstar|unfavou?rite)\b/.test(query) || (/\b(favou?rite|star)\b/.test(query) && !/\b(show|list|read|see|favorites|favourites|star unstar)\b/.test(query)));
|
|
1295
|
+
return result(mutate ? ["oxygen_tables_favorite", "oxygen_tables_favorites"] : ["oxygen_tables_favorites", "oxygen_tables_favorite"], mutate ? ["tables favorite", "tables favorites"] : ["tables favorites", "tables favorite"], "Read your member-specific Table/folder stars, then change exactly one table or folder with favorite=true or false. This costs 0 credits. Tool-catalog favorites are separate.");
|
|
1296
|
+
}
|
|
1297
|
+
if (table && /\b(webhooks?|inbound.*endpoint|push.*endpoint|endpoint.*(?:inbound|push))\b/.test(query)) {
|
|
1298
|
+
if (/\bdeliver\w*\b/.test(query))
|
|
1299
|
+
return result(["oxygen_table_webhook_deliveries", "oxygen_table_webhook_get"], ["tables webhook deliveries", "tables webhook get"], "Inspect this Table endpoint and its delivery ledger. A direct Table webhook lands rows; a Workflow webhook starts a published graph.");
|
|
1300
|
+
if (/\b(change|edit|update|rotat\w*|pause|disable|clear)\b/.test(query) && !/\bcreate\b/.test(query))
|
|
1301
|
+
return result(["oxygen_table_webhook_update", "oxygen_table_webhook_get"], ["tables webhook update", "tables webhook get"], "Inspect the endpoint, then update it by endpoint_id. auth_mode=secret rotates the secret and returns it once. auto_run is standing permission; delivery ceilings are explicit or plan-default. Preserve required authorization.");
|
|
1302
|
+
if (/\b(create|add|new|inbound)\b/.test(query) && !/\b(inspect|show|list|read)\b/.test(query))
|
|
1303
|
+
return result(["oxygen_table_webhook_create", "oxygen_table_webhooks_list"], ["tables webhook create", "tables webhook list"], "Create a direct inbound Table endpoint to insert or upsert rows. Inspect configured columns before setting auto_run: it is standing permission, with explicit or plan-default delivery ceilings. Workflows own graph triggers.");
|
|
1304
|
+
return result(["oxygen_table_webhooks_list", "oxygen_table_webhook_get", "oxygen_table_webhook_deliveries"], ["tables webhook list", "tables webhook get", "tables webhook deliveries"], "Inspect direct Table endpoints and their deliveries. Use oxygen_table_webhook_create/update for changes; auth_mode=secret rotates protection. Workflows own graph triggers.");
|
|
1305
|
+
}
|
|
1306
|
+
if (table && /\bfeeds?\b/.test(query)) {
|
|
1307
|
+
return /\b(bind|attach|create|new)\b/.test(query)
|
|
1308
|
+
? result(["oxygen_feeds_bind", "oxygen_feeds_list"], ["feeds bind", "feeds list"], "Bind the native Table feed: a declared-schema push source or scheduled provider pull. Inspect source, cadence and standing credit scope first; a pull feed is not an inbound webhook endpoint.")
|
|
1309
|
+
: result(["oxygen_feeds_list", "oxygen_feeds_get"], ["feeds list", "feeds get"], "Inspect the native Table feed's source, cadence, caps and state. Pull feeds refill Tables on their own schedule. The current MCP catalog has no general cadence-update tool; do not substitute a Workflow or generic HTTP call.");
|
|
1310
|
+
}
|
|
1311
|
+
const file = /\b(csv|jsonl?|xlsx|excel|spreadsheet|staged|uploaded|file)\b/.test(query)
|
|
1312
|
+
|| /\b(?:pending|stuck|abandoned) imports?\b|\bimports?\b.{0,30}\b(pending|stuck|recover\w*)\b/.test(query);
|
|
1313
|
+
if (file && /\b(import\w*|ingestion|upload\w*|preview|columns|sample|chunks)\b/.test(query)) {
|
|
1314
|
+
if (/\b(pending|leased|failed|recover|chunks)\b/.test(query))
|
|
1315
|
+
return result(/\b(chunks|items)\b/.test(query) ? ["oxygen_table_ingestions_items", "oxygen_table_ingestions_get"] : ["oxygen_table_ingestions_get", "oxygen_table_ingestions_items"], ["table-ingestions get", "table-ingestions items"], "Inspect the durable file ingestion and its chunks. Fix the cause before retry-failed; pending or leased chunks are not verified external outcomes. recover_pending polls existing BetterContact requests, not file imports.");
|
|
1316
|
+
if (/\b(url|https?)\b/.test(query))
|
|
1317
|
+
return result(["oxygen_tables_import_url"], ["tables import"], "Use the native public-file URL preview/import tool through the call gateway even for preview. Importing into an existing Table can fire its standing import auto-run; preview and new unarmed targets do not authorize later paid or external actions.");
|
|
1318
|
+
if (/\b(preview|inspect|columns|sample|sheet)\b/.test(query))
|
|
1319
|
+
return result(["oxygen_tables_import_preview", "oxygen_tables_import_staged"], ["tables import-preview", "tables import-staged"], "Inspect the owned staged file's worksheet, complete columns and sample before importing. Keep the selected sheet/mapping intact. Import into an existing Table can fire its standing import auto-run; preview grants no spend authority.");
|
|
1320
|
+
if (/\b(prepare|upload)\b/.test(query))
|
|
1321
|
+
return result(["oxygen_tables_import_upload", "oxygen_tables_import_preview", "oxygen_tables_import_staged"], ["tables import-upload", "tables import-preview", "tables import-staged"], "Prepare an organization-owned upload, transfer bytes to the returned presigned URL, then inspect and import that storage key. Preparing the upload creates no Table/run. Public URL imports use oxygen_tables_import_url.");
|
|
1322
|
+
return result(["oxygen_tables_import_staged", "oxygen_tables_import_preview"], ["tables import-staged", "tables import-preview"], "Import the inspected owned staged file with its selected worksheet/mapping. Existing targets can fire standing import auto-run; a new target has no pre-existing armed columns. Preserve exact authorization and downstream credit/effect guards.");
|
|
1323
|
+
}
|
|
1324
|
+
if (table && /\b(actions?|cells?|items?|runs?)\b/.test(query)) {
|
|
1325
|
+
if (/\b(verified|confirmed)\b/.test(query) && /\b(record|resolve)\b/.test(query) && !/\b(inspect|list|show|read)\b/.test(query))
|
|
1326
|
+
return /\bcells?\b/.test(query)
|
|
1327
|
+
? result(["oxygen_table_cells_resolve", "oxygen_table_runs_effect_unknown"], ["cells resolve", "table-runs effect-unknown"], "After verifying the external destination, record applied or not_applied by Table cell coordinates. This records an outcome without repeating the effect; retry remains a separate guarded action.")
|
|
1328
|
+
: result(["oxygen_table_action_item_resolve", "oxygen_table_runs_effect_unknown"], ["table-actions resolve", "table-runs effect-unknown"], "After verifying the external destination, record applied or not_applied by action item_id. This records an outcome without repeating the effect; retry remains a separate guarded action.");
|
|
1329
|
+
if (/\b(effect.*unknown|uncertain|verified outcome|blocked.*resolve)\b/.test(query))
|
|
1330
|
+
return result(["oxygen_table_runs_effect_unknown", "oxygen_table_runs_get", "oxygen_table_runs_items"], ["table-runs effect-unknown", "table-runs get", "table-runs items"], "Inspect exact effect-unknown items and verify the external destination. Only then record a verdict with oxygen_table_action_item_resolve by item_id or oxygen_table_cells_resolve by coordinates. Pending/failed items are not proof; retry is separate.");
|
|
1331
|
+
return result(["oxygen_table_action_runs_list", "oxygen_table_runs_get", "oxygen_table_runs_items"], ["table-runs list", "table-runs get", "table-runs items"], "Find the Table's durable action run, then inspect its status and items. Pending, leased and failed are distinct from effect-unknown; do not record a verified verdict or retry an external effect without evidence.");
|
|
1332
|
+
}
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1076
1335
|
function explicitCapabilityIntent(query) {
|
|
1336
|
+
if (databaseRecommendation(query))
|
|
1337
|
+
return ROUTE_BY_ID.get("platform-operations") ?? null;
|
|
1077
1338
|
if (isConnectedAppsIntent(query) || isConnectedAppEventsIntent(query) || isConnectedAppSpendIntent(query)) {
|
|
1078
1339
|
return ROUTE_BY_ID.get("workspace-access") ?? null;
|
|
1079
1340
|
}
|
|
@@ -1082,6 +1343,16 @@ function explicitCapabilityIntent(query) {
|
|
|
1082
1343
|
if (isWorkspacePagesIntent(query) || isWorkspaceSettingsIntent(query)) {
|
|
1083
1344
|
return ROUTE_BY_ID.get("workspace-access") ?? null;
|
|
1084
1345
|
}
|
|
1346
|
+
if (/\btables?\b/.test(query) && isSecondPartyDecisionIntent(query))
|
|
1347
|
+
return ROUTE_BY_ID.get("collaboration") ?? null;
|
|
1348
|
+
if (tableReadRecommendation(query) || tableMaintenanceRecommendation(query))
|
|
1349
|
+
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
1350
|
+
if (/\btables?\b/.test(query) && /\b(navigation|nav|paging|pagination)\b/.test(query)) {
|
|
1351
|
+
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
1352
|
+
}
|
|
1353
|
+
if (/\b(unibox|inbox)\b/.test(query) && /\b(metadata|taxonomy|filters)\b/.test(query)) {
|
|
1354
|
+
return ROUTE_BY_ID.get("messages") ?? null;
|
|
1355
|
+
}
|
|
1085
1356
|
if (/\b(infographic|graphic designer|render html|carousel pages|visual design|gtm flow image)\b/.test(query))
|
|
1086
1357
|
return ROUTE_BY_ID.get("visual-rendering") ?? null;
|
|
1087
1358
|
if (isUgcIntent(query))
|
|
@@ -1148,6 +1419,9 @@ function explicitCapabilityIntent(query) {
|
|
|
1148
1419
|
// hid every Sequences command.
|
|
1149
1420
|
if (isSequenceScheduleIntent(query) || isSequenceUnsubscribeIntent(query))
|
|
1150
1421
|
return ROUTE_BY_PRIMITIVE.get("sequences") ?? null;
|
|
1422
|
+
if (isMailboxVolumeIntent(query) && !/\b(workflow|automation|automate|webhook|cron)\b/.test(query)) {
|
|
1423
|
+
return ROUTE_BY_ID.get("sending-infrastructure") ?? null;
|
|
1424
|
+
}
|
|
1151
1425
|
if (isHostedWorkflowIntent(query))
|
|
1152
1426
|
return ROUTE_BY_PRIMITIVE.get("workflows") ?? null;
|
|
1153
1427
|
if (isCompanySourcingIntent(query))
|
|
@@ -1229,6 +1503,8 @@ function explicitCapabilityIntent(query) {
|
|
|
1229
1503
|
// and the "label" wording fell to the Tags card below.
|
|
1230
1504
|
if (isRowClassificationIntent(query))
|
|
1231
1505
|
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
1506
|
+
if (isTableMaintenanceIntent(query))
|
|
1507
|
+
return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
|
|
1232
1508
|
if (/\b(tag|tags|label|labels)\b/.test(query))
|
|
1233
1509
|
return ROUTE_BY_PRIMITIVE.get("tags") ?? null;
|
|
1234
1510
|
if (/\b(disposable|working)\b.{0,30}\b(list|dataset|table)\b|\b(prospect|sourcing) table\b/.test(query)) {
|
|
@@ -1347,6 +1623,15 @@ function isPublishingPostIntent(query) {
|
|
|
1347
1623
|
&& !(/\b(find|search|scrape|research)\b/.test(query) && /\b(about|mention|containing)\b/.test(query));
|
|
1348
1624
|
}
|
|
1349
1625
|
function recommendationsFor(card, query) {
|
|
1626
|
+
const database = card.id === "platform-operations" ? databaseRecommendation(query) : null;
|
|
1627
|
+
if (database)
|
|
1628
|
+
return database;
|
|
1629
|
+
if (card.id === "billing-and-budgets" && /\b(credit prices|credit price catalog|customer credit)\b/.test(query)) {
|
|
1630
|
+
return { tools: ["oxygen_customer_credit_prices"], commands: ["pricing customer-credit-prices"] };
|
|
1631
|
+
}
|
|
1632
|
+
if (card.id === "messages" && /\b(unibox|inbox)\b/.test(query) && /\b(metadata|taxonomy|filters|accounts|tags)\b/.test(query)) {
|
|
1633
|
+
return { tools: ["oxygen_unibox_metadata"], commands: ["unibox metadata"] };
|
|
1634
|
+
}
|
|
1350
1635
|
// A program's lifecycle and a creator's voice are UGC work the Publishing card
|
|
1351
1636
|
// also claims ("archive program", "creator voice"); before these they got the
|
|
1352
1637
|
// post tools (UGC E2E pass, 2026-09-29).
|
|
@@ -1508,6 +1793,12 @@ function recommendationsFor(card, query) {
|
|
|
1508
1793
|
],
|
|
1509
1794
|
};
|
|
1510
1795
|
}
|
|
1796
|
+
if (card.id === "sending-infrastructure" && isMailboxVolumeIntent(query)) {
|
|
1797
|
+
return {
|
|
1798
|
+
tools: ["oxygen_mailboxes_set_ramp", "oxygen_mailboxes_set_cap", "oxygen_mailboxes_get"],
|
|
1799
|
+
commands: ["mailboxes ramp set", "mailboxes cap set", "mailboxes get"],
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1511
1802
|
if (card.id === "sending-infrastructure" && isMailboxOnboardingIntent(query)) {
|
|
1512
1803
|
return {
|
|
1513
1804
|
tools: [
|
|
@@ -1568,6 +1859,12 @@ function recommendationsFor(card, query) {
|
|
|
1568
1859
|
};
|
|
1569
1860
|
}
|
|
1570
1861
|
if (card.primitive === "tables") {
|
|
1862
|
+
const read = tableReadRecommendation(query);
|
|
1863
|
+
if (read)
|
|
1864
|
+
return read;
|
|
1865
|
+
const maintenance = tableMaintenanceRecommendation(query);
|
|
1866
|
+
if (maintenance)
|
|
1867
|
+
return maintenance;
|
|
1571
1868
|
if (isTableCapacityReadIntent(query))
|
|
1572
1869
|
return {
|
|
1573
1870
|
tools: ["oxygen_limits_show", "oxygen_tables_query", "oxygen_tables_describe"],
|
|
@@ -1618,6 +1915,33 @@ function recommendationsFor(card, query) {
|
|
|
1618
1915
|
exactMcpCall: { ...CAPABILITY_ROUTE_MCP_CALLS.functionsList(), ...(/\b(favorites|favourites)\b/.test(query) ? { arguments: { operation: "list_functions", filter: "favorites" } } : {}) },
|
|
1619
1916
|
};
|
|
1620
1917
|
}
|
|
1918
|
+
if (isTableMaintenanceIntent(query)) {
|
|
1919
|
+
if (/\b(skills?|instructions?|guidance)\b/.test(query))
|
|
1920
|
+
return {
|
|
1921
|
+
tools: ["oxygen_skills_get", "oxygen_tables_tidy_suggest", "oxygen_tables_describe"],
|
|
1922
|
+
commands: ["skills get", "tables tidy-suggest", "tables describe"],
|
|
1923
|
+
exactCommand: "oxygen skills get oxygen-table-tidy --json",
|
|
1924
|
+
exactMcpCall: { tool: "oxygen_skills_get", arguments: { name: "oxygen-table-tidy" } },
|
|
1925
|
+
};
|
|
1926
|
+
if (/\b(favou?rites?|unfavou?rite|star|unstar)\b/.test(query)) {
|
|
1927
|
+
const read = /\b(list|read|show|see)\b/.test(query);
|
|
1928
|
+
return {
|
|
1929
|
+
tools: read ? ["oxygen_tables_favorites", "oxygen_tables_favorite"] : ["oxygen_tables_favorite", "oxygen_tables_favorites"],
|
|
1930
|
+
commands: read ? ["tables favorites", "tables favorite"] : ["tables favorite", "tables favorites"],
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
if (/\bcolumns?\b/.test(query) && /\b(rename|renaming|label|key)\b/.test(query)) {
|
|
1934
|
+
const key = /\b(stable key|column key|snake case|rename key)\b/.test(query);
|
|
1935
|
+
return {
|
|
1936
|
+
tools: [key ? "oxygen_columns_rename" : "oxygen_columns_update", "oxygen_tables_describe"],
|
|
1937
|
+
commands: [key ? "columns rename" : "columns update", "tables describe"],
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
return {
|
|
1941
|
+
tools: ["oxygen_tables_tidy_suggest", "oxygen_columns_update", "oxygen_tables_describe", "oxygen_skills_get"],
|
|
1942
|
+
commands: ["tables tidy-suggest", "columns update", "tables describe", "skills get"],
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1621
1945
|
if (isLinkedInProfileWatcherIntent(query)) {
|
|
1622
1946
|
return {
|
|
1623
1947
|
tools: ["oxygen_tables_watcher"],
|
|
@@ -2004,10 +2328,11 @@ function isSecondPartyDecisionIntent(query) {
|
|
|
2004
2328
|
const decisionLanguage = /\b(sign ?off|signoff|approval request|request approval|approval gate|go no go)\b/.test(query);
|
|
2005
2329
|
const clientDecision = /\bclient\b.{0,20}\b(approv\w*|sign ?off|review|decide|decision|login|role)\b/.test(query)
|
|
2006
2330
|
|| /\b(approv\w*|sign ?off|decision)\b.{0,20}\bfrom the client\b/.test(query);
|
|
2331
|
+
const teammateDecision = /\b(teammate|colleague|workspace member)\b.{0,25}\b(approv\w*|sign ?off|review|decid\w*)\b/.test(query);
|
|
2007
2332
|
const internalThread = /\b(comment|comments|thread)\b/.test(query)
|
|
2008
2333
|
&& /\b(internal|client|teammate|workspace member|discuss)\b/.test(query)
|
|
2009
2334
|
&& !/\b(linkedin|public|published|post|posts|publishing)\b/.test(query);
|
|
2010
|
-
return decisionLanguage || clientDecision || internalThread;
|
|
2335
|
+
return decisionLanguage || clientDecision || teammateDecision || internalThread;
|
|
2011
2336
|
}
|
|
2012
2337
|
/** An X (Twitter) post format: thread, poll, alt text, who-can-reply, quote, photo tags. */
|
|
2013
2338
|
function isXPostFormatIntent(query) {
|