@memberjunction/ng-conversations 6.2.0-edge.4 → 6.2.0-edge.5
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 +29 -0
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +3 -3
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +75 -14
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +711 -359
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.js +9 -9
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +137 -16
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +1361 -296
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +20 -2
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +28 -4
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.d.ts +152 -31
- package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.js +2227 -214
- package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +4 -4
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +11 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +25 -28
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +8 -8
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +7 -7
- package/dist/lib/services/browser-realtime-media-host.js +8 -78
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +16 -8
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +57 -27
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +9 -2
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/conversation-tasks-filter.d.ts +15 -0
- package/dist/lib/services/conversation-tasks-filter.d.ts.map +1 -0
- package/dist/lib/services/conversation-tasks-filter.js +69 -0
- package/dist/lib/services/conversation-tasks-filter.js.map +1 -0
- package/dist/lib/services/realtime-audio-recorder.d.ts +94 -86
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +222 -195
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +30 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +33 -6
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts +3 -0
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js +489 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts +48 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.js +170 -0
- package/dist/lib/services/recording/libopus-worker-source.js.map +1 -0
- package/dist/lib/services/recording/linear-resampler.d.ts +45 -0
- package/dist/lib/services/recording/linear-resampler.d.ts.map +1 -0
- package/dist/lib/services/recording/linear-resampler.js +85 -0
- package/dist/lib/services/recording/linear-resampler.js.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts +50 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.js +41 -0
- package/dist/lib/services/recording/opus-packet-encoder.js.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts +86 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js +232 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts +39 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js +101 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js.map +1 -0
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +3 -16
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/utils/distinct-artifacts.d.ts +9 -3
- package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
- package/dist/lib/utils/distinct-artifacts.js +24 -5
- package/dist/lib/utils/distinct-artifacts.js.map +1 -1
- package/package.json +36 -36
- package/dist/lib/services/browser-recording-unload-guard.d.ts +0 -30
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +0 -1
- package/dist/lib/services/browser-recording-unload-guard.js +0 -43
- package/dist/lib/services/browser-recording-unload-guard.js.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.d.ts +0 -79
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.js +0 -213
- package/dist/lib/services/realtime-pcm-wav.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-agent.service.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-agent.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { Metadata, IMetadataProvider, RunView, UserInfo } from '@memberjunction/core';\nimport { GraphQLDataProvider, GraphQLAIClient, type RunDecisionParams, type RunDecisionResult } from '@memberjunction/graphql-dataprovider';\nimport { ExecuteAgentResult, AgentExecutionProgressCallback, coerceFailedExecuteAgentResult } from '@memberjunction/ai-core-plus';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport {\n ConversationEngine,\n MJConversationDetailEntity,\n MJArtifactVersionEntity,\n MJArtifactEntity\n} from '@memberjunction/core-entities';\nimport { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended } from '@memberjunction/ai-core-plus';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { AgentClientService } from '@memberjunction/ng-agent-client';\nimport { RunAgentFromConversationDetailParams } from '@memberjunction/ai-agent-client';\nimport { ConversationsRuntime } from '@memberjunction/conversations-runtime';\nimport { LazyArtifactInfo } from '../models/lazy-artifact-info';\nimport { MentionParserService } from './mention-parser.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\nimport { ConversationsRuntimeBootstrap } from './conversations-runtime-bootstrap.service';\nimport {\n GroupVersionsByArtifact,\n type AgentArtifactSummary\n} from '../utils/agent-artifact-summary';\n\n/**\n * Rows the configuration-preset lookup parses before giving up. The SQL prefilter is a LIKE,\n * so a few candidates may not be real mention blobs; this bounds how many we inspect.\n */\nconst CONFIG_PRESET_CANDIDATE_ROWS = 5;\n\n/**\n * Cap on artifact versions listed for the intent classifier.\n *\n * The block is a hint, not a record: the prompt prints a name, a type, a version count and\n * the latest version per artifact. Newest-first ordering means the cap only ever trims the\n * oldest versions of the busiest artifacts, which are the least useful lines in it.\n */\nconst MAX_AGENT_ARTIFACT_VERSIONS = 40;\n\n/**\n * Context for artifact lookups — pre-loaded conversation data.\n *\n * NO LONGER CONSUMED by this service. Both readers were converted to queries when transcript\n * windowing made these maps a partial view: they are keyed to the loaded window, so any\n * lookup for an older row silently missed. Retained as an exported type for API\n * compatibility; new code should not build one.\n */\nexport interface ArtifactLookupContext {\n agentRunsByDetailId: Map<string, MJAIAgentRunEntityExtended>;\n artifactsByDetailId: Map<string, LazyArtifactInfo[]>;\n}\n\n/**\n * An agent's prior OUTPUT artifact, resolved for payload continuity.\n *\n * `payload` is the parsed `ArtifactVersion.Content`, typed to match what actually consumes it\n * — `executeAgentContinuation` and `invokeSubAgent` both take `Record<string, unknown> | null`.\n * It is null when the version carried no content, the content did not parse, or the content\n * parsed to something that is not a JSON object; callers treat all three the same as \"no prior\n * artifact\", which is already a legal agent input.\n */\nexport interface AgentPayloadSource {\n artifactId: string;\n versionId: string;\n versionNumber: number;\n payload: Record<string, unknown> | null;\n}\n\n/**\n * Result from intent check - indicates whether to continue with agent\n * and which artifact version to use as payload\n */\nexport interface IntentCheckResult {\n decision: 'YES' | 'NO' | 'UNSURE';\n reasoning: string;\n targetArtifactVersionId?: string;\n}\n\n/**\n * Angular DI service for conversation-level agent orchestration.\n *\n * After PR 2 of the conversations-runtime extraction, the core\n * `processMessage` flow and the conversation-manager-agent resolution are\n * delegated to `@memberjunction/conversations-runtime`. This service is\n * primarily a shim for those operations PLUS the holder of the helpers\n * that haven't been ported yet:\n *\n * - `invokeSubAgent(...)` — used by Sage's routing decisions in\n * `message-input.component`.\n * - `checkAgentContinuityIntent(...)` — fast intent classification when the\n * user replies to a previous-agent thread.\n * - `FindConfigurationPresetForAgent(...)` — locates an agent's preset\n * from prior @mentions in the conversation.\n * - `clearSession(...)` — per-conversation session-id bookkeeping.\n *\n * These can move to the runtime in a follow-up; they aren't strictly needed\n * to invoke an agent end-to-end and stay here so the shim has zero behavior\n * difference vs. the original.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class ConversationAgentService {\n /** GraphQL AI client - retained for RunAIPrompt (intent checking) which AgentClientService doesn't wrap */\n private _aiClient: GraphQLAIClient | null = null;\n /** Cached resolution of the conversation manager agent (default agent). */\n private _conversationManagerAgent: MJAIAgentEntityExtended | null = null;\n private _sessionIds: Map<string, string> = new Map();\n\n /** Observable indicating if the ambient agent is currently processing — delegated to the runtime's AgentRunner. */\n public readonly IsProcessing$: Observable<boolean>;\n\n /** @deprecated Use {@link IsProcessing$}. */\n public get isProcessing$(): Observable<boolean> {\n return this.IsProcessing$;\n }\n\n private _provider: IMetadataProvider | null = null;\n\n constructor(\n _bootstrap: ConversationsRuntimeBootstrap,\n private mentionParser: MentionParserService,\n private agentClientService: AgentClientService\n ) {\n // Injecting `_bootstrap` forces the runtime's INotificationAdapter +\n // IActiveTaskTracker adapters to register before any shim method runs.\n this.IsProcessing$ = ConversationsRuntime.Instance.AgentRunner.isProcessing$;\n this.initializeAIClient();\n }\n\n /**\n * The metadata provider this service uses. When unset, falls back to Metadata.Provider.\n * Setting it re-initializes the AI client and forwards the provider to the runtime's runner.\n */\n public get Provider(): IMetadataProvider {\n return this._provider ?? Metadata.Provider;\n }\n public set Provider(value: IMetadataProvider | null) {\n this._provider = value;\n this.initializeAIClient();\n ConversationsRuntime.Instance.AgentRunner.Provider = value;\n }\n\n /**\n * Initialize the GraphQL AI Client.\n * Retained for RunAIPrompt calls (intent checking) which the AgentClientService doesn't wrap.\n * Agent execution (RunAIAgentFromConversationDetail) now goes through ConversationsRuntime.AgentRunner.\n */\n private initializeAIClient(): void {\n try {\n const provider = this.Provider as GraphQLDataProvider;\n if (provider) {\n this._aiClient = new GraphQLAIClient(provider);\n } else {\n console.warn('GraphQLDataProvider not available, agent functionality will be limited');\n }\n } catch (error) {\n console.error('Failed to initialize GraphQL AI Client:', error);\n }\n }\n\n /**\n * Resolve the conversation manager agent via the runtime's 4-step\n * DefaultAgentResolver chain (explicit input → app-scoped Application\n * Setting → global Application Setting → code-const Sage fallback). The\n * result is cached on this service for use by the synchronous\n * {@link ConversationManagerAgentName} getter.\n *\n * Existing callers expect a Promise<MJAIAgentEntityExtended | null> — we\n * preserve that shape (returning null on failure rather than throwing)\n * so the call sites don't need to change.\n */\n public async GetConversationManagerAgent(): Promise<MJAIAgentEntityExtended | null> {\n if (this._conversationManagerAgent) {\n return this._conversationManagerAgent;\n }\n\n try {\n const provider = this.Provider;\n const agent = await ConversationsRuntime.Instance.DefaultAgent.resolve({\n contextUser: provider.CurrentUser ?? undefined,\n provider,\n });\n this._conversationManagerAgent = agent;\n return agent;\n } catch (error) {\n const errorMsg = 'Error resolving conversation manager agent: ' + (error instanceof Error ? error.message : String(error));\n console.error(errorMsg);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return null;\n }\n }\n\n /** @deprecated Use {@link GetConversationManagerAgent}. */\n public async getConversationManagerAgent(): Promise<MJAIAgentEntityExtended | null> {\n return this.GetConversationManagerAgent();\n }\n\n /**\n * Synchronous read of the cached conversation-manager-agent name. Returns\n * `null` until {@link getConversationManagerAgent} has been called at least\n * once and resolved successfully. Used by `MessageItemComponent.isConversationManager`\n * to flag messages from the routing agent without hardcoding `'Sage'`.\n */\n public get ConversationManagerAgentName(): string | null {\n return this._conversationManagerAgent?.Name ?? null;\n }\n\n /**\n * Returns `true` if the supplied agent identifier (UUID or name) matches the\n * currently cached conversation manager agent. Robust to either input.\n */\n public IsConversationManagerAgent(agentIdOrName: string | null | undefined): boolean {\n if (!agentIdOrName || !this._conversationManagerAgent) return false;\n return (\n UUIDsEqual(this._conversationManagerAgent.ID, agentIdOrName) ||\n this._conversationManagerAgent.Name === agentIdOrName\n );\n }\n\n /**\n * Process a message through the conversation manager agent. Delegates to\n * `ConversationsRuntime.Instance.AgentRunner.processMessage(...)`.\n *\n * Signature is preserved verbatim from the original service so existing\n * call sites continue to compile. The unused `conversationHistory`\n * parameter is kept for backwards compatibility (it was already\n * documented as \"kept for backwards compatibility but not used\" in the\n * original).\n */\n async ProcessMessage(\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n conversationDetailId: string,\n onProgress?: AgentExecutionProgressCallback,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n /** The agents the conversation manager may delegate to. Null or omitted allows every agent. */\n allowedAgentIDs?: readonly string[] | null,\n /** The first moment of the conversation the run may read. Null or omitted reads all of it. */\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n // Warm the cached default-agent name for any synchronous consumers\n // before the runtime resolves on its own.\n if (!this._conversationManagerAgent) {\n await this.GetConversationManagerAgent();\n }\n return ConversationsRuntime.Instance.AgentRunner.processMessage({\n conversationId,\n message,\n conversationDetailId,\n appContext,\n onProgress,\n ...(planMode ? { planMode: true } : {}),\n ...(requestedSkillIDs?.length ? { requestedSkillIDs } : {}),\n ...(allowedAgentIDs != null ? { AllowedAgentIDs: allowedAgentIDs } : {}),\n ...(agentHistoryFrom ? { AgentHistoryFrom: agentHistoryFrom } : {}),\n });\n }\n\n /** @deprecated Use {@link ProcessMessage}. */\n async processMessage(\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n conversationDetailId: string,\n onProgress?: AgentExecutionProgressCallback,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n allowedAgentIDs?: readonly string[] | null,\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n return this.ProcessMessage(conversationId, message, conversationHistory, conversationDetailId, onProgress, appContext, planMode, requestedSkillIDs, allowedAgentIDs, agentHistoryFrom);\n }\n\n /**\n * Configuration preset an agent was pinned to by a previous `@mention` in this conversation.\n *\n * Resolved by QUERY, not by scanning the display array. The pinning `@mention` is normally\n * the FIRST message of an exchange and everything after it is follow-up, so it is the\n * message most likely to fall below the loaded transcript window — and `undefined` is a\n * legal value for `configurationPresetId`, so the miss is silent. The visible consequence\n * is a run executed under the default configuration (a different model tier) instead of the\n * one the user explicitly chose, with a plausible-looking result and no error.\n *\n * There is no column to filter on: the preset lives inside the message body as a JSON\n * mention blob (`@{\"type\":\"agent\",\"id\":\"…\",\"configId\":\"…\"}`). So SQL narrows and the parser\n * decides — both `configId` and the agent id appear verbatim in that blob, which makes the\n * two LIKEs a tight prefilter, and `parseMentions` is what actually confirms a match.\n *\n * @param branchId The active branch. Only messages on its path count; null or omitted reads\n * the trunk.\n */\n public async FindConfigurationPresetForAgent(\n conversationId: string,\n agentId: string,\n branchId?: string | null\n ): Promise<string | undefined> {\n type MentionRow = Pick<MJConversationDetailEntity, 'ID' | 'Message'>;\n const pathFilter = await this.branchPathFilter(conversationId, branchId);\n if (pathFilter == null) {\n return undefined;\n }\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<MentionRow>({\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: `${pathFilter} AND Role='User'`\n + ` AND Message LIKE '%\"configId\"%' AND Message LIKE '%${agentId}%'`,\n OrderBy: 'Sequence DESC',\n // >1 because LIKE cannot tell a mention blob from the same id appearing elsewhere in\n // the prose; the parse below is authoritative and picks the newest genuine match.\n MaxRows: CONFIG_PRESET_CANDIDATE_ROWS,\n Fields: ['ID', 'Message'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to resolve configuration preset:', result.ErrorMessage);\n return undefined;\n }\n\n for (const row of result.Results || []) {\n const configurationId = this.readAgentConfigFromMention(row.Message, agentId);\n if (configurationId) {\n console.log(`\\u{1F3AF} Found configuration preset from @mention: ${configurationId}`);\n return configurationId;\n }\n }\n return undefined;\n }\n\n /** Returns the configId this message pins for `agentId`, or null when it pins none. */\n private readAgentConfigFromMention(message: string | null, agentId: string): string | null {\n if (!message) {\n return null;\n }\n const parsed = this.mentionParser.parseMentions(message, AIEngineBase.Instance.Agents, []);\n const mention = parsed.agentMention;\n return mention?.id === agentId && mention.configurationId ? mention.configurationId : null;\n }\n\n\n /**\n * Clear the session for a conversation (useful when starting a new topic)\n */\n ClearSession(conversationId: string): void {\n this._sessionIds.delete(conversationId);\n }\n\n /** @deprecated Use {@link ClearSession}. */\n clearSession(conversationId: string): void {\n return this.ClearSession(conversationId);\n }\n\n /**\n * Surfaces a warning toast when the user requested skills (via /skill mentions) that the\n * target agent cannot activate — the server drops such requests, and without this the\n * refusal is invisible to the user. Client-side check uses the agent gate only (the server\n * additionally intersects with the user's Run permission).\n */\n private warnOnUnacceptedSkills(agent: MJAIAgentEntityExtended, requestedSkillIDs: string[]): void {\n const allowed = AIEngineBase.Instance.GetSkillsForAgent(agent);\n const dropped = requestedSkillIDs.filter(id => !allowed.some(s => UUIDsEqual(s.ID, id)));\n if (dropped.length === 0) return;\n const names = dropped.map(\n id => AIEngineBase.Instance.Skills.find(s => UUIDsEqual(s.ID, id))?.Name ?? 'requested skill'\n );\n const reason = agent.AcceptsSkills === 'None'\n ? `${agent.Name} doesn't accept skills`\n : `${agent.Name} can't activate ${names.length === 1 ? 'this skill' : 'these skills'}`;\n MJNotificationService.Instance?.CreateSimpleNotification(\n `${reason} — ${names.join(', ')} won't be used for this run.`,\n 'warning',\n 6000\n );\n }\n\n /**\n * Invoke a sub-agent based on Sage Agent's payload.\n * This is called when Sage decides to delegate to a specialist agent.\n *\n * Stays on the Angular shim because it directly uses AgentClientService.\n * Could move to the runtime in a follow-up if needed.\n */\n async InvokeSubAgent(\n agentName: string,\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n reasoning: string,\n conversationDetailId: string,\n payload?: Record<string, unknown> | null,\n onProgress?: AgentExecutionProgressCallback,\n sourceArtifactId?: string,\n sourceArtifactVersionId?: string,\n agentConfigurationPresetId?: string,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n /** The first moment of the conversation the run may read. Null or omitted reads all of it. */\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n try {\n // Ensure AIEngineBase is configured\n await AIEngineBase.Instance.Config(false);\n\n // Find the agent by name\n const agent = AIEngineBase.Instance.Agents.find(a => a.Name === agentName);\n\n if (!agent || !agent.ID) {\n const errorMsg = `Sub-agent \"${agentName}\" not found`;\n console.warn(`${errorMsg}`);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return null;\n }\n\n if (requestedSkillIDs?.length) {\n this.warnOnUnacceptedSkills(agent, requestedSkillIDs);\n }\n\n console.log(`Invoking sub-agent: ${agentName}`, { reasoning, hasPayload: !!payload, hasConfigPreset: !!agentConfigurationPresetId });\n\n // Map AIAgentConfiguration preset ID to actual AIConfiguration ID\n let aiConfigurationId: string | undefined = undefined;\n if (agentConfigurationPresetId) {\n const presets = AIEngineBase.Instance.GetAgentConfigurationPresets(agent.ID, false);\n const preset = presets.find(p => UUIDsEqual(p.ID, agentConfigurationPresetId) || UUIDsEqual(p.AIConfigurationID, agentConfigurationPresetId));\n\n if (preset) {\n aiConfigurationId = preset.AIConfigurationID || undefined;\n console.log(`Mapped agent configuration preset \"${preset.Name}\" to AIConfigurationID: ${aiConfigurationId || 'default'}`);\n } else {\n console.warn(`Agent configuration preset ${agentConfigurationPresetId} not found for agent ${agent.ID}`);\n }\n }\n\n const agentParams: RunAgentFromConversationDetailParams = {\n ConversationDetailId: conversationDetailId,\n AgentId: agent.ID,\n MaxHistoryMessages: 20,\n Data: {\n conversationId: conversationId,\n latestMessageId: message.ID,\n invocationReason: reasoning,\n ...(appContext ? { appContext } : {}),\n },\n ...(payload ? { Payload: payload } : {}),\n ...(aiConfigurationId ? { ConfigurationId: aiConfigurationId } : {}),\n ...(planMode ? { PlanMode: true } : {}),\n ...(requestedSkillIDs?.length ? { RequestedSkillIDs: requestedSkillIDs } : {}),\n ...(agentHistoryFrom ? { AgentHistoryFrom: agentHistoryFrom } : {}),\n CreateArtifacts: true,\n CreateNotification: true,\n SourceArtifactId: sourceArtifactId,\n SourceArtifactVersionId: sourceArtifactVersionId,\n OnProgress: onProgress ? (progress) => {\n onProgress({\n step: progress.CurrentStep as 'initialization' | 'validation' | 'prompt_execution' | 'action_execution' | 'subagent_execution' | 'decision_processing' | 'finalization',\n percentage: progress.Percentage,\n message: progress.Message,\n metadata: progress.Metadata\n });\n } : undefined\n };\n\n const runResult = await this.agentClientService.RunAgentFromConversationDetail(agentParams);\n\n if (runResult.Success && runResult.Result) {\n return runResult.Result as ExecuteAgentResult;\n }\n\n const failed = coerceFailedExecuteAgentResult(\n runResult.Result as ExecuteAgentResult | null | undefined,\n runResult.ErrorMessage || `Sub-agent \"${agentName}\" failed`,\n );\n const errorMsg = `Sub-agent \"${agentName}\" failed: ${failed.errorMessage}`;\n console.error(errorMsg);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return failed;\n } catch (error) {\n const errorMsg = `Error invoking sub-agent \"${agentName}\": ` + (error instanceof Error ? error.message : String(error));\n console.error(`Error invoking sub-agent \"${agentName}\":`, error);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return coerceFailedExecuteAgentResult<ExecuteAgentResult>(undefined, errorMsg);\n }\n }\n\n /** @deprecated Use {@link InvokeSubAgent}. */\n async invokeSubAgent(\n agentName: string,\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n reasoning: string,\n conversationDetailId: string,\n payload?: Record<string, unknown> | null,\n onProgress?: AgentExecutionProgressCallback,\n sourceArtifactId?: string,\n sourceArtifactVersionId?: string,\n agentConfigurationPresetId?: string,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n return this.InvokeSubAgent(agentName, conversationId, message, conversationHistory, reasoning, conversationDetailId, payload, onProgress, sourceArtifactId, sourceArtifactVersionId, agentConfigurationPresetId, appContext, planMode, requestedSkillIDs, agentHistoryFrom);\n }\n\n /**\n * Check if user's latest message should continue with the previous agent or route through Sage.\n * Uses fast inference (<500ms) to determine intent and avoid unnecessary Sage overhead.\n *\n * Stays on the Angular shim because it directly uses GraphQLAIClient.\n * Could move to the runtime in a follow-up.\n *\n * @param branchId The active branch. Only the agent's artifacts on its path are listed for the\n * classifier; null or omitted reads the trunk.\n */\n async CheckAgentContinuityIntent(\n conversationId: string,\n agentId: string,\n latestMessage: string,\n conversationHistory: MJConversationDetailEntity[],\n branchId?: string | null\n ): Promise<IntentCheckResult> {\n if (!this._aiClient) {\n console.warn('AI Client not initialized, defaulting to UNSURE for intent check');\n return { decision: 'UNSURE', reasoning: 'AI Client not initialized' };\n }\n\n try {\n await AIEngineBase.Instance.Config(false);\n const prompt = AIEngineBase.Instance.Prompts.find(p => p.Name === 'Check Sage Intent');\n if (!prompt) {\n console.warn('⚠️ Check Sage Intent prompt not found, defaulting to UNSURE');\n return { decision: 'UNSURE', reasoning: 'Check Sage Intent prompt not found' };\n }\n\n const agent = AIEngineBase.Instance.Agents.find(a => UUIDsEqual(a.ID, agentId));\n if (!agent) {\n console.warn('⚠️ Previous agent not found, defaulting to UNSURE');\n return { decision: 'UNSURE', reasoning: 'Previous agent not found' };\n }\n\n // Queried, not read off the caller's window-scoped maps — see findAllAgentArtifacts.\n // `conversationHistory` below is still the window on purpose: the `.slice(-10)` wants\n // the most recent exchange, which the loaded tail always contains.\n const agentArtifacts = await this.findAllAgentArtifacts(conversationId, agentId, undefined, branchId);\n\n const recentHistory = conversationHistory.slice(-10);\n const compactHistory = recentHistory.map((msg, idx) => {\n const role = msg.Role === 'User' ? 'User' : agent.Name || 'Agent';\n const content = msg.Message || '';\n return `${idx + 1}. ${role}: ${content.substring(0, 150)}${content.length > 150 ? '...' : ''}`;\n }).join('\\n');\n\n let artifactContext = '';\n if (agentArtifacts.length > 0) {\n artifactContext = '\\n\\n**Prior Artifacts Created by This Agent**:\\n';\n agentArtifacts.forEach((artifact, idx) => {\n artifactContext += `${idx + 1}. ${artifact.artifactName} (${artifact.ArtifactType})\\n`;\n artifactContext += ` - Versions: ${artifact.Versions.length}\\n`;\n if (artifact.Versions.length > 0) {\n artifactContext += ` - Latest: v${artifact.Versions[0].versionNumber}`;\n if (artifact.Versions[0].versionName) {\n artifactContext += ` - ${artifact.Versions[0].versionName}`;\n }\n artifactContext += '\\n';\n }\n });\n }\n\n const userMessage = `**Previous Agent**: ${agent.Name} - ${agent.Description || 'No description'}\n\n**Conversation History** (last ${recentHistory.length} messages):\n${compactHistory}${artifactContext}\n\n**Latest User Message**: \"${latestMessage}\"`;\n\n console.log('🔍 Checking agent continuity intent...', {\n agentName: agent.Name,\n messagePreview: latestMessage.substring(0, 50),\n artifactCount: agentArtifacts.length\n });\n\n const result = await this._aiClient.RunAIPrompt({\n promptId: prompt.ID,\n messages: [{ role: 'user', content: userMessage }],\n data: {\n hasPriorArtifact: agentArtifacts.length > 0,\n priorArtifacts: agentArtifacts\n }\n });\n\n if (result && result.success && (result.parsedResult || result.output)) {\n const parsed = result.parsedResult ||\n (result.output ? JSON.parse(result.output) : null);\n\n if (parsed && parsed.continuesWith) {\n const decision = parsed.continuesWith.toUpperCase();\n const reasoning = parsed.reasoning || 'No reasoning provided';\n const targetArtifactVersionId = parsed.targetArtifactVersionId || undefined;\n\n console.log(`✅ Intent check result: ${decision}`, {\n reasoning,\n targetArtifactVersionId,\n latency: result.executionTimeMs || 'unknown'\n });\n\n if (decision === 'YES' || decision === 'NO' || decision === 'UNSURE') {\n return {\n decision: decision as 'YES' | 'NO' | 'UNSURE',\n reasoning,\n targetArtifactVersionId\n };\n }\n }\n }\n\n console.warn('⚠️ Intent check failed or returned invalid format, defaulting to UNSURE');\n return { decision: 'UNSURE', reasoning: 'Invalid format from intent check prompt' };\n } catch (error) {\n console.error('❌ Error checking agent continuity intent:', error);\n return {\n decision: 'UNSURE',\n reasoning: `Error during intent check: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n }\n\n /** @deprecated Use {@link CheckAgentContinuityIntent}. */\n async checkAgentContinuityIntent(\n conversationId: string,\n agentId: string,\n latestMessage: string,\n conversationHistory: MJConversationDetailEntity[],\n branchId?: string | null\n ): Promise<IntentCheckResult> {\n return this.CheckAgentContinuityIntent(conversationId, agentId, latestMessage, conversationHistory, branchId);\n }\n\n /**\n * Runs a typed decision on the server in one round trip, through\n * {@link GraphQLAIClient.RunDecision}. Decision routing (`EnableDecisionRouting`) asks its\n * routing questions here.\n *\n * Never throws: without an AI client, or on any failure, it resolves with `Success: false` and\n * no answers.\n */\n public async RunDecision(params: RunDecisionParams): Promise<RunDecisionResult> {\n if (!this._aiClient) {\n return { Success: false, ErrorMessage: 'AI Client not initialized', Answers: {} };\n }\n return this._aiClient.RunDecision(params);\n }\n\n /**\n * Every artifact this agent produced on the active branch path, newest version first, for\n * decision routing's artifact question. Resolved by query, as {@link findAllAgentArtifacts} explains.\n *\n * @param historyFrom The chat's history floor. When set, only artifacts on replies written at or\n * after it count, as with {@link FindLatestAgentOutputVersion}.\n * @param branchId The active branch. Only artifacts on its path count, as with\n * {@link FindLatestAgentOutputVersion}; null or omitted reads the trunk.\n */\n public async FindAgentArtifacts(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<AgentArtifactSummary[]> {\n return this.findAllAgentArtifacts(conversationId, agentId, historyFrom, branchId);\n }\n\n /**\n * Every artifact this agent produced on the active branch path, newest version first —\n * resolved by QUERY, not by scanning the display array.\n *\n * The scan this replaces walked `conversationDetails` and looked each row up in the\n * caller's `artifactsByDetailId` / `agentRunsByDetailId` maps. Both are scoped to the\n * LOADED WINDOW, so under transcript windowing it saw only the artifacts attached to the\n * page currently on screen.\n *\n * That matters because this list is the \"Prior Artifacts Created by This Agent\" block fed\n * to the Check Sage Intent prompt, which is what produces `targetArtifactVersionId`. A\n * truncated list does not make the classifier fail — it makes it reason over a partial\n * history and confidently name the wrong version, or miss continuity altogether. Silent,\n * plausible, and wrong: the same failure class as {@link FindLatestAgentOutputVersion},\n * closed the same way.\n *\n * Two reads, not the four the old shape would have needed — see\n * {@link AgentArtifactSummary} for why dropping `runId` removes the join back to agent runs.\n *\n * @param historyFrom The chat's history floor, when set (see {@link FindAgentArtifacts}).\n * @param branchId The branch whose path to read; null or omitted reads the trunk.\n */\n private async findAllAgentArtifacts(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<AgentArtifactSummary[]> {\n type VersionRow = Pick<MJArtifactVersionEntity, 'ID' | 'ArtifactID' | 'VersionNumber' | 'Name'>;\n const pathFilter = await this.branchPathFilter(conversationId, branchId);\n if (pathFilter == null) {\n return []; // the classifier degrades to no artifact context\n }\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const versionResult = await rv.RunView<VersionRow>({\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: this.agentOutputVersionFilter(pathFilter, agentId, historyFrom),\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: MAX_AGENT_ARTIFACT_VERSIONS,\n Fields: ['ID', 'ArtifactID', 'VersionNumber', 'Name'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!versionResult.Success) {\n console.error('Failed to load agent artifact versions:', versionResult.ErrorMessage);\n return []; // the classifier degrades to no artifact context\n }\n const versions = versionResult.Results || [];\n if (versions.length === 0) {\n return [];\n }\n\n const artifactsById = await this.loadArtifactNames(\n [...new Set(versions.map(v => v.ArtifactID))]\n );\n return GroupVersionsByArtifact(versions, artifactsById);\n }\n\n /** Names and types for the artifacts behind a set of versions. */\n private async loadArtifactNames(\n artifactIds: string[]\n ): Promise<Map<string, Pick<MJArtifactEntity, 'ID' | 'Name' | 'Type'>>> {\n type ArtifactRow = Pick<MJArtifactEntity, 'ID' | 'Name' | 'Type'>;\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<ArtifactRow>({\n EntityName: 'MJ: Artifacts',\n ExtraFilter: `ID IN (${artifactIds.map(id => `'${id}'`).join(',')})`,\n Fields: ['ID', 'Name', 'Type'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to load agent artifacts:', result.ErrorMessage);\n return new Map<string, ArtifactRow>();\n }\n return new Map((result.Results || []).map(a => [a.ID, a]));\n }\n\n /**\n * Newest OUTPUT artifact version an agent produced in this conversation — resolved by\n * QUERY, not by scanning the display array.\n *\n * The array scan this replaces was correct only while `conversationHistory` held the whole\n * conversation. Under transcript windowing it holds one page, so the scan silently returns\n * null for any artifact below the window's oldest row — exactly the long \"modify this\n * again\" exchanges where payload continuity matters most. A null payload is a LEGAL agent\n * input, so the failure is silent: the agent regenerates from scratch instead of modifying.\n *\n * One round trip. The subquery walks details -> Output junctions, and versions carry\n * `__mj_CreatedAt`, so \"newest\" is expressible without joining back for `Sequence`.\n *\n * @param historyFrom The chat's history floor. When set, only artifacts on replies written at\n * or after it count: a run that may not read earlier messages must not pick up their work\n * as its payload either.\n * @param branchId The active branch. Only replies on its path count, so an artifact made on\n * another branch is never the latest here; null or omitted reads the trunk.\n */\n public async FindLatestAgentOutputVersion(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<AgentPayloadSource | null> {\n const pathFilter = await this.branchPathFilter(conversationId, branchId);\n if (pathFilter == null) {\n return null;\n }\n return this.runPayloadSourceQuery(\n this.agentOutputVersionFilter(pathFilter, agentId, historyFrom), '__mj_CreatedAt DESC'\n );\n }\n\n /**\n * `ArtifactVersion.ID IN (...)` for every OUTPUT artifact an agent produced on one\n * conversation path, in messages no rerun replaced. Shared by {@link FindLatestAgentOutputVersion} and\n * {@link findAllAgentArtifacts} so the two can never disagree about what \"this agent's\n * artifacts\" means.\n *\n * Filters on the DETAIL's `Status <> 'Error'` rather than the agent run's\n * `Status = 'Completed'` (which is what the array scan this replaced used). Doing it on the\n * run would mean joining back to `MJ: AI Agent Runs` purely to restate a condition the\n * detail already carries.\n *\n * @param pathFilter The conversation-and-branch predicate from {@link branchPathFilter}.\n */\n private agentOutputVersionFilter(pathFilter: string, agentId: string, historyFrom?: Date | null): string {\n const floor = historyFrom ? ` AND ${ConversationEngine.HistoryFromFilter(historyFrom)}` : '';\n return `ID IN (\n SELECT ArtifactVersionID FROM [__mj].[vwConversationDetailArtifacts]\n WHERE Direction='Output' AND ConversationDetailID IN (\n SELECT ID FROM [__mj].[vwConversationDetails]\n WHERE ${ConversationEngine.LiveRowsFilter(pathFilter)} AND AgentID='${agentId}'\n AND Role='AI' AND Status <> 'Error'${floor}\n )\n )`;\n }\n\n /**\n * The SQL predicate for one branch's path in a conversation, from\n * `ConversationEngine.BranchPathFilterFresh`. A null or omitted branch is the trunk and costs\n * no query.\n *\n * Never throws. When the path cannot be built (the branch rows fail to load, or the branch is\n * not among them), it logs the error and returns null. Each lookup then returns its own\n * failure value, as it does when its main query fails. A caller must not fall back to the\n * trunk predicate: on a branch, that reads trunk rows past the fork point.\n */\n private async branchPathFilter(conversationId: string, branchId: string | null | undefined): Promise<string | null> {\n try {\n const user = this.Provider.CurrentUser ?? undefined;\n return await ConversationEngine.BranchPathFilterFresh(conversationId, branchId, user as UserInfo, this.Provider);\n } catch (error) {\n console.error(`Failed to build the path of branch ${branchId} in conversation ${conversationId}:`, error);\n return null;\n }\n }\n\n /**\n * One artifact version by ID, as a payload source.\n *\n * Used by the continuity path after the intent check names a specific version: that ID may\n * belong to a message below the loaded window, so it cannot be resolved from the window's\n * artifact maps.\n */\n public async FindArtifactVersionById(versionId: string): Promise<AgentPayloadSource | null> {\n return this.runPayloadSourceQuery(`ID='${versionId}'`, undefined);\n }\n\n /**\n * Shared read behind {@link FindLatestAgentOutputVersion} and {@link FindArtifactVersionById}.\n *\n * `ResultType: 'simple'` with an explicit `Fields` list: nothing here is mutated, and under\n * `entity_object` the `Fields` narrowing would be silently discarded by `PreRunView`.\n */\n private async runPayloadSourceQuery(\n extraFilter: string,\n orderBy: string | undefined\n ): Promise<AgentPayloadSource | null> {\n type VersionRow = Pick<MJArtifactVersionEntity, 'ID' | 'ArtifactID' | 'VersionNumber' | 'Content'>;\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<VersionRow>({\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: extraFilter,\n OrderBy: orderBy,\n MaxRows: 1,\n Fields: ['ID', 'ArtifactID', 'VersionNumber', 'Content'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to resolve agent payload source:', result.ErrorMessage);\n return null;\n }\n const row = result.Results?.[0];\n if (!row) {\n return null;\n }\n return {\n artifactId: row.ArtifactID,\n versionId: row.ID,\n versionNumber: row.VersionNumber,\n payload: parseArtifactContent(row.Content)\n };\n }\n\n}\n\n/**\n * Parses an artifact version's `Content` into an agent payload. Returns null rather than\n * throwing — a malformed artifact must not take down the send path, and \"no payload\" is\n * already a legal agent input.\n *\n * A payload must be a JSON OBJECT. Valid JSON that parses to an array, string, or number is\n * rejected for the same reason a parse failure is: every consumer spreads it or reads named\n * keys off it, so a non-object would satisfy the type at the boundary and misbehave deeper in.\n */\nfunction parseArtifactContent(content: string | null | undefined): Record<string, unknown> | null {\n if (!content) {\n return null;\n }\n try {\n const parsed: unknown = JSON.parse(content);\n return isPayloadObject(parsed) ? parsed : null;\n } catch (error) {\n console.warn('Artifact version content did not parse as JSON:', error);\n return null;\n }\n}\n\n/** Narrows a parsed JSON value to a plain object — the only shape a payload may take. */\nfunction isPayloadObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"conversation-agent.service.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-agent.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { Metadata, IMetadataProvider, RunView, UserInfo } from '@memberjunction/core';\nimport { GraphQLDataProvider, GraphQLAIClient, type RunDecisionParams, type RunDecisionResult } from '@memberjunction/graphql-dataprovider';\nimport { ExecuteAgentResult, AgentExecutionProgressCallback, coerceFailedExecuteAgentResult } from '@memberjunction/ai-core-plus';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport {\n ConversationEngine,\n MJConversationDetailEntity,\n MJArtifactVersionEntity,\n MJArtifactEntity\n} from '@memberjunction/core-entities';\nimport { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended } from '@memberjunction/ai-core-plus';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { AgentClientService } from '@memberjunction/ng-agent-client';\nimport { RunAgentFromConversationDetailParams } from '@memberjunction/ai-agent-client';\nimport { ConversationsRuntime } from '@memberjunction/conversations-runtime';\nimport { LazyArtifactInfo } from '../models/lazy-artifact-info';\nimport { MentionParserService } from './mention-parser.service';\nimport { EscapeSQLString, UUIDsEqual } from '@memberjunction/global';\n\nimport { ConversationsRuntimeBootstrap } from './conversations-runtime-bootstrap.service';\nimport {\n GroupVersionsByArtifact,\n type AgentArtifactSummary\n} from '../utils/agent-artifact-summary';\n\n/**\n * Rows the configuration-preset lookup parses before giving up. The SQL prefilter is a LIKE,\n * so a few candidates may not be real mention blobs; this bounds how many we inspect.\n */\nconst CONFIG_PRESET_CANDIDATE_ROWS = 5;\n\n/**\n * Cap on artifact versions listed for the intent classifier.\n *\n * The block is a hint, not a record: the prompt prints a name, a type, a version count and\n * the latest version per artifact. Newest-first ordering means the cap only ever trims the\n * oldest versions of the busiest artifacts, which are the least useful lines in it.\n */\nconst MAX_AGENT_ARTIFACT_VERSIONS = 40;\n\n/**\n * Context for artifact lookups — pre-loaded conversation data.\n *\n * NO LONGER CONSUMED by this service. Both readers were converted to queries when transcript\n * windowing made these maps a partial view: they are keyed to the loaded window, so any\n * lookup for an older row silently missed. Retained as an exported type for API\n * compatibility; new code should not build one.\n */\nexport interface ArtifactLookupContext {\n agentRunsByDetailId: Map<string, MJAIAgentRunEntityExtended>;\n artifactsByDetailId: Map<string, LazyArtifactInfo[]>;\n}\n\n/**\n * An agent's prior OUTPUT artifact, resolved for payload continuity.\n *\n * `payload` is the parsed `ArtifactVersion.Content`, typed to match what actually consumes it\n * — `executeAgentContinuation` and `invokeSubAgent` both take `Record<string, unknown> | null`.\n * It is null when the version carried no content, the content did not parse, or the content\n * parsed to something that is not a JSON object; callers treat all three the same as \"no prior\n * artifact\", which is already a legal agent input.\n */\nexport interface AgentPayloadSource {\n artifactId: string;\n versionId: string;\n versionNumber: number;\n payload: Record<string, unknown> | null;\n}\n\n/**\n * Result from intent check - indicates whether to continue with agent\n * and which artifact version to use as payload\n */\nexport interface IntentCheckResult {\n decision: 'YES' | 'NO' | 'UNSURE';\n reasoning: string;\n targetArtifactVersionId?: string;\n}\n\n/**\n * Angular DI service for conversation-level agent orchestration.\n *\n * After PR 2 of the conversations-runtime extraction, the core\n * `processMessage` flow and the conversation-manager-agent resolution are\n * delegated to `@memberjunction/conversations-runtime`. This service is\n * primarily a shim for those operations PLUS the holder of the helpers\n * that haven't been ported yet:\n *\n * - `invokeSubAgent(...)` — used by Sage's routing decisions in\n * `message-input.component`.\n * - `checkAgentContinuityIntent(...)` — fast intent classification when the\n * user replies to a previous-agent thread.\n * - `FindConfigurationPresetForAgent(...)` — locates an agent's preset\n * from prior @mentions in the conversation.\n * - `clearSession(...)` — per-conversation session-id bookkeeping.\n *\n * These can move to the runtime in a follow-up; they aren't strictly needed\n * to invoke an agent end-to-end and stay here so the shim has zero behavior\n * difference vs. the original.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class ConversationAgentService {\n /** GraphQL AI client - retained for RunAIPrompt (intent checking) which AgentClientService doesn't wrap */\n private _aiClient: GraphQLAIClient | null = null;\n /** Cached resolution of the conversation manager agent (default agent). */\n private _conversationManagerAgent: MJAIAgentEntityExtended | null = null;\n private _sessionIds: Map<string, string> = new Map();\n\n /** Observable indicating if the ambient agent is currently processing — delegated to the runtime's AgentRunner. */\n public readonly IsProcessing$: Observable<boolean>;\n\n /** @deprecated Use {@link IsProcessing$}. */\n public get isProcessing$(): Observable<boolean> {\n return this.IsProcessing$;\n }\n\n private _provider: IMetadataProvider | null = null;\n\n constructor(\n _bootstrap: ConversationsRuntimeBootstrap,\n private mentionParser: MentionParserService,\n private agentClientService: AgentClientService\n ) {\n // Injecting `_bootstrap` forces the runtime's INotificationAdapter +\n // IActiveTaskTracker adapters to register before any shim method runs.\n this.IsProcessing$ = ConversationsRuntime.Instance.AgentRunner.isProcessing$;\n this.initializeAIClient();\n }\n\n /**\n * The metadata provider this service uses. When unset, falls back to Metadata.Provider.\n * Setting it re-initializes the AI client and forwards the provider to the runtime's runner.\n */\n public get Provider(): IMetadataProvider {\n return this._provider ?? Metadata.Provider;\n }\n public set Provider(value: IMetadataProvider | null) {\n this._provider = value;\n this.initializeAIClient();\n ConversationsRuntime.Instance.AgentRunner.Provider = value;\n }\n\n /**\n * Initialize the GraphQL AI Client.\n * Retained for RunAIPrompt calls (intent checking) which the AgentClientService doesn't wrap.\n * Agent execution (RunAIAgentFromConversationDetail) now goes through ConversationsRuntime.AgentRunner.\n */\n private initializeAIClient(): void {\n try {\n const provider = this.Provider as GraphQLDataProvider;\n if (provider) {\n this._aiClient = new GraphQLAIClient(provider);\n } else {\n console.warn('GraphQLDataProvider not available, agent functionality will be limited');\n }\n } catch (error) {\n console.error('Failed to initialize GraphQL AI Client:', error);\n }\n }\n\n /**\n * Resolve the conversation manager agent via the runtime's 4-step\n * DefaultAgentResolver chain (explicit input → app-scoped Application\n * Setting → global Application Setting → code-const Sage fallback). The\n * result is cached on this service for use by the synchronous\n * {@link ConversationManagerAgentName} getter.\n *\n * Existing callers expect a Promise<MJAIAgentEntityExtended | null> — we\n * preserve that shape (returning null on failure rather than throwing)\n * so the call sites don't need to change.\n */\n public async GetConversationManagerAgent(): Promise<MJAIAgentEntityExtended | null> {\n if (this._conversationManagerAgent) {\n return this._conversationManagerAgent;\n }\n // A user who may not read the agents has no manager agent to resolve: say nothing, rather than an error for a state\n // that is theirs by design (MJ#5240)\n if (AIEngineBase.Instance.IsPermissionConstrained && AIEngineBase.Instance.ReadableAgents.length === 0) {\n return null;\n }\n\n try {\n const provider = this.Provider;\n const agent = await ConversationsRuntime.Instance.DefaultAgent.resolve({\n contextUser: provider.CurrentUser ?? undefined,\n provider,\n });\n this._conversationManagerAgent = agent;\n return agent;\n } catch (error) {\n const errorMsg = 'Error resolving conversation manager agent: ' + (error instanceof Error ? error.message : String(error));\n console.error(errorMsg);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return null;\n }\n }\n\n /** @deprecated Use {@link GetConversationManagerAgent}. */\n public async getConversationManagerAgent(): Promise<MJAIAgentEntityExtended | null> {\n return this.GetConversationManagerAgent();\n }\n\n /**\n * Synchronous read of the cached conversation-manager-agent name. Returns\n * `null` until {@link getConversationManagerAgent} has been called at least\n * once and resolved successfully. Used by `MessageItemComponent.isConversationManager`\n * to flag messages from the routing agent without hardcoding `'Sage'`.\n */\n public get ConversationManagerAgentName(): string | null {\n return this._conversationManagerAgent?.Name ?? null;\n }\n\n /**\n * Returns `true` if the supplied agent identifier (UUID or name) matches the\n * currently cached conversation manager agent. Robust to either input.\n */\n public IsConversationManagerAgent(agentIdOrName: string | null | undefined): boolean {\n if (!agentIdOrName || !this._conversationManagerAgent) return false;\n return (\n UUIDsEqual(this._conversationManagerAgent.ID, agentIdOrName) ||\n this._conversationManagerAgent.Name === agentIdOrName\n );\n }\n\n /**\n * Process a message through the conversation manager agent. Delegates to\n * `ConversationsRuntime.Instance.AgentRunner.processMessage(...)`.\n *\n * Signature is preserved verbatim from the original service so existing\n * call sites continue to compile. The unused `conversationHistory`\n * parameter is kept for backwards compatibility (it was already\n * documented as \"kept for backwards compatibility but not used\" in the\n * original).\n */\n async ProcessMessage(\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n conversationDetailId: string,\n onProgress?: AgentExecutionProgressCallback,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n /** The agents the conversation manager may delegate to. Null or omitted allows every agent. */\n allowedAgentIDs?: readonly string[] | null,\n /** The first moment of the conversation the run may read. Null or omitted reads all of it. */\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n // Warm the cached default-agent name for any synchronous consumers\n // before the runtime resolves on its own.\n if (!this._conversationManagerAgent) {\n await this.GetConversationManagerAgent();\n }\n return ConversationsRuntime.Instance.AgentRunner.processMessage({\n conversationId,\n message,\n conversationDetailId,\n appContext,\n onProgress,\n ...(planMode ? { planMode: true } : {}),\n ...(requestedSkillIDs?.length ? { requestedSkillIDs } : {}),\n ...(allowedAgentIDs != null ? { AllowedAgentIDs: allowedAgentIDs } : {}),\n ...(agentHistoryFrom ? { AgentHistoryFrom: agentHistoryFrom } : {}),\n });\n }\n\n /** @deprecated Use {@link ProcessMessage}. */\n async processMessage(\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n conversationDetailId: string,\n onProgress?: AgentExecutionProgressCallback,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n allowedAgentIDs?: readonly string[] | null,\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n return this.ProcessMessage(conversationId, message, conversationHistory, conversationDetailId, onProgress, appContext, planMode, requestedSkillIDs, allowedAgentIDs, agentHistoryFrom);\n }\n\n /**\n * Configuration preset an agent was pinned to by a previous `@mention` in this conversation.\n *\n * Resolved by QUERY, not by scanning the display array. The pinning `@mention` is normally\n * the FIRST message of an exchange and everything after it is follow-up, so it is the\n * message most likely to fall below the loaded transcript window — and `undefined` is a\n * legal value for `configurationPresetId`, so the miss is silent. The visible consequence\n * is a run executed under the default configuration (a different model tier) instead of the\n * one the user explicitly chose, with a plausible-looking result and no error.\n *\n * There is no column to filter on: the preset lives inside the message body as a JSON\n * mention blob (`@{\"type\":\"agent\",\"id\":\"…\",\"configId\":\"…\"}`). So SQL narrows and the parser\n * decides — both `configId` and the agent id appear verbatim in that blob, which makes the\n * two LIKEs a tight prefilter, and `parseMentions` is what actually confirms a match.\n *\n * @param branchId The active branch. Only messages on its path count; null or omitted reads\n * the trunk.\n */\n public async FindConfigurationPresetForAgent(\n conversationId: string,\n agentId: string,\n branchId?: string | null\n ): Promise<string | undefined> {\n type MentionRow = Pick<MJConversationDetailEntity, 'ID' | 'Message'>;\n const pathFilter = await this.branchPathFilter(conversationId, branchId);\n if (pathFilter == null) {\n return undefined;\n }\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<MentionRow>({\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: `${pathFilter} AND Role='User'`\n + ` AND Message LIKE '%\"configId\"%' AND Message LIKE '%${agentId}%'`,\n OrderBy: 'Sequence DESC',\n // >1 because LIKE cannot tell a mention blob from the same id appearing elsewhere in\n // the prose; the parse below is authoritative and picks the newest genuine match.\n MaxRows: CONFIG_PRESET_CANDIDATE_ROWS,\n Fields: ['ID', 'Message'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to resolve configuration preset:', result.ErrorMessage);\n return undefined;\n }\n\n for (const row of result.Results || []) {\n const configurationId = this.readAgentConfigFromMention(row.Message, agentId);\n if (configurationId) {\n console.log(`\\u{1F3AF} Found configuration preset from @mention: ${configurationId}`);\n return configurationId;\n }\n }\n return undefined;\n }\n\n /** Returns the configId this message pins for `agentId`, or null when it pins none. */\n private readAgentConfigFromMention(message: string | null, agentId: string): string | null {\n if (!message) {\n return null;\n }\n const parsed = this.mentionParser.parseMentions(message, AIEngineBase.Instance.ReadableAgents, []);\n const mention = parsed.agentMention;\n return mention?.id === agentId && mention.configurationId ? mention.configurationId : null;\n }\n\n\n /**\n * Clear the session for a conversation (useful when starting a new topic)\n */\n ClearSession(conversationId: string): void {\n this._sessionIds.delete(conversationId);\n }\n\n /** @deprecated Use {@link ClearSession}. */\n clearSession(conversationId: string): void {\n return this.ClearSession(conversationId);\n }\n\n /**\n * Surfaces a warning toast when the user requested skills (via /skill mentions) that the\n * target agent cannot activate — the server drops such requests, and without this the\n * refusal is invisible to the user. Client-side check uses the agent gate only (the server\n * additionally intersects with the user's Run permission).\n */\n private warnOnUnacceptedSkills(agent: MJAIAgentEntityExtended, requestedSkillIDs: string[]): void {\n const allowed = AIEngineBase.Instance.GetSkillsForAgent(agent);\n const dropped = requestedSkillIDs.filter(id => !allowed.some(s => UUIDsEqual(s.ID, id)));\n if (dropped.length === 0) return;\n const names = dropped.map(\n id => AIEngineBase.Instance.Skills.find(s => UUIDsEqual(s.ID, id))?.Name ?? 'requested skill'\n );\n const reason = agent.AcceptsSkills === 'None'\n ? `${agent.Name} doesn't accept skills`\n : `${agent.Name} can't activate ${names.length === 1 ? 'this skill' : 'these skills'}`;\n MJNotificationService.Instance?.CreateSimpleNotification(\n `${reason} — ${names.join(', ')} won't be used for this run.`,\n 'warning',\n 6000\n );\n }\n\n /**\n * Invoke a sub-agent based on Sage Agent's payload.\n * This is called when Sage decides to delegate to a specialist agent.\n *\n * Stays on the Angular shim because it directly uses AgentClientService.\n * Could move to the runtime in a follow-up if needed.\n */\n async InvokeSubAgent(\n agentName: string,\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n reasoning: string,\n conversationDetailId: string,\n payload?: Record<string, unknown> | null,\n onProgress?: AgentExecutionProgressCallback,\n sourceArtifactId?: string,\n sourceArtifactVersionId?: string,\n agentConfigurationPresetId?: string,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n /** The first moment of the conversation the run may read. Null or omitted reads all of it. */\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n try {\n // Ensure AIEngineBase is configured\n await AIEngineBase.Instance.Config(false);\n\n // Find the agent by name\n const agent = AIEngineBase.Instance.ReadableAgents.find(a => a.Name === agentName);\n\n if (!agent || !agent.ID) {\n const errorMsg = `Sub-agent \"${agentName}\" not found`;\n console.warn(`${errorMsg}`);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return null;\n }\n\n if (requestedSkillIDs?.length) {\n this.warnOnUnacceptedSkills(agent, requestedSkillIDs);\n }\n\n console.log(`Invoking sub-agent: ${agentName}`, { reasoning, hasPayload: !!payload, hasConfigPreset: !!agentConfigurationPresetId });\n\n // Map AIAgentConfiguration preset ID to actual AIConfiguration ID\n let aiConfigurationId: string | undefined = undefined;\n if (agentConfigurationPresetId) {\n const presets = AIEngineBase.Instance.GetAgentConfigurationPresets(agent.ID, false);\n const preset = presets.find(p => UUIDsEqual(p.ID, agentConfigurationPresetId) || UUIDsEqual(p.AIConfigurationID, agentConfigurationPresetId));\n\n if (preset) {\n aiConfigurationId = preset.AIConfigurationID || undefined;\n console.log(`Mapped agent configuration preset \"${preset.Name}\" to AIConfigurationID: ${aiConfigurationId || 'default'}`);\n } else {\n console.warn(`Agent configuration preset ${agentConfigurationPresetId} not found for agent ${agent.ID}`);\n }\n }\n\n const agentParams: RunAgentFromConversationDetailParams = {\n ConversationDetailId: conversationDetailId,\n AgentId: agent.ID,\n MaxHistoryMessages: 20,\n Data: {\n conversationId: conversationId,\n latestMessageId: message.ID,\n invocationReason: reasoning,\n ...(appContext ? { appContext } : {}),\n },\n ...(payload ? { Payload: payload } : {}),\n ...(aiConfigurationId ? { ConfigurationId: aiConfigurationId } : {}),\n ...(planMode ? { PlanMode: true } : {}),\n ...(requestedSkillIDs?.length ? { RequestedSkillIDs: requestedSkillIDs } : {}),\n ...(agentHistoryFrom ? { AgentHistoryFrom: agentHistoryFrom } : {}),\n CreateArtifacts: true,\n CreateNotification: true,\n SourceArtifactId: sourceArtifactId,\n SourceArtifactVersionId: sourceArtifactVersionId,\n OnProgress: onProgress ? (progress) => {\n onProgress({\n step: progress.CurrentStep as 'initialization' | 'validation' | 'prompt_execution' | 'action_execution' | 'subagent_execution' | 'decision_processing' | 'finalization',\n percentage: progress.Percentage,\n message: progress.Message,\n metadata: progress.Metadata\n });\n } : undefined\n };\n\n const runResult = await this.agentClientService.RunAgentFromConversationDetail(agentParams);\n\n if (runResult.Success && runResult.Result) {\n return runResult.Result as ExecuteAgentResult;\n }\n\n const failed = coerceFailedExecuteAgentResult(\n runResult.Result as ExecuteAgentResult | null | undefined,\n runResult.ErrorMessage || `Sub-agent \"${agentName}\" failed`,\n );\n const errorMsg = `Sub-agent \"${agentName}\" failed: ${failed.errorMessage}`;\n console.error(errorMsg);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return failed;\n } catch (error) {\n const errorMsg = `Error invoking sub-agent \"${agentName}\": ` + (error instanceof Error ? error.message : String(error));\n console.error(`Error invoking sub-agent \"${agentName}\":`, error);\n MJNotificationService.Instance?.CreateSimpleNotification(errorMsg, 'error', 5000);\n return coerceFailedExecuteAgentResult<ExecuteAgentResult>(undefined, errorMsg);\n }\n }\n\n /** @deprecated Use {@link InvokeSubAgent}. */\n async invokeSubAgent(\n agentName: string,\n conversationId: string,\n message: MJConversationDetailEntity,\n conversationHistory: MJConversationDetailEntity[],\n reasoning: string,\n conversationDetailId: string,\n payload?: Record<string, unknown> | null,\n onProgress?: AgentExecutionProgressCallback,\n sourceArtifactId?: string,\n sourceArtifactVersionId?: string,\n agentConfigurationPresetId?: string,\n appContext?: Record<string, unknown> | null,\n planMode?: boolean,\n requestedSkillIDs?: string[],\n agentHistoryFrom?: Date | null\n ): Promise<ExecuteAgentResult | null> {\n return this.InvokeSubAgent(agentName, conversationId, message, conversationHistory, reasoning, conversationDetailId, payload, onProgress, sourceArtifactId, sourceArtifactVersionId, agentConfigurationPresetId, appContext, planMode, requestedSkillIDs, agentHistoryFrom);\n }\n\n /**\n * Check if user's latest message should continue with the previous agent or route through Sage.\n * Uses fast inference (<500ms) to determine intent and avoid unnecessary Sage overhead.\n *\n * Stays on the Angular shim because it directly uses GraphQLAIClient.\n * Could move to the runtime in a follow-up.\n *\n * @param branchId The active branch. Only the agent's artifacts on its path are listed for the\n * classifier; null or omitted reads the trunk.\n */\n async CheckAgentContinuityIntent(\n conversationId: string,\n agentId: string,\n latestMessage: string,\n conversationHistory: MJConversationDetailEntity[],\n branchId?: string | null\n ): Promise<IntentCheckResult> {\n if (!this._aiClient) {\n console.warn('AI Client not initialized, defaulting to UNSURE for intent check');\n return { decision: 'UNSURE', reasoning: 'AI Client not initialized' };\n }\n\n try {\n await AIEngineBase.Instance.Config(false);\n const prompt = AIEngineBase.Instance.Prompts.find(p => p.Name === 'Check Sage Intent');\n if (!prompt) {\n console.warn('⚠️ Check Sage Intent prompt not found, defaulting to UNSURE');\n return { decision: 'UNSURE', reasoning: 'Check Sage Intent prompt not found' };\n }\n\n const agent = AIEngineBase.Instance.ReadableAgents.find(a => UUIDsEqual(a.ID, agentId));\n if (!agent) {\n console.warn('⚠️ Previous agent not found, defaulting to UNSURE');\n return { decision: 'UNSURE', reasoning: 'Previous agent not found' };\n }\n\n // Queried, not read off the caller's window-scoped maps — see findAllAgentArtifacts.\n // `conversationHistory` below is still the window on purpose: the `.slice(-10)` wants\n // the most recent exchange, which the loaded tail always contains.\n const agentArtifacts = await this.findAllAgentArtifacts(conversationId, agentId, undefined, branchId);\n\n const recentHistory = conversationHistory.slice(-10);\n const compactHistory = recentHistory.map((msg, idx) => {\n const role = msg.Role === 'User' ? 'User' : agent.Name || 'Agent';\n const content = msg.Message || '';\n return `${idx + 1}. ${role}: ${content.substring(0, 150)}${content.length > 150 ? '...' : ''}`;\n }).join('\\n');\n\n let artifactContext = '';\n if (agentArtifacts.length > 0) {\n artifactContext = '\\n\\n**Prior Artifacts Created by This Agent**:\\n';\n agentArtifacts.forEach((artifact, idx) => {\n artifactContext += `${idx + 1}. ${artifact.artifactName} (${artifact.ArtifactType})\\n`;\n artifactContext += ` - Versions: ${artifact.Versions.length}\\n`;\n if (artifact.Versions.length > 0) {\n artifactContext += ` - Latest: v${artifact.Versions[0].versionNumber}`;\n if (artifact.Versions[0].versionName) {\n artifactContext += ` - ${artifact.Versions[0].versionName}`;\n }\n artifactContext += '\\n';\n }\n });\n }\n\n const userMessage = `**Previous Agent**: ${agent.Name} - ${agent.Description || 'No description'}\n\n**Conversation History** (last ${recentHistory.length} messages):\n${compactHistory}${artifactContext}\n\n**Latest User Message**: \"${latestMessage}\"`;\n\n console.log('🔍 Checking agent continuity intent...', {\n agentName: agent.Name,\n messagePreview: latestMessage.substring(0, 50),\n artifactCount: agentArtifacts.length\n });\n\n const result = await this._aiClient.RunAIPrompt({\n promptId: prompt.ID,\n messages: [{ role: 'user', content: userMessage }],\n data: {\n hasPriorArtifact: agentArtifacts.length > 0,\n priorArtifacts: agentArtifacts\n }\n });\n\n if (result && result.success && (result.parsedResult || result.output)) {\n const parsed = result.parsedResult ||\n (result.output ? JSON.parse(result.output) : null);\n\n if (parsed && parsed.continuesWith) {\n const decision = parsed.continuesWith.toUpperCase();\n const reasoning = parsed.reasoning || 'No reasoning provided';\n const targetArtifactVersionId = parsed.targetArtifactVersionId || undefined;\n\n console.log(`✅ Intent check result: ${decision}`, {\n reasoning,\n targetArtifactVersionId,\n latency: result.executionTimeMs || 'unknown'\n });\n\n if (decision === 'YES' || decision === 'NO' || decision === 'UNSURE') {\n return {\n decision: decision as 'YES' | 'NO' | 'UNSURE',\n reasoning,\n targetArtifactVersionId\n };\n }\n }\n }\n\n console.warn('⚠️ Intent check failed or returned invalid format, defaulting to UNSURE');\n return { decision: 'UNSURE', reasoning: 'Invalid format from intent check prompt' };\n } catch (error) {\n console.error('❌ Error checking agent continuity intent:', error);\n return {\n decision: 'UNSURE',\n reasoning: `Error during intent check: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n }\n\n /** @deprecated Use {@link CheckAgentContinuityIntent}. */\n async checkAgentContinuityIntent(\n conversationId: string,\n agentId: string,\n latestMessage: string,\n conversationHistory: MJConversationDetailEntity[],\n branchId?: string | null\n ): Promise<IntentCheckResult> {\n return this.CheckAgentContinuityIntent(conversationId, agentId, latestMessage, conversationHistory, branchId);\n }\n\n /**\n * Runs a typed decision on the server in one round trip, through\n * {@link GraphQLAIClient.RunDecision}. Decision routing (`EnableDecisionRouting`) asks its\n * routing questions here.\n *\n * Never throws: without an AI client, or on any failure, it resolves with `Success: false` and\n * no answers.\n */\n public async RunDecision(params: RunDecisionParams): Promise<RunDecisionResult> {\n if (!this._aiClient) {\n return { Success: false, ErrorMessage: 'AI Client not initialized', Answers: {} };\n }\n return this._aiClient.RunDecision(params);\n }\n\n /**\n * Every artifact this agent produced on the active branch path, newest version first, for\n * decision routing's artifact question. Resolved by query, as {@link findAllAgentArtifacts} explains.\n *\n * @param historyFrom The chat's history floor. When set, only artifacts on replies written at or\n * after it count, as with {@link FindLatestAgentOutputVersion}.\n * @param branchId The active branch. Only artifacts on its path count, as with\n * {@link FindLatestAgentOutputVersion}; null or omitted reads the trunk.\n */\n public async FindAgentArtifacts(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<AgentArtifactSummary[]> {\n return this.findAllAgentArtifacts(conversationId, agentId, historyFrom, branchId);\n }\n\n /**\n * Every artifact this agent produced on the active branch path, newest version first —\n * resolved by QUERY, not by scanning the display array.\n *\n * The scan this replaces walked `conversationDetails` and looked each row up in the\n * caller's `artifactsByDetailId` / `agentRunsByDetailId` maps. Both are scoped to the\n * LOADED WINDOW, so under transcript windowing it saw only the artifacts attached to the\n * page currently on screen.\n *\n * That matters because this list is the \"Prior Artifacts Created by This Agent\" block fed\n * to the Check Sage Intent prompt, which is what produces `targetArtifactVersionId`. A\n * truncated list does not make the classifier fail — it makes it reason over a partial\n * history and confidently name the wrong version, or miss continuity altogether. Silent,\n * plausible, and wrong: the same failure class as {@link FindLatestAgentOutputVersion},\n * closed the same way.\n *\n * Three reads: the agent's replies, their Output versions, and the artifacts' names. See\n * {@link AgentArtifactSummary} for why dropping `runId` removes the join back to agent runs.\n *\n * @param historyFrom The chat's history floor, when set (see {@link FindAgentArtifacts}).\n * @param branchId The branch whose path to read; null or omitted reads the trunk.\n */\n private async findAllAgentArtifacts(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<AgentArtifactSummary[]> {\n type VersionRow = Pick<MJArtifactVersionEntity, 'ID' | 'ArtifactID' | 'VersionNumber' | 'Name'>;\n const versionFilter = await this.agentOutputVersionFilter(conversationId, agentId, historyFrom, branchId);\n if (!versionFilter) {\n return []; // the classifier degrades to no artifact context\n }\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const versionResult = await rv.RunView<VersionRow>({\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: versionFilter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: MAX_AGENT_ARTIFACT_VERSIONS,\n Fields: ['ID', 'ArtifactID', 'VersionNumber', 'Name'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!versionResult.Success) {\n console.error('Failed to load agent artifact versions:', versionResult.ErrorMessage);\n return []; // the classifier degrades to no artifact context\n }\n const versions = versionResult.Results || [];\n if (versions.length === 0) {\n return [];\n }\n\n const artifactsById = await this.loadArtifactNames(\n [...new Set(versions.map(v => v.ArtifactID))]\n );\n return GroupVersionsByArtifact(versions, artifactsById);\n }\n\n /** Names and types for the artifacts behind a set of versions. */\n private async loadArtifactNames(\n artifactIds: string[]\n ): Promise<Map<string, Pick<MJArtifactEntity, 'ID' | 'Name' | 'Type'>>> {\n type ArtifactRow = Pick<MJArtifactEntity, 'ID' | 'Name' | 'Type'>;\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<ArtifactRow>({\n EntityName: 'MJ: Artifacts',\n ExtraFilter: `ID IN (${artifactIds.map(id => `'${id}'`).join(',')})`,\n Fields: ['ID', 'Name', 'Type'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to load agent artifacts:', result.ErrorMessage);\n return new Map<string, ArtifactRow>();\n }\n return new Map((result.Results || []).map(a => [a.ID, a]));\n }\n\n /**\n * Newest OUTPUT artifact version an agent produced in this conversation — resolved by\n * QUERY, not by scanning the display array.\n *\n * The array scan this replaces was correct only while `conversationHistory` held the whole\n * conversation. Under transcript windowing it holds one page, so the scan silently returns\n * null for any artifact below the window's oldest row — exactly the long \"modify this\n * again\" exchanges where payload continuity matters most. A null payload is a LEGAL agent\n * input, so the failure is silent: the agent regenerates from scratch instead of modifying.\n *\n * Two reads: the agent's replies, then their newest Output version. Versions carry\n * `__mj_CreatedAt`, so \"newest\" is expressible without joining back for `Sequence`.\n *\n * @param historyFrom The chat's history floor. When set, only artifacts on replies written at\n * or after it count: a run that may not read earlier messages must not pick up their work\n * as its payload either.\n * @param branchId The active branch. Only replies on its path count, so an artifact made on\n * another branch is never the latest here; null or omitted reads the trunk.\n */\n public async FindLatestAgentOutputVersion(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<AgentPayloadSource | null> {\n const versionFilter = await this.agentOutputVersionFilter(conversationId, agentId, historyFrom, branchId);\n return versionFilter ? this.runPayloadSourceQuery(versionFilter, '__mj_CreatedAt DESC') : null;\n }\n\n /**\n * `ArtifactVersion.ID IN (...)` for every OUTPUT artifact an agent produced on one\n * conversation path, in messages no rerun replaced, or null when the agent has no such reply\n * there. Shared by {@link FindLatestAgentOutputVersion} and {@link findAllAgentArtifacts} so\n * the two can never disagree about what \"this agent's artifacts\" means.\n *\n * The replies are read with their own RunView ({@link agentReplyIds}), so the row-level\n * security on conversation messages applies. A subquery over their view would skip it, and the\n * server refuses one for a user whose read of messages is row-filtered.\n */\n private async agentOutputVersionFilter(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<string | null> {\n const replyIds = await this.agentReplyIds(conversationId, agentId, historyFrom, branchId);\n if (replyIds.length === 0) {\n return null;\n }\n const inReplies = replyIds.map(id => `'${EscapeSQLString(id)}'`).join(',');\n return `ID IN (\n SELECT ArtifactVersionID FROM [__mj].[vwConversationDetailArtifacts]\n WHERE Direction='Output' AND ConversationDetailID IN (${inReplies})\n )`;\n }\n\n /**\n * IDs of the agent's replies on one conversation path, in messages no rerun replaced, written\n * at or after the history floor when one is set. Empty when the path cannot be built\n * ({@link branchPathFilter}) or the read fails.\n *\n * Filters on the DETAIL's `Status <> 'Error'` rather than the agent run's\n * `Status = 'Completed'` (which is what the array scan this replaced used). Doing it on the\n * run would mean joining back to `MJ: AI Agent Runs` purely to restate a condition the\n * detail already carries.\n */\n private async agentReplyIds(\n conversationId: string,\n agentId: string,\n historyFrom?: Date | null,\n branchId?: string | null\n ): Promise<string[]> {\n const pathFilter = await this.branchPathFilter(conversationId, branchId);\n if (pathFilter == null) {\n return [];\n }\n const floor = historyFrom ? ` AND ${ConversationEngine.HistoryFromFilter(historyFrom)}` : '';\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<Pick<MJConversationDetailEntity, 'ID'>>({\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: `${ConversationEngine.LiveRowsFilter(pathFilter)} AND AgentID='${EscapeSQLString(agentId)}'` +\n ` AND Role='AI' AND Status <> 'Error'${floor}`,\n Fields: ['ID'],\n ResultType: 'simple',\n IgnoreMaxRows: true\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to load agent replies:', result.ErrorMessage);\n return [];\n }\n return (result.Results || []).map(reply => reply.ID);\n }\n\n /**\n * The SQL predicate for one branch's path in a conversation, from\n * `ConversationEngine.BranchPathFilterFresh`. A null or omitted branch is the trunk and costs\n * no query.\n *\n * Never throws. When the path cannot be built (the branch rows fail to load, or the branch is\n * not among them), it logs the error and returns null. Each lookup then returns its own\n * failure value, as it does when its main query fails. A caller must not fall back to the\n * trunk predicate: on a branch, that reads trunk rows past the fork point.\n */\n private async branchPathFilter(conversationId: string, branchId: string | null | undefined): Promise<string | null> {\n try {\n const user = this.Provider.CurrentUser ?? undefined;\n return await ConversationEngine.BranchPathFilterFresh(conversationId, branchId, user as UserInfo, this.Provider);\n } catch (error) {\n console.error(`Failed to build the path of branch ${branchId} in conversation ${conversationId}:`, error);\n return null;\n }\n }\n\n /**\n * One artifact version by ID, as a payload source.\n *\n * Used by the continuity path after the intent check names a specific version: that ID may\n * belong to a message below the loaded window, so it cannot be resolved from the window's\n * artifact maps.\n */\n public async FindArtifactVersionById(versionId: string): Promise<AgentPayloadSource | null> {\n return this.runPayloadSourceQuery(`ID='${versionId}'`, undefined);\n }\n\n /**\n * Shared read behind {@link FindLatestAgentOutputVersion} and {@link FindArtifactVersionById}.\n *\n * `ResultType: 'simple'` with an explicit `Fields` list: nothing here is mutated, and under\n * `entity_object` the `Fields` narrowing would be silently discarded by `PreRunView`.\n */\n private async runPayloadSourceQuery(\n extraFilter: string,\n orderBy: string | undefined\n ): Promise<AgentPayloadSource | null> {\n type VersionRow = Pick<MJArtifactVersionEntity, 'ID' | 'ArtifactID' | 'VersionNumber' | 'Content'>;\n\n const rv = RunView.FromMetadataProvider(this.Provider);\n const result = await rv.RunView<VersionRow>({\n EntityName: 'MJ: Artifact Versions',\n ExtraFilter: extraFilter,\n OrderBy: orderBy,\n MaxRows: 1,\n Fields: ['ID', 'ArtifactID', 'VersionNumber', 'Content'],\n ResultType: 'simple'\n }, this.Provider.CurrentUser ?? undefined);\n\n if (!result.Success) {\n console.error('Failed to resolve agent payload source:', result.ErrorMessage);\n return null;\n }\n const row = result.Results?.[0];\n if (!row) {\n return null;\n }\n return {\n artifactId: row.ArtifactID,\n versionId: row.ID,\n versionNumber: row.VersionNumber,\n payload: parseArtifactContent(row.Content)\n };\n }\n\n}\n\n/**\n * Parses an artifact version's `Content` into an agent payload. Returns null rather than\n * throwing — a malformed artifact must not take down the send path, and \"no payload\" is\n * already a legal agent input.\n *\n * A payload must be a JSON OBJECT. Valid JSON that parses to an array, string, or number is\n * rejected for the same reason a parse failure is: every consumer spreads it or reads named\n * keys off it, so a non-object would satisfy the type at the boundary and misbehave deeper in.\n */\nfunction parseArtifactContent(content: string | null | undefined): Record<string, unknown> | null {\n if (!content) {\n return null;\n }\n try {\n const parsed: unknown = JSON.parse(content);\n return isPayloadObject(parsed) ? parsed : null;\n } catch (error) {\n console.warn('Artifact version content did not parse as JSON:', error);\n return null;\n }\n}\n\n/** Narrows a parsed JSON value to a plain object — the only shape a payload may take. */\nfunction isPayloadObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-naming.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,EAAE,mBAAmB,EAAmB,KAAK,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAGpH,6CAA6C;AAC7C,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,uGAAuG;AACvG,MAAM,MAAM,gBAAgB,GAAG,CAC7B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;AAEpF,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,4DAA4D;AAC5D,MAAM,WAAW,+BAAgC,SAAQ,mBAAmB;IAC1E,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,WAAW,EAAE,QAAQ,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,WAAW,EAAE,QAAQ,CAAC;CACvB;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"conversation-naming.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGnE,OAAO,EAAE,mBAAmB,EAAmB,KAAK,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAGpH,6CAA6C;AAC7C,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,uGAAuG;AACvG,MAAM,MAAM,gBAAgB,GAAG,CAC7B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;AAEpF,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,4DAA4D;AAC5D,MAAM,WAAW,+BAAgC,SAAQ,mBAAmB;IAC1E,gFAAgF;IAChF,cAAc,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,WAAW,EAAE,QAAQ,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,WAAW,EAAE,QAAQ,CAAC;CACvB;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAiDnH;AAED;;;;;;;;GAQG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAoBxC;AAED,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,8GAA8G;IAC9G,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gEAAgE;IAChE,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,+DAA+D;IAC/D,WAAW,EAAE,QAAQ,CAAC;IACtB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBjF;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBvG"}
|
|
@@ -30,10 +30,17 @@ export async function GenerateConversationName(options) {
|
|
|
30
30
|
messages: [{ role: 'user', content: messageText }]
|
|
31
31
|
}));
|
|
32
32
|
const timeoutMs = options.TimeoutMs ?? 30000;
|
|
33
|
+
let timeoutHandle;
|
|
33
34
|
const timeoutPromise = new Promise((_, reject) => {
|
|
34
|
-
setTimeout(() => reject(new Error(`Conversation naming timed out after ${Math.round(timeoutMs / 1000)} seconds`)), timeoutMs);
|
|
35
|
+
timeoutHandle = setTimeout(() => reject(new Error(`Conversation naming timed out after ${Math.round(timeoutMs / 1000)} seconds`)), timeoutMs);
|
|
35
36
|
});
|
|
36
|
-
|
|
37
|
+
let result;
|
|
38
|
+
try {
|
|
39
|
+
result = await Promise.race([run(prompt.ID, options.MessageText), timeoutPromise]);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
clearTimeout(timeoutHandle);
|
|
43
|
+
}
|
|
37
44
|
if (!result || !result.success || (!result.parsedResult && !result.output)) {
|
|
38
45
|
return null;
|
|
39
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-naming.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Shared conversation auto-naming helper — extracted from the message\n * input's first-message naming flow so BOTH chat paths use one implementation:\n *\n * - **Regular chat**: the composer names a brand-new conversation from its first\n * user message (the original behavior, now delegated here).\n * - **Realtime sessions**: a voice call that created a fresh conversation names it\n * from the first user utterance when the call ends.\n * - **Forks**: a Fork or Edit fork is named from the first message sent into it, when it\n * still has no name ({@link GenerateAndApplyForkName}).\n *\n * The naming itself is DB-driven: the `Name Conversation` AI prompt runs through the\n * GraphQL AI client (same path agents use) with a timeout guard ({@link GenerateConversationName}).\n * A conversation's parsed `{ name, description }` is saved through\n * {@link ConversationEngine.SaveConversation}, which updates the engine's cached conversation\n * list in place (the sidebar reacts through the engine's observables); a fork's name is saved\n * on its `MJ: Conversation Branches` row. Failures are logged and return `null` — naming is\n * always best-effort background work that must never affect the user experience.\n */\nimport { IMetadataProvider, UserInfo } from '@memberjunction/core';\nimport { CleanAndParseJSON } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { GraphQLDataProvider, GraphQLAIClient, type RunAIPromptResult } from '@memberjunction/graphql-dataprovider';\nimport { ConversationEngine, type MJConversationBranchEntity } from '@memberjunction/core-entities';\n\n/** The result of a successful naming run. */\nexport interface ConversationNameResult {\n /** The generated name, trimmed. */\n Name: string;\n /** The generated description; empty string when the prompt omitted it. */\n Description: string;\n}\n\n/** The prompt runner {@link GenerateConversationName} calls; a test seam for the GraphQL AI client. */\nexport type NamePromptRunner = (\n promptId: string,\n messageText: string\n) => Promise<Pick<RunAIPromptResult, 'success' | 'parsedResult' | 'output'> | null>;\n\n/** Options for {@link GenerateConversationName}. */\nexport interface GenerateNameOptions {\n /**\n * The text the name is derived from — the first user message (regular chat and forks) or the\n * first spoken user utterance (realtime). Callers strip mentions/markup first.\n */\n MessageText: string;\n /** The GraphQL provider the AI client runs over. */\n Provider: GraphQLDataProvider;\n /** Abort guard for the prompt run. Default 30s — the target keeps its current name on timeout. */\n TimeoutMs?: number;\n /**\n * Test seam: overrides the prompt execution. Production leaves this undefined and the\n * helper runs the `Name Conversation` prompt via {@link GraphQLAIClient.RunAIPrompt}.\n */\n RunPrompt?: NamePromptRunner;\n}\n\n/** Options for {@link GenerateAndApplyConversationName}. */\nexport interface GenerateConversationNameOptions extends GenerateNameOptions {\n /** The conversation to name (must exist; the caller owns membership checks). */\n ConversationId: string;\n /** The acting user (threaded into the conversation save). */\n CurrentUser: UserInfo;\n}\n\n/** Options for {@link GenerateAndApplyForkName}. */\nexport interface GenerateForkNameOptions extends GenerateNameOptions {\n /** The fork (`MJ: Conversation Branches` row) to name. */\n ForkId: string;\n /** The acting user; the branch entity's write rule applies to the save. */\n CurrentUser: UserInfo;\n}\n\n/** The seeded name of the AI prompt that generates conversation names. */\nexport const NAME_CONVERSATION_PROMPT = 'Name Conversation';\n\n/** Longest fork name the `MJ: Conversation Branches` Name field holds. */\nexport const MAX_FORK_NAME_LENGTH = 255;\n\n/**\n * Runs the `Name Conversation` prompt on a message and parses its `{ name, description }`. Saves nothing.\n *\n * @returns The generated `{ Name, Description }`, or `null` when the prompt is missing, the provider is\n * unavailable, the run fails or times out, or the output has no name. Failures are logged.\n */\nexport async function GenerateConversationName(options: GenerateNameOptions): Promise<ConversationNameResult | null> {\n try {\n await AIEngineBase.Instance.Config(false);\n const prompt = AIEngineBase.Instance.Prompts.find(pr => pr.Name === NAME_CONVERSATION_PROMPT);\n if (!prompt) {\n console.warn(`⚠️ ${NAME_CONVERSATION_PROMPT} prompt not found`);\n return null;\n }\n if (!options.Provider) {\n console.warn('⚠️ GraphQLDataProvider not available for conversation naming');\n return null;\n }\n\n const run: NamePromptRunner = options.RunPrompt\n ?? ((promptId: string, messageText: string) =>\n new GraphQLAIClient(options.Provider).RunAIPrompt({\n promptId,\n messages: [{ role: 'user', content: messageText }]\n }));\n\n const timeoutMs = options.TimeoutMs ?? 30000;\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`Conversation naming timed out after ${Math.round(timeoutMs / 1000)} seconds`)), timeoutMs);\n });\n\n const result = await Promise.race([run(prompt.ID, options.MessageText), timeoutPromise]);\n if (!result || !result.success || (!result.parsedResult && !result.output)) {\n return null;\n }\n\n // parsedResult preferred; CleanAndParseJSON tolerates ```json fences in raw output.\n const parsed = (result.parsedResult ?? (result.output ? CleanAndParseJSON(result.output) : null)) as\n | { name?: string; description?: string }\n | null;\n const name = typeof parsed?.name === 'string' ? parsed.name.trim() : '';\n if (!name) {\n return null;\n }\n return { Name: name, Description: parsed?.description || '' };\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (the current name stays):', error);\n return null;\n }\n}\n\n/**\n * Generates a name + description for a conversation from its first message and SAVES it\n * (DB + engine cache) — the single naming implementation shared by the regular composer\n * and the realtime session path.\n *\n * @returns The applied `{ Name, Description }`, or `null` when naming was skipped/failed\n * (missing prompt, provider unavailable, timeout, unparseable output, save failure) —\n * the conversation keeps its current name in every null case.\n */\nexport async function GenerateAndApplyConversationName(\n options: GenerateConversationNameOptions\n): Promise<ConversationNameResult | null> {\n const generated = await GenerateConversationName(options);\n if (!generated) {\n return null;\n }\n try {\n const saved = await ConversationEngine.Instance.SaveConversation(\n options.ConversationId,\n { Name: generated.Name, Description: generated.Description },\n options.CurrentUser\n );\n if (!saved) {\n console.warn('⚠️ Conversation naming generated a name but the save failed');\n return null;\n }\n return generated;\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (conversation keeps its default name):', error);\n return null;\n }\n}\n\n/** Options for {@link SaveForkName}. */\nexport interface SaveForkNameOptions {\n /** The fork (`MJ: Conversation Branches` row) to name. */\n ForkId: string;\n /** The new name; null or blank clears it, so the default label shows. Cut to {@link MAX_FORK_NAME_LENGTH}. */\n Name: string | null;\n /** The provider the branch entity is read and saved through. */\n Provider: IMetadataProvider;\n /** The acting user; the branch entity's write rule applies. */\n CurrentUser: UserInfo;\n /** When true, saves nothing if the row read fresh already has a name. */\n OnlyIfUnnamed?: boolean;\n}\n\n/**\n * Saves a fork's Name through the `MJ: Conversation Branches` entity, after reading the row fresh.\n *\n * @returns true when the name was saved; false when the row cannot be read, when `OnlyIfUnnamed` is\n * set and the row has a name, or when the save fails (logged).\n * @throws when the entity read or save throws\n */\nexport async function SaveForkName(options: SaveForkNameOptions): Promise<boolean> {\n const fork = await options.Provider.GetEntityObject<MJConversationBranchEntity>('MJ: Conversation Branches', options.CurrentUser);\n if (!(await fork.Load(options.ForkId))) {\n console.warn(`⚠️ Could not read fork ${options.ForkId} to save its name`);\n return false;\n }\n if (options.OnlyIfUnnamed && fork.Name?.trim()) {\n return false;\n }\n const name = options.Name?.trim().slice(0, MAX_FORK_NAME_LENGTH).trim();\n fork.Name = name ? name : null;\n if (!(await fork.Save())) {\n console.warn(`⚠️ Could not save the name of fork ${options.ForkId}: ${fork.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n return false;\n }\n return true;\n}\n\n/**\n * Names a fork from its first message: runs the `Name Conversation` prompt ({@link GenerateConversationName})\n * and saves the name as the fork's Name only when the fork, read fresh right before the save, still has\n * no name, so a person's rename wins.\n *\n * @returns The saved name, or `null` when naming failed, the fork already has a name, or the save failed.\n * Failures are logged.\n */\nexport async function GenerateAndApplyForkName(options: GenerateForkNameOptions): Promise<string | null> {\n const generated = await GenerateConversationName(options);\n if (!generated) {\n return null;\n }\n try {\n const saved = await SaveForkName({\n ForkId: options.ForkId,\n Name: generated.Name,\n Provider: options.Provider,\n CurrentUser: options.CurrentUser,\n OnlyIfUnnamed: true,\n });\n return saved ? generated.Name.slice(0, MAX_FORK_NAME_LENGTH).trim() : null;\n } catch (error) {\n console.warn(`⚠️ Fork naming failed (fork ${options.ForkId} keeps its current name):`, error);\n return null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"conversation-naming.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-naming.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAuB,eAAe,EAA0B,MAAM,sCAAsC,CAAC;AACpH,OAAO,EAAE,kBAAkB,EAAmC,MAAM,+BAA+B,CAAC;AAkDpG,0EAA0E;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAAG,mBAAmB,CAAC;AAE5D,0EAA0E;AAC1E,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAA4B;IACzE,IAAI,CAAC;QACH,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,wBAAwB,CAAC,CAAC;QAC9F,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,MAAM,wBAAwB,mBAAmB,CAAC,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;YAC7E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,GAAG,GAAqB,OAAO,CAAC,SAAS;eAC1C,CAAC,CAAC,QAAgB,EAAE,WAAmB,EAAE,EAAE,CAC5C,IAAI,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC;gBAChD,QAAQ;gBACR,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;aACnD,CAAC,CAAC,CAAC;QAER,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAC7C,IAAI,aAAwD,CAAC;QAC7D,MAAM,cAAc,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YACtD,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uCAAuC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAChJ,CAAC,CAAC,CAAC;QAEH,IAAI,MAA6C,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;QACrF,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,aAAa,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,oFAAoF;QACpF,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAExF,CAAC;QACT,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,EAAE,EAAE,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,yDAAyD,EAAE,KAAK,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,OAAwC;IAExC,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,gBAAgB,CAC9D,OAAO,CAAC,cAAc,EACtB,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,EAC5D,OAAO,CAAC,WAAW,CACpB,CAAC;QACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;YAC5E,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,sEAAsE,EAAE,KAAK,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAgBD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B,2BAA2B,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAClI,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,0BAA0B,OAAO,CAAC,MAAM,mBAAmB,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,EAAE,CAAC;IACxE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/B,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,sCAAsC,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,YAAY,EAAE,eAAe,IAAI,eAAe,EAAE,CAAC,CAAC;QAC/H,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAgC;IAC7E,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;YAC/B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,+BAA+B,OAAO,CAAC,MAAM,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAC9F,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["/**\n * @fileoverview Shared conversation auto-naming helper — extracted from the message\n * input's first-message naming flow so BOTH chat paths use one implementation:\n *\n * - **Regular chat**: the composer names a brand-new conversation from its first\n * user message (the original behavior, now delegated here).\n * - **Realtime sessions**: a voice call that created a fresh conversation names it\n * from the first user utterance when the call ends.\n * - **Forks**: a Fork or Edit fork is named from the first message sent into it, when it\n * still has no name ({@link GenerateAndApplyForkName}).\n *\n * The naming itself is DB-driven: the `Name Conversation` AI prompt runs through the\n * GraphQL AI client (same path agents use) with a timeout guard ({@link GenerateConversationName}).\n * A conversation's parsed `{ name, description }` is saved through\n * {@link ConversationEngine.SaveConversation}, which updates the engine's cached conversation\n * list in place (the sidebar reacts through the engine's observables); a fork's name is saved\n * on its `MJ: Conversation Branches` row. Failures are logged and return `null` — naming is\n * always best-effort background work that must never affect the user experience.\n */\nimport { IMetadataProvider, UserInfo } from '@memberjunction/core';\nimport { CleanAndParseJSON } from '@memberjunction/global';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { GraphQLDataProvider, GraphQLAIClient, type RunAIPromptResult } from '@memberjunction/graphql-dataprovider';\nimport { ConversationEngine, type MJConversationBranchEntity } from '@memberjunction/core-entities';\n\n/** The result of a successful naming run. */\nexport interface ConversationNameResult {\n /** The generated name, trimmed. */\n Name: string;\n /** The generated description; empty string when the prompt omitted it. */\n Description: string;\n}\n\n/** The prompt runner {@link GenerateConversationName} calls; a test seam for the GraphQL AI client. */\nexport type NamePromptRunner = (\n promptId: string,\n messageText: string\n) => Promise<Pick<RunAIPromptResult, 'success' | 'parsedResult' | 'output'> | null>;\n\n/** Options for {@link GenerateConversationName}. */\nexport interface GenerateNameOptions {\n /**\n * The text the name is derived from — the first user message (regular chat and forks) or the\n * first spoken user utterance (realtime). Callers strip mentions/markup first.\n */\n MessageText: string;\n /** The GraphQL provider the AI client runs over. */\n Provider: GraphQLDataProvider;\n /** Abort guard for the prompt run. Default 30s — the target keeps its current name on timeout. */\n TimeoutMs?: number;\n /**\n * Test seam: overrides the prompt execution. Production leaves this undefined and the\n * helper runs the `Name Conversation` prompt via {@link GraphQLAIClient.RunAIPrompt}.\n */\n RunPrompt?: NamePromptRunner;\n}\n\n/** Options for {@link GenerateAndApplyConversationName}. */\nexport interface GenerateConversationNameOptions extends GenerateNameOptions {\n /** The conversation to name (must exist; the caller owns membership checks). */\n ConversationId: string;\n /** The acting user (threaded into the conversation save). */\n CurrentUser: UserInfo;\n}\n\n/** Options for {@link GenerateAndApplyForkName}. */\nexport interface GenerateForkNameOptions extends GenerateNameOptions {\n /** The fork (`MJ: Conversation Branches` row) to name. */\n ForkId: string;\n /** The acting user; the branch entity's write rule applies to the save. */\n CurrentUser: UserInfo;\n}\n\n/** The seeded name of the AI prompt that generates conversation names. */\nexport const NAME_CONVERSATION_PROMPT = 'Name Conversation';\n\n/** Longest fork name the `MJ: Conversation Branches` Name field holds. */\nexport const MAX_FORK_NAME_LENGTH = 255;\n\n/**\n * Runs the `Name Conversation` prompt on a message and parses its `{ name, description }`. Saves nothing.\n *\n * @returns The generated `{ Name, Description }`, or `null` when the prompt is missing, the provider is\n * unavailable, the run fails or times out, or the output has no name. Failures are logged.\n */\nexport async function GenerateConversationName(options: GenerateNameOptions): Promise<ConversationNameResult | null> {\n try {\n await AIEngineBase.Instance.Config(false);\n const prompt = AIEngineBase.Instance.Prompts.find(pr => pr.Name === NAME_CONVERSATION_PROMPT);\n if (!prompt) {\n console.warn(`⚠️ ${NAME_CONVERSATION_PROMPT} prompt not found`);\n return null;\n }\n if (!options.Provider) {\n console.warn('⚠️ GraphQLDataProvider not available for conversation naming');\n return null;\n }\n\n const run: NamePromptRunner = options.RunPrompt\n ?? ((promptId: string, messageText: string) =>\n new GraphQLAIClient(options.Provider).RunAIPrompt({\n promptId,\n messages: [{ role: 'user', content: messageText }]\n }));\n\n const timeoutMs = options.TimeoutMs ?? 30000;\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => reject(new Error(`Conversation naming timed out after ${Math.round(timeoutMs / 1000)} seconds`)), timeoutMs);\n });\n\n let result: Awaited<ReturnType<NamePromptRunner>>;\n try {\n result = await Promise.race([run(prompt.ID, options.MessageText), timeoutPromise]);\n } finally {\n clearTimeout(timeoutHandle);\n }\n if (!result || !result.success || (!result.parsedResult && !result.output)) {\n return null;\n }\n\n // parsedResult preferred; CleanAndParseJSON tolerates ```json fences in raw output.\n const parsed = (result.parsedResult ?? (result.output ? CleanAndParseJSON(result.output) : null)) as\n | { name?: string; description?: string }\n | null;\n const name = typeof parsed?.name === 'string' ? parsed.name.trim() : '';\n if (!name) {\n return null;\n }\n return { Name: name, Description: parsed?.description || '' };\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (the current name stays):', error);\n return null;\n }\n}\n\n/**\n * Generates a name + description for a conversation from its first message and SAVES it\n * (DB + engine cache) — the single naming implementation shared by the regular composer\n * and the realtime session path.\n *\n * @returns The applied `{ Name, Description }`, or `null` when naming was skipped/failed\n * (missing prompt, provider unavailable, timeout, unparseable output, save failure) —\n * the conversation keeps its current name in every null case.\n */\nexport async function GenerateAndApplyConversationName(\n options: GenerateConversationNameOptions\n): Promise<ConversationNameResult | null> {\n const generated = await GenerateConversationName(options);\n if (!generated) {\n return null;\n }\n try {\n const saved = await ConversationEngine.Instance.SaveConversation(\n options.ConversationId,\n { Name: generated.Name, Description: generated.Description },\n options.CurrentUser\n );\n if (!saved) {\n console.warn('⚠️ Conversation naming generated a name but the save failed');\n return null;\n }\n return generated;\n } catch (error) {\n console.warn('⚠️ Conversation naming failed (conversation keeps its default name):', error);\n return null;\n }\n}\n\n/** Options for {@link SaveForkName}. */\nexport interface SaveForkNameOptions {\n /** The fork (`MJ: Conversation Branches` row) to name. */\n ForkId: string;\n /** The new name; null or blank clears it, so the default label shows. Cut to {@link MAX_FORK_NAME_LENGTH}. */\n Name: string | null;\n /** The provider the branch entity is read and saved through. */\n Provider: IMetadataProvider;\n /** The acting user; the branch entity's write rule applies. */\n CurrentUser: UserInfo;\n /** When true, saves nothing if the row read fresh already has a name. */\n OnlyIfUnnamed?: boolean;\n}\n\n/**\n * Saves a fork's Name through the `MJ: Conversation Branches` entity, after reading the row fresh.\n *\n * @returns true when the name was saved; false when the row cannot be read, when `OnlyIfUnnamed` is\n * set and the row has a name, or when the save fails (logged).\n * @throws when the entity read or save throws\n */\nexport async function SaveForkName(options: SaveForkNameOptions): Promise<boolean> {\n const fork = await options.Provider.GetEntityObject<MJConversationBranchEntity>('MJ: Conversation Branches', options.CurrentUser);\n if (!(await fork.Load(options.ForkId))) {\n console.warn(`⚠️ Could not read fork ${options.ForkId} to save its name`);\n return false;\n }\n if (options.OnlyIfUnnamed && fork.Name?.trim()) {\n return false;\n }\n const name = options.Name?.trim().slice(0, MAX_FORK_NAME_LENGTH).trim();\n fork.Name = name ? name : null;\n if (!(await fork.Save())) {\n console.warn(`⚠️ Could not save the name of fork ${options.ForkId}: ${fork.LatestResult?.CompleteMessage ?? 'unknown error'}`);\n return false;\n }\n return true;\n}\n\n/**\n * Names a fork from its first message: runs the `Name Conversation` prompt ({@link GenerateConversationName})\n * and saves the name as the fork's Name only when the fork, read fresh right before the save, still has\n * no name, so a person's rename wins.\n *\n * @returns The saved name, or `null` when naming failed, the fork already has a name, or the save failed.\n * Failures are logged.\n */\nexport async function GenerateAndApplyForkName(options: GenerateForkNameOptions): Promise<string | null> {\n const generated = await GenerateConversationName(options);\n if (!generated) {\n return null;\n }\n try {\n const saved = await SaveForkName({\n ForkId: options.ForkId,\n Name: generated.Name,\n Provider: options.Provider,\n CurrentUser: options.CurrentUser,\n OnlyIfUnnamed: true,\n });\n return saved ? generated.Name.slice(0, MAX_FORK_NAME_LENGTH).trim() : null;\n } catch (error) {\n console.warn(`⚠️ Fork naming failed (fork ${options.ForkId} keeps its current name):`, error);\n return null;\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
|
|
2
|
+
/** The ExtraFilter for the top-level tasks a user owns. */
|
|
3
|
+
export declare function OwnTasksFilter(user: UserInfo): string;
|
|
4
|
+
/**
|
|
5
|
+
* The ExtraFilter for the top-level tasks the conversations UI shows a user: the tasks the user
|
|
6
|
+
* owns, and the tasks linked to a message the user wrote or that is in a conversation the user
|
|
7
|
+
* owns.
|
|
8
|
+
*
|
|
9
|
+
* The conversation and message IDs are read with their own RunView, so the row-level security on
|
|
10
|
+
* those entities applies. A subquery over their views would skip it, and the server refuses one
|
|
11
|
+
* for a user whose read of them is row-filtered. When a read fails, the result is the user's own
|
|
12
|
+
* tasks.
|
|
13
|
+
*/
|
|
14
|
+
export declare function BuildConversationTasksFilter(provider: IMetadataProvider, user: UserInfo): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=conversation-tasks-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-tasks-filter.d.ts","sourceRoot":"","sources":["../../../src/lib/services/conversation-tasks-filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,iBAAiB,EAAsB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAG3H,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAAC,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB/G"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { RunView } from '@memberjunction/core';
|
|
2
|
+
import { EscapeSQLString } from '@memberjunction/global';
|
|
3
|
+
/** The ExtraFilter for the top-level tasks a user owns. */
|
|
4
|
+
export function OwnTasksFilter(user) {
|
|
5
|
+
return `ParentID IS NULL AND UserID = '${EscapeSQLString(user.ID)}'`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The ExtraFilter for the top-level tasks the conversations UI shows a user: the tasks the user
|
|
9
|
+
* owns, and the tasks linked to a message the user wrote or that is in a conversation the user
|
|
10
|
+
* owns.
|
|
11
|
+
*
|
|
12
|
+
* The conversation and message IDs are read with their own RunView, so the row-level security on
|
|
13
|
+
* those entities applies. A subquery over their views would skip it, and the server refuses one
|
|
14
|
+
* for a user whose read of them is row-filtered. When a read fails, the result is the user's own
|
|
15
|
+
* tasks.
|
|
16
|
+
*/
|
|
17
|
+
export async function BuildConversationTasksFilter(provider, user) {
|
|
18
|
+
const ownTasks = OwnTasksFilter(user);
|
|
19
|
+
const tasks = provider.EntityByName('MJ: Tasks');
|
|
20
|
+
if (!tasks) {
|
|
21
|
+
return ownTasks;
|
|
22
|
+
}
|
|
23
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
24
|
+
const conversationIds = await readIds(rv, user, {
|
|
25
|
+
EntityName: 'MJ: Conversations',
|
|
26
|
+
ExtraFilter: `UserID = '${EscapeSQLString(user.ID)}'`,
|
|
27
|
+
Fields: ['ID'],
|
|
28
|
+
});
|
|
29
|
+
if (conversationIds == null) {
|
|
30
|
+
return ownTasks;
|
|
31
|
+
}
|
|
32
|
+
const messageIds = await readIds(rv, user, {
|
|
33
|
+
EntityName: 'MJ: Conversation Details',
|
|
34
|
+
ExtraFilter: taskMessagesFilter(user, conversationIds, tasks),
|
|
35
|
+
Fields: ['ID'],
|
|
36
|
+
});
|
|
37
|
+
if (messageIds == null || messageIds.length === 0) {
|
|
38
|
+
return ownTasks;
|
|
39
|
+
}
|
|
40
|
+
return `ParentID IS NULL AND (UserID = '${EscapeSQLString(user.ID)}' OR ConversationDetailID IN (${sqlInList(messageIds)}))`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The messages that have a top-level task and that the user wrote or that are in one of the
|
|
44
|
+
* user's conversations. The task subquery reads Tasks, which has no row filter in a default
|
|
45
|
+
* install. Its identifiers are bracketed so the PostgreSQL provider quotes them.
|
|
46
|
+
*/
|
|
47
|
+
function taskMessagesFilter(user, conversationIds, tasks) {
|
|
48
|
+
const inConversations = conversationIds.length > 0 ? ` OR ConversationID IN (${sqlInList(conversationIds)})` : '';
|
|
49
|
+
const taskView = `[${tasks.SchemaName}].[${tasks.BaseView}]`;
|
|
50
|
+
return (`(UserID = '${EscapeSQLString(user.ID)}'${inConversations}) AND ID IN ` +
|
|
51
|
+
`(SELECT [ConversationDetailID] FROM ${taskView} WHERE [ParentID] IS NULL AND [ConversationDetailID] IS NOT NULL)`);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The IDs of the rows `read` selects, with no row cap; null when the read fails. Each caller names
|
|
55
|
+
* an MJ core entity in `read`, so its key column is `ID`.
|
|
56
|
+
*/
|
|
57
|
+
async function readIds(rv, user, read) {
|
|
58
|
+
const result = await rv.RunView({ ...read, ResultType: 'simple', IgnoreMaxRows: true }, user);
|
|
59
|
+
if (!result.Success) {
|
|
60
|
+
console.error(`Failed to read ${read.EntityName} for the tasks filter:`, result.ErrorMessage);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return (result.Results ?? []).map(row => row.ID);
|
|
64
|
+
}
|
|
65
|
+
/** A quoted, comma-separated list of IDs for an IN clause. */
|
|
66
|
+
function sqlInList(ids) {
|
|
67
|
+
return ids.map(id => `'${EscapeSQLString(id)}'`).join(',');
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=conversation-tasks-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-tasks-filter.js","sourceRoot":"","sources":["../../../src/lib/services/conversation-tasks-filter.ts"],"names":[],"mappings":"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","sourcesContent":["import { RunView, type EntityInfo, type IMetadataProvider, type RunViewParams, type UserInfo } from '@memberjunction/core';\nimport { EscapeSQLString } from '@memberjunction/global';\n\n/** The ExtraFilter for the top-level tasks a user owns. */\nexport function OwnTasksFilter(user: UserInfo): string {\n return `ParentID IS NULL AND UserID = '${EscapeSQLString(user.ID)}'`;\n}\n\n/**\n * The ExtraFilter for the top-level tasks the conversations UI shows a user: the tasks the user\n * owns, and the tasks linked to a message the user wrote or that is in a conversation the user\n * owns.\n *\n * The conversation and message IDs are read with their own RunView, so the row-level security on\n * those entities applies. A subquery over their views would skip it, and the server refuses one\n * for a user whose read of them is row-filtered. When a read fails, the result is the user's own\n * tasks.\n */\nexport async function BuildConversationTasksFilter(provider: IMetadataProvider, user: UserInfo): Promise<string> {\n const ownTasks = OwnTasksFilter(user);\n const tasks = provider.EntityByName('MJ: Tasks');\n if (!tasks) {\n return ownTasks;\n }\n const rv = RunView.FromMetadataProvider(provider);\n const conversationIds = await readIds(rv, user, {\n EntityName: 'MJ: Conversations',\n ExtraFilter: `UserID = '${EscapeSQLString(user.ID)}'`,\n Fields: ['ID'],\n });\n if (conversationIds == null) {\n return ownTasks;\n }\n const messageIds = await readIds(rv, user, {\n EntityName: 'MJ: Conversation Details',\n ExtraFilter: taskMessagesFilter(user, conversationIds, tasks),\n Fields: ['ID'],\n });\n if (messageIds == null || messageIds.length === 0) {\n return ownTasks;\n }\n return `ParentID IS NULL AND (UserID = '${EscapeSQLString(user.ID)}' OR ConversationDetailID IN (${sqlInList(messageIds)}))`;\n}\n\n/**\n * The messages that have a top-level task and that the user wrote or that are in one of the\n * user's conversations. The task subquery reads Tasks, which has no row filter in a default\n * install. Its identifiers are bracketed so the PostgreSQL provider quotes them.\n */\nfunction taskMessagesFilter(user: UserInfo, conversationIds: readonly string[], tasks: EntityInfo): string {\n const inConversations = conversationIds.length > 0 ? ` OR ConversationID IN (${sqlInList(conversationIds)})` : '';\n const taskView = `[${tasks.SchemaName}].[${tasks.BaseView}]`;\n return (\n `(UserID = '${EscapeSQLString(user.ID)}'${inConversations}) AND ID IN ` +\n `(SELECT [ConversationDetailID] FROM ${taskView} WHERE [ParentID] IS NULL AND [ConversationDetailID] IS NOT NULL)`\n );\n}\n\n/**\n * The IDs of the rows `read` selects, with no row cap; null when the read fails. Each caller names\n * an MJ core entity in `read`, so its key column is `ID`.\n */\nasync function readIds(rv: RunView, user: UserInfo, read: Pick<RunViewParams, 'EntityName' | 'ExtraFilter' | 'Fields'>): Promise<string[] | null> {\n const result = await rv.RunView<{ ID: string }>({ ...read, ResultType: 'simple', IgnoreMaxRows: true }, user);\n if (!result.Success) {\n console.error(`Failed to read ${read.EntityName} for the tasks filter:`, result.ErrorMessage);\n return null;\n }\n return (result.Results ?? []).map(row => row.ID);\n}\n\n/** A quoted, comma-separated list of IDs for an IN clause. */\nfunction sqlInList(ids: readonly string[]): string {\n return ids.map(id => `'${EscapeSQLString(id)}'`).join(',');\n}\n"]}
|