manychat-ai-agent 0.26.0 → 0.26.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agent/tools/build.d.ts +23 -0
  3. package/dist/agent/tools/build.js +42 -0
  4. package/dist/agent/tools/contact-actions.d.ts +63 -0
  5. package/dist/agent/tools/contact-actions.js +64 -0
  6. package/dist/agent/tools/copy.d.ts +18 -0
  7. package/dist/agent/tools/copy.js +21 -0
  8. package/dist/agent/tools/get-contact.d.ts +5 -0
  9. package/dist/agent/tools/get-contact.js +26 -0
  10. package/dist/agent/tools/lookups.d.ts +90 -0
  11. package/dist/agent/tools/lookups.js +70 -0
  12. package/dist/agent/tools/notes.d.ts +4 -0
  13. package/dist/agent/tools/notes.js +36 -0
  14. package/dist/agent/tools/nudge.d.ts +4 -0
  15. package/dist/agent/tools/nudge.js +29 -0
  16. package/dist/agent/tools/send-flow.d.ts +4 -0
  17. package/dist/agent/tools/send-flow.js +115 -0
  18. package/dist/agent/tools/set-field.d.ts +7 -0
  19. package/dist/agent/tools/set-field.js +142 -0
  20. package/dist/agent/tools/stage.d.ts +92 -0
  21. package/dist/agent/tools/stage.js +176 -0
  22. package/dist/agent/tools/tags.d.ts +4 -0
  23. package/dist/agent/tools/tags.js +26 -0
  24. package/dist/agent/tools/turn.d.ts +93 -0
  25. package/dist/agent/tools/turn.js +93 -0
  26. package/dist/agent/tools.d.ts +11 -266
  27. package/dist/agent/tools.js +7 -738
  28. package/dist/channels/manychat/client.d.ts +11 -0
  29. package/dist/channels/manychat/client.js +16 -1
  30. package/dist/contracts/config/catalog.d.ts +55 -0
  31. package/dist/contracts/config/catalog.js +36 -0
  32. package/dist/contracts/config/channels.d.ts +14 -0
  33. package/dist/contracts/config/channels.js +50 -0
  34. package/dist/contracts/config/env.d.ts +51 -0
  35. package/dist/contracts/config/env.js +126 -0
  36. package/dist/contracts/config/funnel.d.ts +20 -0
  37. package/dist/contracts/config/funnel.js +27 -0
  38. package/dist/contracts/config/prompt-overrides.d.ts +26 -0
  39. package/dist/contracts/config/prompt-overrides.js +26 -0
  40. package/dist/contracts/config/rules.d.ts +54 -0
  41. package/dist/contracts/config/rules.js +98 -0
  42. package/dist/contracts/config/tools.d.ts +121 -0
  43. package/dist/contracts/config/tools.js +286 -0
  44. package/dist/contracts/config.d.ts +11 -329
  45. package/dist/contracts/config.js +11 -650
  46. package/dist/server.js +1 -1
  47. package/dist/turn/admission.d.ts +52 -0
  48. package/dist/turn/admission.js +94 -0
  49. package/dist/turn/completion.d.ts +23 -0
  50. package/dist/turn/completion.js +1 -0
  51. package/dist/turn/context.d.ts +23 -0
  52. package/dist/turn/context.js +33 -0
  53. package/dist/turn/deferred.d.ts +38 -0
  54. package/dist/turn/deferred.js +76 -0
  55. package/dist/turn/delivery.d.ts +100 -0
  56. package/dist/turn/delivery.js +162 -0
  57. package/dist/turn/fold.d.ts +44 -0
  58. package/dist/turn/fold.js +59 -0
  59. package/dist/{routes/turn.d.ts → turn/handler.d.ts} +14 -68
  60. package/dist/turn/handler.js +335 -0
  61. package/dist/turn/logger.d.ts +10 -0
  62. package/dist/turn/logger.js +11 -0
  63. package/dist/turn/media.d.ts +46 -0
  64. package/dist/turn/media.js +109 -0
  65. package/dist/turn/order.d.ts +49 -0
  66. package/dist/turn/order.js +115 -0
  67. package/dist/turn/prechecks.d.ts +30 -0
  68. package/dist/turn/prechecks.js +48 -0
  69. package/dist/turn/race.d.ts +7 -0
  70. package/dist/turn/race.js +18 -0
  71. package/dist/turn/recorder.d.ts +86 -0
  72. package/dist/turn/recorder.js +125 -0
  73. package/dist/turn/replies.d.ts +15 -0
  74. package/dist/turn/replies.js +25 -0
  75. package/dist/turn/result.d.ts +20 -0
  76. package/dist/turn/result.js +1 -0
  77. package/dist/turn/scope.d.ts +83 -0
  78. package/dist/turn/scope.js +71 -0
  79. package/package.json +1 -1
  80. package/dist/routes/turn.js +0 -1007
@@ -0,0 +1,93 @@
1
+ import { LINK_SENT, PROSPECT } from "../../contracts/config.js";
2
+ import { funnelField, intentField, offeringField, stageIndex } from "./lookups.js";
3
+ /** What a sales tool returns while the contact is not a prospect (specs/034). */
4
+ export const NOT_PROSPECT = { staged: false, reason: 'not_prospect' };
5
+ /** Whether a flow serves the turn's offering: its own, or every one (specs/028). */
6
+ export const fitsOffering = (flow, current) => flow.offering === undefined || flow.offering === current;
7
+ /**
8
+ * What every tool of one turn reads as it runs: the gate on intent, the
9
+ * turn's offering and the floor under the funnel stage. Read from the stage
10
+ * each time, so a write staged by one tool is seen by the next, in the same
11
+ * step included.
12
+ */
13
+ export class ToolTurn {
14
+ config;
15
+ stage;
16
+ contact;
17
+ options;
18
+ funnel;
19
+ intent;
20
+ offering;
21
+ /**
22
+ * A flow already sent to this contact is not offered again, so a repeat is
23
+ * unrepresentable rather than discouraged (specs/023 § Every content flow
24
+ * is a leaf, sent once). An offering change does not bring one back
25
+ * (specs/028). The opening flow is the server's to send, never the model's
26
+ * (specs/032).
27
+ */
28
+ unsent;
29
+ /**
30
+ * A payment link marked here before any await on its way out, so a call
31
+ * beside it in the same step already sees it (specs/029, specs/032).
32
+ */
33
+ linkStarting = 0;
34
+ constructor(config, stage, contact, options) {
35
+ this.config = config;
36
+ this.stage = stage;
37
+ this.contact = contact;
38
+ this.options = options;
39
+ this.funnel = funnelField(config);
40
+ this.intent = intentField(config);
41
+ this.offering = offeringField(config);
42
+ this.unsent = config.flows.filter(flow => flow.role !== 'opening' && (flow.repeatable || !contact.sentFlows.has(flow.id)));
43
+ }
44
+ /**
45
+ * The contact's intent as the server knows it, a write staged earlier this
46
+ * turn included, so a first message can be recorded as a prospect and sold
47
+ * to in one turn (specs/034 § Until intent is prospect, the sale's tools
48
+ * refuse).
49
+ */
50
+ turnIntent() {
51
+ const staged = this.stage.staged.findLast((action) => action.tool === 'set_field' && action.id === this.intent?.id);
52
+ return staged?.value ?? this.contact.intent;
53
+ }
54
+ /**
55
+ * Refused rather than removed from the enums: removing them would rule out
56
+ * the same-turn unlock. A refusal makes no request and takes no slot of the
57
+ * cap (specs/034).
58
+ */
59
+ closed() {
60
+ return this.intent !== undefined && this.turnIntent() !== PROSPECT;
61
+ }
62
+ /**
63
+ * The turn's offering: one staged on the offering field earlier in this
64
+ * turn, or else the contact's (specs/028 § A flow belongs to one offering or
65
+ * to all).
66
+ */
67
+ turnOffering() {
68
+ const staged = this.stage.staged.findLast((action) => action.tool === 'set_field' && action.offering === true);
69
+ return staged?.value ?? this.contact.offering;
70
+ }
71
+ /**
72
+ * The earliest stage a write may name: the last one performed for this
73
+ * contact, or a later one already staged this turn. Parallel calls in one
74
+ * step must not walk a lead back any more than a later turn may.
75
+ */
76
+ stageFloor() {
77
+ const { stage, contact, funnel } = this;
78
+ return Math.max(stageIndex(contact.funnelStage), this.linkStarting > 0 ? stageIndex(LINK_SENT) : -1, ...stage.staged.map(action => action.tool === 'set_field' && action.id === funnel?.id ? stageIndex(action.value) : -1),
79
+ // Writes already made this turn, a payment link's `link_sent` among
80
+ // them (specs/029), so nothing staged after can walk the stage back.
81
+ ...stage.sent.flatMap(sent => sent.records.map(record => record.tool === 'set_field' && record.id === funnel?.id && record.status === 'performed'
82
+ ? stageIndex(record.value)
83
+ : -1)),
84
+ // A payment link still in flight counts at the stage it is about to
85
+ // write: a call in the same step runs while it waits (the SDK starts a
86
+ // step's calls together), and would otherwise stage a lower write
87
+ // that lands after `link_sent`. If the link then fails, the turn has
88
+ // at most one step left.
89
+ ...stage.sent.map(sent => sent.pending && sent.action.tool === 'send_flow' && sent.action.followOn?.id === funnel?.id
90
+ ? stageIndex(sent.action.followOn?.value)
91
+ : -1));
92
+ }
93
+ }
@@ -1,267 +1,12 @@
1
- import { type ToolSet } from 'ai';
2
- import type { Catalog, Tools, INTENT_VALUES } from '../contracts/config.ts';
3
- import type { ActionRecord, ActionStatus, PerformableAction, StagedAction } from '../contracts/agent.ts';
4
- import type { ContactReads } from './contact.ts';
5
- import type { FlowSends, SendFlowAction } from './flows.ts';
6
- import type { Plugins } from '../plugins/plugins.ts';
7
- import type { PluginReads } from '../plugins/reads.ts';
8
1
  /**
9
- * Steps one to three may call tools; step four offers none, so it must
10
- * produce the reply. Four fit read, act, read again and reply (specs/024
11
- * § The loop grows to four steps and eight actions). Chosen, not measured.
12
- */
13
- export declare const MAX_STEPS = 4;
14
- /**
15
- * Bounds the burst one turn can put through the ManyChat rate limiter, one
16
- * request per action. Eight fit a flow, a funnel stage, two qualification
17
- * fields, a tag and three notes (specs/024). Chosen, not measured.
18
- */
19
- export declare const MAX_ACTIONS_PER_TURN = 8;
20
- /** `send_flow intro_course_brochure`, `set_field preferred_shift=evening`. */
21
- export declare function describeAction(action: {
22
- tool: string;
23
- id: string;
24
- value?: string | undefined;
25
- }): string;
26
- /**
27
- * The entry recorded on the turn: ids and values, never ManyChat names. A
28
- * note is recorded by its length, never its text (specs/024 § Note text never
29
- * reaches the record or the logs).
30
- */
31
- export declare function recordOf(action: PerformableAction, status: ActionStatus, error?: string): ActionRecord;
32
- /**
33
- * Everything the model staged on one turn. A tool's `execute` writes here and
34
- * nothing else: no ManyChat write is made inside the model call, because at
35
- * that point the model has not decided whether to escalate and the guardrails
36
- * have not run (ADR-0010). The exception is a flow on an inbound turn, sent
37
- * when called so the reply can follow it (specs/029, ADR-0019); it is kept
38
- * here with what became of it, in call order.
39
- *
40
- * Created by the caller rather than the runner, so what was staged is still
41
- * known when the model call is aborted and never returns.
42
- */
43
- export declare class ActionStage {
44
- private readonly accepted;
45
- private readonly overCap;
46
- private readonly sentNow;
47
- /** Staged and sent entries in the order the model made them, for the record. */
48
- private readonly order;
49
- /** Sends the cap does not count: the opening flow is the server's (specs/032). */
50
- private uncapped;
51
- /**
52
- * Whether the action is staged. A repeat of one already staged is. Compared
53
- * whole rather than by record, since two notes of one length differ.
54
- */
55
- stage(action: StagedAction): boolean;
56
- /** A flow sent this turn counts against the cap as a staged action does. */
57
- private get full();
58
- /**
59
- * Sends a flow now (specs/029). Returns whether ManyChat accepted it, or
60
- * `undefined` when it is over the cap and was not sent. A flow already sent
61
- * this turn is not sent again; its first outcome stands.
62
- *
63
- * `first` are actions already staged that must reach ManyChat before the
64
- * flow: a payment link's `link_sent` would otherwise be overwritten by an
65
- * earlier funnel write performed after the reply (specs/029 § A payment link
66
- * takes the turn's stage writes with it). They are sent ahead of it, keep
67
- * their place in the record, and are no longer staged.
68
- */
69
- send(action: SendFlowAction, sends: FlowSends, first?: readonly StagedAction[],
70
- /** Not counted against the cap: the server's opening flow (specs/032). */
71
- options?: {
72
- uncapped?: boolean;
73
- }): Promise<boolean | undefined>;
74
- /**
75
- * Resolves once every send started this turn has its answer. A call aborted
76
- * while a request is in flight does not stop the request, so the record waits
77
- * for it rather than keeping the placeholder (specs/029). Bounded by the
78
- * client's request timeout.
79
- */
80
- settled(): Promise<void>;
81
- /** Actions sent this turn, whatever became of them. */
82
- get sent(): readonly {
83
- action: StagedAction;
84
- records: readonly ActionRecord[];
85
- pending: boolean;
86
- }[];
87
- /** In the order the model staged them, which is the order they are performed in. */
88
- get staged(): readonly StagedAction[];
89
- get dropped(): readonly StagedAction[];
90
- /**
91
- * What an escalated turn still performs: the notes marked `onEscalation`,
92
- * and only when the model or the confidence threshold escalated (specs/024
93
- * § A handoff summary survives the escalation it describes).
94
- */
95
- survivors(keepNotes: boolean): StagedAction[];
96
- /**
97
- * The turn's record before anything is performed: every accepted action
98
- * with `status`, then those dropped over the cap. On an escalated turn
99
- * (`discarded`), an action in `kept` is recorded `staged` instead, since it
100
- * will still be performed.
101
- */
102
- records(status: 'staged' | 'discarded', kept?: readonly StagedAction[]): ActionRecord[];
103
- }
104
- /** The field the agent's position in the sale is kept in, if the tenant marked one (specs/023). */
105
- export declare function funnelField(config: Tools): {
106
- id: string;
107
- field: string;
108
- values: string[];
109
- description: string;
110
- funnel?: boolean | undefined;
111
- offering?: boolean | undefined;
112
- switchable?: boolean | undefined;
113
- intent?: boolean | undefined;
114
- } | undefined;
115
- /** The flow that ends the sale, if the tenant marked one (specs/023). */
116
- export declare function paymentLinkFlow(config: Tools): {
117
- id: string;
118
- flowNs: string;
119
- description: string;
120
- repeatable?: boolean | undefined;
121
- role?: "payment_link" | "opening" | undefined;
122
- onStage?: "qualifying" | "nurturing" | "offered" | "prepared" | undefined;
123
- offering?: string | undefined;
124
- settleSeconds?: number | undefined;
125
- silent?: boolean | undefined;
126
- } | undefined;
127
- /**
128
- * The link a reply must carry because the turn sent a silent payment-link
129
- * flow, which leaves the link to the reply (specs/023 § A silent payment flow
130
- * leaves the link to the reply). `undefined` when the turn neither sent such
131
- * a flow nor staged it to be sent after the reply.
132
- *
133
- * The link is the catalog `url` of the turn's offering: one written this turn,
134
- * else the contact's, else the catalog's only offering. `null` when the flow
135
- * went out and no offering or link is known, which the loader's checks leave
136
- * to a contact with no offering recorded yet.
137
- */
138
- export declare function silentPaymentLink(config: Tools, catalog: Catalog, stage: ActionStage, contact: {
139
- offering?: string | undefined;
140
- } | undefined): string | null | undefined;
141
- /** The flow the server sends on a contact's prospect turn, if the tenant marked one (specs/034). */
142
- export declare function openingFlow(config: Tools): {
143
- id: string;
144
- flowNs: string;
145
- description: string;
146
- repeatable?: boolean | undefined;
147
- role?: "payment_link" | "opening" | undefined;
148
- onStage?: "qualifying" | "nurturing" | "offered" | "prepared" | undefined;
149
- offering?: string | undefined;
150
- settleSeconds?: number | undefined;
151
- silent?: boolean | undefined;
152
- } | undefined;
153
- /** The field the contact's offering is kept in, if the tenant marked one (specs/028). */
154
- export declare function offeringField(config: Tools): {
155
- id: string;
156
- field: string;
157
- values: string[];
158
- description: string;
159
- funnel?: boolean | undefined;
160
- offering?: boolean | undefined;
161
- switchable?: boolean | undefined;
162
- intent?: boolean | undefined;
163
- } | undefined;
164
- /** The field the contact's intent is kept in, if the tenant marked one (specs/034). */
165
- export declare function intentField(config: Tools): {
166
- id: string;
167
- field: string;
168
- values: string[];
169
- description: string;
170
- funnel?: boolean | undefined;
171
- offering?: boolean | undefined;
172
- switchable?: boolean | undefined;
173
- intent?: boolean | undefined;
174
- } | undefined;
175
- export type Intent = (typeof INTENT_VALUES)[number];
176
- /**
177
- * Whether the turn staged a write of `prospect`, which makes it the turn the
178
- * opening belongs to (specs/034 § The opening waits for a prospect).
179
- */
180
- export declare function stagesProspect(stage: ActionStage, config: Tools): boolean;
181
- /**
182
- * The offering a request presented, if it is one: a value of the offering
183
- * field. Empty, unrendered (`{{offering}}`) or unknown is no offering at all,
184
- * never a guess (specs/028 § The server learns the offering from the inbound
185
- * request).
186
- */
187
- export declare function knownOffering(raw: string | null | undefined, config: Tools): string | undefined;
188
- export interface ContactActions {
189
- /** Flows performed for the contact within the history window. */
190
- sentFlows: ReadonlySet<string>;
191
- /** The funnel stage last recorded as performed for the contact, if any. */
192
- funnelStage?: string | undefined;
193
- /**
194
- * The contact's offering as the turn starts: the request's, or else the
195
- * one the conversation keeps (specs/028). Not read from the actions.
196
- */
197
- offering?: string | undefined;
198
- /** The offering the conversation held before the request changed it, if it did. */
199
- offeringChangedFrom?: string | undefined;
200
- /**
201
- * The contact's intent as the server knows it: the last performed write,
202
- * or `prospect` by the rollout rule. Absent is unknown (specs/034).
203
- */
204
- intent?: Intent | undefined;
205
- /**
206
- * The contact has had the opening, or a turn that staged `prospect`, so
207
- * the opening is never sent again (specs/034 § The opening waits for a
208
- * prospect).
209
- */
210
- openingSpent?: boolean | undefined;
211
- /**
212
- * The opening goes out on this turn if it stages `prospect` and does not
213
- * forfeit it by escalating (specs/034 § The opening waits for a prospect).
214
- */
215
- openingDue?: boolean | undefined;
216
- /**
217
- * The offering a bound request stored and the agent did not write: the
218
- * contact arrived through its advert (specs/034 § What counts as prospect
219
- * intent).
220
- */
221
- advertOffering?: string | undefined;
222
- }
223
- export declare const NO_CONTACT_ACTIONS: ContactActions;
224
- /**
225
- * Folds a contact's agent turns, oldest first, into `ContactActions`.
226
- *
227
- * Flows count only inside the history window (specs/018): a contact back
228
- * after it starts clean, as their history does. The stage counts however old,
229
- * because it only ever moves forward, and so do intent and the opening.
230
- */
231
- export declare function contactActionsFrom(turns: readonly {
232
- createdAt: Date;
233
- actions: readonly ActionRecord[] | null;
234
- }[], config: Tools, since: Date): ContactActions;
235
- /**
236
- * The tools for one turn, or undefined when `tools.json` configures none.
237
- *
238
- * Each parameter is an enum of the configured ids, so the model can only name
239
- * something the tenant set up (C3), and no tool takes a subscriber: the action
240
- * lands on whoever the turn belongs to (C4, C5). A tool whose list is empty is
241
- * not offered at all.
242
- */
243
- export declare function buildTools(config: Tools, stage: ActionStage, contact?: ContactActions,
244
- /** The turn's own contact, readable only on a turn that reads history (specs/024). */
245
- reads?: ContactReads,
246
- /**
247
- * A nudge turn is offered no `schedule_nudge`, so a nudge never schedules
248
- * another (specs/025). `flows`, when given, sends a flow when it is called
249
- * instead of staging it (specs/029).
250
- */
251
- options?: {
252
- nudgeTurn?: boolean;
253
- flows?: FlowSends | undefined;
254
- /**
255
- * Runs before the turn's first flow goes out: on the prospect turn it
256
- * sends the opening, so no content reaches the contact ahead of it
257
- * (specs/032 § The opening flow is the server's, not the model's).
258
- */
259
- beforeFlow?: (() => Promise<void>) | undefined;
260
- /** The tenant's plugin tools, staged as the built-in ones are (specs/036). */
261
- plugins?: Plugins | undefined;
262
- /**
263
- * The turn's plugin reads. Absent, no read tool is offered: as for
264
- * `get_contact`, only a turn that reads history may read (specs/039).
265
- */
266
- pluginReads?: PluginReads | undefined;
267
- }): ToolSet | undefined;
2
+ * The tools the model may call on a turn (specs/012), and the stage that
3
+ * holds what it chose (ADR-0010). Split across `tools/` by concern; this
4
+ * file is the one place they are imported from.
5
+ */
6
+ export { MAX_STEPS, buildTools } from './tools/build.ts';
7
+ export type { BuildToolsOptions } from './tools/turn.ts';
8
+ export { MAX_ACTIONS_PER_TURN, ActionStage, describeAction, recordOf } from './tools/stage.ts';
9
+ export { funnelField, intentField, knownOffering, offeringField, openingFlow, paymentLinkFlow, silentPaymentLink, stagesProspect, } from './tools/lookups.ts';
10
+ export type { Intent } from './tools/lookups.ts';
11
+ export { NO_CONTACT_ACTIONS, contactActionsFrom } from './tools/contact-actions.ts';
12
+ export type { ContactActions } from './tools/contact-actions.ts';