@mj-biz-apps/marketing-server 0.0.0 → 0.2.0

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.
Files changed (87) hide show
  1. package/LICENSE +183 -0
  2. package/dist/agents/BaseMarketingAgent.d.ts +120 -0
  3. package/dist/agents/BaseMarketingAgent.d.ts.map +1 -0
  4. package/dist/agents/BaseMarketingAgent.js +323 -0
  5. package/dist/agents/BaseMarketingAgent.js.map +1 -0
  6. package/dist/agents/MarketingExperimentationAgent.d.ts +123 -0
  7. package/dist/agents/MarketingExperimentationAgent.d.ts.map +1 -0
  8. package/dist/agents/MarketingExperimentationAgent.js +371 -0
  9. package/dist/agents/MarketingExperimentationAgent.js.map +1 -0
  10. package/dist/agents/MarketingOperationsAgent.d.ts +24 -0
  11. package/dist/agents/MarketingOperationsAgent.d.ts.map +1 -0
  12. package/dist/agents/MarketingOperationsAgent.js +36 -0
  13. package/dist/agents/MarketingOperationsAgent.js.map +1 -0
  14. package/dist/agents/MarketingPodcastIngestionAgent.d.ts +21 -0
  15. package/dist/agents/MarketingPodcastIngestionAgent.d.ts.map +1 -0
  16. package/dist/agents/MarketingPodcastIngestionAgent.js +33 -0
  17. package/dist/agents/MarketingPodcastIngestionAgent.js.map +1 -0
  18. package/dist/agents/MarketingStrategyOnboardingAgent.d.ts +206 -0
  19. package/dist/agents/MarketingStrategyOnboardingAgent.d.ts.map +1 -0
  20. package/dist/agents/MarketingStrategyOnboardingAgent.js +1264 -0
  21. package/dist/agents/MarketingStrategyOnboardingAgent.js.map +1 -0
  22. package/dist/agents/index.d.ts +14 -0
  23. package/dist/agents/index.d.ts.map +1 -0
  24. package/dist/agents/index.js +25 -0
  25. package/dist/agents/index.js.map +1 -0
  26. package/dist/config.d.ts +6 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +6 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/generated/class-registrations-manifest.d.ts +7 -0
  31. package/dist/generated/class-registrations-manifest.d.ts.map +1 -0
  32. package/dist/generated/class-registrations-manifest.js +7 -0
  33. package/dist/generated/class-registrations-manifest.js.map +1 -0
  34. package/dist/generated/generated.d.ts +7 -0
  35. package/dist/generated/generated.d.ts.map +1 -0
  36. package/dist/generated/generated.js +7 -0
  37. package/dist/generated/generated.js.map +1 -0
  38. package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.d.ts +3522 -0
  39. package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.d.ts.map +1 -0
  40. package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.js +18854 -0
  41. package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.js.map +1 -0
  42. package/dist/index.d.ts +33 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +107 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/programs/ContentPostProgramDriver.d.ts +44 -0
  47. package/dist/programs/ContentPostProgramDriver.d.ts.map +1 -0
  48. package/dist/programs/ContentPostProgramDriver.js +185 -0
  49. package/dist/programs/ContentPostProgramDriver.js.map +1 -0
  50. package/dist/programs/EmailProgramDriver.d.ts +56 -0
  51. package/dist/programs/EmailProgramDriver.d.ts.map +1 -0
  52. package/dist/programs/EmailProgramDriver.js +224 -0
  53. package/dist/programs/EmailProgramDriver.js.map +1 -0
  54. package/dist/programs/google/GoogleAdsClient.d.ts +93 -0
  55. package/dist/programs/google/GoogleAdsClient.d.ts.map +1 -0
  56. package/dist/programs/google/GoogleAdsClient.js +279 -0
  57. package/dist/programs/google/GoogleAdsClient.js.map +1 -0
  58. package/dist/programs/google/GoogleAdsProgramDriver.d.ts +56 -0
  59. package/dist/programs/google/GoogleAdsProgramDriver.d.ts.map +1 -0
  60. package/dist/programs/google/GoogleAdsProgramDriver.js +357 -0
  61. package/dist/programs/google/GoogleAdsProgramDriver.js.map +1 -0
  62. package/dist/programs/google/googleAdsExecutionContext.d.ts +47 -0
  63. package/dist/programs/google/googleAdsExecutionContext.d.ts.map +1 -0
  64. package/dist/programs/google/googleAdsExecutionContext.js +128 -0
  65. package/dist/programs/google/googleAdsExecutionContext.js.map +1 -0
  66. package/dist/programs/google/googleBrandAssets.d.ts +27 -0
  67. package/dist/programs/google/googleBrandAssets.d.ts.map +1 -0
  68. package/dist/programs/google/googleBrandAssets.js +81 -0
  69. package/dist/programs/google/googleBrandAssets.js.map +1 -0
  70. package/dist/programs/index.d.ts +18 -0
  71. package/dist/programs/index.d.ts.map +1 -0
  72. package/dist/programs/index.js +27 -0
  73. package/dist/programs/index.js.map +1 -0
  74. package/dist/programs/linkedin/LinkedInAdsClient.d.ts +145 -0
  75. package/dist/programs/linkedin/LinkedInAdsClient.d.ts.map +1 -0
  76. package/dist/programs/linkedin/LinkedInAdsClient.js +408 -0
  77. package/dist/programs/linkedin/LinkedInAdsClient.js.map +1 -0
  78. package/dist/programs/linkedin/LinkedInAdsProgramDriver.d.ts +94 -0
  79. package/dist/programs/linkedin/LinkedInAdsProgramDriver.d.ts.map +1 -0
  80. package/dist/programs/linkedin/LinkedInAdsProgramDriver.js +449 -0
  81. package/dist/programs/linkedin/LinkedInAdsProgramDriver.js.map +1 -0
  82. package/dist/programs/linkedin/linkedInExecutionContext.d.ts +42 -0
  83. package/dist/programs/linkedin/linkedInExecutionContext.d.ts.map +1 -0
  84. package/dist/programs/linkedin/linkedInExecutionContext.js +97 -0
  85. package/dist/programs/linkedin/linkedInExecutionContext.js.map +1 -0
  86. package/package.json +46 -7
  87. package/index.js +0 -1
@@ -0,0 +1,123 @@
1
+ import type { AgentConfiguration, AIPromptParams, ExecuteAgentParams, BaseAgentNextStep, MJAIAgentRunEntityExtended, MJAIAgentRunStepEntityExtended } from '@memberjunction/ai-core-plus';
2
+ import { BaseMarketingAgent } from './BaseMarketingAgent.js';
3
+ /**
4
+ * Marketing Programs Agent — driver class.
5
+ *
6
+ * The `MJ: AI Agents` metadata row has declared `DriverClass = MarketingExperimentationAgent`
7
+ * since the agent was seeded, but no such class existed, so MJ's ClassFactory silently fell back
8
+ * to plain `BaseAgent` and none of the doctrine below was enforced. (Exactly what had happened to
9
+ * MarketingStrategyOnboardingAgent before its driver class was written.)
10
+ *
11
+ * PRD §4 is binding on this agent, and the division of labour follows from it:
12
+ *
13
+ * * "Code owns numbers and dates" — the agent NEVER computes a metric, a threshold comparison,
14
+ * or a decision. `findingSynthesis` composes the factual finding from measured values before
15
+ * the agent is consulted.
16
+ * * "No invented evidence" — the agent's only contribution to a Learning is the MECHANISM, the
17
+ * causal reading that code cannot derive. It passes through `enrichFinding`, which rejects any
18
+ * interpretation citing a number that is not among the measured facts, or asserting an outcome
19
+ * that contradicts the recorded decision.
20
+ * * "Flow-critical outcomes run in post-hooks, never as optional LLM tool calls" — the learning
21
+ * write happens in `validateSuccessNextStep` below. It is not a tool the model may decline to
22
+ * call, because a decision that produces no Learning is the failure mode this whole framework
23
+ * exists to prevent.
24
+ * * "The prompt narrates published state" — the agent may not claim a program launched or
25
+ * decided. Those transitions belong to the lifecycle service, which the agent does not call.
26
+ */
27
+ export declare class MarketingExperimentationAgent extends BaseMarketingAgent {
28
+ /**
29
+ * Payload key the prompt writes its causal reading into.
30
+ *
31
+ * Deliberately named for what it is. The model is asked for a mechanism WITHOUT numbers — the
32
+ * numbers are already in the factual sentence this gets appended to, and every number the model
33
+ * adds is one more thing the guard has to reject.
34
+ */
35
+ private static readonly INTERPRETATION_KEY;
36
+ /** Payload key naming which decided program the interpretation is about. */
37
+ private static readonly PROGRAM_KEY;
38
+ /**
39
+ * Injects the program knowledge base before every prompt turn.
40
+ *
41
+ * This is what makes the agent propose FROM evidence rather than from the strategy document
42
+ * plus its own priors. It runs on every turn, deterministically, in code — not as a tool the
43
+ * model may choose to call, because an agent that can decline to look at prior results will
44
+ * eventually propose something that was already killed.
45
+ *
46
+ * Exposed to the template as `{{ programKnowledge }}`. A load failure is logged and the turn
47
+ * proceeds WITHOUT the block rather than aborting: losing the history degrades proposal
48
+ * quality, while failing the run loses the turn entirely. The block is self-describing, so its
49
+ * absence cannot be mistaken by the model for "there is no history".
50
+ */
51
+ protected preparePromptParams<P>(config: AgentConfiguration, payload: P, params: ExecuteAgentParams): Promise<AIPromptParams>;
52
+ /**
53
+ * The text findings are ranked against, drawn from the conversation.
54
+ *
55
+ * The obvious candidate — the draft hypothesis — does not exist yet: this runs BEFORE the model
56
+ * writes anything. What does exist is the user's request, which is what the turn is about, so it
57
+ * is the honest relevance signal available at this point.
58
+ *
59
+ * Returns null for a short or generic request ("review the programs", "what next?"). Ranking
60
+ * against those would narrow the corpus on noise, and a narrowed corpus is strictly worse than
61
+ * the full one when the query carries no topic — the model would lose evidence and be told the
62
+ * remainder was "most relevant".
63
+ */
64
+ private retrievalQuery;
65
+ /**
66
+ * Post-hook: fold the agent's mechanism into the Learning the decision already recorded.
67
+ *
68
+ * Runs after a successful step, so it sees the payload the model produced. Everything it needs
69
+ * beyond that comes from the database, never from the model: the program's own numbers, and
70
+ * the Learning row the writeback wrote.
71
+ *
72
+ * Failures here are logged and swallowed. A missing mechanism leaves a Learning that is still
73
+ * true and still cites its numbers; aborting the agent run over it would trade a complete
74
+ * record for no record.
75
+ */
76
+ protected validateSuccessNextStep<P>(params: ExecuteAgentParams, nextStep: BaseAgentNextStep<P>, currentPayload: P, agentRun: MJAIAgentRunEntityExtended, currentStep: MJAIAgentRunStepEntityExtended): Promise<BaseAgentNextStep<P>>;
77
+ /** A turn that ends by asking the user something can still have proposed — same stamp. */
78
+ protected validateChatNextStep<P>(params: ExecuteAgentParams, nextStep: BaseAgentNextStep<P>, currentPayload: P, agentRun: MJAIAgentRunEntityExtended, currentStep: MJAIAgentRunStepEntityExtended): Promise<BaseAgentNextStep<P>>;
79
+ /**
80
+ * Decides, in code, whether this run may SAVE a proposal or only DRAFT one.
81
+ *
82
+ * Inside the in-app Assistant a person is reading the proposal as it is written, so the
83
+ * Program row is theirs to create: the run drafts (`Propose Program` with `DraftOnly=true`)
84
+ * and the proposal card's Approve click commits. Everywhere else — the hourly agent, sprint
85
+ * end, a scheduled job — nobody is watching, and a draft nobody can see would simply be lost,
86
+ * so those runs commit directly and queue for approval as before.
87
+ *
88
+ * The Assistant is recognised by the app context it sends (the same signal that makes the
89
+ * brand picker authoritative). The template reads `proposalMode`; it does not decide it.
90
+ */
91
+ protected initializeStartingPayload<P = unknown>(params: ExecuteAgentParams<unknown, P>): Promise<void>;
92
+ /**
93
+ * Stamps what THIS run proposed onto the payload, as `proposals`.
94
+ *
95
+ * The payload is what the conversation renders as the run's artifact, and the proposal card
96
+ * is drawn from this list. It is built from the run's own recorded `Propose Program` action
97
+ * results — never from the model's account of what it did ("the prompt narrates published
98
+ * state"):
99
+ * * DRAFTED → the full validated draft rides along, because no row exists to load. The card
100
+ * renders it, and re-submits exactly these inputs when the user approves.
101
+ * * SUCCESS → a committed program; ids only, and the card loads the row live.
102
+ * A failed or blocked call produced no proposal and is skipped.
103
+ */
104
+ private attachProposals;
105
+ /** One recorded `Propose Program` result → a proposal reference, or null when it produced none. */
106
+ private proposalFromStep;
107
+ /**
108
+ * Applies the model's mechanism to the most recent Learning for the named program.
109
+ *
110
+ * No-ops silently when the payload carries no interpretation — the agent has other jobs
111
+ * (proposing), and only the decision-interpretation turn produces one.
112
+ */
113
+ private applyLearningInterpretation;
114
+ /**
115
+ * `Program.Decision` is title-case ('Keep'); the writeback rules are upper-case ('KEEP').
116
+ * The two columns genuinely disagree on casing, so the mapping is explicit rather than a
117
+ * `toUpperCase()` that would quietly produce an invalid value for anything unexpected.
118
+ */
119
+ private toDecisionOutcome;
120
+ }
121
+ /** Anti-tree-shaking loader — the @RegisterClass above is a side effect. */
122
+ export declare function LoadMarketingExperimentationAgent(): void;
123
+ //# sourceMappingURL=MarketingExperimentationAgent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarketingExperimentationAgent.d.ts","sourceRoot":"","sources":["../../src/agents/MarketingExperimentationAgent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAa1L,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAmC7D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBACa,6BAA8B,SAAQ,kBAAkB;IACjE;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAA4B;IAEtE,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA0B;IAE7D;;;;;;;;;;;;OAYG;cACsB,mBAAmB,CAAC,CAAC,EAC1C,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,CAAC,EACV,MAAM,EAAE,kBAAkB,GAC3B,OAAO,CAAC,cAAc,CAAC;IA6B1B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;IAkBtB;;;;;;;;;;OAUG;cACsB,uBAAuB,CAAC,CAAC,EAC9C,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC9B,cAAc,EAAE,CAAC,EACjB,QAAQ,EAAE,0BAA0B,EACpC,WAAW,EAAE,8BAA8B,GAC5C,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAahC,0FAA0F;cACjE,oBAAoB,CAAC,CAAC,EAC3C,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC9B,cAAc,EAAE,CAAC,EACjB,QAAQ,EAAE,0BAA0B,EACpC,WAAW,EAAE,8BAA8B,GAC5C,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAMhC;;;;;;;;;;;OAWG;cACsB,yBAAyB,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,kBAAkB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtH;;;;;;;;;;;OAWG;YACW,eAAe;IAkC7B,mGAAmG;IACnG,OAAO,CAAC,gBAAgB;IA0CxB;;;;;OAKG;YACW,2BAA2B;IA0FzC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAc5B;AAED,4EAA4E;AAC5E,wBAAgB,iCAAiC,IAAI,IAAI,CAAG"}
@@ -0,0 +1,371 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var MarketingExperimentationAgent_1;
8
+ import { EscapeSQLString, RegisterClass } from '@memberjunction/global';
9
+ import { BaseAgent } from '@memberjunction/ai-agents';
10
+ import { LogStatus, LogError, Metadata, RunView } from '@memberjunction/core';
11
+ import { enrichFinding, loadProgramKnowledge, renderKnowledgeBase, toMarketingEntityName, } from '@mj-biz-apps/marketing-core';
12
+ import { BaseMarketingAgent } from './BaseMarketingAgent.js';
13
+ /** Below this, a request is too short to rank a corpus against. */
14
+ const MIN_RETRIEVAL_QUERY_CHARS = 25;
15
+ /**
16
+ * Process vocabulary that says nothing about SUBJECT. "Review the programs and propose one"
17
+ * is a valid instruction and a useless retrieval query — stripping these leaves nothing, which is
18
+ * the signal to fall back to the full corpus.
19
+ */
20
+ const GENERIC_REQUEST_WORDS = /\b(review|propose|suggest|new|next|one|an?|the|and|or|for|to|of|please|what|should|we|i|you|program|programs|please|now|then|also|with|from|this|that|it|be|do|make|create|give|me|us|any|some|based|on|using|cite|codes?|numbers?)\b/g;
21
+ /**
22
+ * Marketing Programs Agent — driver class.
23
+ *
24
+ * The `MJ: AI Agents` metadata row has declared `DriverClass = MarketingExperimentationAgent`
25
+ * since the agent was seeded, but no such class existed, so MJ's ClassFactory silently fell back
26
+ * to plain `BaseAgent` and none of the doctrine below was enforced. (Exactly what had happened to
27
+ * MarketingStrategyOnboardingAgent before its driver class was written.)
28
+ *
29
+ * PRD §4 is binding on this agent, and the division of labour follows from it:
30
+ *
31
+ * * "Code owns numbers and dates" — the agent NEVER computes a metric, a threshold comparison,
32
+ * or a decision. `findingSynthesis` composes the factual finding from measured values before
33
+ * the agent is consulted.
34
+ * * "No invented evidence" — the agent's only contribution to a Learning is the MECHANISM, the
35
+ * causal reading that code cannot derive. It passes through `enrichFinding`, which rejects any
36
+ * interpretation citing a number that is not among the measured facts, or asserting an outcome
37
+ * that contradicts the recorded decision.
38
+ * * "Flow-critical outcomes run in post-hooks, never as optional LLM tool calls" — the learning
39
+ * write happens in `validateSuccessNextStep` below. It is not a tool the model may decline to
40
+ * call, because a decision that produces no Learning is the failure mode this whole framework
41
+ * exists to prevent.
42
+ * * "The prompt narrates published state" — the agent may not claim a program launched or
43
+ * decided. Those transitions belong to the lifecycle service, which the agent does not call.
44
+ */
45
+ let MarketingExperimentationAgent = class MarketingExperimentationAgent extends BaseMarketingAgent {
46
+ static { MarketingExperimentationAgent_1 = this; }
47
+ /**
48
+ * Payload key the prompt writes its causal reading into.
49
+ *
50
+ * Deliberately named for what it is. The model is asked for a mechanism WITHOUT numbers — the
51
+ * numbers are already in the factual sentence this gets appended to, and every number the model
52
+ * adds is one more thing the guard has to reject.
53
+ */
54
+ static { this.INTERPRETATION_KEY = 'learningInterpretation'; }
55
+ /** Payload key naming which decided program the interpretation is about. */
56
+ static { this.PROGRAM_KEY = 'interpretedProgramId'; }
57
+ /**
58
+ * Injects the program knowledge base before every prompt turn.
59
+ *
60
+ * This is what makes the agent propose FROM evidence rather than from the strategy document
61
+ * plus its own priors. It runs on every turn, deterministically, in code — not as a tool the
62
+ * model may choose to call, because an agent that can decline to look at prior results will
63
+ * eventually propose something that was already killed.
64
+ *
65
+ * Exposed to the template as `{{ programKnowledge }}`. A load failure is logged and the turn
66
+ * proceeds WITHOUT the block rather than aborting: losing the history degrades proposal
67
+ * quality, while failing the run loses the turn entirely. The block is self-describing, so its
68
+ * absence cannot be mistaken by the model for "there is no history".
69
+ */
70
+ async preparePromptParams(config, payload, params) {
71
+ const result = await super.preparePromptParams(config, payload, params);
72
+ const bag = (payload ?? {});
73
+ const brandId = typeof bag['brandId'] === 'string' ? bag['brandId'] : null;
74
+ if (!brandId || !result.data)
75
+ return result;
76
+ try {
77
+ // Rank the corpus against what is actually being asked, when there is something to rank
78
+ // against. The draft hypothesis does not exist yet at injection time — the model has not
79
+ // written one — so the user's request is the best available signal for relevance, and it
80
+ // is what the whole turn is about.
81
+ const relevantTo = this.retrievalQuery(params);
82
+ const kb = await loadProgramKnowledge({
83
+ brandId,
84
+ contextUser: params.contextUser,
85
+ ...(relevantTo ? { relevantTo } : {}),
86
+ });
87
+ result.data['programKnowledge'] = renderKnowledgeBase(kb);
88
+ LogStatus(`MarketingExperimentationAgent: injected ${kb.learnings.length} finding(s) and `
89
+ + `${kb.sprints.length} sprint(s) of history (${kb.excludedStrategyFacts} strategy fact(s) excluded)`
90
+ + `${kb.rankedSemantically ? ` — ranked semantically against "${(relevantTo ?? '').slice(0, 60)}…"` : ' — date order'}.`);
91
+ }
92
+ catch (e) {
93
+ LogError('MarketingExperimentationAgent: knowledge base load failed, proceeding without it — '
94
+ + (e instanceof Error ? e.message : String(e)));
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * The text findings are ranked against, drawn from the conversation.
100
+ *
101
+ * The obvious candidate — the draft hypothesis — does not exist yet: this runs BEFORE the model
102
+ * writes anything. What does exist is the user's request, which is what the turn is about, so it
103
+ * is the honest relevance signal available at this point.
104
+ *
105
+ * Returns null for a short or generic request ("review the programs", "what next?"). Ranking
106
+ * against those would narrow the corpus on noise, and a narrowed corpus is strictly worse than
107
+ * the full one when the query carries no topic — the model would lose evidence and be told the
108
+ * remainder was "most relevant".
109
+ */
110
+ retrievalQuery(params) {
111
+ // The FIRST user message, not the last. The agent loop appends its own turns with
112
+ // role='user' — including action results — so by turn 3 the "latest user message" is the
113
+ // text of an action result, and ranking findings against that is arbitrary. Observed:
114
+ // turn 1 ranked against the real request, turn 3 against "Action results: …".
115
+ // The originating request is stable across the loop and is what the turn is about.
116
+ const messages = params.conversationMessages ?? [];
117
+ const firstUser = messages.find(m => m.role === 'user');
118
+ const text = typeof firstUser?.content === 'string' ? firstUser.content.trim() : '';
119
+ if (text.length < MIN_RETRIEVAL_QUERY_CHARS)
120
+ return null;
121
+ // A request made only of process words carries no topic to rank on.
122
+ const withoutFiller = text.toLowerCase().replace(GENERIC_REQUEST_WORDS, ' ').replace(/\s+/g, ' ').trim();
123
+ if (withoutFiller.length < MIN_RETRIEVAL_QUERY_CHARS)
124
+ return null;
125
+ return text;
126
+ }
127
+ /**
128
+ * Post-hook: fold the agent's mechanism into the Learning the decision already recorded.
129
+ *
130
+ * Runs after a successful step, so it sees the payload the model produced. Everything it needs
131
+ * beyond that comes from the database, never from the model: the program's own numbers, and
132
+ * the Learning row the writeback wrote.
133
+ *
134
+ * Failures here are logged and swallowed. A missing mechanism leaves a Learning that is still
135
+ * true and still cites its numbers; aborting the agent run over it would trade a complete
136
+ * record for no record.
137
+ */
138
+ async validateSuccessNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
139
+ const baseResult = await super.validateSuccessNextStep(params, nextStep, currentPayload, agentRun, currentStep);
140
+ if (baseResult.step === 'Retry')
141
+ return baseResult;
142
+ try {
143
+ await this.applyLearningInterpretation(currentPayload, params.contextUser, agentRun.ID);
144
+ }
145
+ catch (e) {
146
+ LogError(`MarketingExperimentationAgent: learning enrichment failed — ${e instanceof Error ? e.message : String(e)}`);
147
+ }
148
+ await this.attachProposals(baseResult, currentPayload, agentRun, params.contextUser);
149
+ return baseResult;
150
+ }
151
+ /** A turn that ends by asking the user something can still have proposed — same stamp. */
152
+ async validateChatNextStep(params, nextStep, currentPayload, agentRun, currentStep) {
153
+ const baseResult = await super.validateChatNextStep(params, nextStep, currentPayload, agentRun, currentStep);
154
+ await this.attachProposals(baseResult, currentPayload, agentRun, params.contextUser);
155
+ return baseResult;
156
+ }
157
+ /**
158
+ * Decides, in code, whether this run may SAVE a proposal or only DRAFT one.
159
+ *
160
+ * Inside the in-app Assistant a person is reading the proposal as it is written, so the
161
+ * Program row is theirs to create: the run drafts (`Propose Program` with `DraftOnly=true`)
162
+ * and the proposal card's Approve click commits. Everywhere else — the hourly agent, sprint
163
+ * end, a scheduled job — nobody is watching, and a draft nobody can see would simply be lost,
164
+ * so those runs commit directly and queue for approval as before.
165
+ *
166
+ * The Assistant is recognised by the app context it sends (the same signal that makes the
167
+ * brand picker authoritative). The template reads `proposalMode`; it does not decide it.
168
+ */
169
+ async initializeStartingPayload(params) {
170
+ await super.initializeStartingPayload(params);
171
+ const payload = params.payload;
172
+ if (payload)
173
+ payload['proposalMode'] = this.brandFromAppContext(params) ? 'draft' : 'commit';
174
+ }
175
+ /**
176
+ * Stamps what THIS run proposed onto the payload, as `proposals`.
177
+ *
178
+ * The payload is what the conversation renders as the run's artifact, and the proposal card
179
+ * is drawn from this list. It is built from the run's own recorded `Propose Program` action
180
+ * results — never from the model's account of what it did ("the prompt narrates published
181
+ * state"):
182
+ * * DRAFTED → the full validated draft rides along, because no row exists to load. The card
183
+ * renders it, and re-submits exactly these inputs when the user approves.
184
+ * * SUCCESS → a committed program; ids only, and the card loads the row live.
185
+ * A failed or blocked call produced no proposal and is skipped.
186
+ */
187
+ async attachProposals(nextStep, currentPayload, agentRun, contextUser) {
188
+ const bag = (currentPayload ?? {});
189
+ try {
190
+ const res = await new RunView().RunView({
191
+ EntityName: 'MJ: AI Agent Run Steps',
192
+ ExtraFilter: `AgentRunID='${EscapeSQLString(agentRun.ID)}' AND StepType='Actions' AND Status='Completed' AND StepName LIKE '%Propose Program%'`,
193
+ Fields: ['OutputData'],
194
+ OrderBy: 'StepNumber ASC', ResultType: 'simple', BypassCache: true,
195
+ }, contextUser);
196
+ if (!res.Success) {
197
+ LogError(`MarketingExperimentationAgent: could not read this run's proposal steps — ${res.ErrorMessage}`);
198
+ return;
199
+ }
200
+ const proposals = (res.Results ?? [])
201
+ .map(step => this.proposalFromStep(step.OutputData))
202
+ .filter((p) => p !== null);
203
+ if (proposals.length === 0)
204
+ return;
205
+ bag['proposals'] = proposals;
206
+ const next = nextStep.newPayload;
207
+ if (next && next !== bag)
208
+ next['proposals'] = proposals;
209
+ LogStatus(`MarketingExperimentationAgent: ${proposals.length} proposal(s) from this run attached to the payload `
210
+ + `(${proposals.filter(p => p.draft).length} draft).`);
211
+ }
212
+ catch (e) {
213
+ LogError(`MarketingExperimentationAgent: attaching proposals failed — ${e instanceof Error ? e.message : String(e)}`);
214
+ }
215
+ }
216
+ /** One recorded `Propose Program` result → a proposal reference, or null when it produced none. */
217
+ proposalFromStep(outputData) {
218
+ if (!outputData)
219
+ return null;
220
+ let parsed;
221
+ try {
222
+ parsed = JSON.parse(outputData);
223
+ }
224
+ catch {
225
+ return null; // not JSON — not an action result this shell understands
226
+ }
227
+ const result = parsed.actionResult;
228
+ if (!result?.success || !Array.isArray(result.parameters))
229
+ return null;
230
+ const byType = (type) => Object.fromEntries(result.parameters.filter(p => p.Type === type && p.Value !== null && p.Value !== undefined).map(p => [p.Name, p.Value]));
231
+ const inputs = byType('Input');
232
+ const outputs = byType('Output');
233
+ const text = (v) => (typeof v === 'string' && v.trim() ? v : null);
234
+ if (result.resultCode === 'DRAFTED') {
235
+ const draftKey = text(outputs['DraftKey']);
236
+ if (!draftKey)
237
+ return null;
238
+ delete inputs['DraftOnly']; // the re-submit on Approve must COMMIT
239
+ return {
240
+ programId: null, code: null, name: text(inputs['Name']), approvalRequestId: null,
241
+ draft: {
242
+ key: draftKey,
243
+ inputs,
244
+ programTier: text(outputs['ProgramTier']),
245
+ programType: text(outputs['ProgramType']),
246
+ proposalConfidence: text(outputs['ProposalConfidence']),
247
+ requiresOverride: outputs['RequiresOverride'] === true,
248
+ },
249
+ };
250
+ }
251
+ const programId = text(outputs['ProgramID']);
252
+ if (!programId)
253
+ return null;
254
+ return {
255
+ programId, code: text(outputs['Code']), name: text(inputs['Name']),
256
+ approvalRequestId: text(outputs['ApprovalRequestID']), draft: null,
257
+ };
258
+ }
259
+ /**
260
+ * Applies the model's mechanism to the most recent Learning for the named program.
261
+ *
262
+ * No-ops silently when the payload carries no interpretation — the agent has other jobs
263
+ * (proposing), and only the decision-interpretation turn produces one.
264
+ */
265
+ async applyLearningInterpretation(payload, contextUser, agentRunId) {
266
+ const bag = (payload ?? {});
267
+ const interpretation = bag[MarketingExperimentationAgent_1.INTERPRETATION_KEY];
268
+ const programId = bag[MarketingExperimentationAgent_1.PROGRAM_KEY];
269
+ if (typeof interpretation !== 'string' || !interpretation.trim())
270
+ return;
271
+ if (typeof programId !== 'string' || !programId.trim()) {
272
+ LogError('MarketingExperimentationAgent: an interpretation was supplied with no '
273
+ + `${MarketingExperimentationAgent_1.PROGRAM_KEY} — refusing to guess which program it belongs to.`);
274
+ return;
275
+ }
276
+ const rv = new RunView();
277
+ // The program's own numbers define what the model is allowed to cite.
278
+ const exp = (await rv.RunView({
279
+ EntityName: toMarketingEntityName('Programs'),
280
+ ExtraFilter: `ID='${EscapeSQLString(programId)}'`,
281
+ Fields: ['ID', 'Code', 'Decision', 'MetricBaseline', 'KeepThreshold', 'KillThreshold', 'IterateRangeMin', 'IterateRangeMax'],
282
+ MaxRows: 1, ResultType: 'simple', BypassCache: true,
283
+ }, contextUser)).Results?.[0];
284
+ if (!exp) {
285
+ LogError(`MarketingExperimentationAgent: program ${programId} not found; interpretation dropped.`);
286
+ return;
287
+ }
288
+ if (!exp.Decision) {
289
+ LogError(`MarketingExperimentationAgent: program ${exp.Code ?? programId} has no recorded Decision. `
290
+ + 'An interpretation cannot precede the decision it interprets — dropped.');
291
+ return;
292
+ }
293
+ // The Learning the writeback already created. Read fresh: it was written moments ago.
294
+ const learningRow = (await rv.RunView({
295
+ EntityName: toMarketingEntityName('Agent Learnings'),
296
+ ExtraFilter: `RelatedProgramID='${EscapeSQLString(programId)}'`,
297
+ Fields: ['ID', 'Finding'],
298
+ OrderBy: '__mj_CreatedAt DESC', MaxRows: 1, ResultType: 'simple', BypassCache: true,
299
+ }, contextUser)).Results?.[0];
300
+ if (!learningRow) {
301
+ LogError(`MarketingExperimentationAgent: no Learning recorded for ${exp.Code ?? programId} yet; `
302
+ + 'nothing to enrich. The decision writeback runs first.');
303
+ return;
304
+ }
305
+ // Observed values live on the segment results the observation path wrote.
306
+ const observed = (await rv.RunView({
307
+ EntityName: toMarketingEntityName('Program Segment Results'),
308
+ ExtraFilter: `ProgramID='${EscapeSQLString(programId)}'`,
309
+ Fields: ['ObservedMetric', 'ConversionsCount'], ResultType: 'simple', BypassCache: true,
310
+ }, contextUser)).Results ?? [];
311
+ const allowedNumbers = [
312
+ exp.MetricBaseline, exp.KeepThreshold, exp.KillThreshold, exp.IterateRangeMin, exp.IterateRangeMax,
313
+ ...observed.flatMap(o => [o.ObservedMetric, o.ConversionsCount]),
314
+ ];
315
+ const result = enrichFinding(learningRow.Finding ?? '', interpretation, {
316
+ decision: this.toDecisionOutcome(exp.Decision),
317
+ allowedNumbers,
318
+ });
319
+ if (!result.enriched) {
320
+ // Not an error — the guard doing its job. Logged loudly because a repeatedly-rejected
321
+ // interpretation means the prompt needs fixing, not the guard.
322
+ LogStatus(`MarketingExperimentationAgent: interpretation REJECTED for ${exp.Code ?? programId} `
323
+ + `(${result.problems.join('; ')}). The factual finding stands unchanged.`);
324
+ return;
325
+ }
326
+ const md = new Metadata();
327
+ const learning = await md.GetEntityObject(toMarketingEntityName('Agent Learnings'), contextUser);
328
+ if (!await learning.Load(learningRow.ID)) {
329
+ LogError(`MarketingExperimentationAgent: could not load Learning ${learningRow.ID}.`);
330
+ return;
331
+ }
332
+ learning.Finding = result.finding;
333
+ // Source moves off 'program' only when an agent actually contributed: 'analysis' is the
334
+ // value list's slot for agent-derived reasoning, and it keeps agent-enriched findings
335
+ // distinguishable from purely mechanical ones.
336
+ learning.Source = 'analysis';
337
+ if (!await learning.Save()) {
338
+ LogError(`MarketingExperimentationAgent: Learning ${learningRow.ID} save failed — `
339
+ + `${learning.LatestResult?.CompleteMessage ?? 'unknown'}`);
340
+ return;
341
+ }
342
+ LogStatus(`MarketingExperimentationAgent: enriched Learning ${learningRow.ID} for ${exp.Code ?? programId} `
343
+ + `(agent run ${agentRunId}).`);
344
+ }
345
+ /**
346
+ * `Program.Decision` is title-case ('Keep'); the writeback rules are upper-case ('KEEP').
347
+ * The two columns genuinely disagree on casing, so the mapping is explicit rather than a
348
+ * `toUpperCase()` that would quietly produce an invalid value for anything unexpected.
349
+ */
350
+ toDecisionOutcome(decision) {
351
+ switch (decision.trim().toLowerCase()) {
352
+ case 'keep': return 'KEEP';
353
+ case 'iterate': return 'ITERATE';
354
+ case 'kill': return 'KILL';
355
+ case 'graduate': return 'GRADUATE';
356
+ default:
357
+ // Treat an unknown decision as the most restrictive: ITERATE permits no
358
+ // outcome claim at all, so a mismatched interpretation gets rejected.
359
+ LogError(`MarketingExperimentationAgent: unrecognised Decision "${decision}" — `
360
+ + 'treating as ITERATE so no outcome claim is licensed.');
361
+ return 'ITERATE';
362
+ }
363
+ }
364
+ };
365
+ MarketingExperimentationAgent = MarketingExperimentationAgent_1 = __decorate([
366
+ RegisterClass(BaseAgent, 'MarketingExperimentationAgent')
367
+ ], MarketingExperimentationAgent);
368
+ export { MarketingExperimentationAgent };
369
+ /** Anti-tree-shaking loader — the @RegisterClass above is a side effect. */
370
+ export function LoadMarketingExperimentationAgent() { }
371
+ //# sourceMappingURL=MarketingExperimentationAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarketingExperimentationAgent.js","sourceRoot":"","sources":["../../src/agents/MarketingExperimentationAgent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { BaseMarketingAgent } from './BaseMarketingAgent.js';
2
+ /**
3
+ * Marketing Operations Agent — driver class (PRD v3 S7 item 4 / readiness follow-through).
4
+ *
5
+ * The `MJ: AI Agents` row for the Operations Agent declared no DriverClass at all, so MJ's
6
+ * ClassFactory instantiated plain `BaseAgent` and NONE of the marketing base-class doctrine
7
+ * applied to the hourly loop: no brand self-resolution from the caller's grants, no payload
8
+ * bootstrap (`brandName`/`companyId`), no authorized-brand disambiguation. The same silent
9
+ * fallback had already bitten MarketingStrategyOnboardingAgent and
10
+ * MarketingExperimentationAgent before their driver classes were written — this closes the
11
+ * last gap in the set.
12
+ *
13
+ * Deliberately THIN. The Operations Agent's work is tool calls (Refresh Program Status, Close
14
+ * Due Sprints, Start Due Sprints, Sync Marketing Data, Get Program Context …), and every one of
15
+ * those actions enforces its own brand/role gate server-side — the doctrine this class needs is
16
+ * exactly what {@link BaseMarketingAgent} centralizes, nothing more. Numbers and dates stay
17
+ * owned by code inside the actions; the loop narrates and sequences. When the ops loop grows a
18
+ * flow-critical outcome of its own (the Experimentation agent's learning post-hook is the
19
+ * precedent), it gets a post-hook here — not an optional tool the model may forget.
20
+ */
21
+ export declare class MarketingOperationsAgent extends BaseMarketingAgent {
22
+ }
23
+ export declare function LoadMarketingOperationsAgent(): void;
24
+ //# sourceMappingURL=MarketingOperationsAgent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarketingOperationsAgent.d.ts","sourceRoot":"","sources":["../../src/agents/MarketingOperationsAgent.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,wBAAyB,SAAQ,kBAAkB;CAC/D;AAED,wBAAgB,4BAA4B,SAAK"}
@@ -0,0 +1,36 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { BaseAgent } from '@memberjunction/ai-agents';
9
+ import { BaseMarketingAgent } from './BaseMarketingAgent.js';
10
+ /**
11
+ * Marketing Operations Agent — driver class (PRD v3 S7 item 4 / readiness follow-through).
12
+ *
13
+ * The `MJ: AI Agents` row for the Operations Agent declared no DriverClass at all, so MJ's
14
+ * ClassFactory instantiated plain `BaseAgent` and NONE of the marketing base-class doctrine
15
+ * applied to the hourly loop: no brand self-resolution from the caller's grants, no payload
16
+ * bootstrap (`brandName`/`companyId`), no authorized-brand disambiguation. The same silent
17
+ * fallback had already bitten MarketingStrategyOnboardingAgent and
18
+ * MarketingExperimentationAgent before their driver classes were written — this closes the
19
+ * last gap in the set.
20
+ *
21
+ * Deliberately THIN. The Operations Agent's work is tool calls (Refresh Program Status, Close
22
+ * Due Sprints, Start Due Sprints, Sync Marketing Data, Get Program Context …), and every one of
23
+ * those actions enforces its own brand/role gate server-side — the doctrine this class needs is
24
+ * exactly what {@link BaseMarketingAgent} centralizes, nothing more. Numbers and dates stay
25
+ * owned by code inside the actions; the loop narrates and sequences. When the ops loop grows a
26
+ * flow-critical outcome of its own (the Experimentation agent's learning post-hook is the
27
+ * precedent), it gets a post-hook here — not an optional tool the model may forget.
28
+ */
29
+ let MarketingOperationsAgent = class MarketingOperationsAgent extends BaseMarketingAgent {
30
+ };
31
+ MarketingOperationsAgent = __decorate([
32
+ RegisterClass(BaseAgent, 'MarketingOperationsAgent')
33
+ ], MarketingOperationsAgent);
34
+ export { MarketingOperationsAgent };
35
+ export function LoadMarketingOperationsAgent() { }
36
+ //# sourceMappingURL=MarketingOperationsAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarketingOperationsAgent.js","sourceRoot":"","sources":["../../src/agents/MarketingOperationsAgent.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AAEI,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,kBAAkB;CAC/D,CAAA;AADY,wBAAwB;IADpC,aAAa,CAAC,SAAS,EAAE,0BAA0B,CAAC;GACxC,wBAAwB,CACpC;;AAED,MAAM,UAAU,4BAA4B,KAAI,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { BaseMarketingAgent } from './BaseMarketingAgent.js';
2
+ /**
3
+ * Marketing Podcast Ingestion Agent — driver class (Content Engine PRD, Phase A row A2).
4
+ *
5
+ * The `MJ: AI Agents` row named this class but nothing defined it, so MJ's ClassFactory fell
6
+ * back to plain `BaseAgent` — the same silent fault that bit the Onboarding, Experimentation and
7
+ * Operations agents in turn: no brand self-resolution from the caller's grants or the app
8
+ * context, no payload bootstrap (`brandName` / `companyId`), no authorized-brand disambiguation.
9
+ * With Content's "Ingest now" and the per-brand Ingest-sources job about to run this agent, the
10
+ * brand must come from the run's context, never from a question.
11
+ *
12
+ * Deliberately THIN, like the Operations agent. The ingestion work is tool calls (Fetch Podcast
13
+ * From RSS, Intake Podcast From Box, Diarize Podcast Episode, Transcribe Audio …) and every one
14
+ * of them enforces its own brand gate server-side; the doctrine this class needs is exactly what
15
+ * {@link BaseMarketingAgent} centralizes. Idempotency lives in the actions and, for generation,
16
+ * in the pipeline's final-save check (CE-7) — not in the narration here.
17
+ */
18
+ export declare class MarketingPodcastIngestionAgent extends BaseMarketingAgent {
19
+ }
20
+ export declare function LoadMarketingPodcastIngestionAgent(): void;
21
+ //# sourceMappingURL=MarketingPodcastIngestionAgent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarketingPodcastIngestionAgent.d.ts","sourceRoot":"","sources":["../../src/agents/MarketingPodcastIngestionAgent.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,qBACa,8BAA+B,SAAQ,kBAAkB;CACrE;AAED,wBAAgB,kCAAkC,SAAK"}