@diegoaltoworks/chatter 0.61.0 → 0.62.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.
- package/README.md +55 -17
- package/dist/auth/secretStrength.d.ts +1 -1
- package/dist/auth/secretStrength.d.ts.map +1 -1
- package/dist/bin/create-apikey.js +45 -28
- package/dist/bin/wa-pair.js +113 -46
- package/dist/channels/backoff.d.ts +10 -0
- package/dist/channels/backoff.d.ts.map +1 -0
- package/dist/channels/gates.d.ts +15 -8
- package/dist/channels/gates.d.ts.map +1 -1
- package/dist/channels/index.d.ts +1 -1
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +38 -5
- package/dist/channels/index.mjs +37 -5
- package/dist/channels/matrix/api.d.ts +25 -6
- package/dist/channels/matrix/api.d.ts.map +1 -1
- package/dist/channels/matrix/channel.d.ts +4 -56
- package/dist/channels/matrix/channel.d.ts.map +1 -1
- package/dist/channels/matrix/handler.d.ts +16 -9
- package/dist/channels/matrix/handler.d.ts.map +1 -1
- package/dist/channels/matrix/index.d.ts +2 -2
- package/dist/channels/matrix/index.d.ts.map +1 -1
- package/dist/channels/matrix/index.js +196 -40
- package/dist/channels/matrix/index.mjs +189 -39
- package/dist/channels/matrix/sync.d.ts +4 -1
- package/dist/channels/matrix/sync.d.ts.map +1 -1
- package/dist/channels/matrix/updates.d.ts +39 -10
- package/dist/channels/matrix/updates.d.ts.map +1 -1
- package/dist/channels/pipeline.d.ts +14 -14
- package/dist/channels/pipeline.d.ts.map +1 -1
- package/dist/channels/polling.d.ts +67 -0
- package/dist/channels/polling.d.ts.map +1 -0
- package/dist/channels/telegram/channel.d.ts +2 -56
- package/dist/channels/telegram/channel.d.ts.map +1 -1
- package/dist/channels/telegram/index.js +53 -23
- package/dist/channels/telegram/index.mjs +53 -23
- package/dist/channels/telegram/poll.d.ts +5 -1
- package/dist/channels/telegram/poll.d.ts.map +1 -1
- package/dist/channels/telegram/webhook.d.ts +2 -10
- package/dist/channels/telegram/webhook.d.ts.map +1 -1
- package/dist/channels/whatsapp/authState.d.ts +40 -9
- package/dist/channels/whatsapp/authState.d.ts.map +1 -1
- package/dist/channels/whatsapp/channel.d.ts +25 -4
- package/dist/channels/whatsapp/channel.d.ts.map +1 -1
- package/dist/channels/whatsapp/inbound.d.ts +23 -25
- package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.d.ts +3 -3
- package/dist/channels/whatsapp/index.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.js +123 -41
- package/dist/channels/whatsapp/index.mjs +120 -41
- package/dist/channels/whatsapp/pairing.d.ts.map +1 -1
- package/dist/client/src/Chat.d.ts.map +1 -1
- package/dist/client/src/ChatButton.d.ts.map +1 -1
- package/dist/client/src/browser.d.ts.map +1 -1
- package/dist/core/answer.d.ts +8 -0
- package/dist/core/answer.d.ts.map +1 -1
- package/dist/core/buildLock.d.ts +52 -0
- package/dist/core/buildLock.d.ts.map +1 -0
- package/dist/core/pipeline.d.ts +42 -5
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/prompts.d.ts +2 -0
- package/dist/core/prompts.d.ts.map +1 -1
- package/dist/core/retrieval.d.ts +100 -25
- package/dist/core/retrieval.d.ts.map +1 -1
- package/dist/core/session.d.ts +8 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/flows/index.d.ts +1 -1
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +8 -6
- package/dist/flows/index.mjs +7 -6
- package/dist/flows/intent.d.ts +1 -1
- package/dist/flows/intent.d.ts.map +1 -1
- package/dist/flows/loader.d.ts +1 -2
- package/dist/flows/loader.d.ts.map +1 -1
- package/dist/flows/params.d.ts +1 -1
- package/dist/flows/params.d.ts.map +1 -1
- package/dist/flows/session.d.ts +4 -2
- package/dist/flows/session.d.ts.map +1 -1
- package/dist/flows/types.d.ts +2 -3
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/history/index.d.ts +1 -1
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +6 -3
- package/dist/history/index.mjs +5 -3
- package/dist/history/tursoStore.d.ts +6 -4
- package/dist/history/tursoStore.d.ts.map +1 -1
- package/dist/images/index.js +2 -2
- package/dist/images/index.mjs +2 -2
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +596 -295
- package/dist/index.mjs +595 -295
- package/dist/mcp-server/index.d.ts +5 -5
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/logger.d.ts +12 -2
- package/dist/mcp-server/logger.d.ts.map +1 -1
- package/dist/mcp-server/rate-limiter.d.ts +10 -3
- package/dist/mcp-server/rate-limiter.d.ts.map +1 -1
- package/dist/mcp-server/types.d.ts +20 -5
- package/dist/mcp-server/types.d.ts.map +1 -1
- package/dist/mcp-server.js +479 -244
- package/dist/mcp-server.mjs +485 -244
- package/dist/middleware/apiKey.d.ts +10 -0
- package/dist/middleware/apiKey.d.ts.map +1 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/ratelimit.d.ts.map +1 -1
- package/dist/middleware/referrer.d.ts.map +1 -1
- package/dist/middleware/session.d.ts +1 -1
- package/dist/middleware/session.d.ts.map +1 -1
- package/dist/routes/demo.d.ts.map +1 -1
- package/dist/routes/openai.d.ts.map +1 -1
- package/dist/routes/private.d.ts.map +1 -1
- package/dist/routes/public.d.ts.map +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/scheduler/index.mjs +1 -1
- package/dist/scheduler/scheduler.d.ts +9 -1
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +491 -268
- package/dist/server.mjs +497 -268
- package/dist/shortener.d.ts +5 -4
- package/dist/shortener.d.ts.map +1 -1
- package/dist/types.d.ts +129 -75
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Baileys auth state, encrypted at rest, over an injectable {@link WaAuthKV}.
|
|
3
3
|
*
|
|
4
4
|
* Same contract as Baileys' own `useMultiFileAuthState`, but rows in a
|
|
5
|
-
*
|
|
6
|
-
* session material
|
|
7
|
-
* readable.
|
|
5
|
+
* key-value store instead of files, AES-GCM encrypted (see `crypto.ts`) so
|
|
6
|
+
* session material - which grants full account access - is never stored
|
|
7
|
+
* readable. The store itself only ever sees ciphertext: encryption lives in
|
|
8
|
+
* this module, above the store, so a custom `WaAuthKV` cannot accidentally
|
|
9
|
+
* persist plaintext session material.
|
|
8
10
|
*
|
|
9
11
|
* Only Baileys *types* are imported here (erased at compile time, so they add
|
|
10
12
|
* no runtime dependency); the few Baileys runtime values this module needs
|
|
11
13
|
* (`BufferJSON`, `initAuthCreds`, the app-state-sync-key constructor) are
|
|
12
14
|
* passed in by the caller, which already holds them from the dynamic import
|
|
13
|
-
* in `baileys.ts`
|
|
15
|
+
* in `baileys.ts` - see that module for why the import is dynamic.
|
|
14
16
|
*/
|
|
15
17
|
import type { Client } from "@libsql/client";
|
|
16
18
|
import type { AuthenticationCreds, AuthenticationState, SignalDataTypeMap } from "@whiskeysockets/baileys";
|
|
@@ -30,10 +32,39 @@ export interface AuthStateRuntime {
|
|
|
30
32
|
appStateSyncKeyFromObject: (value: Record<string, unknown>) => SignalDataTypeMap["app-state-sync-key"];
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* support is introduced.
|
|
35
|
+
* Raw storage for Baileys auth rows, keyed by an already session-scoped
|
|
36
|
+
* `id` (see `useAuthState`'s `rowId`). Values are opaque ciphertext strings -
|
|
37
|
+
* this layer has no encryption knowledge, only persistence.
|
|
37
38
|
*/
|
|
39
|
+
export interface WaAuthKV {
|
|
40
|
+
read(id: string): Promise<string | null>;
|
|
41
|
+
write(id: string, value: string): Promise<void>;
|
|
42
|
+
remove(id: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Deletes every row belonging to `sessionId` and no other session's -
|
|
45
|
+
* use {@link isAuthRowForSession} to decide which stored ids qualify
|
|
46
|
+
* rather than re-deriving the "default" session's unprefixed special case
|
|
47
|
+
* by hand; getting this wrong logs out a sibling number.
|
|
48
|
+
*/
|
|
49
|
+
clear(sessionId: string): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Pure: does row id `id` (as stored - already passed through `rowId`) belong
|
|
53
|
+
* to `sessionId`? Mirrors `useAuthState`'s `rowId` and the SQL in
|
|
54
|
+
* `createTursoWaAuthKV`'s `clear` - keep the three in sync. The "default"
|
|
55
|
+
* session's rows are UNPREFIXED (see `useAuthState`), so its scope is
|
|
56
|
+
* everything *not* claimed by a named session's `s:<sessionId>/` prefix.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isAuthRowForSession(id: string, sessionId: string): boolean;
|
|
59
|
+
/** The shipped `WaAuthKV`: a `wa_auth` table in the same libsql database the rest of chatter uses. */
|
|
60
|
+
export declare function createTursoWaAuthKV(db: Client): WaAuthKV;
|
|
61
|
+
/**
|
|
62
|
+
* Sessions share one `WaAuthKV`, namespaced by row-id prefix. The "default"
|
|
63
|
+
* session uses UNPREFIXED ids - exactly a single-session layout - so an
|
|
64
|
+
* existing default session needs no migration when multi-session support is
|
|
65
|
+
* introduced.
|
|
66
|
+
*/
|
|
67
|
+
export declare function useAuthState(store: WaAuthKV, secret: string, sessionId: string, runtime: AuthStateRuntime): Promise<TursoAuthStateResult>;
|
|
68
|
+
/** Convenience wrapper over `useAuthState` for the shipped Turso-backed `WaAuthKV`. */
|
|
38
69
|
export declare function useTursoAuthState(db: Client, secret: string, sessionId: string, runtime: AuthStateRuntime): Promise<TursoAuthStateResult>;
|
|
39
70
|
//# sourceMappingURL=authState.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authState.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/authState.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authState.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/authState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,mBAAmB,CAAC;IAC3B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,kDAAkD;IAClD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE;QACV,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;QACnD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;KACnD,CAAC;IACF,aAAa,EAAE,MAAM,mBAAmB,CAAC;IACzC,yBAAyB,EAAE,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;CAC9C;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;;;;;OAKG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAG1E;AAiBD,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,CAmCxD;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CA2D/B;AAED,uFAAuF;AACvF,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAE/B"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WhatsApp web-client transport: a {@link Channel} that runs one Baileys
|
|
3
3
|
* socket per configured session id (one WhatsApp number each), auth state
|
|
4
|
-
* encrypted
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* encrypted above an injectable {@link WaAuthKV} (defaults to a table in the
|
|
5
|
+
* host's own database, `deps.db` - no second connection opened), and a
|
|
6
|
+
* deploy lease behind an injectable `WaLeaseStore` so two overlapping
|
|
7
|
+
* instances can never hold the same session's socket at once (WhatsApp
|
|
8
|
+
* treats a second connection as a takeover and logs the first one out).
|
|
8
9
|
*
|
|
9
10
|
* Message INTERPRETATION — mention/reply detection, allowlists, loop guards —
|
|
10
11
|
* is deliberately not this module's job; it hands every raw inbound message
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
import type { WAMessage, WASocket } from "@whiskeysockets/baileys";
|
|
19
20
|
import { type Logger } from "../../core/logger";
|
|
20
21
|
import type { Channel } from "../index";
|
|
22
|
+
import type { WaAuthKV } from "./authState";
|
|
21
23
|
import { type Baileys } from "./baileys";
|
|
22
24
|
import { type WaLeaseStore } from "./lease";
|
|
23
25
|
/** Exponential backoff: 5s, 10s, 20s ... capped at 10 minutes. Hammering
|
|
@@ -31,6 +33,8 @@ export interface WhatsAppMessageEvent {
|
|
|
31
33
|
export interface WhatsAppChannelConfig {
|
|
32
34
|
/** Passphrase that encrypts auth state at rest (AES-256-GCM key material). Keep it stable across restarts and deploys — losing it means re-pairing. */
|
|
33
35
|
sessionSecret: string;
|
|
36
|
+
/** Channel and sender-registry name prefix (see {@link senderNameFor}). Override to run more than one WhatsApp channel in one process. @default "whatsapp" */
|
|
37
|
+
name?: string;
|
|
34
38
|
/** One Baileys connection per id, each a separate WhatsApp number. Defaults to `["default"]`, whose auth rows are unprefixed (a pre-multi-session deployment needs no migration). */
|
|
35
39
|
sessionIds?: string[];
|
|
36
40
|
/**
|
|
@@ -52,6 +56,10 @@ export interface WhatsAppChannelConfig {
|
|
|
52
56
|
waitMs?: number;
|
|
53
57
|
/** Logger for connection/lease lifecycle events. Default: a console logger writing to stderr. */
|
|
54
58
|
logger?: Logger;
|
|
59
|
+
/** Deploy-overlap lease. Defaults to a `wa_lease` table in `deps.db`; inject your own to run this channel without a libsql database (see docs/patterns/adding-a-store.md). */
|
|
60
|
+
leaseStore?: WaLeaseStore;
|
|
61
|
+
/** Baileys auth-state persistence, encrypted above this seam. Defaults to a `wa_auth` table in `deps.db`; inject your own to run this channel without a libsql database. */
|
|
62
|
+
authStore?: WaAuthKV;
|
|
55
63
|
}
|
|
56
64
|
/** A live, leased session: what `stop()` (or losing the lease) must tear down. */
|
|
57
65
|
export interface WaSessionHandle {
|
|
@@ -95,5 +103,18 @@ export interface LeaseGatedConnectDeps {
|
|
|
95
103
|
export declare function acquireSessionLease(sessionId: string, deps: LeaseGatedConnectDeps): Promise<void>;
|
|
96
104
|
/** Sender-registry name for a session — the default session stays unprefixed so single-number deployments see a plain `"whatsapp"` name. */
|
|
97
105
|
export declare function senderNameFor(channelName: string, sessionId: string): string;
|
|
106
|
+
/** `ChannelSender.sendMedia`'s payload shape for this channel: a URL Baileys fetches itself, matching `./images`' own `{ image: { url } }` usage. A bare string is shorthand for the URL, the same convention `./telegram` and `./matrix` use. */
|
|
107
|
+
export interface WhatsAppMediaPayload {
|
|
108
|
+
url: string;
|
|
109
|
+
caption?: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Turns the registry's opaque `sendMedia` payload into what `sock.sendMessage`
|
|
113
|
+
* needs. `ChannelSender.sendMedia` types its payload as `unknown` (payload
|
|
114
|
+
* shapes are transport-defined), so this is where that unknown is checked:
|
|
115
|
+
* a malformed payload throws here, which the sender registry reports as
|
|
116
|
+
* `false` rather than sending Baileys a `{ image: { url: undefined } }`.
|
|
117
|
+
*/
|
|
118
|
+
export declare function normalizeWaMediaPayload(payload: unknown): WhatsAppMediaPayload;
|
|
98
119
|
export declare function createWhatsAppChannel(config: WhatsAppChannelConfig): Channel;
|
|
99
120
|
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/channel.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
* interpretation.
|
|
7
7
|
*
|
|
8
8
|
* Message-shape parsing (text/caption extraction, contextInfo mentions and
|
|
9
|
-
* quoted-reply resolution)
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* quoted-reply resolution) accounts for a Baileys quirk: text AND contextInfo
|
|
10
|
+
* live in a DIFFERENT place per message shape - plain text carries both on
|
|
11
|
+
* `extendedTextMessage`, but a photo/video/document carries its caption on
|
|
12
|
+
* its own message type and its contextInfo there too. Missing that meant
|
|
13
|
+
* mentions in photo captions were invisible and group photo requests were
|
|
14
|
+
* silently ignored.
|
|
15
15
|
*
|
|
16
16
|
* `createWhatsAppInboundHandler` needs `ServerDependencies`
|
|
17
17
|
* (`client`/`store`/`prompts`), which only exists once `createServer` builds
|
|
@@ -34,11 +34,10 @@
|
|
|
34
34
|
* client: deps.client,
|
|
35
35
|
* store: deps.store,
|
|
36
36
|
* prompts: deps.prompts,
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* transformReply: deps.config.transformReply,
|
|
37
|
+
* // Falls back to deps.config.{answerFn,bucketsFor,rewriteQuery,
|
|
38
|
+
* // rerankContext,fallbackFn,transformReply} for whichever of those
|
|
39
|
+
* // this config doesn't set itself.
|
|
40
|
+
* serverConfig: deps.config,
|
|
42
41
|
* registry: new Map(),
|
|
43
42
|
* logger: deps.logger,
|
|
44
43
|
* });
|
|
@@ -48,14 +47,12 @@
|
|
|
48
47
|
*/
|
|
49
48
|
import type { WAMessage, WASocket } from "@whiskeysockets/baileys";
|
|
50
49
|
import type OpenAI from "openai";
|
|
51
|
-
import type { AnswerFn, TransformReply } from "../../core/answer";
|
|
52
|
-
import type { BucketsFor } from "../../core/buckets";
|
|
53
50
|
import { type Logger } from "../../core/logger";
|
|
54
|
-
import type { RerankContext, RewriteQuery } from "../../core/pipeline";
|
|
55
51
|
import type { PromptLoader } from "../../core/prompts";
|
|
56
|
-
import type {
|
|
52
|
+
import type { Retriever } from "../../core/retrieval";
|
|
57
53
|
import type { HistoryCompactionOptions } from "../../history/compaction";
|
|
58
54
|
import type { HistoryStore } from "../../history/types";
|
|
55
|
+
import type { BrainHooks } from "../../types";
|
|
59
56
|
import { type ChannelMessage, type SessionIdentityRegistry } from "../gates";
|
|
60
57
|
import type { WhatsAppMessageEvent } from "./channel";
|
|
61
58
|
import type { WhatsAppImageHandler } from "./images";
|
|
@@ -127,18 +124,19 @@ export interface ResolvedWaMessage {
|
|
|
127
124
|
* multiplies this work.
|
|
128
125
|
*/
|
|
129
126
|
export declare function resolveWaMessage(event: WhatsAppMessageEvent, registry: SessionIdentityRegistry): ResolvedWaMessage;
|
|
130
|
-
export interface WhatsAppInboundConfig {
|
|
127
|
+
export interface WhatsAppInboundConfig extends BrainHooks {
|
|
131
128
|
client: OpenAI;
|
|
132
|
-
store:
|
|
129
|
+
store: Retriever;
|
|
133
130
|
prompts: PromptLoader;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Fallback source for the brain hooks above, each consulted only when this
|
|
133
|
+
* config's own field is unset. Pass `deps.config` from the `customRoutes`
|
|
134
|
+
* callback (see the module docstring) so this handler automatically
|
|
135
|
+
* honours a server-level hook, the same precedence `./telegram` and
|
|
136
|
+
* `./matrix` apply internally via `resolveBrainHooks`. Unset: only this
|
|
137
|
+
* config's own fields count.
|
|
138
|
+
*/
|
|
139
|
+
serverConfig?: BrainHooks;
|
|
142
140
|
model?: string;
|
|
143
141
|
/**
|
|
144
142
|
* Own identities per session — share ONE registry across every session
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/inbound.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/inbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @packageDocumentation
|
|
25
25
|
*/
|
|
26
|
-
export type { AuthStateRuntime, TursoAuthStateResult } from "./authState";
|
|
27
|
-
export { useTursoAuthState } from "./authState";
|
|
26
|
+
export type { AuthStateRuntime, TursoAuthStateResult, WaAuthKV } from "./authState";
|
|
27
|
+
export { createTursoWaAuthKV, useAuthState, useTursoAuthState } from "./authState";
|
|
28
28
|
export type { Baileys } from "./baileys";
|
|
29
29
|
export { loadBaileys } from "./baileys";
|
|
30
|
-
export { acquireSessionLease, createWhatsAppChannel, type LeaseGatedConnectDeps, reconnectDelayMs, senderNameFor, shutdownWaSessions, type WaSessionHandle, type WhatsAppChannelConfig, type WhatsAppMessageEvent, } from "./channel";
|
|
30
|
+
export { acquireSessionLease, createWhatsAppChannel, type LeaseGatedConnectDeps, normalizeWaMediaPayload, reconnectDelayMs, senderNameFor, shutdownWaSessions, type WaSessionHandle, type WhatsAppChannelConfig, type WhatsAppMediaPayload, type WhatsAppMessageEvent, } from "./channel";
|
|
31
31
|
export { decrypt, encrypt } from "./crypto";
|
|
32
32
|
export { createWhatsAppImageHandler, type DrawRequestDetectorConfig, drawSubject, isDrawRequest, type WhatsAppImageHandler, type WhatsAppImageHandlerDeps, type WhatsAppImageRequestContext, type WhatsAppImageStrings, } from "./images";
|
|
33
33
|
export { createWhatsAppInboundHandler, extractText, isGroupJid, jidsMatch, jidToPhoneNumber, messageContext, type ResolvedWaMessage, resolveWaMessage, senderPhoneFor, stripOwnMentions, type WaMessageContext, type WhatsAppInboundConfig, } from "./inbound";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnF,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,uBAAuB,EACvB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EACL,0BAA0B,EAC1B,KAAK,yBAAyB,EAC9B,WAAW,EACX,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,4BAA4B,EAC5B,WAAW,EACX,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,2BAA2B,EAC3B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,GACjC,MAAM,UAAU,CAAC"}
|
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
LEASE_WAIT_MS: () => LEASE_WAIT_MS,
|
|
36
36
|
acquireSessionLease: () => acquireSessionLease,
|
|
37
37
|
canAcquireLease: () => canAcquireLease,
|
|
38
|
+
createTursoWaAuthKV: () => createTursoWaAuthKV,
|
|
38
39
|
createTursoWaLeaseStore: () => createTursoWaLeaseStore,
|
|
39
40
|
createWhatsAppChannel: () => createWhatsAppChannel,
|
|
40
41
|
createWhatsAppImageHandler: () => createWhatsAppImageHandler,
|
|
@@ -50,12 +51,14 @@ __export(index_exports, {
|
|
|
50
51
|
jidsMatch: () => jidsMatch,
|
|
51
52
|
loadBaileys: () => loadBaileys,
|
|
52
53
|
messageContext: () => messageContext,
|
|
54
|
+
normalizeWaMediaPayload: () => normalizeWaMediaPayload,
|
|
53
55
|
reconnectDelayMs: () => reconnectDelayMs,
|
|
54
56
|
resolveWaMessage: () => resolveWaMessage,
|
|
55
57
|
senderNameFor: () => senderNameFor,
|
|
56
58
|
senderPhoneFor: () => senderPhoneFor,
|
|
57
59
|
shutdownWaSessions: () => shutdownWaSessions,
|
|
58
60
|
stripOwnMentions: () => stripOwnMentions,
|
|
61
|
+
useAuthState: () => useAuthState,
|
|
59
62
|
useTursoAuthState: () => useTursoAuthState
|
|
60
63
|
});
|
|
61
64
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -129,27 +132,55 @@ function ensureAuthSchema(client) {
|
|
|
129
132
|
}
|
|
130
133
|
return ready;
|
|
131
134
|
}
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
function createTursoWaAuthKV(db) {
|
|
136
|
+
return {
|
|
137
|
+
async read(id) {
|
|
138
|
+
await ensureAuthSchema(db);
|
|
139
|
+
const result = await db.execute({
|
|
140
|
+
sql: "SELECT value FROM wa_auth WHERE id = ?",
|
|
141
|
+
args: [id]
|
|
142
|
+
});
|
|
143
|
+
const row = result.rows[0];
|
|
144
|
+
return row ? row.value : null;
|
|
145
|
+
},
|
|
146
|
+
async write(id, value) {
|
|
147
|
+
await ensureAuthSchema(db);
|
|
148
|
+
await db.execute({
|
|
149
|
+
sql: "INSERT OR REPLACE INTO wa_auth (id, value) VALUES (?, ?)",
|
|
150
|
+
args: [id, value]
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
async remove(id) {
|
|
154
|
+
await ensureAuthSchema(db);
|
|
155
|
+
await db.execute({ sql: "DELETE FROM wa_auth WHERE id = ?", args: [id] });
|
|
156
|
+
},
|
|
157
|
+
// Mirrors isAuthRowForSession - keep the two in sync.
|
|
158
|
+
async clear(sessionId) {
|
|
159
|
+
await ensureAuthSchema(db);
|
|
160
|
+
if (sessionId === "default") {
|
|
161
|
+
await db.execute("DELETE FROM wa_auth WHERE id NOT LIKE 's:%'");
|
|
162
|
+
} else {
|
|
163
|
+
await db.execute({
|
|
164
|
+
sql: "DELETE FROM wa_auth WHERE id LIKE ?",
|
|
165
|
+
args: [`s:${sessionId}/%`]
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async function useAuthState(store, secret, sessionId, runtime) {
|
|
134
172
|
const rowId = (id) => sessionId === "default" ? id : `s:${sessionId}/${id}`;
|
|
135
173
|
async function read(id) {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
140
|
-
const row = result.rows[0];
|
|
141
|
-
if (!row) return null;
|
|
142
|
-
return JSON.parse(await decrypt(row.value, secret), runtime.bufferJSON.reviver);
|
|
174
|
+
const value = await store.read(rowId(id));
|
|
175
|
+
if (value === null) return null;
|
|
176
|
+
return JSON.parse(await decrypt(value, secret), runtime.bufferJSON.reviver);
|
|
143
177
|
}
|
|
144
178
|
async function write(id, value) {
|
|
145
179
|
const payload = await encrypt(JSON.stringify(value, runtime.bufferJSON.replacer), secret);
|
|
146
|
-
await
|
|
147
|
-
sql: "INSERT OR REPLACE INTO wa_auth (id, value) VALUES (?, ?)",
|
|
148
|
-
args: [rowId(id), payload]
|
|
149
|
-
});
|
|
180
|
+
await store.write(rowId(id), payload);
|
|
150
181
|
}
|
|
151
182
|
async function remove(id) {
|
|
152
|
-
await
|
|
183
|
+
await store.remove(rowId(id));
|
|
153
184
|
}
|
|
154
185
|
const creds = await read("creds") ?? runtime.initAuthCreds();
|
|
155
186
|
return {
|
|
@@ -186,18 +217,13 @@ async function useTursoAuthState(db, secret, sessionId, runtime) {
|
|
|
186
217
|
}
|
|
187
218
|
},
|
|
188
219
|
saveCreds: () => write("creds", creds),
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
await db.execute("DELETE FROM wa_auth WHERE id NOT LIKE 's:%'");
|
|
192
|
-
} else {
|
|
193
|
-
await db.execute({
|
|
194
|
-
sql: "DELETE FROM wa_auth WHERE id LIKE ?",
|
|
195
|
-
args: [`s:${sessionId}/%`]
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
220
|
+
// Scoped to THIS session - never nuke a sibling number's pairing.
|
|
221
|
+
clear: () => store.clear(sessionId)
|
|
199
222
|
};
|
|
200
223
|
}
|
|
224
|
+
async function useTursoAuthState(db, secret, sessionId, runtime) {
|
|
225
|
+
return useAuthState(createTursoWaAuthKV(db), secret, sessionId, runtime);
|
|
226
|
+
}
|
|
201
227
|
|
|
202
228
|
// src/channels/whatsapp/baileys.ts
|
|
203
229
|
function wrapMissingBaileysError(cause) {
|
|
@@ -260,6 +286,11 @@ function createConsoleLogger(level = "info") {
|
|
|
260
286
|
};
|
|
261
287
|
}
|
|
262
288
|
|
|
289
|
+
// src/channels/backoff.ts
|
|
290
|
+
function exponentialBackoffMs(baseMs, maxMs, n) {
|
|
291
|
+
return Math.min(baseMs * 2 ** Math.max(0, Math.min(n, 20)), maxMs);
|
|
292
|
+
}
|
|
293
|
+
|
|
263
294
|
// src/channels/whatsapp/lease.ts
|
|
264
295
|
var LEASE_STALE_MS = 9e4;
|
|
265
296
|
var LEASE_HEARTBEAT_MS = 3e4;
|
|
@@ -318,7 +349,7 @@ function createTursoWaLeaseStore(client) {
|
|
|
318
349
|
var RECONNECT_DELAY_MS = 5e3;
|
|
319
350
|
var RECONNECT_MAX_DELAY_MS = 10 * 60 * 1e3;
|
|
320
351
|
function reconnectDelayMs(failures) {
|
|
321
|
-
return
|
|
352
|
+
return exponentialBackoffMs(RECONNECT_DELAY_MS, RECONNECT_MAX_DELAY_MS, failures);
|
|
322
353
|
}
|
|
323
354
|
async function shutdownWaSessions(sessions) {
|
|
324
355
|
await Promise.all(
|
|
@@ -389,9 +420,18 @@ async function acquireSessionLease(sessionId, deps) {
|
|
|
389
420
|
function senderNameFor(channelName, sessionId) {
|
|
390
421
|
return sessionId === "default" ? channelName : `${channelName}:${sessionId}`;
|
|
391
422
|
}
|
|
423
|
+
function normalizeWaMediaPayload(payload) {
|
|
424
|
+
const media = typeof payload === "string" ? { url: payload } : payload;
|
|
425
|
+
if (!media || typeof media !== "object" || typeof media.url !== "string" || !media.url) {
|
|
426
|
+
throw new TypeError(
|
|
427
|
+
`WhatsApp sendMedia payload must be a URL string or { url, caption? }, got: ${typeof payload}`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return media;
|
|
431
|
+
}
|
|
392
432
|
function createWhatsAppChannel(config) {
|
|
393
433
|
assertStrongSecret(config.sessionSecret, "WhatsApp sessionSecret (e.g. WA_SESSION_SECRET)");
|
|
394
|
-
const channelName = "whatsapp";
|
|
434
|
+
const channelName = config.name ?? "whatsapp";
|
|
395
435
|
const sessionIds = config.sessionIds && config.sessionIds.length > 0 ? config.sessionIds : ["default"];
|
|
396
436
|
const now = config.now ?? Date.now;
|
|
397
437
|
const schedule = config.schedule ?? ((fn, ms) => void setTimeout(fn, ms));
|
|
@@ -409,8 +449,13 @@ function createWhatsAppChannel(config) {
|
|
|
409
449
|
name: channelName,
|
|
410
450
|
async start(deps) {
|
|
411
451
|
const log = config.logger ?? deps.logger ?? createConsoleLogger();
|
|
412
|
-
|
|
413
|
-
|
|
452
|
+
if ((!config.leaseStore || !config.authStore) && !deps.db) {
|
|
453
|
+
throw new Error(
|
|
454
|
+
"The WhatsApp channel needs a libsql client for auth state and the session lease: set config.database (config.retriever alone does not open one), or supply both config.leaseStore and config.authStore."
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
const leaseStore = config.leaseStore ?? createTursoWaLeaseStore(deps.db);
|
|
458
|
+
const authStore = config.authStore ?? createTursoWaAuthKV(deps.db);
|
|
414
459
|
senders = deps.senders;
|
|
415
460
|
await loadBaileys2();
|
|
416
461
|
async function connect(sessionId) {
|
|
@@ -421,8 +466,8 @@ function createWhatsAppChannel(config) {
|
|
|
421
466
|
initAuthCreds: baileys.initAuthCreds,
|
|
422
467
|
appStateSyncKeyFromObject: (value) => baileys.proto.Message.AppStateSyncKeyData.fromObject(value)
|
|
423
468
|
};
|
|
424
|
-
const { state, saveCreds } = await
|
|
425
|
-
|
|
469
|
+
const { state, saveCreds } = await useAuthState(
|
|
470
|
+
authStore,
|
|
426
471
|
config.sessionSecret,
|
|
427
472
|
sessionId,
|
|
428
473
|
runtime
|
|
@@ -466,6 +511,13 @@ function createWhatsAppChannel(config) {
|
|
|
466
511
|
sendText: async (chatId, text) => {
|
|
467
512
|
await sock.sendMessage(chatId, { text });
|
|
468
513
|
},
|
|
514
|
+
sendMedia: async (chatId, payload) => {
|
|
515
|
+
const { url, caption } = normalizeWaMediaPayload(payload);
|
|
516
|
+
await sock.sendMessage(
|
|
517
|
+
chatId,
|
|
518
|
+
caption !== void 0 ? { image: { url }, caption } : { image: { url } }
|
|
519
|
+
);
|
|
520
|
+
},
|
|
469
521
|
sendReaction: async (chatId, messageRef, emoji) => {
|
|
470
522
|
await sock.sendMessage(chatId, {
|
|
471
523
|
react: { text: emoji, key: messageRef }
|
|
@@ -741,7 +793,8 @@ async function answerOnce({
|
|
|
741
793
|
async function applyTransformReply(transformReply, input, logger) {
|
|
742
794
|
if (!transformReply) return input.text;
|
|
743
795
|
try {
|
|
744
|
-
|
|
796
|
+
const result = await transformReply(input);
|
|
797
|
+
return typeof result === "string" ? result : null;
|
|
745
798
|
} catch (error) {
|
|
746
799
|
logger?.error(
|
|
747
800
|
`transformReply threw for channel "${input.channel}"; sending the original reply`,
|
|
@@ -803,6 +856,7 @@ async function prepareChat({
|
|
|
803
856
|
sender,
|
|
804
857
|
rewriteQuery,
|
|
805
858
|
rerankContext,
|
|
859
|
+
fallbackFn,
|
|
806
860
|
logger
|
|
807
861
|
}) {
|
|
808
862
|
const lastUserMsg = lastUserMessage(messages);
|
|
@@ -819,21 +873,39 @@ async function prepareChat({
|
|
|
819
873
|
logger?.error("rewriteQuery threw; falling back to the original query", error);
|
|
820
874
|
}
|
|
821
875
|
}
|
|
822
|
-
|
|
876
|
+
const resolvedBuckets = buckets ?? defaultBuckets(mode);
|
|
877
|
+
const retrievedChunks = await store.query(query, topK, resolvedBuckets);
|
|
878
|
+
let ctx = retrievedChunks;
|
|
823
879
|
if (rerankContext) {
|
|
824
880
|
try {
|
|
825
|
-
const reranked = await rerankContext({ query, chunks: ctx });
|
|
881
|
+
const reranked = await rerankContext({ query, chunks: [...ctx] });
|
|
826
882
|
if (Array.isArray(reranked) && reranked.every((c) => typeof c === "string")) ctx = reranked;
|
|
827
883
|
} catch (error) {
|
|
828
884
|
logger?.error("rerankContext threw; falling back to the original chunks", error);
|
|
829
885
|
}
|
|
830
886
|
}
|
|
887
|
+
let fallback;
|
|
888
|
+
if (ctx.length === 0 && fallbackFn) {
|
|
889
|
+
try {
|
|
890
|
+
const guidance = await fallbackFn({
|
|
891
|
+
query,
|
|
892
|
+
mode,
|
|
893
|
+
buckets: resolvedBuckets,
|
|
894
|
+
sender,
|
|
895
|
+
retrievedChunks
|
|
896
|
+
});
|
|
897
|
+
if (typeof guidance === "string" && guidance.trim()) fallback = guidance.trim();
|
|
898
|
+
} catch (error) {
|
|
899
|
+
logger?.error("fallbackFn threw; proceeding without fallback guidance", error);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
831
902
|
const persona = personaLayer?.trim() || (mode === "private" ? prompts.privatePersona : prompts.publicPersona);
|
|
832
903
|
const hint = channelHint?.trim();
|
|
833
904
|
const system = [
|
|
834
905
|
prompts.baseSystemRules,
|
|
835
906
|
persona,
|
|
836
907
|
...hint ? [hint] : [],
|
|
908
|
+
...fallback ? [fallback] : [],
|
|
837
909
|
`${label}:
|
|
838
910
|
${ctx.join("\n\n")}`
|
|
839
911
|
].join("\n\n");
|
|
@@ -841,7 +913,7 @@ ${ctx.join("\n\n")}`
|
|
|
841
913
|
}
|
|
842
914
|
|
|
843
915
|
// src/history/compaction.ts
|
|
844
|
-
var
|
|
916
|
+
var COMPACTION_TIMEOUT_MS = 8e3;
|
|
845
917
|
var LOAD_ALL = Number.MAX_SAFE_INTEGER;
|
|
846
918
|
var SUMMARY_PREFIX = "Summary of earlier conversation: ";
|
|
847
919
|
function defaultSummarize(client, model) {
|
|
@@ -869,7 +941,7 @@ function createHistoryCompactor(deps, options) {
|
|
|
869
941
|
throw new Error(`Invalid history compaction keep: ${keep}`);
|
|
870
942
|
}
|
|
871
943
|
const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
|
|
872
|
-
const timeoutMs = options.timeoutMs ??
|
|
944
|
+
const timeoutMs = options.timeoutMs ?? COMPACTION_TIMEOUT_MS;
|
|
873
945
|
return {
|
|
874
946
|
async maybeCompact(store, conversationId) {
|
|
875
947
|
const turns = await store.load(conversationId, LOAD_ALL);
|
|
@@ -910,6 +982,16 @@ function createHistoryCompactor(deps, options) {
|
|
|
910
982
|
}
|
|
911
983
|
|
|
912
984
|
// src/channels/pipeline.ts
|
|
985
|
+
function resolveBrainHooks(config, fallback) {
|
|
986
|
+
return {
|
|
987
|
+
answerFn: config.answerFn ?? fallback?.answerFn,
|
|
988
|
+
bucketsFor: config.bucketsFor ?? fallback?.bucketsFor,
|
|
989
|
+
rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
|
|
990
|
+
rerankContext: config.rerankContext ?? fallback?.rerankContext,
|
|
991
|
+
fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
|
|
992
|
+
transformReply: config.transformReply ?? fallback?.transformReply
|
|
993
|
+
};
|
|
994
|
+
}
|
|
913
995
|
var DEFAULT_HISTORY_LIMIT = 20;
|
|
914
996
|
var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
|
|
915
997
|
var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
|
|
@@ -994,6 +1076,7 @@ function createInboundPipeline(deps, config) {
|
|
|
994
1076
|
sender,
|
|
995
1077
|
rewriteQuery: config.rewriteQuery,
|
|
996
1078
|
rerankContext: config.rerankContext,
|
|
1079
|
+
fallbackFn: config.fallbackFn,
|
|
997
1080
|
logger: config.logger
|
|
998
1081
|
});
|
|
999
1082
|
const { content: produced } = await answerOnce({
|
|
@@ -1129,13 +1212,9 @@ function createWhatsAppInboundHandler(config) {
|
|
|
1129
1212
|
{ client: config.client, store: config.store, prompts: config.prompts },
|
|
1130
1213
|
{
|
|
1131
1214
|
channel: "whatsapp",
|
|
1132
|
-
|
|
1133
|
-
bucketsFor: config.bucketsFor,
|
|
1134
|
-
rewriteQuery: config.rewriteQuery,
|
|
1135
|
-
rerankContext: config.rerankContext,
|
|
1136
|
-
transformReply: config.transformReply,
|
|
1215
|
+
...resolveBrainHooks(config, config.serverConfig),
|
|
1137
1216
|
model: config.model,
|
|
1138
|
-
channelHint: config.channelHint,
|
|
1217
|
+
channelHint: config.channelHint ?? "Channel: WhatsApp.",
|
|
1139
1218
|
personaResolver: personaResolver ? ({ sender, text }) => personaResolver({ senderPhone: sender, text }) : void 0,
|
|
1140
1219
|
history: config.history,
|
|
1141
1220
|
allowedChats,
|
|
@@ -1296,6 +1375,7 @@ function createWhatsAppMessageRouter(config) {
|
|
|
1296
1375
|
LEASE_WAIT_MS,
|
|
1297
1376
|
acquireSessionLease,
|
|
1298
1377
|
canAcquireLease,
|
|
1378
|
+
createTursoWaAuthKV,
|
|
1299
1379
|
createTursoWaLeaseStore,
|
|
1300
1380
|
createWhatsAppChannel,
|
|
1301
1381
|
createWhatsAppImageHandler,
|
|
@@ -1311,11 +1391,13 @@ function createWhatsAppMessageRouter(config) {
|
|
|
1311
1391
|
jidsMatch,
|
|
1312
1392
|
loadBaileys,
|
|
1313
1393
|
messageContext,
|
|
1394
|
+
normalizeWaMediaPayload,
|
|
1314
1395
|
reconnectDelayMs,
|
|
1315
1396
|
resolveWaMessage,
|
|
1316
1397
|
senderNameFor,
|
|
1317
1398
|
senderPhoneFor,
|
|
1318
1399
|
shutdownWaSessions,
|
|
1319
1400
|
stripOwnMentions,
|
|
1401
|
+
useAuthState,
|
|
1320
1402
|
useTursoAuthState
|
|
1321
1403
|
});
|