@memberjunction/conversations-runtime 0.0.1 → 5.41.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 +99 -43
- package/dist/ConversationsRuntime.d.ts +193 -0
- package/dist/ConversationsRuntime.d.ts.map +1 -0
- package/dist/ConversationsRuntime.js +268 -0
- package/dist/ConversationsRuntime.js.map +1 -0
- package/dist/adapters/IActiveTaskTracker.d.ts +49 -0
- package/dist/adapters/IActiveTaskTracker.d.ts.map +1 -0
- package/dist/adapters/IActiveTaskTracker.js +26 -0
- package/dist/adapters/IActiveTaskTracker.js.map +1 -0
- package/dist/adapters/INotificationAdapter.d.ts +60 -0
- package/dist/adapters/INotificationAdapter.d.ts.map +1 -0
- package/dist/adapters/INotificationAdapter.js +45 -0
- package/dist/adapters/INotificationAdapter.js.map +1 -0
- package/dist/adapters/ISessionsAdapter.d.ts +124 -0
- package/dist/adapters/ISessionsAdapter.d.ts.map +1 -0
- package/dist/adapters/ISessionsAdapter.js +44 -0
- package/dist/adapters/ISessionsAdapter.js.map +1 -0
- package/dist/agent-runner/ConversationAgentRunner.d.ts +121 -0
- package/dist/agent-runner/ConversationAgentRunner.d.ts.map +1 -0
- package/dist/agent-runner/ConversationAgentRunner.js +191 -0
- package/dist/agent-runner/ConversationAgentRunner.js.map +1 -0
- package/dist/bridge/ConversationBridge.d.ts +93 -0
- package/dist/bridge/ConversationBridge.d.ts.map +1 -0
- package/dist/bridge/ConversationBridge.js +105 -0
- package/dist/bridge/ConversationBridge.js.map +1 -0
- package/dist/context/IConversationsRuntimeContext.d.ts +29 -0
- package/dist/context/IConversationsRuntimeContext.d.ts.map +1 -0
- package/dist/context/IConversationsRuntimeContext.js +21 -0
- package/dist/context/IConversationsRuntimeContext.js.map +1 -0
- package/dist/default-agent/DefaultAgentResolver.d.ts +87 -0
- package/dist/default-agent/DefaultAgentResolver.d.ts.map +1 -0
- package/dist/default-agent/DefaultAgentResolver.js +103 -0
- package/dist/default-agent/DefaultAgentResolver.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/mentions/MentionParser.d.ts +109 -0
- package/dist/mentions/MentionParser.d.ts.map +1 -0
- package/dist/mentions/MentionParser.js +276 -0
- package/dist/mentions/MentionParser.js.map +1 -0
- package/dist/sessions/SessionsObserver.d.ts +87 -0
- package/dist/sessions/SessionsObserver.d.ts.map +1 -0
- package/dist/sessions/SessionsObserver.js +103 -0
- package/dist/sessions/SessionsObserver.js.map +1 -0
- package/dist/streaming/ConversationStreaming.d.ts +169 -0
- package/dist/streaming/ConversationStreaming.d.ts.map +1 -0
- package/dist/streaming/ConversationStreaming.js +355 -0
- package/dist/streaming/ConversationStreaming.js.map +1 -0
- package/package.json +33 -7
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Default-agent resolution chain.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the hardcoded `Agents.find(a => a.Name === 'Sage')` lookup that previously lived
|
|
5
|
+
* in three places inside `@memberjunction/ng-conversations` with a metadata-driven chain
|
|
6
|
+
* routed through `MJ: Application Settings`.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order on every {@link DefaultAgentResolver.resolve} call:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Explicit `explicitAgentId`** on the call (matches the widget's `[DefaultAgentId]`
|
|
11
|
+
* `@Input` — already works today, preserved here for layering).
|
|
12
|
+
* 2. **App-scoped `MJ: Application Settings`** row (`ApplicationID = <current app>`,
|
|
13
|
+
* `Name = 'Conversations.DefaultAgentID'`, `Value = <agent ID>`).
|
|
14
|
+
* 3. **Global `MJ: Application Settings`** row (`ApplicationID IS NULL`, same name).
|
|
15
|
+
* Ships as a metadata seed pointing at Sage on a fresh install.
|
|
16
|
+
* 4. **Code-const fallback** — `Agents.find(a => a.Name === 'Sage')`. Safety net for
|
|
17
|
+
* installs where the seed was skipped; preserves today's behavior so the system never
|
|
18
|
+
* silently fails to route a turn.
|
|
19
|
+
*
|
|
20
|
+
* Steps 2 and 3 are handled by `ApplicationSettingEngine.GetSetting` in one call — that API
|
|
21
|
+
* already does app-scoped-first / global-fallback resolution internally.
|
|
22
|
+
*
|
|
23
|
+
* @module @memberjunction/conversations-runtime
|
|
24
|
+
*/
|
|
25
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
26
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
27
|
+
import { ApplicationSettingEngine } from '@memberjunction/core-entities';
|
|
28
|
+
/**
|
|
29
|
+
* Resolves the default agent for a conversation turn.
|
|
30
|
+
*
|
|
31
|
+
* Usually accessed via `ConversationsRuntime.Instance.DefaultAgent`. Stateless beyond
|
|
32
|
+
* lazy delegation to `ApplicationSettingEngine` and `AIEngineBase`.
|
|
33
|
+
*/
|
|
34
|
+
export class DefaultAgentResolver {
|
|
35
|
+
/** Application Setting key consulted in steps 2 and 3. */
|
|
36
|
+
static { this.SETTING_NAME = 'Conversations.DefaultAgentID'; }
|
|
37
|
+
/**
|
|
38
|
+
* Last-resort fallback agent name (step 4). Kept as a constant rather than another
|
|
39
|
+
* setting so the system has a hard floor even if metadata sync has never run on a
|
|
40
|
+
* fresh install — preserves today's "Sage is the default" behavior unconditionally.
|
|
41
|
+
*/
|
|
42
|
+
static { this.FALLBACK_AGENT_NAME = 'Sage'; }
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the default agent for this turn. Walks the 4-step chain; throws a descriptive
|
|
45
|
+
* error if every step misses (vs. the previous code path's silent `null` return, which
|
|
46
|
+
* made misconfigurations hard to spot at the call site).
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const agent = await runtime.DefaultAgent.resolve({
|
|
51
|
+
* explicitAgentId: widgetInput.DefaultAgentId, // wins if non-null and matches
|
|
52
|
+
* applicationId: currentAppId, // scopes the settings lookup
|
|
53
|
+
* contextUser: this.ProviderToUse.CurrentUser,
|
|
54
|
+
* provider: this.ProviderToUse,
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
async resolve(options = {}) {
|
|
59
|
+
const { explicitAgentId, applicationId, contextUser, provider } = options;
|
|
60
|
+
// Lazy-config the engines we depend on. Both `Config(false, ...)` calls are
|
|
61
|
+
// idempotent — first caller pays the load cost, others are cache hits.
|
|
62
|
+
await AIEngineBase.Instance.Config(false, contextUser, provider);
|
|
63
|
+
await ApplicationSettingEngine.Instance.Config(false, contextUser, provider);
|
|
64
|
+
// Step 1: explicit ID wins if it resolves to a real agent.
|
|
65
|
+
if (explicitAgentId) {
|
|
66
|
+
const explicit = this.findAgentById(explicitAgentId);
|
|
67
|
+
if (explicit)
|
|
68
|
+
return explicit;
|
|
69
|
+
// If an explicit ID was supplied but doesn't resolve, fall through — this is
|
|
70
|
+
// surprising enough to warrant a warning but not surprising enough to throw
|
|
71
|
+
// (the rest of the chain may still produce a sensible default).
|
|
72
|
+
console.warn(`DefaultAgentResolver: explicitAgentId "${explicitAgentId}" did not match any known agent — falling through to settings chain.`);
|
|
73
|
+
}
|
|
74
|
+
// Steps 2 + 3: Application Setting resolution. `GetSetting` already does
|
|
75
|
+
// app-scoped-first / global-fallback in one call.
|
|
76
|
+
const settingValue = ApplicationSettingEngine.Instance.GetSetting(DefaultAgentResolver.SETTING_NAME, applicationId ?? undefined);
|
|
77
|
+
if (settingValue) {
|
|
78
|
+
const fromSetting = this.findAgentById(settingValue);
|
|
79
|
+
if (fromSetting)
|
|
80
|
+
return fromSetting;
|
|
81
|
+
console.warn(`DefaultAgentResolver: Application Setting "${DefaultAgentResolver.SETTING_NAME}" resolved to "${settingValue}" but no matching agent was found — falling through to code-const fallback.`);
|
|
82
|
+
}
|
|
83
|
+
// Step 4: code-const fallback. Find the agent named `Sage` and return it.
|
|
84
|
+
const fallback = AIEngineBase.Instance.Agents.find((a) => a.Name === DefaultAgentResolver.FALLBACK_AGENT_NAME);
|
|
85
|
+
if (fallback)
|
|
86
|
+
return fallback;
|
|
87
|
+
// No agent at any layer — descriptive error so the call site sees the misconfiguration.
|
|
88
|
+
throw new Error(`DefaultAgentResolver: could not resolve a default conversation manager agent. ` +
|
|
89
|
+
`Tried (1) explicitAgentId=${explicitAgentId ?? 'null'}, ` +
|
|
90
|
+
`(2)+(3) Application Setting "${DefaultAgentResolver.SETTING_NAME}" (applicationId=${applicationId ?? 'null'}) = "${settingValue ?? 'undefined'}", ` +
|
|
91
|
+
`(4) code-const fallback agent name = "${DefaultAgentResolver.FALLBACK_AGENT_NAME}". ` +
|
|
92
|
+
`Configure the Application Setting or seed the fallback agent.`);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Find an agent by ID from the AIEngineBase cache. Returns `undefined` if not found.
|
|
96
|
+
* Uses {@link UUIDsEqual} per the standing rule about comparing UUIDs across
|
|
97
|
+
* SQL Server / Postgres (case differences would silently miss).
|
|
98
|
+
*/
|
|
99
|
+
findAgentById(id) {
|
|
100
|
+
return AIEngineBase.Instance.Agents.find((a) => UUIDsEqual(a.ID, id));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=DefaultAgentResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultAgentResolver.js","sourceRoot":"","sources":["../../src/default-agent/DefaultAgentResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AA4BzE;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IAC7B,0DAA0D;aACnC,iBAAY,GAAG,8BAA8B,CAAC;IAErE;;;;OAIG;aACoB,wBAAmB,GAAG,MAAM,CAAC;IAEpD;;;;;;;;;;;;;;OAcG;IACI,KAAK,CAAC,OAAO,CAAC,UAAsC,EAAE;QACzD,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAE1E,4EAA4E;QAC5E,uEAAuE;QACvE,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QACjE,MAAM,wBAAwB,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAE7E,2DAA2D;QAC3D,IAAI,eAAe,EAAE,CAAC;YAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;YACrD,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YAC9B,6EAA6E;YAC7E,4EAA4E;YAC5E,gEAAgE;YAChE,OAAO,CAAC,IAAI,CACR,0CAA0C,eAAe,sEAAsE,CAClI,CAAC;QACN,CAAC;QAED,yEAAyE;QACzE,kDAAkD;QAClD,MAAM,YAAY,GAAG,wBAAwB,CAAC,QAAQ,CAAC,UAAU,CAC7D,oBAAoB,CAAC,YAAY,EACjC,aAAa,IAAI,SAAS,CAC7B,CAAC;QACF,IAAI,YAAY,EAAE,CAAC;YACf,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;YACrD,IAAI,WAAW;gBAAE,OAAO,WAAW,CAAC;YACpC,OAAO,CAAC,IAAI,CACR,8CAA8C,oBAAoB,CAAC,YAAY,kBAAkB,YAAY,6EAA6E,CAC7L,CAAC;QACN,CAAC;QAED,0EAA0E;QAC1E,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,mBAAmB,CAC7D,CAAC;QACF,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,wFAAwF;QACxF,MAAM,IAAI,KAAK,CACX,gFAAgF;YAC5E,6BAA6B,eAAe,IAAI,MAAM,IAAI;YAC1D,gCAAgC,oBAAoB,CAAC,YAAY,oBAAoB,aAAa,IAAI,MAAM,QAAQ,YAAY,IAAI,WAAW,KAAK;YACpJ,yCAAyC,oBAAoB,CAAC,mBAAmB,KAAK;YACtF,+DAA+D,CACtE,CAAC;IACN,CAAC;IAED;;;;OAIG;IACK,aAAa,CAAC,EAAU;QAC5B,OAAO,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public entry point for `@memberjunction/conversations-runtime`.
|
|
3
|
+
*
|
|
4
|
+
* Pure-TypeScript, framework-agnostic runtime for MemberJunction conversational AI
|
|
5
|
+
* experiences. Consumable from browser (Angular widget, React, Vue, Node-side workers)
|
|
6
|
+
* or server (Node tests, CLI tools).
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/conversations-runtime
|
|
9
|
+
*/
|
|
10
|
+
export { ConversationsRuntime } from './ConversationsRuntime.js';
|
|
11
|
+
export { MentionParser, type Mention, type MentionParseResult } from './mentions/MentionParser.js';
|
|
12
|
+
export { ConversationBridge, type ConversationSwitchEvent, type ConversationDeepLink, } from './bridge/ConversationBridge.js';
|
|
13
|
+
export { DefaultAgentResolver, type DefaultAgentResolveOptions, } from './default-agent/DefaultAgentResolver.js';
|
|
14
|
+
export { SessionsObserver, type SessionLifecycleEvent, type SessionChannelState, type SessionEndReason, } from './sessions/SessionsObserver.js';
|
|
15
|
+
export { ConversationStreaming, type CompletionEvent, type MessageProgressUpdate, type MessageProgressMetadata, type MessageProgressCallback, type StreamingConnectionStatus, } from './streaming/ConversationStreaming.js';
|
|
16
|
+
export { ConversationAgentRunner, type ProcessMessageInput, } from './agent-runner/ConversationAgentRunner.js';
|
|
17
|
+
export { type INotificationAdapter, type NotificationLevel, ConsoleNotificationAdapter, } from './adapters/INotificationAdapter.js';
|
|
18
|
+
export { type IActiveTaskTracker, NoOpActiveTaskTracker, } from './adapters/IActiveTaskTracker.js';
|
|
19
|
+
export { type ISessionsAdapter, NoOpSessionsAdapter, } from './adapters/ISessionsAdapter.js';
|
|
20
|
+
export type { IConversationsRuntimeContext } from './context/IConversationsRuntimeContext.js';
|
|
21
|
+
export { ClientToolRegistry, type ClientToolDefinition, type ClientToolHandler, } from '@memberjunction/ai-agent-client';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EACH,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC5B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,oBAAoB,EACpB,KAAK,0BAA0B,GAClC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,GACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,GACjC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,uBAAuB,EACvB,KAAK,mBAAmB,GAC3B,MAAM,wCAAwC,CAAC;AAGhD,OAAO,EACH,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,0BAA0B,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACH,KAAK,kBAAkB,EACvB,qBAAqB,GACxB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,KAAK,gBAAgB,EACrB,mBAAmB,GACtB,MAAM,6BAA6B,CAAC;AAIrC,YAAY,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AAM3F,OAAO,EACH,kBAAkB,EAClB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACzB,MAAM,iCAAiC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Public entry point for `@memberjunction/conversations-runtime`.
|
|
3
|
+
*
|
|
4
|
+
* Pure-TypeScript, framework-agnostic runtime for MemberJunction conversational AI
|
|
5
|
+
* experiences. Consumable from browser (Angular widget, React, Vue, Node-side workers)
|
|
6
|
+
* or server (Node tests, CLI tools).
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/conversations-runtime
|
|
9
|
+
*/
|
|
10
|
+
// Top-level runtime singleton
|
|
11
|
+
export { ConversationsRuntime } from './ConversationsRuntime.js';
|
|
12
|
+
// Sub-components and their public types
|
|
13
|
+
export { MentionParser } from './mentions/MentionParser.js';
|
|
14
|
+
export { ConversationBridge, } from './bridge/ConversationBridge.js';
|
|
15
|
+
export { DefaultAgentResolver, } from './default-agent/DefaultAgentResolver.js';
|
|
16
|
+
export { SessionsObserver, } from './sessions/SessionsObserver.js';
|
|
17
|
+
export { ConversationStreaming, } from './streaming/ConversationStreaming.js';
|
|
18
|
+
export { ConversationAgentRunner, } from './agent-runner/ConversationAgentRunner.js';
|
|
19
|
+
// Adapter interfaces + defaults
|
|
20
|
+
export { ConsoleNotificationAdapter, } from './adapters/INotificationAdapter.js';
|
|
21
|
+
export { NoOpActiveTaskTracker, } from './adapters/IActiveTaskTracker.js';
|
|
22
|
+
export { NoOpSessionsAdapter, } from './adapters/ISessionsAdapter.js';
|
|
23
|
+
// Re-export `ClientToolRegistry` from `@memberjunction/ai-agent-client` so consumers
|
|
24
|
+
// can use the runtime's tool layer (`runtime.Tools`) without importing a second package
|
|
25
|
+
// just to know the type. The class itself is owned by `ai-agent-client` — we are NOT
|
|
26
|
+
// reimplementing it, just exposing the established surface here.
|
|
27
|
+
export { ClientToolRegistry, } from '@memberjunction/ai-agent-client';
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,wCAAwC;AACxC,OAAO,EAAE,aAAa,EAAyC,MAAM,0BAA0B,CAAC;AAChG,OAAO,EACH,kBAAkB,GAGrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,oBAAoB,GAEvB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACH,gBAAgB,GAInB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,qBAAqB,GAMxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,uBAAuB,GAE1B,MAAM,wCAAwC,CAAC;AAEhD,gCAAgC;AAChC,OAAO,EAGH,0BAA0B,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEH,qBAAqB,GACxB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEH,mBAAmB,GACtB,MAAM,6BAA6B,CAAC;AAMrC,qFAAqF;AACrF,wFAAwF;AACxF,qFAAqF;AACrF,iEAAiE;AACjE,OAAO,EACH,kBAAkB,GAGrB,MAAM,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pure-TypeScript mention parser for conversation message text.
|
|
3
|
+
*
|
|
4
|
+
* Ported from `@memberjunction/ng-conversations/src/lib/services/mention-parser.service.ts`
|
|
5
|
+
* — the original was already pure string + regex logic, the only Angular bit was the
|
|
6
|
+
* `@Injectable()` decorator. Stripped that, kept everything else identical.
|
|
7
|
+
*
|
|
8
|
+
* Supports both formats currently in use in MJ conversations:
|
|
9
|
+
* - **JSON format** (new): `@{"type":"agent","id":"<uuid>","name":"Sage","configId":"<uuid>"}`
|
|
10
|
+
* - **Legacy text format**: `@AgentName` or `@"Agent Name With Spaces"`
|
|
11
|
+
*
|
|
12
|
+
* @module @memberjunction/conversations-runtime
|
|
13
|
+
*/
|
|
14
|
+
import { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';
|
|
15
|
+
import { UserInfo } from '@memberjunction/core';
|
|
16
|
+
/** A single parsed mention. */
|
|
17
|
+
export interface Mention {
|
|
18
|
+
type: 'agent' | 'user' | 'entity';
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
/** Configuration preset ID — agent mentions only. */
|
|
22
|
+
configurationId?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Result of parsing all mentions out of a message. */
|
|
25
|
+
export interface MentionParseResult {
|
|
26
|
+
/** All mentions, in order of appearance. */
|
|
27
|
+
mentions: Mention[];
|
|
28
|
+
/** First agent mention (if any). Conventionally the routing target. */
|
|
29
|
+
agentMention: Mention | null;
|
|
30
|
+
/** All user mentions. */
|
|
31
|
+
userMentions: Mention[];
|
|
32
|
+
/** All entity mentions (`#Entity` / `@{"type":"entity",…}`). */
|
|
33
|
+
entityMentions: Mention[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parses `@`-mentions out of conversation message text.
|
|
37
|
+
*
|
|
38
|
+
* Pure logic — no framework deps, no I/O, no observable state. Safe to call from
|
|
39
|
+
* browser, Node, tests, or anywhere TypeScript runs.
|
|
40
|
+
*
|
|
41
|
+
* Consumers usually access this via `ConversationsRuntime.Instance.Mentions`.
|
|
42
|
+
*/
|
|
43
|
+
export declare class MentionParser {
|
|
44
|
+
/** Matches JSON-encoded mentions like `@{"type":"agent","id":"…","name":"…"}`. */
|
|
45
|
+
private readonly JSON_MENTION_REGEX;
|
|
46
|
+
/** Matches legacy text mentions — quoted names with spaces or unquoted names. */
|
|
47
|
+
private readonly LEGACY_MENTION_REGEX;
|
|
48
|
+
/**
|
|
49
|
+
* Parse every mention out of the supplied text.
|
|
50
|
+
*
|
|
51
|
+
* Tries JSON format first; if no JSON mentions are present, falls back to the legacy
|
|
52
|
+
* text format and resolves names against `availableAgents` / `availableUsers`.
|
|
53
|
+
*
|
|
54
|
+
* @param text Message text to parse
|
|
55
|
+
* @param availableAgents Agents to resolve legacy `@Name` references against
|
|
56
|
+
* @param availableUsers Optional users to resolve legacy `@Name` references against
|
|
57
|
+
* @returns Parsed mentions with agent/user separation
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const result = parser.parseMentions(
|
|
62
|
+
* '@Sage help me with this',
|
|
63
|
+
* AIEngineBase.Instance.Agents
|
|
64
|
+
* );
|
|
65
|
+
* if (result.agentMention) {
|
|
66
|
+
* // Route the message to result.agentMention.id
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
parseMentions(text: string, availableAgents: MJAIAgentEntityExtended[], availableUsers?: UserInfo[]): MentionParseResult;
|
|
71
|
+
/**
|
|
72
|
+
* Validate every mention in `text`. Returns an array of mention names that could not be
|
|
73
|
+
* resolved to a known agent or user.
|
|
74
|
+
*/
|
|
75
|
+
validateMentions(text: string, availableAgents: MJAIAgentEntityExtended[], availableUsers?: UserInfo[]): string[];
|
|
76
|
+
/**
|
|
77
|
+
* Extract every raw mention name from `text` (no resolution against agents/users).
|
|
78
|
+
*/
|
|
79
|
+
extractMentionNames(text: string): string[];
|
|
80
|
+
/**
|
|
81
|
+
* Rewrite mentions in `text` to a canonical `@Name` format using the proper casing
|
|
82
|
+
* from `mentions`. Useful when normalizing user-typed mentions before storage or display.
|
|
83
|
+
*/
|
|
84
|
+
formatMentions(text: string, mentions: Mention[]): string;
|
|
85
|
+
/**
|
|
86
|
+
* Convert a message containing JSON-encoded mentions to plain text — `@{…}` blocks
|
|
87
|
+
* become simple `@Name` strings. Delegates to
|
|
88
|
+
* {@link ConversationUtility.ToPlainText} which is the canonical implementation.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* // Input: '@{"type":"agent","id":"123","name":"Sage"} help me'
|
|
93
|
+
* // Output: '@Sage help me'
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
toPlainText(text: string, agents?: MJAIAgentEntityExtended[], users?: UserInfo[]): string;
|
|
97
|
+
/**
|
|
98
|
+
* Find an agent by name (case-insensitive). Tries exact match first, then starts-with.
|
|
99
|
+
* Explicitly does NOT do a contains-match — that would be ambiguous when multiple agent
|
|
100
|
+
* names share a substring (`@Agent` matching `Marketing Agent`, `Data Agent`, …).
|
|
101
|
+
*/
|
|
102
|
+
private findAgent;
|
|
103
|
+
/**
|
|
104
|
+
* Find a user by name (case-insensitive). Tries exact name, email, then starts-with name.
|
|
105
|
+
* Same no-contains-match rule as {@link findAgent} for consistency.
|
|
106
|
+
*/
|
|
107
|
+
private findUser;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=MentionParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MentionParser.d.ts","sourceRoot":"","sources":["../../src/mentions/MentionParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,uBAAuB,EAAuB,MAAM,8BAA8B,CAAC;AAC5F,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,+BAA+B;AAC/B,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,uDAAuD;AACvD,MAAM,WAAW,kBAAkB;IAC/B,4CAA4C;IAC5C,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,uEAAuE;IACvE,YAAY,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,yBAAyB;IACzB,YAAY,EAAE,OAAO,EAAE,CAAC;IACxB,gEAAgE;IAChE,cAAc,EAAE,OAAO,EAAE,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,qBAAa,aAAa;IACtB,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAiB;IAEpD,iFAAiF;IACjF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAwB;IAE7D;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,aAAa,CAChB,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,uBAAuB,EAAE,EAC1C,cAAc,CAAC,EAAE,QAAQ,EAAE,GAC5B,kBAAkB;IA6ErB;;;OAGG;IACI,gBAAgB,CACnB,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,uBAAuB,EAAE,EAC1C,cAAc,CAAC,EAAE,QAAQ,EAAE,GAC5B,MAAM,EAAE;IAoDX;;OAEG;IACI,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAsBlD;;;OAGG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM;IAkBhE;;;;;;;;;;OAUG;IACI,WAAW,CACd,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,uBAAuB,EAAE,EAClC,KAAK,CAAC,EAAE,QAAQ,EAAE,GACnB,MAAM;IAkBT;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAiBjB;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAenB"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pure-TypeScript mention parser for conversation message text.
|
|
3
|
+
*
|
|
4
|
+
* Ported from `@memberjunction/ng-conversations/src/lib/services/mention-parser.service.ts`
|
|
5
|
+
* — the original was already pure string + regex logic, the only Angular bit was the
|
|
6
|
+
* `@Injectable()` decorator. Stripped that, kept everything else identical.
|
|
7
|
+
*
|
|
8
|
+
* Supports both formats currently in use in MJ conversations:
|
|
9
|
+
* - **JSON format** (new): `@{"type":"agent","id":"<uuid>","name":"Sage","configId":"<uuid>"}`
|
|
10
|
+
* - **Legacy text format**: `@AgentName` or `@"Agent Name With Spaces"`
|
|
11
|
+
*
|
|
12
|
+
* @module @memberjunction/conversations-runtime
|
|
13
|
+
*/
|
|
14
|
+
import { ConversationUtility } from '@memberjunction/ai-core-plus';
|
|
15
|
+
/**
|
|
16
|
+
* Parses `@`-mentions out of conversation message text.
|
|
17
|
+
*
|
|
18
|
+
* Pure logic — no framework deps, no I/O, no observable state. Safe to call from
|
|
19
|
+
* browser, Node, tests, or anywhere TypeScript runs.
|
|
20
|
+
*
|
|
21
|
+
* Consumers usually access this via `ConversationsRuntime.Instance.Mentions`.
|
|
22
|
+
*/
|
|
23
|
+
export class MentionParser {
|
|
24
|
+
constructor() {
|
|
25
|
+
/** Matches JSON-encoded mentions like `@{"type":"agent","id":"…","name":"…"}`. */
|
|
26
|
+
this.JSON_MENTION_REGEX = /@\{[^}]+\}/g;
|
|
27
|
+
/** Matches legacy text mentions — quoted names with spaces or unquoted names. */
|
|
28
|
+
this.LEGACY_MENTION_REGEX = /@"([^"]+)"|@(\S+)/g;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse every mention out of the supplied text.
|
|
32
|
+
*
|
|
33
|
+
* Tries JSON format first; if no JSON mentions are present, falls back to the legacy
|
|
34
|
+
* text format and resolves names against `availableAgents` / `availableUsers`.
|
|
35
|
+
*
|
|
36
|
+
* @param text Message text to parse
|
|
37
|
+
* @param availableAgents Agents to resolve legacy `@Name` references against
|
|
38
|
+
* @param availableUsers Optional users to resolve legacy `@Name` references against
|
|
39
|
+
* @returns Parsed mentions with agent/user separation
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const result = parser.parseMentions(
|
|
44
|
+
* '@Sage help me with this',
|
|
45
|
+
* AIEngineBase.Instance.Agents
|
|
46
|
+
* );
|
|
47
|
+
* if (result.agentMention) {
|
|
48
|
+
* // Route the message to result.agentMention.id
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
parseMentions(text, availableAgents, availableUsers) {
|
|
53
|
+
const mentions = [];
|
|
54
|
+
// First, try to parse JSON mentions (new format)
|
|
55
|
+
const jsonMatches = Array.from(text.matchAll(this.JSON_MENTION_REGEX));
|
|
56
|
+
for (const match of jsonMatches) {
|
|
57
|
+
try {
|
|
58
|
+
// Extract JSON string (remove @ prefix)
|
|
59
|
+
const jsonStr = match[0].substring(1);
|
|
60
|
+
const mentionData = JSON.parse(jsonStr);
|
|
61
|
+
// Validate required fields
|
|
62
|
+
if (mentionData.type && mentionData.id && mentionData.name) {
|
|
63
|
+
const mention = {
|
|
64
|
+
type: mentionData.type,
|
|
65
|
+
id: mentionData.id,
|
|
66
|
+
name: mentionData.name,
|
|
67
|
+
};
|
|
68
|
+
// Add configuration if present (for agents)
|
|
69
|
+
if (mentionData.configId) {
|
|
70
|
+
mention.configurationId = mentionData.configId;
|
|
71
|
+
}
|
|
72
|
+
mentions.push(mention);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.warn('MentionParser: failed to parse JSON mention:', match[0], error);
|
|
77
|
+
// Continue to next match
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// If no JSON mentions found, fall back to legacy text format
|
|
81
|
+
if (mentions.length === 0) {
|
|
82
|
+
const legacyMatches = Array.from(text.matchAll(this.LEGACY_MENTION_REGEX));
|
|
83
|
+
for (const match of legacyMatches) {
|
|
84
|
+
// Extract the mention name (either quoted or unquoted)
|
|
85
|
+
const mentionName = match[1] || match[2];
|
|
86
|
+
if (!mentionName)
|
|
87
|
+
continue;
|
|
88
|
+
// Try to match against agents first
|
|
89
|
+
const agent = this.findAgent(mentionName, availableAgents);
|
|
90
|
+
if (agent) {
|
|
91
|
+
mentions.push({
|
|
92
|
+
type: 'agent',
|
|
93
|
+
id: agent.ID,
|
|
94
|
+
name: agent.Name || 'Unknown',
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Try to match against users
|
|
99
|
+
if (availableUsers) {
|
|
100
|
+
const user = this.findUser(mentionName, availableUsers);
|
|
101
|
+
if (user) {
|
|
102
|
+
mentions.push({
|
|
103
|
+
type: 'user',
|
|
104
|
+
id: user.ID,
|
|
105
|
+
name: user.Name,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Extract first agent mention, all user mentions, and all entity mentions.
|
|
112
|
+
// Entity mentions arrive as JSON (`@{"type":"entity",…}`) from the editor and are
|
|
113
|
+
// resolved against the target entity downstream (e.g. Skip's EntityMentionResolver).
|
|
114
|
+
const agentMention = mentions.find((m) => m.type === 'agent') || null;
|
|
115
|
+
const userMentions = mentions.filter((m) => m.type === 'user');
|
|
116
|
+
const entityMentions = mentions.filter((m) => m.type === 'entity');
|
|
117
|
+
return { mentions, agentMention, userMentions, entityMentions };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Validate every mention in `text`. Returns an array of mention names that could not be
|
|
121
|
+
* resolved to a known agent or user.
|
|
122
|
+
*/
|
|
123
|
+
validateMentions(text, availableAgents, availableUsers) {
|
|
124
|
+
const invalidMentions = [];
|
|
125
|
+
// Check JSON mentions first
|
|
126
|
+
const jsonMatches = Array.from(text.matchAll(this.JSON_MENTION_REGEX));
|
|
127
|
+
if (jsonMatches.length > 0) {
|
|
128
|
+
for (const match of jsonMatches) {
|
|
129
|
+
try {
|
|
130
|
+
const jsonStr = match[0].substring(1);
|
|
131
|
+
const mentionData = JSON.parse(jsonStr);
|
|
132
|
+
const mentionName = mentionData.name;
|
|
133
|
+
if (mentionData.type === 'agent') {
|
|
134
|
+
const isAgent = this.findAgent(mentionName, availableAgents) !== null;
|
|
135
|
+
if (!isAgent) {
|
|
136
|
+
invalidMentions.push(mentionName);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (mentionData.type === 'user') {
|
|
140
|
+
const isUser = availableUsers
|
|
141
|
+
? this.findUser(mentionName, availableUsers) !== null
|
|
142
|
+
: false;
|
|
143
|
+
if (!isUser) {
|
|
144
|
+
invalidMentions.push(mentionName);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
// Invalid JSON mention
|
|
150
|
+
invalidMentions.push(match[0]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Fall back to legacy format
|
|
156
|
+
const matches = Array.from(text.matchAll(this.LEGACY_MENTION_REGEX));
|
|
157
|
+
for (const match of matches) {
|
|
158
|
+
const mentionName = match[1] || match[2];
|
|
159
|
+
if (!mentionName)
|
|
160
|
+
continue;
|
|
161
|
+
const isAgent = this.findAgent(mentionName, availableAgents) !== null;
|
|
162
|
+
const isUser = availableUsers
|
|
163
|
+
? this.findUser(mentionName, availableUsers) !== null
|
|
164
|
+
: false;
|
|
165
|
+
if (!isAgent && !isUser) {
|
|
166
|
+
invalidMentions.push(mentionName);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return invalidMentions;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Extract every raw mention name from `text` (no resolution against agents/users).
|
|
174
|
+
*/
|
|
175
|
+
extractMentionNames(text) {
|
|
176
|
+
// Check JSON mentions first
|
|
177
|
+
const jsonMatches = Array.from(text.matchAll(this.JSON_MENTION_REGEX));
|
|
178
|
+
if (jsonMatches.length > 0) {
|
|
179
|
+
return jsonMatches
|
|
180
|
+
.map((match) => {
|
|
181
|
+
try {
|
|
182
|
+
const jsonStr = match[0].substring(1);
|
|
183
|
+
const mentionData = JSON.parse(jsonStr);
|
|
184
|
+
return mentionData.name;
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return '';
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
.filter(Boolean);
|
|
191
|
+
}
|
|
192
|
+
// Fall back to legacy format
|
|
193
|
+
const matches = Array.from(text.matchAll(this.LEGACY_MENTION_REGEX));
|
|
194
|
+
return matches.map((match) => match[1] || match[2]).filter(Boolean);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Rewrite mentions in `text` to a canonical `@Name` format using the proper casing
|
|
198
|
+
* from `mentions`. Useful when normalizing user-typed mentions before storage or display.
|
|
199
|
+
*/
|
|
200
|
+
formatMentions(text, mentions) {
|
|
201
|
+
let formattedText = text;
|
|
202
|
+
for (const mention of mentions) {
|
|
203
|
+
// Find the mention in the text and replace with proper name
|
|
204
|
+
const patterns = [
|
|
205
|
+
new RegExp(`@"${mention.name}"`, 'gi'),
|
|
206
|
+
new RegExp(`@${mention.name.replace(/\s+/g, '\\s*')}`, 'gi'),
|
|
207
|
+
];
|
|
208
|
+
for (const pattern of patterns) {
|
|
209
|
+
formattedText = formattedText.replace(pattern, `@${mention.name}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return formattedText;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Convert a message containing JSON-encoded mentions to plain text — `@{…}` blocks
|
|
216
|
+
* become simple `@Name` strings. Delegates to
|
|
217
|
+
* {@link ConversationUtility.ToPlainText} which is the canonical implementation.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* // Input: '@{"type":"agent","id":"123","name":"Sage"} help me'
|
|
222
|
+
* // Output: '@Sage help me'
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
toPlainText(text, agents, users) {
|
|
226
|
+
if (!text)
|
|
227
|
+
return '';
|
|
228
|
+
// Convert agents to the AgentInfo format expected by ConversationUtility
|
|
229
|
+
const agentInfos = agents?.map((a) => ({
|
|
230
|
+
ID: a.ID,
|
|
231
|
+
Name: a.Name || 'Unknown',
|
|
232
|
+
}));
|
|
233
|
+
// Convert users to the UserInfo format expected by ConversationUtility
|
|
234
|
+
const userInfos = users?.map((u) => ({
|
|
235
|
+
ID: u.ID,
|
|
236
|
+
Name: u.Name,
|
|
237
|
+
}));
|
|
238
|
+
return ConversationUtility.ToPlainText(text, agentInfos, userInfos);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Find an agent by name (case-insensitive). Tries exact match first, then starts-with.
|
|
242
|
+
* Explicitly does NOT do a contains-match — that would be ambiguous when multiple agent
|
|
243
|
+
* names share a substring (`@Agent` matching `Marketing Agent`, `Data Agent`, …).
|
|
244
|
+
*/
|
|
245
|
+
findAgent(name, agents) {
|
|
246
|
+
// Remove trailing punctuation and trim
|
|
247
|
+
const cleanName = name.replace(/[.,;!?]+$/, '').trim();
|
|
248
|
+
const lowerName = cleanName.toLowerCase();
|
|
249
|
+
// Try exact match first
|
|
250
|
+
let agent = agents.find((a) => (a.Name?.toLowerCase() || '') === lowerName);
|
|
251
|
+
if (agent)
|
|
252
|
+
return agent;
|
|
253
|
+
// Try starts-with match
|
|
254
|
+
agent = agents.find((a) => (a.Name?.toLowerCase() || '').startsWith(lowerName));
|
|
255
|
+
return agent ?? null;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Find a user by name (case-insensitive). Tries exact name, email, then starts-with name.
|
|
259
|
+
* Same no-contains-match rule as {@link findAgent} for consistency.
|
|
260
|
+
*/
|
|
261
|
+
findUser(name, users) {
|
|
262
|
+
const lowerName = name.toLowerCase().trim();
|
|
263
|
+
// Try exact match first
|
|
264
|
+
let user = users.find((u) => u.Name.toLowerCase() === lowerName);
|
|
265
|
+
if (user)
|
|
266
|
+
return user;
|
|
267
|
+
// Try email match
|
|
268
|
+
user = users.find((u) => u.Email?.toLowerCase() === lowerName);
|
|
269
|
+
if (user)
|
|
270
|
+
return user;
|
|
271
|
+
// Try starts-with match
|
|
272
|
+
user = users.find((u) => u.Name.toLowerCase().startsWith(lowerName));
|
|
273
|
+
return user ?? null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=MentionParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MentionParser.js","sourceRoot":"","sources":["../../src/mentions/MentionParser.ts"],"names":[],"mappings":"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"}
|