@sellable/mcp 0.1.959 → 0.1.960-wip.writers.20261007.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.
@@ -3,14 +3,14 @@
3
3
  * manifests. Keep this free of tool implementation imports so Next can bundle
4
4
  * it; registry parity is enforced in sellable-agent-tool-policy.test.ts.
5
5
  */
6
- export declare const SELLABLE_MCP_TOOL_NAMES: readonly ["add_column", "add_on_demand_leads", "add_rubric_item", "add_teammate", "add_to_comment_campaign", "add_to_connection_campaign", "add_to_inmail_campaign", "add_to_post_campaign", "archive_campaign", "attach_recommended_sequence", "attach_sequence", "bootstrap_create_campaign", "bootstrap_engage", "bootstrap_engage_multi", "bootstrap_find_leads", "bulk_enrich_with_prospeo", "calculate_linkedin_hook_preview", "cancel_campaign_message_preparation", "cancel_find_leads", "cancel_lead_import", "capture_post_idea", "check_inbox_reply_eligibility", "check_rubric", "commit_blueprint", "complete_sender_research", "confirm_harvest_job_companies", "confirm_lead_list", "confirm_prospeo_company_accounts", "copy_sender_config", "create_campaign", "create_on_demand_campaign", "create_on_demand_table", "create_table", "create_workflow_table", "create_workspace", "customer_program", "decide_agent_endpoint_proposal", "delete_column", "delete_rubric_item", "draft_rubrics", "duplicate_campaign", "enrich_with_prospeo", "export_table_csv", "export_workspace_csv", "fetch_company", "fetch_company_posts", "fetch_linkedin_posts", "fetch_linkedin_profile", "fetch_post_engagers", "fill_campaign_horizon", "get_active_workspace", "get_agent_endpoint_run", "get_agent_generation_routing", "get_agent_soul", "get_auth_status", "get_campaign", "get_campaign_context", "get_campaign_framework", "get_campaign_message_preparation_status", "get_campaign_messages_preview", "get_campaign_navigation_state", "get_campaign_refill_state", "get_campaign_table_schema", "get_campaign_waterfall", "get_campaigns", "get_column_schema", "get_company_info", "get_engage_memory", "get_engage_state", "get_engaged_posts", "get_find_leads_run", "get_inbox_thread", "get_integration_connection_status", "get_linkedin_profile", "get_or_create_direct_campaign_table", "get_post_draft", "get_post_find_leads_scout_registry", "get_post_idea", "get_prospeo_credits", "get_provider_prompt", "get_published_post", "get_refill_target_plan", "get_rows", "get_rows_minimal", "get_runtime_identity", "get_scheduler_fill_capacity", "get_sender", "get_sender_routing", "get_source_scout_registry", "get_subskill_asset", "get_subskill_prompt", "get_table_rows", "get_user_posts", "get_workspace", "import_leads", "init_on_demand_sequence", "integrations_call_tool", "integrations_describe_tool", "integrations_list_tools", "list_agent_endpoint_runs", "list_agent_endpoints", "list_column_types", "list_dnc_entries", "list_post_draft_iterations", "list_post_drafts", "list_post_ideas", "list_published_posts", "list_senders", "list_subskill_prompts", "list_tables", "list_workspaces", "load_csv_dnc_entries", "load_csv_domains", "load_csv_linkedin_leads", "lookup_sales_nav_filter", "mark_post_published", "migrate_flat_configs", "opportunity_sequence_enroll", "opportunity_sequence_next_page", "opportunity_sequence_record", "pause_campaign", "pause_direct_campaign", "pause_on_demand_campaign", "preflight_find_leads_provider", "prepare_campaign_ab_test", "publish_agent_endpoint", "queue_campaign_cells", "queue_cells", "record_campaign_review_batch", "record_engage_proven_search", "refill_sends", "refill_v3_advance", "refill_v3_continue", "refill_v3_edit_selected_campaign", "refill_v3_fill_ready", "refill_v3_world_state", "refresh_paid_inmail_credits", "refresh_sender_engagement", "reissue_find_leads_watch_link", "render_linkedin_post_preview", "reorder_columns", "resolve_campaign_fill_route", "revise_message_template_and_rerun", "rotate_agent_endpoint_key", "run_scheduler_sweep", "save_domain_filters", "save_hook_research", "save_post_draft", "save_rubrics", "search_apollo", "search_available_integrations", "search_engagement_posts", "search_harvest_jobs", "search_inbox_threads", "search_prospeo", "search_prospeo_companies", "search_sales_nav", "search_signals", "search_subskill_prompts", "select_campaign_cells", "select_necessary_rubrics", "select_promising_posts", "send_inbox_draft", "send_inbox_manual_reply", "set_active_workspace", "set_agent_generation_flags", "set_campaign_waterfall_order", "set_company_info", "set_engage_state", "set_engage_style_guide", "set_headline_icp_criteria", "set_sender_calendar_link", "set_sender_context", "set_sender_routing", "setup_evergreen_campaigns", "start_campaign", "start_campaign_message_preparation", "start_cli_login", "start_direct_campaign", "start_integration_connection", "start_on_demand_campaign", "stop_agent_endpoint_run", "update_agent_soul", "update_campaign", "update_campaign_brief", "update_cell", "update_column", "update_find_leads_run", "update_inbox_draft", "update_post_draft", "update_published_post_metrics", "update_rubric_item", "upsert_engage_tracked_person", "upsert_rubric", "validate_campaign1_kickoff_handoff", "verify_table_row", "wait_for_campaign_processing", "wait_for_campaign_table_ready", "wait_for_cli_login", "wait_for_find_leads_run", "wait_for_lead_list_ready", "wait_for_rubric_results"];
6
+ export declare const SELLABLE_MCP_TOOL_NAMES: readonly ["add_column", "add_on_demand_leads", "add_rubric_item", "add_teammate", "add_to_comment_campaign", "add_to_connection_campaign", "add_to_inmail_campaign", "add_to_post_campaign", "archive_campaign", "attach_recommended_sequence", "attach_sequence", "bootstrap_create_campaign", "bootstrap_engage", "bootstrap_engage_multi", "bootstrap_find_leads", "bulk_enrich_with_prospeo", "calculate_linkedin_hook_preview", "cancel_campaign_message_preparation", "cancel_find_leads", "cancel_lead_import", "capture_post_idea", "check_inbox_reply_eligibility", "check_rubric", "commit_blueprint", "complete_sender_research", "confirm_harvest_job_companies", "confirm_lead_list", "confirm_prospeo_company_accounts", "copy_sender_config", "create_campaign", "create_on_demand_campaign", "create_on_demand_table", "create_table", "create_workflow_table", "create_workspace", "customer_program", "decide_agent_endpoint_proposal", "delete_column", "delete_rubric_item", "draft_rubrics", "duplicate_campaign", "enrich_with_prospeo", "export_table_csv", "export_workspace_csv", "fetch_company", "fetch_company_posts", "fetch_linkedin_posts", "fetch_linkedin_profile", "fetch_post_engagers", "fill_campaign_horizon", "get_active_workspace", "get_agent_endpoint_run", "get_agent_soul", "get_auth_status", "get_campaign", "get_campaign_context", "get_campaign_framework", "get_campaign_message_preparation_status", "get_campaign_messages_preview", "get_campaign_navigation_state", "get_campaign_refill_state", "get_campaign_table_schema", "get_campaign_waterfall", "get_campaigns", "get_column_schema", "get_company_info", "get_engage_memory", "get_engage_state", "get_engaged_posts", "get_find_leads_run", "get_inbox_thread", "get_integration_connection_status", "get_linkedin_profile", "get_or_create_direct_campaign_table", "get_post_draft", "get_post_find_leads_scout_registry", "get_post_idea", "get_prospeo_credits", "get_provider_prompt", "get_published_post", "get_refill_target_plan", "get_rows", "get_rows_minimal", "get_runtime_identity", "get_scheduler_fill_capacity", "get_sender", "get_sender_routing", "get_source_scout_registry", "get_subskill_asset", "get_subskill_prompt", "get_table_rows", "get_user_posts", "get_workspace", "import_leads", "init_on_demand_sequence", "integrations_call_tool", "integrations_describe_tool", "integrations_list_tools", "list_agent_endpoint_runs", "list_agent_endpoints", "list_column_types", "list_dnc_entries", "list_post_draft_iterations", "list_post_drafts", "list_post_ideas", "list_published_posts", "list_senders", "list_subskill_prompts", "list_tables", "list_workspaces", "load_csv_dnc_entries", "load_csv_domains", "load_csv_linkedin_leads", "lookup_sales_nav_filter", "mark_post_published", "migrate_flat_configs", "opportunity_sequence_enroll", "opportunity_sequence_next_page", "opportunity_sequence_record", "pause_campaign", "pause_direct_campaign", "pause_on_demand_campaign", "preflight_find_leads_provider", "prepare_campaign_ab_test", "publish_agent_endpoint", "queue_campaign_cells", "queue_cells", "record_campaign_review_batch", "record_engage_proven_search", "refill_sends", "refill_v3_advance", "refill_v3_continue", "refill_v3_edit_selected_campaign", "refill_v3_fill_ready", "refill_v3_world_state", "refresh_paid_inmail_credits", "refresh_sender_engagement", "reissue_find_leads_watch_link", "render_linkedin_post_preview", "reorder_columns", "resolve_campaign_fill_route", "revise_message_template_and_rerun", "rotate_agent_endpoint_key", "run_scheduler_sweep", "save_domain_filters", "save_hook_research", "save_post_draft", "save_rubrics", "search_apollo", "search_available_integrations", "search_engagement_posts", "search_harvest_jobs", "search_inbox_threads", "search_prospeo", "search_prospeo_companies", "search_sales_nav", "search_signals", "search_subskill_prompts", "select_campaign_cells", "select_necessary_rubrics", "select_promising_posts", "send_inbox_draft", "send_inbox_manual_reply", "set_active_workspace", "set_campaign_waterfall_order", "set_company_info", "set_engage_state", "set_engage_style_guide", "set_headline_icp_criteria", "set_sender_calendar_link", "set_sender_context", "set_sender_routing", "setup_evergreen_campaigns", "start_campaign", "start_campaign_message_preparation", "start_cli_login", "start_direct_campaign", "start_integration_connection", "start_on_demand_campaign", "stop_agent_endpoint_run", "update_agent_soul", "update_campaign", "update_campaign_brief", "update_cell", "update_column", "update_find_leads_run", "update_inbox_draft", "update_post_draft", "update_published_post_metrics", "update_rubric_item", "upsert_engage_tracked_person", "upsert_rubric", "validate_campaign1_kickoff_handoff", "verify_table_row", "wait_for_campaign_processing", "wait_for_campaign_table_ready", "wait_for_cli_login", "wait_for_find_leads_run", "wait_for_lead_list_ready", "wait_for_rubric_results"];
7
7
  /**
8
8
  * Explicit mutation classification lives beside (but outside) the flat tool
9
9
  * registry. Neither this list nor `isMutatingTool` is an input to
10
10
  * `compileAgentToolPolicy`, so editing it cannot move the fleet-pinned
11
11
  * `policyHash`.
12
12
  */
13
- export declare const MUTATING_TOOL_NAMES: readonly ["create_table", "publish_agent_endpoint", "rotate_agent_endpoint_key", "decide_agent_endpoint_proposal", "stop_agent_endpoint_run", "pause_campaign", "archive_campaign", "update_campaign", "fill_campaign_horizon", "set_campaign_waterfall_order", "set_sender_routing", "set_sender_context", "set_agent_generation_flags", "send_inbox_draft", "send_inbox_manual_reply", "load_csv_dnc_entries", "update_cell", "queue_cells", "check_rubric", "queue_campaign_cells", "start_campaign_message_preparation", "opportunity_sequence_enroll", "opportunity_sequence_record", "refill_v3_fill_ready", "refill_v3_edit_selected_campaign", "refill_v3_advance", "refill_v3_continue"];
13
+ export declare const MUTATING_TOOL_NAMES: readonly ["create_table", "publish_agent_endpoint", "rotate_agent_endpoint_key", "decide_agent_endpoint_proposal", "stop_agent_endpoint_run", "pause_campaign", "archive_campaign", "update_campaign", "fill_campaign_horizon", "set_campaign_waterfall_order", "set_sender_routing", "set_sender_context", "send_inbox_draft", "send_inbox_manual_reply", "load_csv_dnc_entries", "update_cell", "queue_cells", "check_rubric", "queue_campaign_cells", "start_campaign_message_preparation", "opportunity_sequence_enroll", "opportunity_sequence_record", "refill_v3_fill_ready", "refill_v3_edit_selected_campaign", "refill_v3_advance", "refill_v3_continue"];
14
14
  export declare function isMutatingTool(name: string): boolean;
15
15
  export declare const CROSS_WORKSPACE_EXPLICIT_WORKSPACE_REQUIRED: {
16
16
  readonly code: "cross_workspace_explicit_workspace_required";
@@ -56,7 +56,6 @@ export const SELLABLE_MCP_TOOL_NAMES = [
56
56
  "fill_campaign_horizon",
57
57
  "get_active_workspace",
58
58
  "get_agent_endpoint_run",
59
- "get_agent_generation_routing",
60
59
  "get_agent_soul",
61
60
  "get_auth_status",
62
61
  "get_campaign",
@@ -169,7 +168,6 @@ export const SELLABLE_MCP_TOOL_NAMES = [
169
168
  "send_inbox_draft",
170
169
  "send_inbox_manual_reply",
171
170
  "set_active_workspace",
172
- "set_agent_generation_flags",
173
171
  "set_campaign_waterfall_order",
174
172
  "set_company_info",
175
173
  "set_engage_state",
@@ -231,7 +229,6 @@ export const MUTATING_TOOL_NAMES = [
231
229
  // A sender's personal context is what the message writer says about a real
232
230
  // person, so a cross-workspace caller must name the workspace it means.
233
231
  "set_sender_context",
234
- "set_agent_generation_flags",
235
232
  "send_inbox_draft",
236
233
  "send_inbox_manual_reply",
237
234
  "load_csv_dnc_entries",
package/dist/server.js CHANGED
@@ -15,7 +15,6 @@ import { MCP_RUNTIME_IDENTITY } from "./runtime-identity.js";
15
15
  import { getSkillByName, listSkills } from "./skills.js";
16
16
  import { toMcpToolResult } from "./tool-result-envelope.js";
17
17
  import { decideAgentEndpointProposal, getAgentEndpointRun, listAgentEndpointRuns, listAgentEndpoints, publishAgentEndpoint, rotateAgentEndpointKey, stopAgentEndpointRun, } from "./tools/agent-endpoints.js";
18
- import { getAgentGenerationRoutingTool, setAgentGenerationFlagsTool, } from "./tools/agent-generation-routing.js";
19
18
  import { getAgentSoulTool, updateAgentSoulTool } from "./tools/agent-soul.js";
20
19
  import { getAuthStatus } from "./tools/auth.js";
21
20
  import { handleAddColumn, handleCommitBlueprint, } from "./tools/blueprint-commit.js";
@@ -802,12 +801,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
802
801
  case "set_sender_routing":
803
802
  result = await setSenderRoutingTool(args);
804
803
  break;
805
- case "get_agent_generation_routing":
806
- result = await getAgentGenerationRoutingTool(args);
807
- break;
808
- case "set_agent_generation_flags":
809
- result = await setAgentGenerationFlagsTool(args);
810
- break;
811
804
  // Plan 141-06 owns these three `case` labels ONLY. The fail-closed actor
812
805
  // guard above is plan 141-04 T2's and is keyed on the tool-name SET, so it
813
806
  // already ran before this switch and `integrationActor.context` is verified.
@@ -68,8 +68,15 @@ export interface CampaignDetail {
68
68
  sent: number;
69
69
  };
70
70
  automationSettings: CampaignAutomationSettings;
71
+ writers?: CampaignWriters;
72
+ writerEndpoints?: unknown[];
71
73
  watchUrl: string;
72
74
  }
75
+ export interface CampaignWriters {
76
+ openerEndpointId: string | null;
77
+ replyEndpointId: string | null;
78
+ followUpEndpointId: string | null;
79
+ }
73
80
  export interface CampaignAutomationSettings {
74
81
  autoApproveFollowups: boolean | null;
75
82
  enableFollowUps: boolean | null;
@@ -173,6 +180,9 @@ export interface UpdateCampaignInput {
173
180
  autoApproveFollowups?: boolean;
174
181
  enableFollowUps?: boolean;
175
182
  autoApproveReplies?: boolean;
183
+ openerEndpointId?: string | null;
184
+ replyEndpointId?: string | null;
185
+ followUpEndpointId?: string | null;
176
186
  senderIds?: string[];
177
187
  rubric?: unknown[];
178
188
  }
@@ -273,6 +283,9 @@ export declare const campaignToolDefinitions: ({
273
283
  autoApproveFollowups?: undefined;
274
284
  enableFollowUps?: undefined;
275
285
  autoApproveReplies?: undefined;
286
+ openerEndpointId?: undefined;
287
+ replyEndpointId?: undefined;
288
+ followUpEndpointId?: undefined;
276
289
  rubric?: undefined;
277
290
  flowVersion?: undefined;
278
291
  };
@@ -324,6 +337,9 @@ export declare const campaignToolDefinitions: ({
324
337
  autoApproveFollowups?: undefined;
325
338
  enableFollowUps?: undefined;
326
339
  autoApproveReplies?: undefined;
340
+ openerEndpointId?: undefined;
341
+ replyEndpointId?: undefined;
342
+ followUpEndpointId?: undefined;
327
343
  rubric?: undefined;
328
344
  flowVersion?: undefined;
329
345
  };
@@ -377,6 +393,9 @@ export declare const campaignToolDefinitions: ({
377
393
  autoApproveFollowups?: undefined;
378
394
  enableFollowUps?: undefined;
379
395
  autoApproveReplies?: undefined;
396
+ openerEndpointId?: undefined;
397
+ replyEndpointId?: undefined;
398
+ followUpEndpointId?: undefined;
380
399
  rubric?: undefined;
381
400
  flowVersion?: undefined;
382
401
  };
@@ -426,6 +445,9 @@ export declare const campaignToolDefinitions: ({
426
445
  autoApproveFollowups?: undefined;
427
446
  enableFollowUps?: undefined;
428
447
  autoApproveReplies?: undefined;
448
+ openerEndpointId?: undefined;
449
+ replyEndpointId?: undefined;
450
+ followUpEndpointId?: undefined;
429
451
  rubric?: undefined;
430
452
  flowVersion?: undefined;
431
453
  };
@@ -475,6 +497,9 @@ export declare const campaignToolDefinitions: ({
475
497
  autoApproveFollowups?: undefined;
476
498
  enableFollowUps?: undefined;
477
499
  autoApproveReplies?: undefined;
500
+ openerEndpointId?: undefined;
501
+ replyEndpointId?: undefined;
502
+ followUpEndpointId?: undefined;
478
503
  rubric?: undefined;
479
504
  flowVersion?: undefined;
480
505
  };
@@ -567,6 +592,9 @@ export declare const campaignToolDefinitions: ({
567
592
  autoApproveFollowups?: undefined;
568
593
  enableFollowUps?: undefined;
569
594
  autoApproveReplies?: undefined;
595
+ openerEndpointId?: undefined;
596
+ replyEndpointId?: undefined;
597
+ followUpEndpointId?: undefined;
570
598
  rubric?: undefined;
571
599
  flowVersion?: undefined;
572
600
  };
@@ -778,6 +806,9 @@ export declare const campaignToolDefinitions: ({
778
806
  autoApproveFollowups?: undefined;
779
807
  enableFollowUps?: undefined;
780
808
  autoApproveReplies?: undefined;
809
+ openerEndpointId?: undefined;
810
+ replyEndpointId?: undefined;
811
+ followUpEndpointId?: undefined;
781
812
  rubric?: undefined;
782
813
  flowVersion?: undefined;
783
814
  };
@@ -1010,6 +1041,18 @@ export declare const campaignToolDefinitions: ({
1010
1041
  type: string;
1011
1042
  description: string;
1012
1043
  };
1044
+ openerEndpointId: {
1045
+ type: string[];
1046
+ description: string;
1047
+ };
1048
+ replyEndpointId: {
1049
+ type: string[];
1050
+ description: string;
1051
+ };
1052
+ followUpEndpointId: {
1053
+ type: string[];
1054
+ description: string;
1055
+ };
1013
1056
  senderIds: {
1014
1057
  type: string;
1015
1058
  items: {
@@ -1087,6 +1130,9 @@ export declare const campaignToolDefinitions: ({
1087
1130
  autoApproveFollowups?: undefined;
1088
1131
  enableFollowUps?: undefined;
1089
1132
  autoApproveReplies?: undefined;
1133
+ openerEndpointId?: undefined;
1134
+ replyEndpointId?: undefined;
1135
+ followUpEndpointId?: undefined;
1090
1136
  rubric?: undefined;
1091
1137
  flowVersion?: undefined;
1092
1138
  };
@@ -1139,6 +1185,9 @@ export declare const campaignToolDefinitions: ({
1139
1185
  autoApproveFollowups?: undefined;
1140
1186
  enableFollowUps?: undefined;
1141
1187
  autoApproveReplies?: undefined;
1188
+ openerEndpointId?: undefined;
1189
+ replyEndpointId?: undefined;
1190
+ followUpEndpointId?: undefined;
1142
1191
  rubric?: undefined;
1143
1192
  flowVersion?: undefined;
1144
1193
  };
@@ -330,7 +330,7 @@ export const campaignToolDefinitions = [
330
330
  },
331
331
  {
332
332
  name: "get_campaign",
333
- description: "Get detailed campaign context including brief, positioning, sender info, lead scoring rubrics, stats, and follow-up automation settings. Returns workflowTableId for fetching rows.",
333
+ description: "Get detailed campaign context including brief, positioning, sender info, lead scoring rubrics, stats, and follow-up automation settings. Returns workflowTableId for fetching rows. writers says who writes this campaign's first messages, replies and follow-ups (null = Sellable); writerEndpoints lists the endpoints that can be chosen.",
334
334
  inputSchema: {
335
335
  type: "object",
336
336
  properties: {
@@ -487,7 +487,7 @@ export const campaignToolDefinitions = [
487
487
  },
488
488
  {
489
489
  name: "update_campaign",
490
- description: "Update an existing campaign offer with positioning, brief, workflow state, or follow-up automation fields. Returns currentStep plus navigation diagnostics and persisted automation readback when automation settings change.",
490
+ description: "Update an existing campaign offer with positioning, brief, workflow state, or follow-up automation fields. Returns currentStep plus navigation diagnostics and persisted automation readback when automation settings change. Writers (openerEndpointId, replyEndpointId, followUpEndpointId) are chosen per campaign; Sellable writes anything left null.",
491
491
  inputSchema: {
492
492
  type: "object",
493
493
  properties: {
@@ -591,6 +591,18 @@ export const campaignToolDefinitions = [
591
591
  type: "boolean",
592
592
  description: "Whether drafted replies to prospects who answered are sent without the customer reviewing them. Set it only when the customer asks for automatic replies, and tell them replies will go out without their review. Default is off: every reply waits for the customer in the inbox.",
593
593
  },
594
+ openerEndpointId: {
595
+ type: ["string", "null"],
596
+ description: "Who writes this campaign's first messages: an endpoint id of the workspace's Sellable Agent, or null for Sellable. Conversations campaigns only. Read the current choice and the choosable endpoints from get_campaign (writers, writerEndpoints). A refused choice returns the reason and saves nothing.",
597
+ },
598
+ replyEndpointId: {
599
+ type: ["string", "null"],
600
+ description: "Who drafts replies when a prospect replies: an endpoint id, or null for Sellable (the default).",
601
+ },
602
+ followUpEndpointId: {
603
+ type: ["string", "null"],
604
+ description: "Who drafts follow-ups when a prospect who replied goes quiet: an endpoint id, or null for Sellable (the default). Follow-ups never borrow the replies writer.",
605
+ },
594
606
  senderIds: {
595
607
  type: "array",
596
608
  items: { type: "string" },
@@ -678,7 +690,7 @@ export async function getCampaign(campaignId) {
678
690
  // Fetch campaign context and rubrics in parallel
679
691
  const [result, automationSource, rubricsResult] = await Promise.all([
680
692
  api.get(`/api/v3/mcp/campaigns/${campaignId}?mode=${getCampaignBuilderWatchModeParam()}`),
681
- api.get(`/api/v2/campaign-offers/${campaignId}`),
693
+ api.get(`/api/v2/campaign-offers/${campaignId}?include=writers`),
682
694
  fetchCampaignRubrics(campaignId).catch(() => null),
683
695
  ]);
684
696
  // Prefer the server-minted watch link. It carries a fresh single-use token
@@ -706,6 +718,8 @@ export async function getCampaign(campaignId) {
706
718
  leadScoringRubrics: rubrics,
707
719
  },
708
720
  automationSettings: readCampaignAutomationSettings(automationSource),
721
+ writers: automationSource.writers,
722
+ writerEndpoints: automationSource.writerEndpoints,
709
723
  watchUrl,
710
724
  };
711
725
  }
@@ -786,40 +786,6 @@ export declare const allTools: ({
786
786
  readonly idempotentHint: false;
787
787
  readonly openWorldHint: false;
788
788
  };
789
- } | {
790
- name: string;
791
- description: string;
792
- inputSchema: {
793
- type: string;
794
- properties: {
795
- expectedGeneration: {
796
- type: string;
797
- minimum: number;
798
- description: string;
799
- };
800
- openerEnabled: {
801
- type: string;
802
- };
803
- replyEnabled: {
804
- type: string;
805
- };
806
- followUpEnabled: {
807
- type: string;
808
- };
809
- workspaceId: {
810
- type: string;
811
- description: string;
812
- };
813
- };
814
- required: string[];
815
- additionalProperties: boolean;
816
- };
817
- annotations: {
818
- readOnlyHint: boolean;
819
- destructiveHint: boolean;
820
- idempotentHint: boolean;
821
- openWorldHint: boolean;
822
- };
823
789
  } | {
824
790
  readonly name: "get_agent_soul";
825
791
  readonly description: "Read and prove the SOUL.md used by this live Sellable Agent runtime. This tool is runtime-bound and has no target selector.";
@@ -2352,6 +2318,9 @@ export declare const allTools: ({
2352
2318
  autoApproveFollowups?: undefined;
2353
2319
  enableFollowUps?: undefined;
2354
2320
  autoApproveReplies?: undefined;
2321
+ openerEndpointId?: undefined;
2322
+ replyEndpointId?: undefined;
2323
+ followUpEndpointId?: undefined;
2355
2324
  rubric?: undefined;
2356
2325
  flowVersion?: undefined;
2357
2326
  };
@@ -2403,6 +2372,9 @@ export declare const allTools: ({
2403
2372
  autoApproveFollowups?: undefined;
2404
2373
  enableFollowUps?: undefined;
2405
2374
  autoApproveReplies?: undefined;
2375
+ openerEndpointId?: undefined;
2376
+ replyEndpointId?: undefined;
2377
+ followUpEndpointId?: undefined;
2406
2378
  rubric?: undefined;
2407
2379
  flowVersion?: undefined;
2408
2380
  };
@@ -2456,6 +2428,9 @@ export declare const allTools: ({
2456
2428
  autoApproveFollowups?: undefined;
2457
2429
  enableFollowUps?: undefined;
2458
2430
  autoApproveReplies?: undefined;
2431
+ openerEndpointId?: undefined;
2432
+ replyEndpointId?: undefined;
2433
+ followUpEndpointId?: undefined;
2459
2434
  rubric?: undefined;
2460
2435
  flowVersion?: undefined;
2461
2436
  };
@@ -2505,6 +2480,9 @@ export declare const allTools: ({
2505
2480
  autoApproveFollowups?: undefined;
2506
2481
  enableFollowUps?: undefined;
2507
2482
  autoApproveReplies?: undefined;
2483
+ openerEndpointId?: undefined;
2484
+ replyEndpointId?: undefined;
2485
+ followUpEndpointId?: undefined;
2508
2486
  rubric?: undefined;
2509
2487
  flowVersion?: undefined;
2510
2488
  };
@@ -2554,6 +2532,9 @@ export declare const allTools: ({
2554
2532
  autoApproveFollowups?: undefined;
2555
2533
  enableFollowUps?: undefined;
2556
2534
  autoApproveReplies?: undefined;
2535
+ openerEndpointId?: undefined;
2536
+ replyEndpointId?: undefined;
2537
+ followUpEndpointId?: undefined;
2557
2538
  rubric?: undefined;
2558
2539
  flowVersion?: undefined;
2559
2540
  };
@@ -2646,6 +2627,9 @@ export declare const allTools: ({
2646
2627
  autoApproveFollowups?: undefined;
2647
2628
  enableFollowUps?: undefined;
2648
2629
  autoApproveReplies?: undefined;
2630
+ openerEndpointId?: undefined;
2631
+ replyEndpointId?: undefined;
2632
+ followUpEndpointId?: undefined;
2649
2633
  rubric?: undefined;
2650
2634
  flowVersion?: undefined;
2651
2635
  };
@@ -2857,6 +2841,9 @@ export declare const allTools: ({
2857
2841
  autoApproveFollowups?: undefined;
2858
2842
  enableFollowUps?: undefined;
2859
2843
  autoApproveReplies?: undefined;
2844
+ openerEndpointId?: undefined;
2845
+ replyEndpointId?: undefined;
2846
+ followUpEndpointId?: undefined;
2860
2847
  rubric?: undefined;
2861
2848
  flowVersion?: undefined;
2862
2849
  };
@@ -3089,6 +3076,18 @@ export declare const allTools: ({
3089
3076
  type: string;
3090
3077
  description: string;
3091
3078
  };
3079
+ openerEndpointId: {
3080
+ type: string[];
3081
+ description: string;
3082
+ };
3083
+ replyEndpointId: {
3084
+ type: string[];
3085
+ description: string;
3086
+ };
3087
+ followUpEndpointId: {
3088
+ type: string[];
3089
+ description: string;
3090
+ };
3092
3091
  senderIds: {
3093
3092
  type: string;
3094
3093
  items: {
@@ -3166,6 +3165,9 @@ export declare const allTools: ({
3166
3165
  autoApproveFollowups?: undefined;
3167
3166
  enableFollowUps?: undefined;
3168
3167
  autoApproveReplies?: undefined;
3168
+ openerEndpointId?: undefined;
3169
+ replyEndpointId?: undefined;
3170
+ followUpEndpointId?: undefined;
3169
3171
  rubric?: undefined;
3170
3172
  flowVersion?: undefined;
3171
3173
  };
@@ -3218,6 +3220,9 @@ export declare const allTools: ({
3218
3220
  autoApproveFollowups?: undefined;
3219
3221
  enableFollowUps?: undefined;
3220
3222
  autoApproveReplies?: undefined;
3223
+ openerEndpointId?: undefined;
3224
+ replyEndpointId?: undefined;
3225
+ followUpEndpointId?: undefined;
3221
3226
  rubric?: undefined;
3222
3227
  flowVersion?: undefined;
3223
3228
  };
@@ -8720,147 +8725,6 @@ export declare const allTools: ({
8720
8725
  };
8721
8726
  additionalProperties: boolean;
8722
8727
  };
8723
- } | {
8724
- readonly name: "customer_program";
8725
- readonly description: "Observe the home workspace campaign relationship stage, read prior complete daily or weekly campaign results, and retain campaign context. Scheduled stage_delivery grants native posting only when delivery.deliverNow is true; false means stay silent and reconcile. Save only newly learned campaign context or customer work/report preferences; campaign creation and editing stay in the create-campaign workflow. When the customer says where they are or wants updates at their own morning, call set_preferences with preferences.timezone (IANA, e.g. Europe/London); messages then go out at 08:00 and 09:00 their time on their working days. The customer gets one message a day. Some changes are made only in the Sellable web app at https://app.sellable.dev; when asked for one, give the exact link and say what to click: card, invoices and the plan (owner only): /settings?tab=billing; Slack channels, and restarting, stopping or removing the agent: /sellable-agent/connection; adding or reconnecting LinkedIn, daily limits and sending hours: /linkedin-accounts; reply settings for one campaign: /campaign-builder/{campaignId}/settings. Do everything else yourself with your tools.";
8726
- readonly inputSchema: {
8727
- readonly type: "object";
8728
- readonly properties: {
8729
- readonly action: {
8730
- readonly type: "string";
8731
- readonly enum: readonly ["observe", "save_context", "set_preferences", "claim_review", "daily_results", "weekly_review", "record_review_outcome", "stage_delivery", "reconcile_delivery", "retry_delivery"];
8732
- };
8733
- readonly context: {
8734
- readonly type: "object";
8735
- readonly additionalProperties: false;
8736
- readonly properties: {
8737
- readonly linkedinProfileUrl: {
8738
- readonly type: readonly ["string", "null"];
8739
- };
8740
- readonly companyContext: {
8741
- readonly type: readonly ["string", "null"];
8742
- };
8743
- readonly icpContext: {
8744
- readonly type: readonly ["string", "null"];
8745
- };
8746
- readonly voiceContext: {
8747
- readonly type: readonly ["string", "null"];
8748
- };
8749
- readonly dncState: {
8750
- readonly type: "string";
8751
- readonly enum: readonly ["unknown", "provided", "explicit_none"];
8752
- };
8753
- readonly selectedCampaignId: {
8754
- readonly type: readonly ["string", "null"];
8755
- };
8756
- readonly pendingDecisionRef: {
8757
- readonly type: readonly ["string", "null"];
8758
- };
8759
- readonly pendingOperationRef: {
8760
- readonly type: readonly ["string", "null"];
8761
- };
8762
- readonly pendingAsk: {
8763
- readonly type: readonly ["object", "null"];
8764
- readonly additionalProperties: false;
8765
- readonly properties: {
8766
- readonly identity: {
8767
- readonly type: "string";
8768
- };
8769
- readonly firstAskedAt: {
8770
- readonly type: "string";
8771
- };
8772
- readonly reminder48hAt: {
8773
- readonly type: readonly ["string", "null"];
8774
- };
8775
- readonly reminder7dAt: {
8776
- readonly type: readonly ["string", "null"];
8777
- };
8778
- readonly resolvedAt: {
8779
- readonly type: readonly ["string", "null"];
8780
- };
8781
- };
8782
- readonly required: readonly ["identity", "firstAskedAt", "reminder48hAt", "reminder7dAt", "resolvedAt"];
8783
- };
8784
- readonly launchConsent: {
8785
- readonly type: readonly ["object", "null"];
8786
- readonly additionalProperties: false;
8787
- readonly properties: {
8788
- readonly mode: {
8789
- readonly type: "string";
8790
- readonly enum: readonly ["autopilot", "review_first"];
8791
- };
8792
- readonly decidedAt: {
8793
- readonly type: "string";
8794
- };
8795
- };
8796
- readonly required: readonly ["mode", "decidedAt"];
8797
- };
8798
- };
8799
- };
8800
- readonly preferences: {
8801
- readonly type: "object";
8802
- readonly additionalProperties: false;
8803
- readonly properties: {
8804
- readonly workPaused: {
8805
- readonly type: "boolean";
8806
- };
8807
- readonly sendingPaused: {
8808
- readonly type: "boolean";
8809
- };
8810
- readonly dailyResultsMuted: {
8811
- readonly type: "boolean";
8812
- };
8813
- readonly weeklyReviewMuted: {
8814
- readonly type: "boolean";
8815
- };
8816
- readonly timezone: {
8817
- readonly type: "string";
8818
- readonly minLength: 1;
8819
- readonly maxLength: 100;
8820
- readonly description: "The customer's report time zone as an IANA name, e.g. Europe/London. Scheduled messages then go out at their own 08:00 and 09:00 on their working days.";
8821
- };
8822
- };
8823
- };
8824
- readonly trigger: {
8825
- readonly type: "string";
8826
- readonly enum: readonly ["scheduled", "interactive"];
8827
- };
8828
- readonly leaseOwner: {
8829
- readonly type: "string";
8830
- };
8831
- readonly effectId: {
8832
- readonly type: "string";
8833
- };
8834
- readonly fence: {
8835
- readonly type: "integer";
8836
- readonly minimum: 1;
8837
- };
8838
- readonly reviewAction: {
8839
- readonly type: "string";
8840
- readonly enum: readonly ["maintain", "refill", "continue", "edit", "propose_create", "input", "blocker"];
8841
- };
8842
- readonly summary: {
8843
- readonly type: "string";
8844
- };
8845
- readonly decisionRef: {
8846
- readonly type: readonly ["string", "null"];
8847
- };
8848
- readonly operationRef: {
8849
- readonly type: readonly ["string", "null"];
8850
- };
8851
- readonly text: {
8852
- readonly type: "string";
8853
- readonly minLength: 1;
8854
- readonly maxLength: 8000;
8855
- };
8856
- readonly includesDailyResults: {
8857
- readonly type: "boolean";
8858
- readonly description: "stage_delivery only: true when a daily review message already carries yesterday's numbers, so the 09:00 results message stays silent that day.";
8859
- };
8860
- };
8861
- readonly required: readonly ["action"];
8862
- readonly additionalProperties: false;
8863
- };
8864
8728
  } | {
8865
8729
  name: string;
8866
8730
  description: string;
@@ -9240,6 +9104,147 @@ export declare const allTools: ({
9240
9104
  required: string[];
9241
9105
  additionalProperties: boolean;
9242
9106
  };
9107
+ } | {
9108
+ readonly name: "customer_program";
9109
+ readonly description: "Observe the home workspace campaign relationship stage, read prior complete daily or weekly campaign results, and retain campaign context. Scheduled stage_delivery grants native posting only when delivery.deliverNow is true; false means stay silent and reconcile. Save only newly learned campaign context or customer work/report preferences; campaign creation and editing stay in the create-campaign workflow. When the customer says where they are or wants updates at their own morning, call set_preferences with preferences.timezone (IANA, e.g. Europe/London); messages then go out at 08:00 and 09:00 their time on their working days. The customer gets one message a day. Some changes are made only in the Sellable web app at https://app.sellable.dev; when asked for one, give the exact link and say what to click: card, invoices and the plan (owner only): /settings?tab=billing; Slack channels, and restarting, stopping or removing the agent: /sellable-agent/connection; adding or reconnecting LinkedIn, daily limits and sending hours: /linkedin-accounts; reply settings for one campaign: /campaign-builder/{campaignId}/settings. Do everything else yourself with your tools.";
9110
+ readonly inputSchema: {
9111
+ readonly type: "object";
9112
+ readonly properties: {
9113
+ readonly action: {
9114
+ readonly type: "string";
9115
+ readonly enum: readonly ["observe", "save_context", "set_preferences", "claim_review", "daily_results", "weekly_review", "record_review_outcome", "stage_delivery", "reconcile_delivery", "retry_delivery"];
9116
+ };
9117
+ readonly context: {
9118
+ readonly type: "object";
9119
+ readonly additionalProperties: false;
9120
+ readonly properties: {
9121
+ readonly linkedinProfileUrl: {
9122
+ readonly type: readonly ["string", "null"];
9123
+ };
9124
+ readonly companyContext: {
9125
+ readonly type: readonly ["string", "null"];
9126
+ };
9127
+ readonly icpContext: {
9128
+ readonly type: readonly ["string", "null"];
9129
+ };
9130
+ readonly voiceContext: {
9131
+ readonly type: readonly ["string", "null"];
9132
+ };
9133
+ readonly dncState: {
9134
+ readonly type: "string";
9135
+ readonly enum: readonly ["unknown", "provided", "explicit_none"];
9136
+ };
9137
+ readonly selectedCampaignId: {
9138
+ readonly type: readonly ["string", "null"];
9139
+ };
9140
+ readonly pendingDecisionRef: {
9141
+ readonly type: readonly ["string", "null"];
9142
+ };
9143
+ readonly pendingOperationRef: {
9144
+ readonly type: readonly ["string", "null"];
9145
+ };
9146
+ readonly pendingAsk: {
9147
+ readonly type: readonly ["object", "null"];
9148
+ readonly additionalProperties: false;
9149
+ readonly properties: {
9150
+ readonly identity: {
9151
+ readonly type: "string";
9152
+ };
9153
+ readonly firstAskedAt: {
9154
+ readonly type: "string";
9155
+ };
9156
+ readonly reminder48hAt: {
9157
+ readonly type: readonly ["string", "null"];
9158
+ };
9159
+ readonly reminder7dAt: {
9160
+ readonly type: readonly ["string", "null"];
9161
+ };
9162
+ readonly resolvedAt: {
9163
+ readonly type: readonly ["string", "null"];
9164
+ };
9165
+ };
9166
+ readonly required: readonly ["identity", "firstAskedAt", "reminder48hAt", "reminder7dAt", "resolvedAt"];
9167
+ };
9168
+ readonly launchConsent: {
9169
+ readonly type: readonly ["object", "null"];
9170
+ readonly additionalProperties: false;
9171
+ readonly properties: {
9172
+ readonly mode: {
9173
+ readonly type: "string";
9174
+ readonly enum: readonly ["autopilot", "review_first"];
9175
+ };
9176
+ readonly decidedAt: {
9177
+ readonly type: "string";
9178
+ };
9179
+ };
9180
+ readonly required: readonly ["mode", "decidedAt"];
9181
+ };
9182
+ };
9183
+ };
9184
+ readonly preferences: {
9185
+ readonly type: "object";
9186
+ readonly additionalProperties: false;
9187
+ readonly properties: {
9188
+ readonly workPaused: {
9189
+ readonly type: "boolean";
9190
+ };
9191
+ readonly sendingPaused: {
9192
+ readonly type: "boolean";
9193
+ };
9194
+ readonly dailyResultsMuted: {
9195
+ readonly type: "boolean";
9196
+ };
9197
+ readonly weeklyReviewMuted: {
9198
+ readonly type: "boolean";
9199
+ };
9200
+ readonly timezone: {
9201
+ readonly type: "string";
9202
+ readonly minLength: 1;
9203
+ readonly maxLength: 100;
9204
+ readonly description: "The customer's report time zone as an IANA name, e.g. Europe/London. Scheduled messages then go out at their own 08:00 and 09:00 on their working days.";
9205
+ };
9206
+ };
9207
+ };
9208
+ readonly trigger: {
9209
+ readonly type: "string";
9210
+ readonly enum: readonly ["scheduled", "interactive"];
9211
+ };
9212
+ readonly leaseOwner: {
9213
+ readonly type: "string";
9214
+ };
9215
+ readonly effectId: {
9216
+ readonly type: "string";
9217
+ };
9218
+ readonly fence: {
9219
+ readonly type: "integer";
9220
+ readonly minimum: 1;
9221
+ };
9222
+ readonly reviewAction: {
9223
+ readonly type: "string";
9224
+ readonly enum: readonly ["maintain", "refill", "continue", "edit", "propose_create", "input", "blocker"];
9225
+ };
9226
+ readonly summary: {
9227
+ readonly type: "string";
9228
+ };
9229
+ readonly decisionRef: {
9230
+ readonly type: readonly ["string", "null"];
9231
+ };
9232
+ readonly operationRef: {
9233
+ readonly type: readonly ["string", "null"];
9234
+ };
9235
+ readonly text: {
9236
+ readonly type: "string";
9237
+ readonly minLength: 1;
9238
+ readonly maxLength: 8000;
9239
+ };
9240
+ readonly includesDailyResults: {
9241
+ readonly type: "boolean";
9242
+ readonly description: "stage_delivery only: true when a daily review message already carries yesterday's numbers, so the 09:00 results message stays silent that day.";
9243
+ };
9244
+ };
9245
+ readonly required: readonly ["action"];
9246
+ readonly additionalProperties: false;
9247
+ };
9243
9248
  } | {
9244
9249
  name: string;
9245
9250
  description: string;
@@ -1,5 +1,4 @@
1
1
  import { agentEndpointToolDefinitions } from "./agent-endpoints.js";
2
- import { agentGenerationRoutingToolDefinitions } from "./agent-generation-routing.js";
3
2
  import { agentSoulToolDefinitions } from "./agent-soul.js";
4
3
  import { authToolDefinitions } from "./auth.js";
5
4
  import { blueprintCommitToolDefinitions } from "./blueprint-commit.js";
@@ -18,9 +17,9 @@ import { columnReorderToolDefinitions } from "./column-reorder.js";
18
17
  import { columnSchemaToolDefinitions } from "./column-schema.js";
19
18
  import { columnUpdateToolDefinitions } from "./column-update.js";
20
19
  import { companyInfoToolDefinitions } from "./company-info.js";
21
- import { customerProgramToolDefinitions } from "./customer-program.js";
22
20
  import { contentPostToolDefinitions } from "./content-posts.js";
23
21
  import { contextToolDefinitions } from "./context.js";
22
+ import { customerProgramToolDefinitions } from "./customer-program.js";
24
23
  import { directCampaignToolDefinitions } from "./direct-campaigns.js";
25
24
  import { engageBootstrapToolDefinitions } from "./engage-bootstrap.js";
26
25
  import { engageDiscoveryToolDefinitions } from "./engage-discovery.js";
@@ -125,7 +124,6 @@ export const allTools = [
125
124
  ...companyInfoToolDefinitions,
126
125
  ...customerProgramToolDefinitions,
127
126
  ...senderRoutingToolDefinitions,
128
- ...agentGenerationRoutingToolDefinitions,
129
127
  ...senderToolDefinitions,
130
128
  ...engageStateToolDefinitions,
131
129
  ...engageMemoryToolDefinitions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.959",
3
+ "version": "0.1.960-wip.writers.20261007.1",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",
@@ -9,7 +9,7 @@ names, for them.
9
9
  Sellable writes each message from the person's profile; it carries no pitch
10
10
  and no ask, and the offer comes up once they reply. Choose it when replies
11
11
  have an owner: reply drafting is on for the campaign (the default), so each
12
- reply arrives as a draft to approve, or the workspace's Reply Agent answers.
12
+ reply arrives as a draft to approve.
13
13
  Best for fewer, higher-value prospects, where you want replies you can talk with.
14
14
  - **Message Testing** (`messageApproach: "message_test"`). You approve one message, it goes to everyone, and you see which wording gets replies.
15
15
  This is the template flow described in the create-campaign-v2 prompt and
@@ -24,13 +24,20 @@ the right to pitch."
24
24
  When the customer has not said, use Conversations if replies have an owner and
25
25
  Message Testing otherwise. "Same message to everyone", "test my copy" or "I
26
26
  want to approve the wording" means Message Testing. "Write each one",
27
- "personal", "conversational" or "use the reply agent" means Conversations.
27
+ "personal" or "conversational" means Conversations.
28
28
  Change an existing campaign with `update_campaign({ campaignId,
29
29
  messageApproach })`; the customer can also change it in the app. Both
30
30
  approaches draft new copy with the same writing skill, `draft-message`; the
31
31
  approach decides whether one approved message goes to everyone or each person
32
32
  gets their own.
33
33
 
34
+ **Who writes each message.** A campaign chooses its writers: First message,
35
+ Replies and Follow-ups. Each is Sellable unless the customer picks one of their
36
+ Sellable Agent's endpoints (their own prompt, which can use their agent's
37
+ tools). Read them with get_campaign (`writers`) and change them with
38
+ update_campaign (`openerEndpointId`, `replyEndpointId`, `followUpEndpointId`;
39
+ null = Sellable). Never choose an endpoint the customer did not ask for.
40
+
34
41
  **A Conversations campaign has no template.** The backend writes each message
35
42
  only when the campaign carries no approved template, so:
36
43
 
@@ -0,0 +1,42 @@
1
+ {
2
+ "schemaVersion": "conversation-chess-compiled/v1",
3
+ "compilerSha256": "8ae72b0245fff2ee08d0b6e7ec1ba611956a8ac194f091bf4c35e71fe0ef4ffb",
4
+ "selectedModes": [
5
+ "FOLLOW_UP"
6
+ ],
7
+ "sourceHashes": {
8
+ "core/input-contract.md": "78df4f3f0607b3d5d8d747f19fed60be6a1d10443854741b00af9503a539a6ba",
9
+ "core/situation-index.json": "436c319507fb6374fadf691ffd14b742886b6d0a1bddf03bccdc75c11473efb8",
10
+ "references/rapport.md": "445239a872dae24d9f8ee1c315b97e5f953478684b4941143024bc7af396a78f",
11
+ "modes/follow-up.md": "bc1a416cbbfe97845f92e9ae447f040c27c2733a77516e64b5ed536c661790c8"
12
+ },
13
+ "exampleIds": [
14
+ "F-BOOK",
15
+ "F-VALUE",
16
+ "F-SMALL",
17
+ "F-OWED",
18
+ "F-TIMING",
19
+ "F-NONE"
20
+ ],
21
+ "limits": {
22
+ "packUtf8Bytes": 22700
23
+ },
24
+ "compositionValidation": "Policy bytes only; caller separately validates its fully composed request.",
25
+ "outputs": {
26
+ "references/follow-ups.md": {
27
+ "sha256": "09a7688d165addf56f17f27c5978fda05684b382b4d6cf86a8351aad4cc61413",
28
+ "utf8Bytes": 3453,
29
+ "utf16Characters": 3429
30
+ },
31
+ "compiled/follow-up/endpoint.md": {
32
+ "sha256": "c81746801468832fe05ec996756dc550b6138683f89326578d5d0d9e2deb77ca",
33
+ "utf8Bytes": 8726,
34
+ "utf16Characters": 8692
35
+ },
36
+ "compiled/follow-up/semantic.md": {
37
+ "sha256": "9db268a5d21811e4ac0b45b651f7439eb2da8eff99e47381eb9c7c2e531efc37",
38
+ "utf8Bytes": 8417,
39
+ "utf16Characters": 8385
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "schemaVersion": "conversation-chess-compiled/v1",
3
+ "compilerSha256": "8ae72b0245fff2ee08d0b6e7ec1ba611956a8ac194f091bf4c35e71fe0ef4ffb",
4
+ "selectedModes": [
5
+ "OPENER"
6
+ ],
7
+ "sourceHashes": {
8
+ "core/input-contract.md": "78df4f3f0607b3d5d8d747f19fed60be6a1d10443854741b00af9503a539a6ba",
9
+ "core/situation-index.json": "436c319507fb6374fadf691ffd14b742886b6d0a1bddf03bccdc75c11473efb8",
10
+ "references/rapport.md": "445239a872dae24d9f8ee1c315b97e5f953478684b4941143024bc7af396a78f",
11
+ "modes/opener.md": "6a755cb3459f5850f9680afc78170d68cc8eeaff3f2c9e43905b23a95b4ebad5",
12
+ "references/opener-editor.md": "db87d122cb34b4e16f818621aca2335134ab2549162095400c1ccf09ca704e9b"
13
+ },
14
+ "exampleIds": [
15
+ "O-HUMAN",
16
+ "O-HUMAN-QUESTION",
17
+ "O-THIRD",
18
+ "O-WARM-WORK",
19
+ "O-WARM-SHORT",
20
+ "O-OWN",
21
+ "O-THIRD-COMMENT",
22
+ "O-WORK",
23
+ "O-CONTRAST",
24
+ "O-ARTIFACT",
25
+ "O-SPARSE",
26
+ "O-RESOURCE",
27
+ "O-WARM-HUMAN",
28
+ "O-WARM-INTEREST",
29
+ "O-CREATIVE",
30
+ "O-CHOICE"
31
+ ],
32
+ "limits": {
33
+ "packUtf8Bytes": 22700
34
+ },
35
+ "compositionValidation": "Policy bytes only; caller separately validates its fully composed request.",
36
+ "outputs": {
37
+ "references/openers.md": {
38
+ "sha256": "1505140055b437eb1a90f89d4829e5c3f3d15903feac263a415b973e32a0c996",
39
+ "utf8Bytes": 15916,
40
+ "utf16Characters": 15776
41
+ },
42
+ "compiled/opener/endpoint.md": {
43
+ "sha256": "ac515f8e5eeca13b18a18a2e72c3a0e0a6bc46b63f108f766efc1b869620ddc8",
44
+ "utf8Bytes": 22694,
45
+ "utf16Characters": 22548
46
+ },
47
+ "compiled/opener/semantic.md": {
48
+ "sha256": "6929c7f351a81e006aae335b7e47f5beabc4e33f795052c54bd3e458626228f9",
49
+ "utf8Bytes": 22385,
50
+ "utf16Characters": 22241
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "schemaVersion": "conversation-chess-compiled/v1",
3
+ "compilerSha256": "8ae72b0245fff2ee08d0b6e7ec1ba611956a8ac194f091bf4c35e71fe0ef4ffb",
4
+ "selectedModes": [
5
+ "REPLY"
6
+ ],
7
+ "sourceHashes": {
8
+ "core/input-contract.md": "78df4f3f0607b3d5d8d747f19fed60be6a1d10443854741b00af9503a539a6ba",
9
+ "core/situation-index.json": "436c319507fb6374fadf691ffd14b742886b6d0a1bddf03bccdc75c11473efb8",
10
+ "references/rapport.md": "445239a872dae24d9f8ee1c315b97e5f953478684b4941143024bc7af396a78f",
11
+ "modes/reply.md": "8d0e8e7fc4b45e076aac309ac217c2520424a06e01f8c5adbcf2cd436730ddf7"
12
+ },
13
+ "exampleIds": [
14
+ "R-HUMAN",
15
+ "R-CONFIRM",
16
+ "R-MIXED",
17
+ "R-ANSWER",
18
+ "R-PROVENANCE",
19
+ "R-EXPLAIN",
20
+ "R-OBJECTION",
21
+ "R-TIMING",
22
+ "R-INTENT",
23
+ "R-CLOSE",
24
+ "R-SAMPLE",
25
+ "R-CHANNEL"
26
+ ],
27
+ "limits": {
28
+ "packUtf8Bytes": 22700
29
+ },
30
+ "compositionValidation": "Policy bytes only; caller separately validates its fully composed request.",
31
+ "outputs": {
32
+ "references/replies.md": {
33
+ "sha256": "33d0f91acdd8b33a8828a66214dc74029ba986fc09e9e1f37dcd29098e5ccded",
34
+ "utf8Bytes": 7391,
35
+ "utf16Characters": 7363
36
+ },
37
+ "compiled/reply/endpoint.md": {
38
+ "sha256": "067abd6a6270d3a09d1ec8fbebfe38e061e46f762693e61bb59a412d7e31861d",
39
+ "utf8Bytes": 12477,
40
+ "utf16Characters": 12431
41
+ },
42
+ "compiled/reply/semantic.md": {
43
+ "sha256": "f3dc1d637a3629e1f80750af1ff856a9cb9a036e871fed1540da2f8b43462684",
44
+ "utf8Bytes": 12168,
45
+ "utf16Characters": 12124
46
+ }
47
+ }
48
+ }
@@ -12,7 +12,8 @@ three-candidate, finalizer or writer-agent recipe. Explicit operator instruction
12
12
  and approved template authority remain intact; no new writing-strategy flag exists.
13
13
  `useMessagingTemplate` and `messagingModeChoice` are review/delivery choices.
14
14
  A Conversations campaign (`messageApproach: "conversation"`) has no template
15
- and skips Mode 0; its first messages are written per row by the backend.
15
+ and skips Mode 0; its first messages are written per row by the campaign's
16
+ first-message writer (Sellable unless the campaign chose an endpoint).
16
17
 
17
18
  ## Execution Modes
18
19
 
@@ -1,103 +0,0 @@
1
- type GenerationFlags = {
2
- openerEnabled: boolean;
3
- replyEnabled: boolean;
4
- followUpEnabled: boolean;
5
- };
6
- type GenerationRouting = {
7
- workspaceId: string;
8
- agentId: string;
9
- generation: number;
10
- endpointId: string;
11
- openerEndpointId: string | null;
12
- currentPublishedRevisionId: string | null;
13
- flags: GenerationFlags;
14
- };
15
- type SetFlagsInput = {
16
- expectedGeneration?: unknown;
17
- openerEnabled?: unknown;
18
- replyEnabled?: unknown;
19
- followUpEnabled?: unknown;
20
- workspaceId?: unknown;
21
- };
22
- export declare const agentGenerationRoutingToolDefinitions: ({
23
- name: string;
24
- description: string;
25
- inputSchema: {
26
- type: string;
27
- properties: {
28
- workspaceId: {
29
- type: string;
30
- description: string;
31
- };
32
- expectedGeneration?: undefined;
33
- openerEnabled?: undefined;
34
- replyEnabled?: undefined;
35
- followUpEnabled?: undefined;
36
- };
37
- required: never[];
38
- additionalProperties: boolean;
39
- };
40
- annotations?: undefined;
41
- } | {
42
- name: string;
43
- description: string;
44
- inputSchema: {
45
- type: string;
46
- properties: {
47
- expectedGeneration: {
48
- type: string;
49
- minimum: number;
50
- description: string;
51
- };
52
- openerEnabled: {
53
- type: string;
54
- };
55
- replyEnabled: {
56
- type: string;
57
- };
58
- followUpEnabled: {
59
- type: string;
60
- };
61
- workspaceId: {
62
- type: string;
63
- description: string;
64
- };
65
- };
66
- required: string[];
67
- additionalProperties: boolean;
68
- };
69
- annotations: {
70
- readOnlyHint: boolean;
71
- destructiveHint: boolean;
72
- idempotentHint: boolean;
73
- openWorldHint: boolean;
74
- };
75
- })[];
76
- export declare function getAgentGenerationRoutingTool(input?: {
77
- workspaceId?: string;
78
- }): Promise<{
79
- ok: false;
80
- code: string;
81
- message: string;
82
- } | {
83
- ok: true;
84
- routing: GenerationRouting;
85
- }>;
86
- export declare function setAgentGenerationFlagsTool(input?: SetFlagsInput): Promise<{
87
- ok: false;
88
- code: string;
89
- message: string;
90
- } | {
91
- ok: true;
92
- before: {
93
- generation: number;
94
- flags: GenerationFlags;
95
- };
96
- after: {
97
- generation: number;
98
- flags: GenerationFlags;
99
- };
100
- routing: GenerationRouting;
101
- note: string;
102
- }>;
103
- export {};
@@ -1,147 +0,0 @@
1
- import { getApi, SellableApiError } from "../api.js";
2
- import { workspaceRequestOptions } from "./workspace-context.js";
3
- const ROUTE = "/api/v3/sellable-agent/product-generation";
4
- const FLAG_KEYS = ["openerEnabled", "replyEnabled", "followUpEnabled"];
5
- export const agentGenerationRoutingToolDefinitions = [
6
- {
7
- name: "get_agent_generation_routing",
8
- description: "Read the workspace Sellable Agent's message-generation routing: the opener, reply, and follow-up flags plus the current generation number and endpoint ids. Read this before set_agent_generation_flags and pass its generation as expectedGeneration.",
9
- inputSchema: {
10
- type: "object",
11
- properties: {
12
- workspaceId: {
13
- type: "string",
14
- description: "Explicit request-scoped workspace id.",
15
- },
16
- },
17
- required: [],
18
- additionalProperties: false,
19
- },
20
- },
21
- {
22
- name: "set_agent_generation_flags",
23
- description: "Turn the workspace Sellable Agent's opener, reply, or follow-up generation on or off. Only the flags you pass change; the others and the endpoint ids are preserved. Requires expectedGeneration from get_agent_generation_routing (compare-before-write). Turning openerEnabled off stops NEW campaigns from defaulting to the Agent opener. Existing campaigns keep their per-column messageGenerator setting until that Generate Message column is switched to STANDARD.",
24
- inputSchema: {
25
- type: "object",
26
- properties: {
27
- expectedGeneration: {
28
- type: "integer",
29
- minimum: 0,
30
- description: "The generation returned by get_agent_generation_routing.",
31
- },
32
- openerEnabled: { type: "boolean" },
33
- replyEnabled: { type: "boolean" },
34
- followUpEnabled: { type: "boolean" },
35
- workspaceId: {
36
- type: "string",
37
- description: "Explicit target workspace id.",
38
- },
39
- },
40
- required: ["expectedGeneration"],
41
- additionalProperties: false,
42
- },
43
- annotations: {
44
- readOnlyHint: false,
45
- destructiveHint: false,
46
- idempotentHint: true,
47
- openWorldHint: false,
48
- },
49
- },
50
- ];
51
- function isRouting(value) {
52
- const routing = value;
53
- return (!!routing &&
54
- typeof routing.generation === "number" &&
55
- typeof routing.endpointId === "string" &&
56
- !!routing.flags &&
57
- FLAG_KEYS.every((key) => typeof routing.flags[key] === "boolean"));
58
- }
59
- function failure(code, message, extra = {}) {
60
- return { ok: false, code, message, ...extra };
61
- }
62
- function describeError(error) {
63
- if (error instanceof SellableApiError) {
64
- let code = `http_${error.status}`;
65
- try {
66
- const parsed = JSON.parse(error.body);
67
- if (typeof parsed.error === "string" && /^[a-z0-9_]+$/.test(parsed.error))
68
- code = parsed.error;
69
- }
70
- catch {
71
- // Keep the HTTP status code.
72
- }
73
- return failure(code, error.isAuthError
74
- ? "Sellable authentication or authorization failed. OWNER or ADMIN access to the workspace is required."
75
- : `The routing request failed (${error.status}).`, { status: error.status, uncertain: error.status >= 500 });
76
- }
77
- return failure("request_failed", error instanceof Error ? error.message : "The routing request failed.");
78
- }
79
- export async function getAgentGenerationRoutingTool(input = {}) {
80
- try {
81
- const response = await getApi().get(ROUTE, workspaceRequestOptions(input.workspaceId));
82
- if (!isRouting(response?.routing)) {
83
- return failure("malformed_routing_response", "The routing response was incomplete.");
84
- }
85
- return { ok: true, routing: response.routing };
86
- }
87
- catch (error) {
88
- return describeError(error);
89
- }
90
- }
91
- export async function setAgentGenerationFlagsTool(input = {}) {
92
- const changes = {};
93
- for (const key of FLAG_KEYS) {
94
- const value = input[key];
95
- if (value === undefined)
96
- continue;
97
- if (typeof value !== "boolean") {
98
- return failure("invalid_arguments", `${key} must be a boolean.`);
99
- }
100
- changes[key] = value;
101
- }
102
- if (typeof input.expectedGeneration !== "number" ||
103
- !Number.isInteger(input.expectedGeneration) ||
104
- input.expectedGeneration < 0) {
105
- return failure("invalid_arguments", "expectedGeneration is required. Read it from get_agent_generation_routing.");
106
- }
107
- if (Object.keys(changes).length === 0) {
108
- return failure("invalid_arguments", "Pass at least one of openerEnabled, replyEnabled, or followUpEnabled.");
109
- }
110
- const workspaceId = typeof input.workspaceId === "string" ? input.workspaceId : undefined;
111
- const current = await getAgentGenerationRoutingTool({ workspaceId });
112
- if (!current.ok)
113
- return current;
114
- const before = current.routing;
115
- if (before.generation !== input.expectedGeneration) {
116
- return failure("generation_conflict", "The routing changed after it was read. Reread it and retry with the current generation.", { currentGeneration: before.generation, flags: before.flags });
117
- }
118
- const flags = { ...before.flags, ...changes };
119
- try {
120
- const response = await getApi().put(ROUTE, {
121
- expectedGeneration: before.generation,
122
- endpointId: before.endpointId,
123
- ...(before.openerEndpointId
124
- ? { openerEndpointId: before.openerEndpointId }
125
- : {}),
126
- flags,
127
- }, workspaceRequestOptions(workspaceId));
128
- if (!isRouting(response?.routing)) {
129
- return failure("malformed_routing_response", "The update returned an incomplete receipt, so the final state is uncertain. Reread get_agent_generation_routing before retrying.", { uncertain: true });
130
- }
131
- return {
132
- ok: true,
133
- before: { generation: before.generation, flags: before.flags },
134
- after: {
135
- generation: response.routing.generation,
136
- flags: response.routing.flags,
137
- },
138
- routing: response.routing,
139
- note: flags.openerEnabled
140
- ? "Agent openers are on for new campaigns."
141
- : "New campaigns will use the standard template generator. Existing campaigns keep their own Generate Message setting.",
142
- };
143
- }
144
- catch (error) {
145
- return describeError(error);
146
- }
147
- }