pika-shared 1.4.8 → 1.4.9
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/dist/types/chatbot/chatbot-types.d.mts +83 -1
- package/dist/types/chatbot/chatbot-types.d.ts +83 -1
- package/dist/types/chatbot/chatbot-types.js.map +1 -1
- package/dist/types/chatbot/chatbot-types.mjs.map +1 -1
- package/dist/types/chatbot/webcomp-types.d.mts +9 -1
- package/dist/types/chatbot/webcomp-types.d.ts +9 -1
- package/dist/util/server-utils.js.map +1 -1
- package/dist/util/server-utils.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/chatbot/chatbot-types.ts","../../src/util/server-utils.ts"],"names":[],"mappings":"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","file":"server-utils.mjs","sourcesContent":["import type { ActionGroupInvocationInput, AgentCollaboration, FunctionDefinition, RetrievalFilter, Trace } from '@aws-sdk/client-bedrock-agent-runtime';\nimport type { Role } from '@aws-sdk/client-bedrock-agentcore';\n\nexport type CompanyType = 'retailer' | 'supplier';\n\nexport const DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT = 25;\nexport const DEFAULT_MAX_K_MATCHES_PER_STRATEGY = 5;\nexport const DEFAULT_MEMORY_STRATEGIES: UserMemoryStrategy[] = ['preferences', 'semantic'];\nexport const DEFAULT_EVENT_EXPIRY_DURATION = 7;\n\n/**\n * Data persisted by Bedrock Agent for each session, set\n * by calling the `initSession` function for a lambda\n * action group.\n */\nexport interface SessionData {\n /** Unique identifier for the session */\n sessionId: string;\n /** The company id for the session */\n companyId: string;\n /** Type of company participating in the session */\n companyType: CompanyType;\n /** Current date in ISO 8601 format */\n date: string;\n /** The agent id for the session */\n agentId: string;\n}\n\n/**\n * Represents a context item that was sent to the LLM in this session.\n * Used to track which contexts have been sent to avoid redundant transmission.\n */\nexport interface SentContextRecord {\n /** The sourceId of the context that was sent */\n sourceId: string;\n /** Array of message IDs where this context was sent (tracks all occurrences) */\n messageIds: string[];\n /** The content hash of the context when it was sent */\n contentHash: string;\n /** ISO 8601 timestamp of the last time this context was sent */\n lastSentAt: string;\n /** The origin of the context (user or auto) */\n origin: WidgetContextSourceOrigin;\n}\n\n/**\n * Represents a chat session between a user and an agent. A session is a sequential\n * collection of messages between a user and an agent. The most recent message is\n * lastMessageId.\n */\nexport interface ChatSession<T extends RecordOrUndef = undefined> {\n /**\n * Unique identifier for this chat session\n *\n * Note this is a time-based key so you can use it to lexicographically sort the sessions and to compare them\n * as in sessionId1 < sessionId2 if sessionId1 is before sessionId2.\n */\n sessionId: string;\n /** Unique identifier of the user participating in the session */\n userId: string;\n /**\n * The type of user who created this session. Used for filtering sessions by internal vs external users\n * in session insights. Defaults to 'external-user' if not provided.\n */\n userType?: UserType;\n /** Identifier for the specific agent instance */\n agentId: string;\n /** Identifier for the chat app */\n chatAppId: string;\n /** Unique identifier for the user's identity */\n identityId: string;\n /** Mode of the invocation of the agent */\n invocationMode: ConverseInvocationMode;\n /** Title or name of the chat session */\n title?: string;\n /** ID of the most recent message in the session */\n lastMessageId?: string;\n /** Additional session-specific attributes */\n sessionAttributes: SessionDataWithChatUserCustomDataSpreadIn<T>;\n /** Cost of processing input tokens in USD */\n inputCost?: number;\n /** Number of tokens processed in input messages */\n inputTokens?: number;\n /** Cost of generating output tokens in USD */\n outputCost?: number;\n /** Number of tokens generated in output messages */\n outputTokens?: number;\n /** Total cost of the session (input + output) in USD */\n totalCost?: number;\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate: string;\n /** ISO 8601 formatted timestamp of the last session update */\n lastUpdate: string;\n\n /**\n * If the entity feature is enabled, this is the entity ID of the user who created the session at the moment of creation.\n *\n * If the site wide entity feature is not enabled or if the associated chat app has disabled the entity feature or\n * if this session is being created in the context of a direct invocation (no chat app involved) then this is the string\n * \"chat-app-global\" indicating that if the user chooses to share this session, it will be accessible to anyone with access to the chat app who has the link.\n * Otherwise, only those who have access to the chat app and are associated with the same entity ID as the session owner will be able to access the session.\n */\n entityId: string;\n\n /**\n * Last Message that has been analyzed by the system for insights, this lets us detect if the user came back to\n * the chat after the session is believed to be complete and added another message that we should analyze again.\n *\n * Note this is a time-based key so you can use it to lexicographically sort the messages and compare message IDs\n * as in messageId1 < messageId2 if messageId1 is before messageId2.\n *\n * If present and insightsS3Url is not present then this is a bug.\n *\n * If lastAnalyzedMessageId is not the same as lastMessageId then this means the user has added another message\n * to the session since we computed insights and we need to recompute them.\n */\n lastAnalyzedMessageId?: string;\n\n /**\n * If present, this is the url to the s3 object that contains the insights for the session. If not present,\n * then the insights are not yet computed. If this is present and lastAnalyzedMessageId is not present, then\n * this is a bug.\n *\n * The url to the s3 object in this form:\n *\n * s3://<bucket-name>/<session-id>/insights.json\n */\n insightsS3Url?: string;\n\n /**\n * Insights for the session computed after the session is believed to be complete.\n *\n * This is not persisted in dynamodb, it's only in S3 and then added to the chat session in opensearch.\n */\n insights?: SessionInsights;\n\n /**\n * Feedback for the session.\n *\n * This is persisted in a separate dynamodb table (chat-session-feedback)and then added to the chat session in opensearch.\n */\n feedback?: ChatSessionFeedback[];\n\n /**\n * Expiration date of the message in Unix seconds. Internally used in dynamodb. Don't expect that this will\n * be set as it never will be made available to apps. That's why it's in snake case when nothing else is.\n */\n exp_date_unix_seconds?: number;\n\n /**\n * This is used to those sessions that we need to recompute the insights for.\n *\n * It will be set to NEEDS_INSIGHTS_ANALYSIS when we first create a session. Then we will have a lambda wake up\n * periodically and check if the session is ready to be analyzed (it's been some time since the last message was added).\n * We will then compute the insights and set lastAnalyzedMessageId and insightsS3Url. We will not put the insights\n * on the session object as it is stored in dynamodb, too big. It will go into opensearch on the session however.\n *\n * The actual computation will not be done until there is a messageId that is at last X old (message ID is really a\n * date UUID v7) where X is whatever we set (probably an hour or two). This is to avoid recomputing the insights\n * for every message.\n *\n * Also, if we detect that the lastMessageId is not equal to lastAnalyzedMessageId then we will once again set\n * insight_status_partition_key to NEEDS_INSIGHTS_ANALYSIS so that we can recompute the insights after enough time\n * goes by since the new last message was added.\n *\n * We will unset this value once we have computed the insights and set lastAnalyzedMessageId and insightsS3Url.\n *\n * Note that the GSI that governs this will not include a session record unless NEEDS_INSIGHTS_ANALYSIS is set\n * (insightStatus is the partition key)and lastMessageId is set (the sort key). There could be a short gap between\n * when the session is created and when the last message ID is added. This should be fine.\n */\n insightStatus?: InsightStatusNeedsInsightsAnalysis | undefined;\n\n /**\n * Tracks context items that have been sent to the LLM in this session.\n * Keyed by sourceId to allow efficient lookups when determining if a context has changed or needs to be resent.\n *\n * This is used to:\n * - Avoid sending the same context multiple times\n * - Detect when context has changed (via contentHash comparison)\n * - Track which message included each piece of context\n */\n sentContexts?: Record<string, SentContextRecord>;\n /** The share ID if this session is shared */\n shareId?: string;\n /** User ID of the user who created the share */\n shareCreatedByUserId?: string;\n /** When this session was first shared */\n shareDate?: string;\n /** When this session's share was revoked */\n shareRevokedDate?: string;\n\n /** If set to 'mock', this session is used for integration testing purposes. */\n testType?: 'mock';\n\n /**\n * The source of the converse request. Defaults to 'user'. The composite key chat_app_sk looks like this:\n *\n * ${chatAppId}#${source}#${updateDate}\n *\n * The source in the composite key here will only ever be either `user` or `component`. If this attribute's value is missing or is `user` or `component-as-user`,\n * then the composite key will be set to `user` so when we query on behalf of the user, we will get all sessions for that user.\n */\n source: ConverseSource;\n}\n\n/**\n * Convenience type for updating a session with the last analyzed message id and insights s3 url.\n *\n * Field update behavior:\n * - If a value is null: the field will be REMOVED from the database entirely (using DynamoDB REMOVE expression)\n * - If a value is undefined: the field will not be updated at all (field remains unchanged)\n * - If a value is present: the field will be SET to that value (using DynamoDB SET expression)\n *\n * Note: Setting insightStatus to null removes it from the sparse GSI since the field no longer exists.\n */\nexport interface ChatSessionLiteForUpdate {\n userId: string;\n sessionId: string;\n lastAnalyzedMessageId: string | undefined | null;\n insightStatus: InsightStatusNeedsInsightsAnalysis | undefined | null;\n insightsS3Url: string | undefined | null;\n}\n\nexport interface ChatSessionFeedback {\n /** The session ID of the session that the feedback is about. */\n sessionId: string;\n /** This is a V7 UUID that is date sortable and comparable */\n feedbackId: string;\n /** The user ID of the user who flagged the session. */\n userId: string;\n /** The message ID of the session message that the feedback is about. */\n messageId?: string;\n /** Whether the flag was reported by a human or an AI. */\n reportedByHuman: boolean;\n /** Whether the feedback was created by the customer or the system. */\n createdByCustomer: boolean;\n /** The status of the feedback. */\n status: SessionFeedbackStatus;\n /** The severity of the feedback. */\n severity: SessionFeedbackSeverity;\n /** The type of the feedback. */\n type: SessionFeedbackType;\n /** A comment from the user who flagged the session. Limit to 1000 characters. */\n userComment?: string;\n /** Comments from the internal team. This is stored zipped in dynamodb.*/\n internalComments?: FeedbackInternalComment[];\n /** Attachments to the feedback. */\n attachments?: Attachment[];\n /** The date and time the feedback was created as a string in ISO 8601 format. */\n createdOn: string;\n /** The date and time the feedback was updated as a string in ISO 8601 format. */\n updatedOn: string;\n /** The date and time the feedback will expire as a unix timestamp in seconds. It's snake case because it's never going to be used by the app itself. */\n exp_date_unix_seconds?: number;\n}\n\nexport interface Attachment {\n /**\n * The url to the s3 object in this form:\n *\n * s3://<bucket-name>/<session-id>/<attachment-id>.{extension}\n */\n s3Url: string;\n /** Name of the attachment. */\n name: string;\n /** MIME type of the attachment. */\n mimeType: string;\n}\n\nexport const INSIGHT_STATUS_NEEDS_INSIGHTS_ANALYSIS = 'NEEDS_INSIGHTS_ANALYSIS';\nexport type InsightStatusNeedsInsightsAnalysis = typeof INSIGHT_STATUS_NEEDS_INSIGHTS_ANALYSIS;\n\nexport const SESSION_FEEDBACK_STATUS = ['open', 'in_review', 'resolved', 'closed'] as const;\nexport type SessionFeedbackStatus = (typeof SESSION_FEEDBACK_STATUS)[number];\nexport const SESSION_FEEDBACK_STATUS_VALUES: NameValuePair<SessionFeedbackStatus>[] = [\n { name: 'Open', value: 'open' },\n { name: 'In Review', value: 'in_review' },\n { name: 'Resolved', value: 'resolved' },\n { name: 'Closed', value: 'closed' }\n];\n\nexport const SESSION_FEEDBACK_SEVERITY = ['low', 'medium', 'high', 'critical'] as const;\nexport type SessionFeedbackSeverity = (typeof SESSION_FEEDBACK_SEVERITY)[number];\nexport const SESSION_FEEDBACK_SEVERITY_VALUES: NameValuePair<SessionFeedbackSeverity>[] = [\n { name: 'Low', value: 'low' },\n { name: 'Medium', value: 'medium' },\n { name: 'High', value: 'high' },\n { name: 'Critical', value: 'critical' }\n];\n\nexport const SESSION_FEEDBACK_TYPE = [\n 'user_thumbs_up',\n 'user_thumbs_down',\n 'incorrect_information',\n 'incomplete_information',\n 'off_topic',\n 'hallucination',\n 'confusing_response',\n 'outdated_information',\n 'inappropriate_content',\n 'privacy_concern',\n 'harmful_content',\n 'system_error',\n 'timeout_occurred',\n 'tool_failure',\n 'poor_performance',\n 'training_example',\n 'context_awareness_issue',\n 'goal_misalignment',\n 'tool_capability_gap',\n 'tool_performance_issue',\n 'cost_issue',\n 'high_complexity_session',\n 'low_ai_confidence_level',\n 'critical_issues_present',\n 'user_dissatisfied',\n 'user_question_to_chat_author',\n 'other'\n] as const;\nexport type SessionFeedbackType = (typeof SESSION_FEEDBACK_TYPE)[number];\nexport const SESSION_FEEDBACK_TYPE_VALUES: NameValueDescTriple<SessionFeedbackType>[] = [\n { name: 'Confusing Response', value: 'confusing_response', desc: 'Session was confusing' },\n { name: 'Context Awareness Issue', value: 'context_awareness_issue', desc: 'Session had context awareness issue' },\n { name: 'Cost Issue', value: 'cost_issue', desc: 'Session had cost issue' },\n { name: 'Critical Issues Present', value: 'critical_issues_present', desc: 'Session had critical issues present' },\n { name: 'Goal Misalignment', value: 'goal_misalignment', desc: 'Session had goal misalignment' },\n { name: 'Hallucination', value: 'hallucination', desc: 'Session contained hallucinations' },\n { name: 'Harmful Content', value: 'harmful_content', desc: 'Session contained harmful content' },\n { name: 'High Complexity Session', value: 'high_complexity_session', desc: 'Session was high complexity' },\n { name: 'Inappropriate Content', value: 'inappropriate_content', desc: 'Session contained inappropriate content' },\n { name: 'Incorrect Information', value: 'incorrect_information', desc: 'Session contained incorrect information' },\n { name: 'Incomplete Information', value: 'incomplete_information', desc: 'Session contained incomplete information' },\n { name: 'Low AI Confidence Level', value: 'low_ai_confidence_level', desc: 'Session had low AI confidence level' },\n { name: 'Off Topic', value: 'off_topic', desc: 'Session was off topic' },\n { name: 'Other', value: 'other', desc: 'Session had indeterminate issue' },\n { name: 'Outdated Information', value: 'outdated_information', desc: 'Session contained outdated information' },\n { name: 'Poor Performance', value: 'poor_performance', desc: 'Session experienced poor performance' },\n { name: 'Privacy Concern', value: 'privacy_concern', desc: 'Session contained privacy concern' },\n { name: 'System Error', value: 'system_error', desc: 'Session encountered system error' },\n { name: 'Timeout Occurred', value: 'timeout_occurred', desc: 'Session timed out' },\n { name: 'Tool Capability Gap', value: 'tool_capability_gap', desc: 'Session had tool capability gap' },\n { name: 'Tool Failure', value: 'tool_failure', desc: 'Session encountered tool failure' },\n { name: 'Tool Performance Issue', value: 'tool_performance_issue', desc: 'Session had tool performance issue' },\n { name: 'Training Example', value: 'training_example', desc: 'Session was training example' },\n { name: 'User Dissatisfied', value: 'user_dissatisfied', desc: 'User was dissatisfied with session.' },\n { name: 'User Question to Chat Author', value: 'user_question_to_chat_author', desc: 'User asked question not to AI but to chat app author' },\n { name: 'User Thumbs Down', value: 'user_thumbs_down', desc: 'User gave thumbs down to session' },\n { name: 'User Thumbs Up', value: 'user_thumbs_up', desc: 'User gave thumbs up to session' }\n];\n\nexport type ChatSessionFeedbackForCreate = Omit<ChatSessionFeedback, 'createdOn' | 'updatedOn' | 'internalComments' | 'exp_date_unix_seconds'>;\nexport type ChatSessionFeedbackForUpdate = Omit<\n ChatSessionFeedback,\n 'userId' | 'messageId' | 'reportedByHuman' | 'createdOn' | 'updatedOn' | 'exp_date_unix_seconds' | 'createdByCustomer'\n>;\n\nexport const UPDATEABLE_FEEDBACK_FIELDS = ['status', 'severity', 'type', 'internalComments', 'userComment', 'attachments'] as const;\nexport type UpdateableFeedbackFields = (typeof UPDATEABLE_FEEDBACK_FIELDS)[number];\n\nexport interface FeedbackInternalComment {\n /** This is a V7 UUID that is date sortable and comparable */\n commentId: string;\n /** The user ID of the user who made the comment. */\n userId: string;\n /** The comment. */\n comment: string;\n /** The attachments to the comment. */\n attachments?: Attachment[];\n /** The date and time the comment was made as a string in ISO 8601 format. */\n createdOn: string;\n\n type: FeedbackInternalCommentType;\n\n status: FeedbackInternalCommentStatus;\n}\n\nexport const FEEDBACK_INTERNAL_COMMENT_STATUS = ['open', 'closed'] as const;\nexport type FeedbackInternalCommentStatus = (typeof FEEDBACK_INTERNAL_COMMENT_STATUS)[number];\nexport const FEEDBACK_INTERNAL_COMMENT_STATUS_VALUES: NameValueDescTriple<FeedbackInternalCommentStatus>[] = [\n { name: 'Open', value: 'open', desc: 'The comment is open and is awaiting action.' },\n { name: 'Closed', value: 'closed', desc: 'The comment is closed and has been resolved.' }\n];\n\nexport const FEEDBACK_INTERNAL_COMMENT_TYPE = [\n 'comment',\n 'customer_outreach_recommended',\n 'customer_outreach_made',\n 'technical_action_required',\n 'technical_action_completed'\n] as const;\nexport type FeedbackInternalCommentType = (typeof FEEDBACK_INTERNAL_COMMENT_TYPE)[number];\nexport const FEEDBACK_INTERNAL_COMMENT_TYPE_VALUES: NameValueDescTriple<FeedbackInternalCommentType>[] = [\n { name: 'Comment', value: 'comment', desc: 'A comment about the feedback.' },\n { name: 'Customer Outreach Recommended', value: 'customer_outreach_recommended', desc: 'A recommendation to reach out to the customer.' },\n { name: 'Customer Outreach Made', value: 'customer_outreach_made', desc: 'A record that an outreach was made to the customer.' },\n { name: 'Technical Action Required', value: 'technical_action_required', desc: 'A technical action is required to resolve the feedback.' },\n { name: 'Technical Action Completed', value: 'technical_action_completed', desc: 'A record that a technical action was completed to resolve the feedback.' }\n];\n\nexport interface SessionInsights {\n model: string;\n /** The version of the insights algorithm that was used to compute the insights. */\n version: string;\n usage: SessionInsightUsage;\n scoring: SessionInsightScoring;\n detailMarkdown: string;\n}\n\nexport interface SessionInsightUsage {\n inputTokens: number;\n cacheCreationInputTokens: number;\n cacheReadInputTokens: number;\n outputTokens: number;\n}\n\nexport interface SessionInsightScoring {\n scores: {\n goalAchievement: {\n score: number;\n description: string;\n };\n userSatisfaction: {\n score: number;\n description: string;\n };\n aiPerformance: {\n accuracy: {\n score: number;\n description: string;\n };\n helpfulness: {\n score: number;\n description: string;\n };\n communication: {\n score: number;\n description: string;\n };\n efficiency: {\n score: number;\n description: string;\n };\n overall: {\n score: number;\n description: string;\n };\n };\n interactionQuality: {\n score: number;\n description: string;\n };\n };\n assessments: {\n userSentiment: SessionInsightUserSentiment;\n goalCompletionStatus: SessionInsightGoalCompletionStatus;\n satisfactionLevel: SessionInsightSatisfactionLevel;\n requiresFollowup: boolean;\n criticalIssuesPresent: boolean;\n escalationNeeded: boolean;\n };\n metrics: {\n sessionDurationEstimate: SessionInsightMetricsSessionDurationEstimate;\n complexityLevel: SessionInsightMetricsComplexityLevel;\n userEffortRequired: SessionInsightMetricsUserEffortRequired;\n aiConfidenceLevel: SessionInsightMetricsAiConfidenceLevel;\n };\n}\n\nexport const SESSION_INSIGHT_USER_SENTIMENT = ['positive', 'neutral', 'negative'] as const;\nexport type SessionInsightUserSentiment = (typeof SESSION_INSIGHT_USER_SENTIMENT)[number];\nexport const SESSION_INSIGHT_USER_SENTIMENT_VALUES: NameValueDescTriple<SessionInsightUserSentiment>[] = [\n { name: 'Positive', value: 'positive', desc: 'The user is satisfied with the session.' },\n { name: 'Neutral', value: 'neutral', desc: 'The user is neutral about the session.' },\n { name: 'Negative', value: 'negative', desc: 'The user is dissatisfied with the session.' }\n];\n\nexport const SESSION_INSIGHT_GOAL_COMPLETION_STATUS = ['completed', 'partially_completed', 'not_completed'] as const;\nexport type SessionInsightGoalCompletionStatus = (typeof SESSION_INSIGHT_GOAL_COMPLETION_STATUS)[number];\nexport const SESSION_INSIGHT_GOAL_COMPLETION_STATUS_VALUES: NameValueDescTriple<SessionInsightGoalCompletionStatus>[] = [\n { name: 'Completed', value: 'completed', desc: 'The agent achieved the goal.' },\n { name: 'Partially Completed', value: 'partially_completed', desc: 'The agent partially achieved the goal.' },\n { name: 'Not Completed', value: 'not_completed', desc: 'The agent did not achieve the goal.' }\n];\n\nexport const SESSION_INSIGHT_SATISFACTION_LEVEL = ['satisfied', 'neutral', 'dissatisfied'] as const;\nexport type SessionInsightSatisfactionLevel = (typeof SESSION_INSIGHT_SATISFACTION_LEVEL)[number];\nexport const SESSION_INSIGHT_SATISFACTION_LEVEL_VALUES: NameValueDescTriple<SessionInsightSatisfactionLevel>[] = [\n { name: 'Satisfied', value: 'satisfied', desc: 'The user is satisfied with the overall session.' },\n { name: 'Neutral', value: 'neutral', desc: 'The user is neutral about the overall session.' },\n { name: 'Dissatisfied', value: 'dissatisfied', desc: 'The user is dissatisfied with the overall session.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_SESSION_DURATION_ESTIMATE = ['short', 'medium', 'long'] as const;\nexport type SessionInsightMetricsSessionDurationEstimate = (typeof SESSION_INSIGHT_METRICS_SESSION_DURATION_ESTIMATE)[number];\nexport const SESSION_INSIGHT_METRICS_SESSION_DURATION_ESTIMATE_VALUES: NameValueDescTriple<SessionInsightMetricsSessionDurationEstimate>[] = [\n { name: 'Short', value: 'short', desc: 'The session was short.' },\n { name: 'Medium', value: 'medium', desc: 'The session was medium.' },\n { name: 'Long', value: 'long', desc: 'The session was long.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_COMPLEXITY_LEVEL = ['low', 'medium', 'high'] as const;\nexport type SessionInsightMetricsComplexityLevel = (typeof SESSION_INSIGHT_METRICS_COMPLEXITY_LEVEL)[number];\nexport const SESSION_INSIGHT_METRICS_COMPLEXITY_LEVEL_VALUES: NameValueDescTriple<SessionInsightMetricsComplexityLevel>[] = [\n { name: 'Low', value: 'low', desc: 'The session was low complexity.' },\n { name: 'Medium', value: 'medium', desc: 'The session was medium complexity.' },\n { name: 'High', value: 'high', desc: 'The session was high complexity.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_USER_EFFORT_REQUIRED = ['low', 'medium', 'high'] as const;\nexport type SessionInsightMetricsUserEffortRequired = (typeof SESSION_INSIGHT_METRICS_USER_EFFORT_REQUIRED)[number];\nexport const SESSION_INSIGHT_METRICS_USER_EFFORT_REQUIRED_VALUES: NameValueDescTriple<SessionInsightMetricsUserEffortRequired>[] = [\n { name: 'Low', value: 'low', desc: 'The user required low effort to get the response they wanted.' },\n { name: 'Medium', value: 'medium', desc: 'The user required medium effort to get the response they wanted.' },\n { name: 'High', value: 'high', desc: 'The user required high effort to get the response they wanted.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_AI_CONFIDENCE_LEVEL = ['low', 'medium', 'high'] as const;\nexport type SessionInsightMetricsAiConfidenceLevel = (typeof SESSION_INSIGHT_METRICS_AI_CONFIDENCE_LEVEL)[number];\nexport const SESSION_INSIGHT_METRICS_AI_CONFIDENCE_LEVEL_VALUES: NameValueDescTriple<SessionInsightMetricsAiConfidenceLevel>[] = [\n { name: 'Low', value: 'low', desc: 'The AI was not confident in the response.' },\n { name: 'Medium', value: 'medium', desc: 'The AI was moderately confident in the response.' },\n { name: 'High', value: 'high', desc: 'The AI was highly confident in the response.' }\n];\n\n/**\n * Additional attributes specific to a chat session. This plus ChatUser.customData spreads into the sessionAttributes on a session using the SessionDataWithChatUserCustomDataSpreadIn type.\n */\nexport interface SessionAttributes {\n /** First name of the user participating in the session */\n firstName?: string;\n /** Last name of the user participating in the session */\n lastName?: string;\n /** Timezone of the session in IANA format */\n timezone?: string;\n //TODO: @clint do we need this still?\n /** A session token that can be used to identify the session. This is used to identify the session in the database. */\n token?: string;\n\n //TODO: @clint do we need sessionID still in this?\n\n /** The user's ID */\n userId: string;\n //TODO: this seems stupid, commented out.\n // /** The ID of the session */\n // sessionId: string;\n /** The ID of the chat app */\n chatAppId: string;\n /** The ID of the agent */\n agentId: string;\n /** The current date in ISO 8601 format */\n currentDate: string;\n}\n\n/** Session attributes with spread type T if T is an object. T is the type of ChatUser.customData. If T is undefined, then SessionAttributes is returned. */\nexport type SessionDataWithChatUserCustomDataSpreadIn<T extends RecordOrUndef = undefined> = T extends object ? SessionAttributes & T : SessionAttributes;\n\n/** This is used when creating a new chat session initially, the token will be generated. */\nexport type SessionAttributesWithoutToken<T extends RecordOrUndef = undefined> = Omit<SessionDataWithChatUserCustomDataSpreadIn<T>, 'token'>;\n\n/** This is used when creating a new chat session initially, the omitted fields are generated. */\nexport type ChatSessionForCreate<T extends RecordOrUndef = undefined> = Omit<ChatSession<T>, 'sessionId' | 'createDate' | 'lastUpdate' | 'sessionAttributes'> & {\n sessionAttributes: SessionAttributesWithoutToken<T>;\n};\n\nexport const MessageSource = ['user', 'assistant'] as const;\nexport type MessageSource = (typeof MessageSource)[number];\n\n/**\n * Represents a message in a chat session, containing metadata about the message\n * and its usage statistics.\n */\nexport interface ChatMessage {\n /** Unique identifier of the user who sent/received the message */\n userId: string;\n /** Unique identifier for the chat session this message belongs to */\n sessionId: string;\n /** Unique identifier for this specific message */\n messageId: string;\n /** The message content */\n message: string;\n /** Indicates whether the message originated from a user or the assistant */\n source: MessageSource;\n /** The AI model used to generate the response (if from bot) */\n model?: string;\n /** ISO 8601 formatted timestamp of when the message was created */\n timestamp: string;\n /** Usage statistics for this message */\n usage?: ChatMessageUsage;\n /** Array of AWS Bedrock traces containing detailed information about the model's execution */\n traces?: Trace[];\n /** Duration of the message in milliseconds */\n executionDuration?: number;\n /** Additional data to be stored in the message. Currently used to store any errors that may have occurred during agent invocation*/\n additionalData?: string;\n\n /** Files associated with the message */\n files?: ChatMessageFile[];\n\n /** Expiration date of the message in Unix seconds */\n exp_date_unix_seconds?: number;\n\n /** Verification Classifications */\n verifications?: {\n main: VerifyResponseClassification;\n correction?: VerifyResponseClassification;\n };\n}\n\nexport interface ChatMessageForRendering extends ChatMessage {\n segments: MessageSegment[];\n isStreaming?: boolean;\n}\n\n/** Supported file storage locations */\nexport const ChatMessageFileLocationType = ['s3'] as const;\nexport type ChatMessageFileLocationType = (typeof ChatMessageFileLocationType)[number];\n\n/** Supported file use cases */\nexport const ChatMessageFileUseCase = [\n /** This means the file will be read by the LLM and it will be used to answer the user's question. */\n 'chat',\n /**\n * We will append the following to the user's message before we give it to the LLM:\n *\n * (if the file is of type ChatMessageFileS3)\n * Available S3 files: s3://<s3-bucket-name>/<s3-key>\n *\n * You can be certain the <s3-bucket-name> will always be this value from SSM `/stack/chatbot/${this.stage}/s3/pika_bucket_name` so you\n * can add permissions to allow your lambda tool to have read access to the uploaded files.\n */\n 'pass-through',\n /**\n * This means that the LLM will write and execute Python code to analyze the contents of the file to answer the user's question.\n */\n 'analytics'\n] as const;\nexport type ChatMessageFileUseCase = (typeof ChatMessageFileUseCase)[number];\n\n/** Base properties for message files */\nexport interface ChatMessageFileBase {\n /**\n * Unique identifier for the file\n *\n * In the case of S3 files, this is `s3://<s3-bucket-name>/<s3-key>`\n */\n fileId: string;\n /** The name of the file for display purposes */\n fileName: string;\n /** The size of the file in bytes */\n size: number;\n /** The last modified date of the file in milliseconds since epoch */\n lastModified: number;\n /** The type of the file */\n type: string;\n /** Type of file */\n locationType: ChatMessageFileLocationType;\n /** The use case for the file. Defaults to `pass-through` if not provided. */\n useCase?: ChatMessageFileUseCase;\n}\n\n/** S3-stored message file */\nexport interface ChatMessageFileS3 extends ChatMessageFileBase {\n locationType: 's3';\n s3Bucket: string;\n s3Key: string;\n}\n\n/** Union type for all message file types */\nexport type ChatMessageFile = ChatMessageFileS3;\n\n/**\n * This is used when creating a new chat message, the messageId and timestamp are generated.\n */\nexport type ChatMessageForCreate = Omit<ChatMessage, 'messageId' | 'timestamp'>;\n\nexport const UserTypes = ['internal-user', 'external-user'] as const;\nexport type UserType = (typeof UserTypes)[number];\n\n// A type to differentiate known Pika roles\ntype PikaRoleType<T, B> = T & { __pika: B };\n\n// Define known Pika roles\nexport const PikaUserRoles = [\n // A content admin may choose any user in the system and view his chat sessions and messages\n 'pika:content-admin',\n\n // A site admin may modify access settings for chat apps and assign roles to users\n 'pika:site-admin'\n] as const;\nexport type PikaUserRole = PikaRoleType<(typeof PikaUserRoles)[number], 'PikaUserRole'>;\n\n// User-defined roles can be any string, but PikaUserRole is special\nexport type UserRole = PikaUserRole | (string & { __pika?: never });\n\nexport type RecordOrUndef = Record<string, string | undefined> | undefined;\n\nexport interface UserCognitoIdentity {\n cognitoIdentityId: string;\n cognitoAccessToken: string;\n}\n\nexport interface UserAwsCredentials {\n accessKeyId: string;\n secretKey: string;\n sessionToken: string;\n expiration: string;\n}\n\nexport interface UserAwsCredentialsResponse {\n success: boolean;\n awsCredentials: UserAwsCredentials;\n}\n\n/**\n * Represents a user in the chat system with their associated features and preferences.\n * This is saved in the chat user database.\n *\n * T is the type of customData you want to store in the user object, such as accountId, accountName, accountType, etc. This\n * data will be available to agent tools but not to the agent itself.\n */\nexport interface ChatUser<T extends RecordOrUndef = undefined> {\n /** Unique identifier for the user */\n userId: string;\n /** First name of the user */\n firstName?: string;\n /** Last name of the user */\n lastName?: string;\n /** Custom user data to associate with the user. For example, accountId, accountName, accountType, etc. */\n customData?: T;\n /**\n * If the user is a content admin, this will be set to the user they are viewing content for.\n * This is used to allow content admins to view chat sessions and messages for all users for debugging purposes.\n *\n * The key is the chatAppId and the value is the user they are viewing content for.\n */\n viewingContentFor?: Record<string, ChatUserLite>;\n /**\n * This will be set by the pika infrastructure when we find a user that is allowed to use the user override data\n * feature and actually has used the webapp user override data dialog to choose what values to override.\n *\n * This allows for the user to override `customData` specific to a chat app.\n *\n * It is never persisted to the database, it is saved server side in a secure cookie.\n *\n * The key is the chatAppId and the value is the override data for that chat app.\n */\n overrideData?: Record<string, T>;\n /** ISO 8601 formatted timestamp of when the user was created */\n createDate?: string;\n /** ISO 8601 formatted timestamp of when the user was last updated */\n lastUpdate?: string;\n /** Some chat apps and features are only accessible to internal users. This is used to determine if the user is internal or external. */\n userType?: UserType;\n /** The only role supported right now is 'pika:content-admin'. Pika Content Admin users are allowed to view chat sessions and messages for all users to help with debugging. */\n roles?: (PikaUserRole | string)[];\n /** Map of feature types to their corresponding feature configurations */\n features: {\n [K in FeatureType]: K extends 'instruction' ? InstructionFeature : K extends 'history' ? HistoryFeature : never;\n };\n\n /** If set to 'mock', this user is used for integration testing purposes. */\n testType?: 'mock';\n}\n\nexport interface ChatUserLite {\n userId: string;\n firstName?: string;\n lastName?: string;\n}\n\n/**\n * This includes auth information that is not stored in the chat user database.\n * It is not provided to clients and is used server side.\n *\n * Auth data is data your app needs such as access tokens, refresh tokens, etc.\n *\n * T is the type you want to store in the authData field, if any. This is not stored in the database.\n * U is the type of customData you want to store in the user object.\n */\nexport interface AuthenticatedUser<T extends RecordOrUndef = undefined, U extends RecordOrUndef = undefined> extends ChatUser<U> {\n authData?: T;\n /** ISO 8601 timestamp of when ChatUser data was last refreshed from DynamoDB (the pikaframework sets this) */\n lastChatUserRefresh?: string;\n}\n\n/**\n * This is a simplified version of AuthenticatedUser that is used for auth headers.\n * Note that type T may be the type \"undefined\" indicating that there is no custom user data.\n * The custom user data comes from the ChatUser.customData field provided by the auth provider.\n *\n * Not that JSON.stringify(SimpleAuthenticatedUser) must not be more than 2k in size or you risk\n * getting an erorr when we try to put it in a JWT token and send it as an http header.\n */\nexport interface SimpleAuthenticatedUser<T extends RecordOrUndef = undefined> {\n userId: string;\n customUserData?: T;\n}\n\n/**\n * These are features that are turned on at the site level in the <root>/pika-config.ts file and that may then\n * be overridden by individual chat apps.\n *\n * This is a short hand to store the computation that went into determining if a given user is allowed\n * to use the various features of pika. It is not persisted to the database or in cookies. We use it\n */\nexport interface ChatAppOverridableFeatures {\n /**\n * If enabled, entity-based access control and filtering is active for this chat app.\n * Chat apps can only disable the entity feature, not modify the site-level configuration\n * like attributeName or display settings.\n */\n entity: {\n /**\n * If false, entity features are disabled for this chat app regardless of site settings. This\n * affects the session share feature. If this is false, then a shared session will be\n * accessible to anyone with access to the chat app that the session exists within.\n */\n enabled: boolean;\n\n /**\n * The attribute name in the user's custom data that is used to match against the entity access control lists.\n *\n * This value is copied from the site level entity feature configuration and may not be overridden at the chat app level.\n *\n * It enabled is true and this is not set, then an error will be thrown.\n */\n attributeName?: string;\n };\n\n /**\n *\n * If true then the verify response feature is enabled.\n *\n * With this feature enabled, Pika will attempt to identify the veracity of the response from the LLM to a\n * user message. @see <root>/docs/developer/verify-response-feature.md\n *\n * The logic for turning this on or off is a merging of the site level setting and the chat app level setting.\n */\n verifyResponse: {\n /** If false, we don't verify responses at all. */\n enabled: boolean;\n /** If not defined, we don't auto-reprompt the user's question. */\n autoRepromptThreshold?: VerifyResponseClassification;\n };\n\n /**\n * If enabled, then the traces feature is enabled. If enabled, then the front end will show the traces from\n * the LLM in the chat app except for the detailed traces for the given user. The detailed traces are only\n * shown to the user if the detailedTraces feature is also enabled for the given user.\n *\n * The logic for turning this on or off is a merging of the site level setting and the chat app level setting.\n *\n * @see <root>/docs/developer/traces-feature.md\n */\n traces: {\n enabled: boolean;\n detailedTraces: boolean;\n };\n\n /**\n * The disclaimer notice to show to the user. This is used to inform the user that the chat is not\n * a substitute for human customer support and that the company is not liable for problems caused by\n * relying solely on the chat.\n */\n chatDisclaimerNotice: string | undefined;\n\n /**\n * If true, then the logout feature is enabled. If enabled, then the user will see a logout menu item\n * in the chat app. If the user clicks the logout menu item, then the user will be logged out and\n * redirected.\n */\n logout: {\n enabled: boolean;\n menuItemTitle: string;\n dialogTitle: string;\n dialogDescription: string;\n };\n\n /**\n * If websiteEnabled is true, users with pika:site-admin role will be able to access the site admin features.\n */\n siteAdmin: {\n websiteEnabled: boolean;\n };\n\n /** If no mime types, then the feature is diabled. */\n fileUpload: {\n mimeTypesAllowed: string[];\n };\n\n /** If no suggestions, then the feature is diabled. */\n suggestions: {\n suggestions: string[];\n randomize: boolean;\n randomizeAfter: number;\n maxToShow: number;\n };\n\n /** If no label, then the feature is diabled. */\n promptInputFieldLabel: {\n label: string | undefined;\n };\n\n uiCustomization: {\n showUserRegionInLeftNav: boolean;\n showChatHistoryInStandaloneMode: boolean;\n };\n\n tags?: TagsChatAppOverridableFeature;\n\n agentInstructionAssistance: AgentInstructionChatAppOverridableFeature;\n\n instructionAugmentation: InstructionAugmentationFeature;\n\n userMemory: UserMemoryFeature;\n}\n\nexport interface AgentInstructionChatAppOverridableFeature {\n enabled: boolean;\n includeOutputFormattingRequirements: boolean;\n includeInstructionsForTags: boolean;\n completeExampleInstructionEnabled: boolean;\n completeExampleInstructionLine?: string;\n jsonOnlyImperativeInstructionEnabled: boolean;\n jsonOnlyImperativeInstructionLine?: string;\n includeTypescriptBackedOutputFormattingRequirements: boolean;\n typescriptBackedOutputFormattingRequirements?: string;\n}\n\nexport interface InstructionAssistanceConfig {\n outputFormattingRequirements: string;\n tagInstructions?: string;\n completeExampleInstructionLine: string;\n jsonOnlyImperativeInstructionLine: string;\n typescriptBackedOutputFormattingRequirements: string;\n}\n\nexport interface TagsChatAppOverridableFeature {\n tagsEnabled: TagDefinitionLite[];\n tagsDisabled: TagDefinitionLite[];\n}\n\nexport type ChatAppOverridableFeaturesForConverseFn = Omit<\n ChatAppOverridableFeatures,\n 'chatDisclaimerNotice' | 'traces' | 'logout' | 'suggestions' | 'promptInputFieldLabel' | 'uiCustomization' | 'fileUpload'\n>;\n\n/**\n * By default, content rules exclude anything not explicitly included.\n */\nexport interface UserChatAppRule {\n /**\n * The user types allowed to access the content this rule is applied to.\n *\n * If you support both internal and external users and internal/external chat apps then you should\n * create two ChatAppContentRule objects, one for internal users and one for external users.\n */\n userTypes?: UserType[];\n\n /**\n * The user types allowed to access the chat apps this rule is applied to.\n *\n * If you support both internal and external users and internal/external chat apps then you should\n * create two ChatAppContentRule objects, one for internal users and one for external users.\n */\n chatAppUserTypes?: UserType[];\n}\n\n/** Array of available feature types in the system */\nexport const FeatureTypeArr = ['instruction', 'history'] as const;\n/** Type representing the available feature types */\nexport type FeatureType = (typeof FeatureTypeArr)[number];\n\n/** Union type of all possible feature configurations */\nexport type ChatUserFeature = InstructionFeature | HistoryFeature;\n\n/**\n * Base interface for all feature configurations\n */\nexport interface ChatUserFeatureBase {\n /** Type identifier for the feature */\n type: FeatureType;\n}\n\n/**\n * Configuration for instruction-based features\n */\nexport interface InstructionFeature extends ChatUserFeatureBase {\n type: 'instruction';\n /** The optional additional instructions for the agent */\n instruction: string;\n}\n\n/**\n * Configuration for history-based features\n */\nexport interface HistoryFeature extends ChatUserFeatureBase {\n type: 'history';\n /** Whether history feature is enabled */\n history: boolean;\n}\n\n/**\n * Contains usage statistics for a chat message, including token counts and associated costs.\n */\nexport interface ChatMessageUsage {\n /** Cost of processing the input tokens in USD */\n inputCost: number;\n /** Number of tokens in the input message */\n inputTokens: number;\n /** Cost of generating the output tokens in USD */\n outputCost: number;\n /** Number of tokens in the output message */\n outputTokens: number;\n /** Total cost of processing this message (input + output) in USD */\n totalCost: number;\n}\n\nexport interface BaseRequestData {\n userId: string;\n sessionId?: string;\n chatAppId?: string;\n agentId?: string;\n timezone?: string;\n}\n\nexport interface ConverseRequestWithCommand {\n command: 'clearConverseLambdaCache';\n cacheType: ClearConverseLambdaCacheType;\n agentId?: string;\n userId: string;\n}\n\nexport const ClearConverseLambdaCacheTypes = ['agent', 'tagDefinitions', 'instructionAssistanceConfig', 'all'] as const;\nexport type ClearConverseLambdaCacheType = (typeof ClearConverseLambdaCacheTypes)[number];\n\nexport interface ConverseRequest extends BaseRequestData {\n message: string;\n\n /**\n * The features that are enabled for the user making the request for the chat app this request is tied to.\n */\n features: ChatAppOverridableFeaturesForConverseFn;\n\n files?: ChatMessageFile[];\n\n /**\n * This it the agentID from the agent definition dynamodb table.\n * It allows us to dynamically change the agent used for the conversation.\n */\n agentId: string;\n\n /**\n * This is the attribute name in the user's custom data that is used to match against the entity access control lists.\n * This is only used if the entity feature is enabled and the user has an entity associated with them.\n *\n * @see pika-config.ts#siteFeatures.entity.attributeName\n */\n entityAttributeNameInUserCustomData?: string;\n\n /**\n * If provided, this will be used to determine the invocation mode of the converse request.\n *\n * If 'chat-app', then the converse request is a chat app request.\n *\n * If 'direct-agent-invoke', then the converse request is a direct agent invoke request and is not\n * in the context of a chat app. Since we are adding mode after the fact, if mode is provided\n * and it doesn't match what we expect, we will throw an error (chat-app requires that chatAppId is provided\n * and direct-agent-invoke requires that chatAppId is not provided).\n *\n * If 'chat-app-component', then the converse request is coming from a chat app component and is not\n * being initiated by the end user. This is used to allow the component to invoke the agent directly\n * without the need for the end user to initiate the request. These do not show up as user-created sessions\n * when we query for the users's sessions in this chat app.\n *\n * They are associated with the user and the chat app and the component in question. When this mode is used,\n * the caller must provide the chatAppId and the agentId and the complete \"tag\" that represents the component doing the calling.\n * Tag definitions have both a scope and a tag. Further, the `componentAgentInstructionName` must also provide so we\n * know which set of instructions from the tag definition to use.\n *\n * If invocationMode is not provided, uses the presence or absence of chatAppId to determine the mode (if chatAppId\n * is provided, then it's a chat app request, otherwise it's a direct agent invoke request).\n */\n invocationMode?: ConverseInvocationMode;\n\n /**\n * When invocationMode is 'chat-app-component', then this is the requiredconfiguration for the chat app component invocation.\n */\n chatAppComponentConfig?: ChatAppComponentConfig;\n\n /**\n * The source of the converse request. Defaults to 'user'. The composite key chat_app_sk looks like this:\n *\n * ${chatAppId}#${source}#${updateDate}\n *\n * The source in the composite key here will only ever be either `user` or `component`. If this attribute's value is missing or is `user` or `component-as-user`,\n * then the composite key will be set to `user` so when we query on behalf of the user, we will get all sessions for that user.\n *\n * If 'user', then the converse request is coming from the user.\n * If 'component-as-user', then the converse request is coming from a component acting as a user and thus sessions should show up in the user's sessions list.\n * If 'component', then the converse request is coming from a component.\n */\n source: ConverseSource;\n\n /**\n * The context items to include in the LLM prompt. Before we call the LLM to answer the\n * user's question, we will first use another LLM request to determine which context items are relevant to the user's question.\n * The relevant context items are then appended to the prompt sent to the LLM.\n */\n llmContextItems?: LLMContextItem[];\n}\n\nexport const ConverseSource = ['user', 'component-as-user', 'component'] as const;\nexport type ConverseSource = (typeof ConverseSource)[number];\n/**\n * This is the configuration for a chat app component invocation to the converse lambda function.\n */\nexport interface ChatAppComponentConfig {\n /**\n * The name of the set of instructions to use for the component invocation.\n * This is the key in the `componentAgentInstructionsMd` record in the tag definition as in\n *\n * `tagDef.componentAgentInstructionsMd[componentAgentInstructionName]`\n */\n componentAgentInstructionName: string;\n\n /**\n * The tag definition that represents the component doing the calling. We use this to look up the\n * right tag definition so we can get the correct instructions. Note that you will get an exception\n * if the tag definition isn't associated with this chat app or isn't marked as `chat-app-global`.\n */\n componentTagDefinition: TagDefinitionLite;\n}\n\nexport const ConverseInvocationModes = ['chat-app', 'direct-agent-invoke', 'chat-app-component'] as const;\nexport type ConverseInvocationMode = (typeof ConverseInvocationModes)[number];\n\nexport interface ChatTitleUpdateRequest extends BaseRequestData {\n /** If provided, this will be used as the title for the session */\n title?: string;\n /** The question that was asked in case we need to use bedrock to generate a title */\n userQuestionAsked?: string;\n /** The response that was generated in case we need to use bedrock to generate a title */\n answerToQuestionFromAgent?: string;\n}\n\nexport interface AddChatSessionFeedbackRequest {\n /** Note you need to generate a feedbackId before calling this function as a V7 UUID. */\n feedback: ChatSessionFeedbackForCreate;\n}\n\nexport interface AddChatSessionFeedbackAdminRequest {\n command: 'addChatSessionFeedback';\n /** Note you need to generate a feedbackId before calling this function as a V7 UUID. */\n feedback: ChatSessionFeedbackForCreate;\n}\n\nexport interface UpdateChatSessionFeedbackAdminRequest {\n command: 'updateChatSessionFeedback';\n feedback: ChatSessionFeedbackForUpdate;\n}\n\nexport interface SessionSearchAdminRequest {\n command: 'sessionSearch';\n search: SessionSearchRequest<RecordOrUndef>;\n}\n\nexport interface GetSessionAnalyticsAdminRequest {\n command: 'getSessionAnalytics';\n analyticsRequest: SessionAnalyticsRequest;\n}\n\nexport interface GetAgentRequest {\n command: 'getAgent';\n agentId: string;\n}\n\nexport interface GetAgentResponse {\n success: boolean;\n agent: AgentDefinition | undefined;\n error?: string;\n}\n\nexport interface GetChatSessionFeedbackResponse {\n success: boolean;\n feedback: ChatSessionFeedback[];\n error?: string;\n}\n\nexport interface AddChatSessionFeedbackResponse {\n success: boolean;\n feedback: ChatSessionFeedback;\n error?: string;\n}\n\nexport interface UpdateChatSessionFeedbackRequest {\n feedback: ChatSessionFeedbackForUpdate;\n}\n\nexport interface UpdateChatSessionFeedbackResponse {\n success: boolean;\n feedback: ChatSessionFeedback;\n error?: string;\n}\n\nexport interface ChatUserResponse<T extends RecordOrUndef = undefined> {\n success: boolean;\n user: ChatUser<T> | undefined;\n error?: string;\n}\n\nexport interface ChatUserSearchResponse {\n success: boolean;\n users: ChatUserLite[];\n error?: string;\n}\n\nexport type UserPrefs = Record<string, unknown>;\n\nexport interface GetChatUserPrefsResponse {\n success: boolean;\n userId: string;\n prefs?: UserPrefs;\n error?: string;\n}\n\nexport interface SetChatUserPrefsRequest {\n prefs: UserPrefs;\n\n /**\n * If true, we will first get the existing prefs for the user and then merge them with the new prefs.\n * If false, we will just set the new prefs and overwrite any existing prefs.\n * If you want to delete a pref when doing a partial update, then you should include the pref and set\n * its value expressly to null. When not doing a partial updated, just omit the pref and it will be deleted.\n * To delete all prefs, send in an empty object when not doing a partial update.\n */\n partial?: boolean;\n}\n\nexport interface SetChatUserPrefsResponse {\n success: boolean;\n userId: string;\n\n /** If successful, returns the new complete prefs object. */\n prefs?: UserPrefs;\n error?: string;\n}\n\n/**\n * Arbitrary key-value storage for web component state.\n * Scoped to user + component (scope.tag).\n * Max 400KB per component.\n */\nexport type UserWidgetData = Record<string, unknown>;\n\nexport interface GetUserWidgetDataRequest {\n scope: string;\n tag: string;\n}\n\nexport interface GetUserWidgetDataResponse {\n success: boolean;\n userId: string;\n scope: string;\n tag: string;\n data?: UserWidgetData;\n error?: string;\n}\n\nexport interface SetUserWidgetDataRequest {\n scope: string;\n tag: string;\n data: UserWidgetData;\n partial?: boolean; // If true, merge with existing data\n}\n\nexport interface SetUserWidgetDataResponse {\n success: boolean;\n userId: string;\n scope: string;\n tag: string;\n data: UserWidgetData;\n error?: string;\n}\n\nexport interface DeleteUserWidgetDataRequest {\n scope: string;\n tag: string;\n}\n\nexport interface DeleteUserWidgetDataResponse {\n success: boolean;\n userId: string;\n scope: string;\n tag: string;\n error?: string;\n}\n\nexport interface ChatUserAddOrUpdateResponse {\n success: boolean;\n user: ChatUser<RecordOrUndef>;\n error?: string;\n}\n\nexport interface ChatMessageResponse {\n success: boolean;\n message: ChatMessage;\n error?: string;\n}\n\nexport interface ChatMessagesResponse {\n success: boolean;\n messages: ChatMessage[];\n error?: string;\n}\n\nexport interface ChatSessionResponse {\n success: boolean;\n session: ChatSession<RecordOrUndef>;\n error?: string;\n}\n\nexport interface ChatSessionsResponse {\n success: boolean;\n sessions: ChatSession<RecordOrUndef>[];\n error?: string;\n}\n\n/**\n * If you are already did a search and got back a scrollId, then on the next request all you need to do is provide the scrollId\n * and nothing else. This will get you the next page of results.\n *\n * Otherwise...\n *\n * If you don't provide any search criteria, it just returns all sessions forever orderd by createDate descending unless\n * specified otherwise.\n *\n * If you provide customUserData, then we will filter results to just the sessions whose sessionAttributes includes\n * the attributes you specified in customUserData. So if you provide customUserData.accountId = 'John', then we will filter\n * to just the sessions whose sessionAttributes.accountId = 'John'.\n *\n * We will and together all the search params you provide. So if you provide userId and chatAppId, then we will filter\n * to just the sessions whose userId and chatAppId match the values you provided.\n *\n * The results will be paginated. You may provide a page token to get the next page of results.\n *\n * TODO: the implementation should make sure that the backend query includes a matching sort: [{ startDate: 'desc' }, { sessionId: 'desc' }].\n */\nexport interface SessionSearchRequest<T extends RecordOrUndef = undefined> {\n /** Matches sessions whose userId matches the given value. */\n userId?: string;\n /** Matches sessions whose chatAppId matches the given value. */\n chatAppId?: string;\n /** Matches sessions whose sessionId matches the given value. */\n sessionId?: string;\n /**\n * This must either be an object or undefined. If an object, then its type must be Record<string, string>.\n * We will then filter the sessions to only those whose sessionAttributes includes the attributes you specified in customUserData.\n * So if you provide customUserData.accountId = 'John', then we will filter to just the sessions whose sessionAttributes.accountId = 'John'.\n */\n customUserData?: T;\n\n /**\n * Allows searching for sessions by title (partial match), sessionId (exact match), or userId (exact match).\n * The search will try to match any of these fields.\n */\n query?: string;\n\n /**\n * Filter by date range.\n */\n dateFilter?: SessionSearchDateFilter;\n\n /** Filter by user type (internal-user or external-user). */\n userType?: UserType[];\n\n /** If true, then we will only return sessions that are flagged for human review and if false the converse. */\n flagged?: boolean;\n\n /** If provided, then we will only return sessions that have insights that match the given insights criteria. */\n insights?: InsightsSearchParams;\n\n /**\n * Used for deep pagination via search_after.\n * Provide the scrollId from the previous page response.\n * This contains the encoded query state including sort values.\n */\n scrollId?: string;\n\n /** If provided, we will only return sessions with feedback in one ofthe given status. */\n feedbackInStatus?: SessionFeedbackStatus[];\n\n /** If true, only return sessions with feedback reported by a human and if false, by a computer and undefined both */\n feedbackReportedByHuman?: boolean;\n\n /** If true, only return sessions with feedback created by the customer and if false, by the system and undefined both */\n feedbackCreatedByCustomer?: boolean;\n\n /** If provided, we will only return sessions with feedback with one of the given severities. */\n feedbackSeverity?: SessionFeedbackSeverity[];\n\n /** If provided, we will only return sessions with feedback with one of the given types. */\n feedbackType?: SessionFeedbackType[];\n\n /** If provided, we will only return sessions with feedback from the given user. */\n feedbackUserId?: string;\n\n /** If provided, we will only return sessions with feedback with one of the given internal comment types. */\n feedbackInternalCommentType?: FeedbackInternalCommentType[];\n\n /** If provided, we will only return sessions with feedback with one of the given internal comment statuses. */\n feedbackInternalCommentStatus?: FeedbackInternalCommentStatus[];\n\n /** If provided, we will only return sessions with feedback with one of the given internal comment user ids. */\n feedbackInternalCommentUserId?: string;\n\n /** If true, then we will include the insights in the response. */\n includeInsights?: boolean;\n\n /** If true, then we will include the feedback in the response. */\n includeFeedback?: boolean;\n\n /**\n * The fields to sort by. Determines the shape of pagination tokens.\n *\n * Defaults to [{ createDate: 'desc' }, { sessionId: 'desc' }].\n * Note that we tack on the sessionId to the end of the sort values\n * to make sure that we can get the next page of results correctly.\n * You don't need to provide the sessionId in the sortBy array, it will be added automatically\n * if it's not already there.\n */\n sortBy?: Array<{\n field: SessionSearchSortField;\n order: 'asc' | 'desc';\n }>;\n\n /**\n * Page size (defaulted by backend if not provided).\n */\n size?: number;\n}\n\nexport const SESSION_SEARCH_SORT_FIELDS = ['createDate', 'lastUpdate', 'sessionId', 'inputTokens', 'outputTokens', 'totalCost', 'insightGoalAchievementScore'] as const;\nexport type SessionSearchSortField = (typeof SESSION_SEARCH_SORT_FIELDS)[number];\nexport const SESSION_SEARCH_SORT_FIELDS_VALUES: NameValuePair<SessionSearchSortField>[] = [\n { name: 'Create Date', value: 'createDate' },\n { name: 'Last Update', value: 'lastUpdate' },\n { name: 'Session ID', value: 'sessionId' },\n { name: 'Input Tokens', value: 'inputTokens' },\n { name: 'Output Tokens', value: 'outputTokens' },\n { name: 'Total Cost', value: 'totalCost' },\n { name: 'Insight Goal Achievement Score', value: 'insightGoalAchievementScore' }\n];\n\nexport const SESSION_SEARCH_DATE_TYPES = ['created', 'updated', 'feedback'] as const;\nexport type SessionSearchDateType = (typeof SESSION_SEARCH_DATE_TYPES)[number];\nexport const SESSION_SEARCH_DATE_TYPES_VALUES: NameValuePair<SessionSearchDateType>[] = [\n { name: 'Create Date', value: 'created' },\n { name: 'Last Update', value: 'updated' },\n { name: 'Feedback Created', value: 'feedback' }\n];\n\nexport interface SessionSearchDateFilter {\n dateType: SessionSearchDateType;\n startDate: string;\n endDate?: string;\n}\n\nexport const SESSION_SEARCH_DATE_PRESETS = [\n '1-minute',\n '5-minutes',\n 'last-hour',\n 'last-day',\n 'last-week',\n 'last-month',\n 'last-3months',\n 'last-6-months',\n 'last-year',\n 'last-2-years'\n] as const;\nexport type SessionSearchDatePreset = (typeof SESSION_SEARCH_DATE_PRESETS)[number];\nexport const SESSION_SEARCH_DATE_PRESETS_VALUES: NameValuePair<SessionSearchDatePreset>[] = [\n { name: '1 Minute', value: '1-minute' },\n { name: '5 Minutes', value: '5-minutes' },\n { name: 'Last Hour', value: 'last-hour' },\n { name: 'Last Day', value: 'last-day' },\n { name: 'Last Week', value: 'last-week' },\n { name: 'Last Month', value: 'last-month' },\n { name: 'Last 3 Months', value: 'last-3months' },\n { name: 'Last 6 Months', value: 'last-6-months' },\n { name: 'Last Year', value: 'last-year' },\n { name: 'Last 2 Years', value: 'last-2-years' }\n];\nexport const SESSION_SEARCH_DATE_PRESETS_SHORT_VALUES: NameValuePair<SessionSearchDatePreset>[] = [\n { name: '1 Min', value: '1-minute' },\n { name: '5 Min', value: '5-minutes' },\n { name: 'Hour', value: 'last-hour' },\n { name: 'Day', value: 'last-day' },\n { name: 'Week', value: 'last-week' },\n { name: 'Month', value: 'last-month' },\n { name: '3 Mo', value: 'last-3months' },\n { name: '6 Mo', value: 'last-6-months' },\n { name: 'Year', value: 'last-year' },\n { name: '2 Yrs', value: 'last-2-years' }\n];\n\n/**\n * All of these are anded together. You must at least provide hasInsights.\n */\nexport interface InsightsSearchParams {\n /** If true, then we will only return sessions that have insights and false returns sessions that don't have insights. */\n hasInsights: boolean;\n goalAchievementScore?: ScoreSearchParams;\n userSatisfactionScore?: ScoreSearchParams;\n aiPerformanceOverallScore?: ScoreSearchParams;\n aiPerformanceAccuracyScore?: ScoreSearchParams;\n aiPerformanceEfficiencyScore?: ScoreSearchParams;\n interactionQualityScore?: ScoreSearchParams;\n\n userSentiment?: SessionInsightUserSentiment[]; // Matches documents that have any of these values.\n goalCompletionStatus?: SessionInsightGoalCompletionStatus[]; // Matches documents that have any of these values.\n satisfactionLevel?: SessionInsightSatisfactionLevel[]; // Matches documents that have any of these values.\n sessionDurationEstimate?: SessionInsightMetricsSessionDurationEstimate[]; // Matches documents that have any of these values.\n complexityLevel?: SessionInsightMetricsComplexityLevel[]; // Matches documents that have any of these values.\n userEffortRequired?: SessionInsightMetricsUserEffortRequired[]; // Matches documents that have any of these values.\n aiConfidenceLevel?: SessionInsightMetricsAiConfidenceLevel[]; // Matches documents that have any of these values.\n}\n\nexport interface ScoreSearchParams {\n score: number;\n operator: ScoreSearchOperator;\n}\n\nexport const SCORE_SEARCH_OPERATORS = ['eq', 'gte', 'lte'] as const;\nexport type ScoreSearchOperator = (typeof SCORE_SEARCH_OPERATORS)[number];\nexport const SCORE_SEARCH_OPERATORS_VALUES: NameValuePair<ScoreSearchOperator>[] = [\n { name: '=', value: 'eq' },\n { name: '>=', value: 'gte' },\n { name: '<=', value: 'lte' }\n];\n\nexport interface SessionSearchResponse<T extends RecordOrUndef = undefined> {\n success: boolean;\n sessions: ChatSession<T>[];\n error?: string;\n /**\n * If returned, then there are more pages of results. On the next request, provide this scrollId and nothing else\n * and we will get you the next page of results.\n */\n scrollId?: string;\n\n /** For now, we will always return the total number of hits. */\n total: number;\n\n /** The page size that was used for this request. */\n pageSize: number;\n}\n\n// Agent Definition System Types\n\n/**\n * Access control rule for agents and tools\n */\nexport interface AccessRule {\n /** Condition expression for access control (e.g., \"user.scope IN ['admin', 'user'] AND account.type = 'retailer'\") */\n condition?: string;\n /** Effect of the rule - allow or deny access */\n effect: 'allow' | 'deny';\n /** Order/priority for rule evaluation (lower numbers evaluated first) */\n order?: number;\n /** Optional description of the rule */\n description?: string;\n}\n\n/**\n * Rollout policy configuration for agent definitions\n */\nexport interface RolloutPolicy {\n /** List of beta account IDs that can access this agent */\n betaAccounts?: string[];\n /** List of AWS regions where this agent is available */\n regionRestrictions?: string[];\n /** Tool overrides mapping old tool IDs to new tool IDs */\n toolOverrides?: Record<string, string>;\n}\n\n/**\n * Agent definition representing an LLM agent configuration\n */\nexport interface AgentDefinition {\n /** Unique agent identifier (e.g., 'weather-bot') */\n agentId: string;\n /** Foundation model to use for this agent. */\n foundationModel?: string;\n /** Foundation model to use for verifying the response of this agent. */\n verificationFoundationModel?: string;\n /** System prompt template (can be a handlebars template with placeholders like {{user.email}}) */\n basePrompt: string;\n /** List of access control rules with conditions. If not provided, the agent will be accessible to all users. */\n accessRules?: AccessRule[];\n /** Optional Lambda ARN for augmenting prompt/session context (future feature) */\n runtimeAdapter?: string;\n /** Rollout gating configuration per account/org/region. If not provided, the agent will be accessible to all users. */\n rolloutPolicy?: RolloutPolicy;\n /** Cache configuration for testing and debugging, used in lambdas that create LRU caches for agent definitions */\n dontCacheThis?: boolean;\n\n /** List of collaborator agent IDs that are used to orchestrate this agent. */\n collaborators?: {\n agentId: string;\n instruction: string;\n historyRelay: 'TO_COLLABORATOR' | 'TO_AGENT';\n }[];\n\n /** The collaboration type for this agent. */\n agentCollaboration?: AgentCollaboration;\n\n /** List of tool definitions that this agent uses */\n toolIds: string[];\n /** A list of knowledge bases that are associated with this agent. */\n knowledgeBases?: KnowledgeBase[];\n /** Agent definition version */\n version: number;\n /** User who created the definition */\n createdBy: string;\n /** Last editor user */\n lastModifiedBy: string;\n /** ISO 8601 formatted timestamp of creation */\n createdAt: string;\n /** ISO 8601 formatted timestamp of last update */\n updatedAt: string;\n\n /** If set to 'mock', this is a test agent that will get deleted after 1 day. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport type UpdateableAgentDefinitionFields = Extract<\n keyof AgentDefinition,\n 'basePrompt' | 'toolIds' | 'accessRules' | 'runtimeAdapter' | 'rolloutPolicy' | 'dontCacheThis' | 'knowledgeBases'\n>;\n\nexport type AgentDefinitionForUpdate = Partial<Omit<AgentDefinition, 'version' | 'createdAt' | 'createdBy' | 'updatedAt' | 'lastModifiedBy' | 'test'>> & {\n agentId: string;\n};\n\nexport type AgentDefinitionForCreate = Omit<AgentDefinition, 'version' | 'createdAt' | 'updatedAt'> & {\n agentId?: AgentDefinition['agentId'];\n};\n\n/**\n * This allows you to do an idempotent create or update of an agent and its tools. You can create or modify\n * and its tools. If you specify tools then we will intelligently create or update the tools. If you don't\n * specify tools then we will just create the agent.\n *\n * If you use this you must provide an agentId so we can match up what's there already with what is being provided.\n * If you provide tools then you must provide a toolId for each tool so we can match up what's there already with what is being provided.\n *\n * Three patterns are supported:\n * 1. tools only: Define new tools (create/update)\n * 2. agent.toolIds only: Reference existing tools by ID\n * 3. Both tools AND agent.toolIds: Mixed approach - define new tools while referencing existing ones\n */\nexport interface AgentDataRequest {\n /**\n * Agent must have an ID provided or we will throw an exception since we can't match up what's there already\n * with what is being provided in the custom resource in an idempotent way.\n */\n agent: AgentDefinitionForIdempotentCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n\n /**\n * Tools must have an ID provided or we will throw an exception since we can't match up what's there already\n * with what is being provided in the custom resource in an idempotent way.\n */\n tools?: ToolDefinitionForIdempotentCreateOrUpdate[];\n}\n\n/**\n * In the AgentDataReqest.tools we find that we need to pass in the arn of the lambda function that is the tool.\n * However, at build time you may not have the arn of the lambda function. So, in the Agent custom resource\n * we allow you to pass in a map of toolId to lambdaArn. Then, the custom resource lambda will use this map\n * to replace the lambdaArn with the actual arn of the lambda function.\n *\n * THe key is the toolID and the value is the lambdaArn.\n */\nexport type ToolIdToLambdaArnMap = Record<string, string>;\n\nexport interface AgentAndTools {\n agent: AgentDefinition;\n collaborators?: AgentDefinition[];\n tools?: ToolDefinition[];\n}\n\nexport interface AgentDataResponse {\n success: boolean;\n error?: string;\n agent: AgentDefinition;\n tools?: ToolDefinition[];\n}\n\nexport interface ChatAppDataResponse {\n success: boolean;\n error?: string;\n chatApp: ChatApp;\n}\n\nexport type AgentDefinitionForIdempotentCreateOrUpdate = Omit<AgentDefinition, 'toolIds' | 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n toolIds?: string[];\n};\n/**\n * Execution type for tool definitions. Right now, only lambda is supported.\n */\nexport type ExecutionType = 'lambda' | 'http' | 'inline' | 'mcp';\n\n/**\n * Lifecycle status for tool definitions\n */\nexport type LifecycleStatus = 'enabled' | 'disabled' | 'retired';\n\n/**\n * Lifecycle management configuration for tools\n */\nexport interface ToolLifecycle {\n /** Current status of the tool */\n status: LifecycleStatus;\n /** Optional deprecation date in ISO 8601 format */\n deprecationDate?: string;\n /** Optional migration path to newer tool version */\n migrationPath?: string;\n}\n\n/**\n * Tool definition representing a callable function/service\n */\nexport interface ToolDefinitionBase {\n /** Type of execution (lambda, http, inline) */\n executionType: ExecutionType;\n\n /** Unique tool name/version (e.g., 'weather-basic@1') */\n toolId: string;\n /** Friendly display name */\n displayName: string;\n /** Must not have spaces and no punctuation except _ and - : ([0-9a-zA-Z][_-]?){1,100} */\n name: string;\n /** Description for LLM consumption. MUST BE LESS THAN 500 CHARACTERS */\n description: string;\n /** Timeout in seconds (default: 30) */\n executionTimeout?: number;\n /**\n * List of agent frameworks that this tool supports\n *\n * If you choose to support bedrock, you must provide a functionSchema.\n */\n supportedAgentFrameworks: AgentFramework[];\n /** Bedrock-specific function schema (auto-generated or provided) */\n functionSchema?: FunctionDefinition[];\n /** Tag map for filtering and categorization */\n tags?: Record<string, string>;\n /** Lifecycle management configuration */\n lifecycle?: ToolLifecycle;\n /** Tool version */\n version: number;\n /** List of access control rules */\n accessRules?: AccessRule[];\n /** User who created the tool */\n createdBy: string;\n /** User who last modified the tool */\n lastModifiedBy: string;\n /** ISO 8601 formatted timestamp of creation */\n createdAt: string;\n /** ISO 8601 formatted timestamp of last update */\n updatedAt: string;\n\n /** If set to 'mock', this is a test tool that will get deleted after 1 day. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport interface LambdaToolDefinition extends ToolDefinitionBase {\n executionType: 'lambda';\n /**\n * If executionType is 'lambda', this is the required ARN of the Lambda function.\n * Note that the Lambda function must have an 'agent-tool' tag set to 'true'.\n */\n lambdaArn: string;\n}\n\nexport interface McpToolDefinition extends ToolDefinitionBase {\n executionType: 'mcp';\n url: string;\n auth?: OAuth;\n}\n\nexport interface InlineToolDefinition extends ToolDefinitionBase {\n executionType: 'inline';\n code: string; // This is the code to execute. It is a stringified function.\n handler?: (event: ActionGroupInvocationInput, params: Record<string, any>) => Promise<unknown>;\n}\n\nexport type ToolDefinition = LambdaToolDefinition | McpToolDefinition | InlineToolDefinition;\n\nexport type UpdateableToolDefinitionFields =\n | Extract<\n keyof ToolDefinitionBase,\n 'name' | 'displayName' | 'description' | 'executionType' | 'executionTimeout' | 'supportedAgentFrameworks' | 'functionSchema' | 'tags' | 'lifecycle' | 'accessRules'\n >\n | 'lambdaArn'\n | 'url'\n | 'auth'\n | 'code';\n\nexport type ToolDefinitionForCreate =\n | (Omit<LambdaToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n toolId?: ToolDefinition['toolId'];\n })\n | (Omit<McpToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n toolId?: ToolDefinition['toolId'];\n });\n\nexport type ToolDefinitionForIdempotentCreateOrUpdate =\n | (Omit<LambdaToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n functionSchema: FunctionDefinition[];\n supportedAgentFrameworks: ['bedrock'];\n })\n | (Omit<InlineToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n functionSchema: FunctionDefinition[];\n supportedAgentFrameworks: ['bedrock'];\n })\n | (Omit<McpToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n functionSchema: FunctionDefinition[];\n supportedAgentFrameworks: ['bedrock'];\n });\n\nexport interface OAuth {\n clientId: string;\n clientSecret: string;\n tokenUrl: string;\n token?: {\n accessToken: string;\n expires: number;\n };\n}\n\nexport type ToolDefinitionForUpdate =\n | (Partial<Omit<LambdaToolDefinition, 'version' | 'createdAt' | 'createdBy' | 'updatedAt' | 'lastModifiedBy'>> & {\n toolId: string;\n })\n | (Partial<Omit<McpToolDefinition, 'version' | 'createdAt' | 'createdBy' | 'updatedAt' | 'lastModifiedBy'>> & {\n toolId: string;\n });\n\nexport type AgentFramework = 'bedrock';\n\nexport interface CreateAgentRequest {\n agent: AgentDefinitionForCreate;\n existingToolsToAssociate?: string[];\n newToolsToCreate?: ToolDefinitionForCreate[];\n userId: string;\n}\n\nexport interface UpdateAgentRequest {\n agent: AgentDefinitionForUpdate;\n userId: string;\n}\n\nexport interface CreateToolRequest {\n tool: ToolDefinitionForCreate;\n userId: string;\n}\nexport interface GetChatAppsByRulesRequest {\n /** We use this to lookup the user and their userType. */\n userId: string;\n\n /** If this request is to figure out which chat apps to show on the home page, then this will be present. */\n homePageFilterRules?: UserChatAppRule[];\n\n /** If provided, then we will only return this one chat app and then only if the user is allowed to access it. */\n chatAppId?: string;\n\n /**\n * If true, then we will return the list of apps that the user is allowed to see on the home page.\n * Note that this could be different than the list of apps that the user is allowed to access\n * if they don't want to show a given app on the home page.\n */\n chatAppsForHomePage?: boolean;\n\n /**\n * We sometimes need to know if a user's associated \"entity\" (account or company) is allowed to access a chat app.\n * This is the path to the custom data field that is used to match against the entity. Of course,\n * your must have enabled the entity feature in pika-config.ts and set the attributeName to the path to the custom data field\n * attribute name that contains the entity value.\n *\n * For example, if a user is associated with an account and has `customData.accountId` then this might be 'accountId'.\n */\n customDataFieldPathToMatchUsersEntity?: string;\n}\n\nexport interface GetChatAppsByRulesResponse {\n success: boolean;\n chatApps: ChatApp[];\n error?: string;\n}\n\nexport interface UpdateToolRequest {\n tool: ToolDefinitionForUpdate;\n userId: string;\n}\n\nexport interface SearchToolsRequest {\n toolIds: string[];\n userId: string;\n}\n\nexport interface CreateChatAppRequest {\n chatApp: ChatAppForCreate;\n userId: string;\n}\n\nexport interface UpdateChatAppRequest {\n chatApp: ChatAppForUpdate;\n userId: string;\n}\n\nexport interface CreateOrUpdateChatAppOverrideRequest {\n override: ChatAppOverrideForCreateOrUpdate;\n userId: string;\n}\n\nexport interface CreateOrUpdateChatAppOverrideResponse {\n success: boolean;\n chatAppOverride: ChatAppOverride;\n}\n\nexport interface DeleteChatAppOverrideResponse {\n success: boolean;\n}\n\nexport interface DeleteChatAppOverrideRequest {}\n\n// ===== MOCK DATA APIS FOR TESTING =====\n\nexport interface DeleteMockDataRequest {\n userId: string;\n sessions?: {\n sessionId: string;\n sessionUserId: string;\n }[];\n chatApps?: {\n chatAppId: string;\n }[];\n agents?: {\n agentId: string;\n }[];\n tools?: {\n toolId: string;\n }[];\n users?: {\n userId: string;\n }[];\n}\n\nexport interface DeleteMockDataResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockSessionRequest {\n session: ChatSessionForCreate & { test: 'test' };\n userId: string; // admin user creating the mock\n}\n\nexport interface CreateOrUpdateMockSessionResponse {\n success: boolean;\n session: ChatSession<RecordOrUndef>;\n}\n\nexport interface DeleteMockSessionRequest {\n sessionId: string;\n sessionUserId: string; // owner of session\n userId: string; // admin user deleting the mock\n}\n\nexport interface DeleteMockSessionResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockChatAppRequest {\n chatApp: ChatApp & { test: 'test' };\n userId: string;\n}\n\nexport interface CreateOrUpdateMockChatAppResponse {\n success: boolean;\n chatApp: ChatApp;\n}\n\nexport interface DeleteMockChatAppRequest {\n chatAppId: string;\n userId: string;\n}\n\nexport interface DeleteMockChatAppResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockAgentRequest {\n agent: AgentDefinition & { test: 'test' };\n userId: string;\n}\n\nexport interface CreateOrUpdateMockAgentResponse {\n success: boolean;\n agent: AgentDefinition;\n}\n\nexport interface DeleteMockAgentRequest {\n agentId: string;\n userId: string;\n}\n\nexport interface DeleteMockAgentResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockToolRequest {\n tool: ToolDefinition & { test: 'test' };\n userId: string;\n}\n\nexport interface CreateOrUpdateMockToolResponse {\n success: boolean;\n tool: ToolDefinition;\n}\n\nexport interface DeleteMockToolRequest {\n toolId: string;\n userId: string;\n}\n\nexport interface DeleteMockToolResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockUserRequest {\n user: ChatUser<RecordOrUndef> & { test: 'test' };\n userId: string; // admin user creating the mock\n}\n\nexport interface CreateOrUpdateMockUserResponse {\n success: boolean;\n user: ChatUser<RecordOrUndef>;\n}\n\nexport interface DeleteMockUserRequest {\n mockUserId: string; // userId of the mock user to delete\n userId: string; // admin user deleting the mock\n}\n\nexport interface DeleteMockUserResponse {\n success: boolean;\n}\n\n// ===== GET ALL MOCK DATA APIS =====\n\nexport interface GetAllMockSessionsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockSessionsResponse {\n success: boolean;\n chatSessions: ChatSession<RecordOrUndef>[];\n nextToken?: string;\n}\n\nexport interface GetMockSessionByUserIdAndSessionIdRequest {\n sessionId: string;\n userId: string;\n}\n\nexport interface GetMockSessionByUserIdAndSessionIdResponse {\n success: boolean;\n chatSession?: ChatSession<RecordOrUndef>;\n}\n\nexport interface GetAllMockUsersRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockUsersResponse {\n success: boolean;\n chatUsers: ChatUser<RecordOrUndef>[];\n nextToken?: string;\n}\n\nexport interface GetAllMockAgentsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockAgentsResponse {\n success: boolean;\n agents: AgentDefinition[];\n nextToken?: string;\n}\n\nexport interface GetAllMockToolsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockToolsResponse {\n success: boolean;\n tools: ToolDefinition[];\n nextToken?: string;\n}\n\nexport interface GetAllMockChatAppsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockChatAppsResponse {\n success: boolean;\n chatApps: ChatApp[];\n nextToken?: string;\n}\n\nexport interface GetAllMockSharedSessionVisitsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockSharedSessionVisitsResponse {\n success: boolean;\n sharedSessionVisits: SharedSessionVisitHistory[];\n nextToken?: string;\n}\n\nexport interface GetAllMockPinnedSessionsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockPinnedSessionsResponse {\n success: boolean;\n pinnedSessions: PinnedSession[];\n nextToken?: string;\n}\n\nexport interface GetAllMockDataRequest {\n limit?: number;\n}\n\nexport interface GetAllMockDataResponse {\n success: boolean;\n data: {\n sessions: ChatSession<RecordOrUndef>[];\n users: ChatUser<RecordOrUndef>[];\n agents: AgentDefinition[];\n tools: ToolDefinition[];\n chatApps: ChatApp[];\n sharedSessionVisits: SharedSessionVisitHistory[];\n pinnedSessions: PinnedSession[];\n };\n}\n\n// ===== DELETE ALL MOCK DATA APIS =====\n\nexport interface DeleteAllMockSessionsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockSessionsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockUsersRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockUsersResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockAgentsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockAgentsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockToolsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockToolsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockChatAppsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockChatAppsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockSharedSessionVisitsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockSharedSessionVisitsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockPinnedSessionsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockPinnedSessionsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockDataRequest {\n userId: string;\n confirm?: boolean;\n}\n\nexport interface DeleteAllMockDataResponse {\n success: boolean;\n deletedCounts: {\n sessions: number;\n users: number;\n agents: number;\n tools: number;\n chatApps: number;\n sharedSessionVisits: number;\n pinnedSessions: number;\n total: number;\n };\n}\n\nexport type ChatAppMode = 'standalone' | 'embedded';\n\n/**\n * This extends AccessRules so you can enable/disable the chat app for certain users.\n */\nexport interface ChatApp extends AccessRules {\n /**\n * Unique ID for the chat. Only - and _ allowed. Will\n * be used in URL to access the chatbot so keep that in mind\n */\n chatAppId: string;\n\n /**\n * The modes that this chat app supports. If not provided, then all modes are supported.\n * `standalone` means that the chat app can be displayed standalone in a website\n * not embedded in another website as an iframe. `embedded` means that the chat app\n * is embedded in another website as an iframe.\n */\n modesSupported?: ChatAppMode[];\n\n /**\n * Set to true when actively developing so changes are reflected immediately.\n * Various lambdas will cache this data for some minutes (usually 5).\n */\n dontCacheThis?: boolean;\n\n /**\n * The title of the chat app, a human readable name. This is the title that will be displayed in the title bar of the chat app when\n * in standalone mode.\n */\n title: string;\n\n /**\n * A description of the chat app. This is used to describe the chat app to the user and in navigation.\n * Required. Must be less than 300 characters (not currently enforced but will be in the future).\n */\n description: string;\n\n /**\n * The ID of the agent that should be invoked for this chat app (e.g. 'weather-agent').\n * Must be the agentId of an agent that exists in the agent definition table.\n */\n agentId: string;\n\n /**\n * Optional way to override the original access control settings provided when the\n * chat app was deployed. This is not stored on the actual chat app record in the\n * chat-app table. If not provided, falls back to the access control settings set\n * by the chat app when it was deployed.\n *\n * This ChatAppOverride data is stored in a separate record in the chat-app table\n * where the chatAppId is `${chatAppId}:override`. It is stored\n * separately so the list of included entities can grow quite large if needed.\n *\n * When you retrieve a ChatApp using the APIs, this will be populated for you if\n * an override record exists.\n *\n * This is useful so we can modify access control settings without having to redeploy the\n * chat app itself.\n */\n override?: ChatAppOverride;\n\n /** Any feature not explicitly defined and turned on is turned off by default. */\n features?: Partial<Record<FeatureIdType, ChatAppFeature>>;\n\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate: string;\n\n /** ISO 8601 formatted timestamp of the last chat app update */\n lastUpdate: string;\n\n /** If set to 'mock', this is a test chat app that will get deleted after 1 day. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport interface ChatAppLite {\n /**\n * Unique ID for the chat. Only - and _ allowed. Will\n * be used in URL to access the chatbot so keep that in mind\n */\n chatAppId: string;\n\n /**\n * The title of the chat app, a human readable name. This is the title that will be displayed in the title bar of the chat app when\n * in standalone mode.\n */\n title: string;\n\n /**\n * A description of the chat app. This is used to describe the chat app to the user and in navigation.\n * Required. Must be less than 300 characters (not currently enforced but will be in the future).\n */\n description: string;\n\n /**\n * The ID of the agent that should be invoked for this chat app (e.g. 'weather-agent').\n * Must be the agentId of an agent that exists in the agent definition table.\n */\n agentId: string;\n\n /**\n * The user types that are allowed to access this chat app. If not provided, then all user types are allowed.\n */\n userTypes?: UserType[];\n}\n\nexport interface KnowledgeBase {\n /** A unique identifier for the knowledge base */\n id: string;\n\n /** The agent frameworks that this knowledge base supports */\n supportedAgentFrameworks: AgentFramework[];\n\n /** A description of the knowledge base */\n description: string;\n\n /**\n * This is the filter values that will be used to filter the knowledge base to restrict the set of\n * documents that are searched as part of the retrieve operation.\n *\n * When you have a file to ingest into the knowledge base in s3, you can include an accompanying metadata file\n * that defines metadata attributes and values applicable to the file.\n *\n * Note that each `value` in this filter may contain templated values like this:\n *\n * my-{name}-and-{company}\n *\n * If present, we will try to match the template attribute name to either a user top level attribute\n * name (one of userId, firstName, lastName) or an attribute within the user.customData object. Note that the template value\n * may include dot notation to access a nested attribute. For example, if the user has a customData object\n * with the following structure:\n *\n * {\n * customData: {\n * account: {\n * id: '123'\n * }\n * }\n *\n * Then the template value 'my-{account.id}' would match the value 'my-123'.\n */\n filter?: RetrievalFilter;\n\n /**\n * The number of results to return from the knowledge base. If not provided, the default is a smaller number,\n * probably 5.\n */\n numberOfResults?: number;\n}\n\nexport type UpdateableChatAppFields = Extract<\n keyof ChatApp,\n 'dontCacheThis' | 'title' | 'description' | 'agentId' | 'features' | 'enabled' | 'userTypes' | 'userRoles' | 'modesSupported'\n>;\n\nexport type ChatAppForCreate = Omit<ChatApp, 'createDate' | 'lastUpdate'>;\n\nexport type ChatAppForUpdate = Partial<Omit<ChatApp, 'createDate' | 'lastUpdate'>>;\n\nexport type ChatAppForIdempotentCreateOrUpdate = Omit<ChatApp, 'createDate' | 'lastUpdate'>;\n\n/**\n * This allows you to do an idempotent create or update of a chat app.\n *\n * If you use this you must provide a chatAppId so we can match up what's there already with what is being provided.\n */\nexport interface ChatAppDataRequest {\n /**\n * ChatApp must have an ID provided or we will throw an exception since we can't match up what's there already\n * with what is being provided in the custom resource in an idempotent way.\n */\n chatApp: ChatAppForIdempotentCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\n/**\n * These are the features that are available to be overridden by the chat app.\n */\nexport type ChatAppFeature =\n | FileUploadFeatureForChatApp\n | SuggestionsFeatureForChatApp\n | PromptInputFieldLabelFeatureForChatApp\n | UiCustomizationFeatureForChatApp\n | VerifyResponseFeatureForChatApp\n | TracesFeatureForChatApp\n | ChatDisclaimerNoticeFeatureForChatApp\n | LogoutFeatureForChatApp\n | SessionInsightsFeatureForChatApp\n | UserDataOverrideFeatureForChatApp\n | TagsFeatureForChatApp\n | AgentInstructionAssistanceFeatureForChatApp\n | InstructionAugmentationFeatureForChatApp\n | UserMemoryFeatureForChatApp\n | EntityFeatureForChatApp;\n\nexport interface Feature {\n /**\n * Must be unique, only alphanumeric and - _ allowed, may not start with a number\n *\n * This is used to identify the feature in the database.\n */\n featureId: FeatureIdType;\n\n /** Whether the feature is on or off for the chat app in question. Most features are off by default, see the specific feature for details. */\n enabled: boolean;\n}\n\nexport const FeatureIdList = [\n 'fileUpload',\n 'promptInputFieldLabel',\n 'suggestions',\n 'uiCustomization',\n 'verifyResponse',\n 'traces',\n 'chatDisclaimerNotice',\n 'logout',\n 'sessionInsights',\n 'userDataOverrides',\n 'tags',\n 'agentInstructionAssistance',\n 'instructionAugmentation',\n 'userMemory',\n 'entity'\n] as const;\nexport type FeatureIdType = (typeof FeatureIdList)[number];\n\nexport const EndToEndFeatureIdList = ['verifyResponse', 'traces'] as const;\nexport type EndToEndFeatureIdType = (typeof EndToEndFeatureIdList)[number];\n\nexport const FEATURE_NAMES: Record<FeatureIdType, string> = {\n fileUpload: 'File Upload',\n promptInputFieldLabel: 'Prompt Input Field Label',\n suggestions: 'Suggestions',\n uiCustomization: 'UI Customization',\n verifyResponse: 'Verify Response',\n traces: 'Traces',\n chatDisclaimerNotice: 'Chat Disclaimer Notice',\n logout: 'Logout',\n sessionInsights: 'Session Insights',\n userDataOverrides: 'User Data Override',\n tags: 'Tags',\n agentInstructionAssistance: 'Agent Instruction Assistance',\n instructionAugmentation: 'Instruction Augmentation',\n userMemory: 'User Memory',\n entity: 'Entity'\n};\n\nexport interface SiteAdminFeature {\n websiteEnabled: boolean;\n\n /** Ignored if websiteEnabled is false. */\n supportUserEntityAccessControl?: {\n /**\n * If you turn this on then we expect that you will provide\n */\n enabled: boolean;\n };\n\n /**\n * If turned on, any user with the pika:site-admin role will be able to view session insights\n * for any chat session in the admin website. This is useful for debugging and troubleshooting.\n * This feature will not be enabled unless you have also first enabled the session insights feature\n * at the site level in pika-config.ts. Note that the entity feature must be turned on\n * if you want to display and filter by entity in the session insights UI.\n */\n sessionInsights?: {\n enabled: boolean;\n };\n\n /**\n * Ignored if websiteEnabled is false.\n *\n * If turned on then you may restrict access to a chat app for only specified users.\n */\n supportSpecificUserAccessControl?: {\n enabled: boolean;\n };\n}\n\n/**\n * Why make this a feature? Some enterprises that allow their internal users to act on behalf of other\n * users and accounts for the purpose of debugging and troubleshooting. So, if the user is logged in as\n * one account, they can click a menu item to logout and then log in as another account. The base case\n * for external users is to likely not have this feature as they are piggy backing on auth from\n * another enterprise site or system.\n */\nexport interface LogoutFeature extends AccessRules {\n /**\n * The title of the menu item that will be displayed to authorized users that when clicked will\n * log them out of the chat app. Defaults to \"Logout\".\n */\n menuItemTitle?: string;\n\n /**\n * The title of the dialog that will be displayed when the user clicks the menu item. Defaults to \"Logout\".\n */\n dialogTitle?: string;\n\n /**\n * The description that appears benath the title in the dialog window. Defaults to\n * \"Are you sure you want to logout?\"\n */\n dialogDescription?: string;\n}\n\nexport interface LogoutFeatureForChatApp extends LogoutFeature, Feature {\n featureId: 'logout';\n}\n\n/**\n * If a notice is provided, Pika will display a disclaimer notice to the user.\n *\n * This feature must be enabled at the site level and then individual chat apps can choose to override\n * the notice text.\n */\nexport interface ChatDisclaimerNoticeFeature {\n enabled: boolean;\n\n /** The notice text to display to the user. If not provided, no notice is displayed. */\n notice?: string;\n}\n\nexport interface ChatDisclaimerNoticeFeatureForChatApp extends ChatDisclaimerNoticeFeature, Feature {\n featureId: 'chatDisclaimerNotice';\n}\n\n/**\n * When turned on, Pika will attempt to identify the veracity of the response from the LLM to a user message.\n *\n * This feature must be enabled at the site level and then individual chat apps can choose to turn it off\n * if they do not want it on. So, to function you must go to pika-config.ts and enable the feature.\n *\n * Further, individual chat apps can choose to override which users are allowed to use the feature.\n *\n * Note that enabling this will have no effect if the feature is not enabled at the site level first (@see pika-config.ts)\n * You can only choose to disable the feature at the chat app level if it is enabled at the site level.\n *\n * @see <root>/docs/developer/verify-response-feature.md\n */\nexport interface VerifyResponseFeature extends AccessRules {\n /**\n * The threshold for which response classifications will trigger an auto-reprompt to the LLM to correct the answer.\n *\n * If not defined, we will not automatically reprompt the user's question to the LLM to correct the answer.\n *\n * The classificationsa are currenly A, B, C and F with F being terrible and A being really really good.\n *\n * So, if you set this to F then the Pika will only automatically send the user's question back to the LLM to correct the answer\n * if the response verification is F. If you set it to B then it would do so on B, C and F.\n *\n * Note you cannot set this to A since it is not retryable.\n *\n * Recommended default: 'C'\n */\n autoRepromptThreshold?: RetryableVerifyResponseClassification;\n}\n\nexport interface VerifyResponseFeatureForChatApp extends VerifyResponseFeature, Feature {\n featureId: 'verifyResponse';\n}\n\n/**\n * When turned on, Pika will show the traces from the LLM in the chat app. There are three primary types of traces:\n * - Orchestration traces: these show the fundamental reasoning process of the LLM\n * - Failure traces: these show the reason the LLM failed to answer the user's question\n * - Parameter traces: these show the actual parameters passed from the LLM to the tools it invoked\n *\n * By default, when you turn on the traces feature, detailed traces (meaning the parameter traces) are not shown\n * because they show a lot of detail about how the LLM is working. You must explicitly turn on the detailed traces\n * feature to show them.\n *\n * Individual chat apps can choose to override which users are allowed to use the feature. This is done\n * by setting the detailedTraces property to an AccessRules object. @see <root>/docs/developer/traces-feature.md\n *\n * Note that enabling this will have no effect if the feature is not enabled at the site level first (@see pika-config.ts)\n * You can only choose to disable the feature at the chat app level if it is enabled at the site level.\n */\nexport interface TracesFeature extends AccessRules {\n /**\n * If not provided, then the detailed traces are not shown. If provided, then the detailed traces are shown\n * to the user if the user is allowed to use the detailed traces feature.\n */\n detailedTraces?: AccessRules;\n}\n\nexport interface TracesFeatureForChatApp extends TracesFeature, Feature {\n featureId: 'traces';\n}\n\n/**\n * Whether to support UI customization in the chat app. If true, then the chat app will support UI customization.\n */\nexport interface UiCustomizationFeature {\n enabled: boolean;\n\n /** Whether to show the chat history as left nav in full page mode. Defaults to true. */\n showChatHistoryInStandaloneMode?: boolean;\n\n /** Whether to show the user region in the left nav in full page mode. Defaults to true. */\n showUserRegionInLeftNav?: boolean;\n}\n\nexport interface UiCustomizationFeatureForChatApp extends UiCustomizationFeature, Feature {\n featureId: 'uiCustomization';\n}\n\n/**\n * Whether to support suggestions in the chat app. If true, then the chat app will support suggestions.\n * If false, then the chat app will not support suggestions.\n *\n * Default is false.\n */\nexport interface SuggestionsFeature {\n enabled: boolean;\n\n /**\n * A list of suggestions that will be displayed to the user relevant to the chat app.\n * Will be stored gzipped hex encoded in db. Gzipped compressed value may not be more than 100kb.\n */\n suggestions: string[];\n\n /**\n * The maximum number of suggestions to show. Defaults to 5.\n */\n maxToShow?: number;\n\n /**\n * Whether to randomize the suggestions. Defaults to false.\n */\n randomize?: boolean;\n\n /**\n * If randomize is true, then this is the number of messages after which to randomize the suggestions.\n * This allws a certain number of suggestions to always show followed by random suggestions. Defaults to 0.\n */\n randomizeAfter?: number;\n}\n\nexport interface SuggestionsFeatureForChatApp extends SuggestionsFeature, Feature {\n featureId: 'suggestions';\n}\n\n/**\n * Whether the chat app supports uploading files and attaching them to the chat.\n */\nexport interface FileUploadFeature {\n enabled: boolean;\n\n /** If you put `*` can upload any file. Example: ['text/csv']. This must have a value or it is an error. */\n mimeTypesAllowed: string[];\n}\n\nexport interface FileUploadFeatureForChatApp extends FileUploadFeature, Feature {\n featureId: 'fileUpload';\n}\n\n/**\n * Whether to show a label above the prompt input field and what value to show. When you first come to the chat app,\n * all you see is a large prompt input field, allowing the user to start a new conversation. This feature allows you\n * to show a label above the prompt input field as you see in other chat apps.\n *\n * This feature is on by default.\n */\nexport interface PromptInputFieldLabelFeature {\n enabled: boolean;\n\n /** Defaults to \"Ready to chat\". The label to show above the prompt input field. */\n promptInputFieldLabel?: string;\n}\n\nexport interface PromptInputFieldLabelFeatureForChatApp extends PromptInputFieldLabelFeature, Feature {\n featureId: 'promptInputFieldLabel';\n}\n\nexport interface AgentInstructionAssistanceFeatureForChatApp extends Feature, AgentInstructionAssistanceFeature {\n featureId: 'agentInstructionAssistance';\n}\n\nexport interface InstructionAugmentationFeatureForChatApp extends InstructionAugmentationFeature, Feature {\n featureId: 'instructionAugmentation';\n}\n\nexport interface UserMemoryFeatureForChatApp extends UserMemoryFeature, Feature {\n featureId: 'userMemory';\n}\n\nexport interface EntityFeatureForChatApp extends Feature {\n featureId: 'entity';\n /** Whether entity feature is enabled for this chat app. Can only be set to false to disable site-level configuration. */\n enabled: boolean;\n attributeName?: string;\n}\n\n/**\n * The prompt instruction assistance feature is used to add a markdown section to the prompt that instructs the agent on how to format its response.\n *\n * The `includeInstructionsForTags` feature is used to inject the instructions for tags into the prompt at `{{tag-instructions}}` if found in the prompt.\n * If not found, then the instructions will be appended to the end of the prompt. Note there is a separate feature named `tags` that is used\n * to define which tags are available for the agent. @see TagsFeatureForChatApp\n *\n * Thus the `tags` feature is how you decide which tags your chat app will allow. Each tag is marked as to whether it can be generated by the LLM or a tool.\n * So, when you turn on the AgentInstructionsAssistance feature in a chat app, pika knows which tags are available that we need to inject into the prompt.\n *\n * Note that when an agent is invoked in the context of a chat app, meaning through the pika chat app UI, the agent will be passed a\n * PromptInstructionAssistance object based on the features of the chat app in question. The site wide features can define the config for this feature\n * and the chat app can override it. So the pika front end will figure out which config is in play and pass the right value to the agent when it is\n * invoked.\n *\n * If the agent is invoked directly by your own custom client, you can pass in your own PromptInstructionAssistanceFeature object to specify the agent instructions\n * config.\n *\n * A common use case for this is to disable the includeInstructionsForTags.\n */\nexport interface AgentInstructionAssistanceFeature {\n /**\n * If enabled, a markdown section titled Output Formatting Requirements will be added into your prompt. You can control where the prompt assistance language is added in\n * by using a replacement placeholder titled `{{prompt-assistance}}` in your prompt. If found, the prompt assistance language will be added at the location of the placeholder.\n * The injected prompt assistance language will first add the output formatting requirements, then the instructions for tags,\n * then the complete example instruction line, and finally the json only imperative instruction line.\n *\n * If `{{prompt-assistance}}` is not found, then we look for more fine-grained control by looking for these specific placeholder tags:\n * `{{output-formatting-requirements}}`, `{{tag-instructions}}`, `{{complete-example-instruction-line}}` and `{{json-only-imperative-instruction-line}}`. Of course,\n * if you haven't turned on the `includeInstructionsForTags` feature, then we will not inject the tag instructions.\n *\n * If neither `{{prompt-assistance}}` nor any of the specific placeholder tags are found, then the prompt assistance language will be appended to the end of the prompt\n * in this order: output formatting requirements, tag instructions, complete example instruction line, and json only imperative instruction line. If `{{prompt-assistance}}`\n * is not found and you did not specify all of the specific placeholder tags but you did turn on a feature that means we should inject instructions then we\n * will add the corresponding instructions to the end of the prompt.\n *\n * Here is what will be added to the prompt at a minimum:\n *\n * ```markdown\n * // If includeOutputFormattingRequirements.enabled is true\n * {{output-formatting-requirements}}\n *\n * // If includeInstructionsForTags.enabled is true\n * {{tag-instructions}}\n *\n * // If completeExampleInstructionLine.enabled is true\n * {{complete-example-instruction-line}}\n *\n * // If jsonOnlyImperativeInstructionLine.enabled is true\n * {{json-only-imperative-instruction-line}}\n *\n * ```\n */\n enabled: boolean;\n\n /**\n * If enabled, basic output formatting requirements will be injected into the prompt at\n * `{{output-formatting-requirements}}` if found in the prompt. If not found, then the requirements will be appended to the end of the prompt.\n * This provides foundational formatting guidance for the agent's responses.\n */\n includeOutputFormattingRequirements?: {\n enabled: boolean;\n };\n\n /**\n * If enabled, then the instructions for tags that are available for the agent will be injected into the prompt at\n * `{{tag-instructions}}` if found in the prompt. If not found, then the instructions will be appended to the end of the prompt.\n */\n includeInstructionsForTags?: {\n enabled: boolean;\n };\n\n /**\n * If true, a line will be added to the prompt assistance language that instructs the agent to include a complete example of the tag structure.\n * If mdLine is provided, it will be used as the line. If mdLine is not provided, a default line will be used:\n *\n * ```markdown\n * `<answer>##Example markdown\\nNormal text and an <image>http://some.url</image> and some **bold text**\\n<chart>(...)</chart></answer>`\n * ```\n *\n * This will intelligenlty not include the <image> and <chart> tags in the exmaple if they are not supported in your instructions.\n */\n completeExampleInstructionLine?: {\n enabled: boolean;\n mdLine?: string;\n };\n\n /**\n * If true, a line will be added to the prompt assistance language that instructs the agent to only respond with valid JSON.\n * If mdLine is provided, it will be used as the line. If mdLine is not provided, a default line will be used:\n *\n * ```markdown\n * BE ABSOLUTELY CERTAIN ANY JSON INCLUDED IS 100% VALID (especially for charts). Invalid JSON will break the user experience.\n * ```\n */\n jsonOnlyImperativeInstructionLine?: {\n enabled: boolean;\n line?: string;\n };\n\n /**\n * This is only used for component invocation instructions. If true, a line will be added to the component invocation\n * instructions that instructs the agent to only respond with valid JSON conforming to the TypeScript interface defined in the <output_schema> block.\n */\n includeTypescriptBackedOutputFormattingRequirements?: {\n enabled: boolean;\n line?: string;\n };\n}\n\nexport type SegmentType = 'text' | 'tag';\n\n/**\n * Represents the status of content being streamed into a segment.\n */\nexport type StreamingStatus =\n /**\n * Initial tag start detected (e.g., \"<ta\") but not enough characters to determine the full tag name.\n * Indicates partial progress in tag parsing and requires more content to identify the tag.\n */\n | 'incomplete'\n /**\n * Actively receiving streaming content into the associated segment.\n * More data is expected and the segment is not yet complete.\n */\n | 'streaming'\n /**\n * Streaming of content into this segment is finished and no more data will be added.\n */\n | 'completed'\n /**\n * An error occurred while streaming content into this segment. Content may be incomplete or corrupted.\n */\n | 'error';\n\nexport interface MessageSegmentBase {\n /** The position of the segment in the message */\n id: number;\n segmentType: SegmentType;\n rawContent: string;\n streamingStatus: StreamingStatus;\n rendererType?: string;\n}\n\nexport interface TagMessageSegment extends MessageSegmentBase {\n segmentType: 'tag';\n tag: string;\n attributes?: Record<string, string>;\n}\n\nexport interface TextMessageSegment extends MessageSegmentBase {\n segmentType: 'text';\n}\n\nexport type MessageSegment = TagMessageSegment | TextMessageSegment;\n\nexport type SiteAdminRequest =\n | GetAgentRequest\n | GetInitialDataRequest\n | RefreshChatAppRequest\n | CreateOrUpdateChatAppOverrideRequest\n | DeleteChatAppOverrideRequest\n | GetValuesForEntityAutoCompleteRequest\n | GetValuesForEntityListRequest\n | GetValuesForUserAutoCompleteRequest\n | ClearConverseLambdaCacheRequest\n | ClearSvelteKitCachesRequest\n | AddChatSessionFeedbackAdminRequest\n | UpdateChatSessionFeedbackAdminRequest\n | SessionSearchAdminRequest\n | GetSessionAnalyticsAdminRequest\n | GetChatMessagesAsAdminRequest\n | CreateOrUpdateTagDefinitionAdminRequest\n | DeleteTagDefinitionAdminRequest\n | SearchTagDefinitionsAdminRequest\n | SearchSemanticDirectivesAdminRequest\n | SemanticDirectiveCreateOrUpdateAdminRequest\n | SemanticDirectiveDeleteAdminRequest\n | GetInstructionAssistanceConfigFromSsmRequest\n | GetAllChatAppsAdminRequest\n | GetAllAgentsAdminRequest\n | GetAllToolsAdminRequest\n | GetAllMemoryRecordsAdminRequest\n | GetInstructionsAddedForUserMemoryAdminRequest;\n\nexport const SiteAdminCommand = [\n 'getAgent',\n 'getInitialData',\n 'refreshChatApp',\n 'createOrUpdateChatAppOverride',\n 'deleteChatAppOverride',\n 'getValuesForEntityAutoComplete',\n 'getValuesForEntityList',\n 'getValuesForUserAutoComplete',\n 'clearConverseLambdaCache',\n 'clearSvelteKitCaches',\n 'addChatSessionFeedback',\n 'updateChatSessionFeedback',\n 'sessionSearch',\n 'getSessionAnalytics',\n 'getChatMessagesAsAdmin',\n 'createOrUpdateTagDefinition',\n 'deleteTagDefinition',\n 'searchTagDefinitions',\n 'searchSemanticDirectives',\n 'createOrUpdateSemanticDirective',\n 'deleteSemanticDirective',\n 'getInstructionAssistanceConfigFromSsm',\n 'getAllChatApps',\n 'getAllAgents',\n 'getAllTools',\n 'getAllMemoryRecords',\n 'getInstructionsAddedForUserMemory'\n] as const;\nexport type SiteAdminCommand = (typeof SiteAdminCommand)[number];\n\nexport interface SiteAdminCommandRequestBase {\n command: SiteAdminCommand;\n}\n\nexport interface GetChatMessagesAsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getChatMessagesAsAdmin';\n sessionId: string;\n chatAppId: string;\n userId: string;\n}\n\nexport interface CreateOrUpdateTagDefinitionAdminRequest extends SiteAdminCommandRequestBase {\n command: 'createOrUpdateTagDefinition';\n request: TagDefinitionCreateOrUpdateRequest;\n}\n\nexport interface DeleteTagDefinitionAdminRequest extends SiteAdminCommandRequestBase {\n command: 'deleteTagDefinition';\n request: TagDefinitionDeleteRequest;\n}\n\nexport interface SearchTagDefinitionsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'searchTagDefinitions';\n request: TagDefinitionSearchRequest;\n}\n\nexport interface SearchSemanticDirectivesAdminRequest extends SiteAdminCommandRequestBase {\n command: 'searchSemanticDirectives';\n request: SearchSemanticDirectivesRequest;\n}\n\nexport interface SemanticDirectiveCreateOrUpdateAdminRequest extends SiteAdminCommandRequestBase {\n command: 'createOrUpdateSemanticDirective';\n request: SemanticDirectiveCreateOrUpdateRequest;\n}\n\nexport interface SemanticDirectiveDeleteAdminRequest extends SiteAdminCommandRequestBase {\n command: 'deleteSemanticDirective';\n request: SemanticDirectiveDeleteRequest;\n}\n\nexport interface GetAllChatAppsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllChatApps';\n}\n\nexport interface GetAllAgentsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllAgents';\n}\n\nexport interface GetAllToolsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllTools';\n}\n\nexport interface GetAllMemoryRecordsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllMemoryRecords';\n request: SearchAllMemoryRecordsRequest;\n}\n\nexport interface GetInstructionsAddedForUserMemoryAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getInstructionsAddedForUserMemory';\n request: GetInstructionsAddedForUserMemoryRequest;\n}\n\n/**\n * Request format for semantic directive data passed to custom CloudFormation resource\n */\nexport type SemanticDirectiveDataRequest = {\n userId: string;\n groupId: string;\n semanticDirectives: SemanticDirectiveForCreateOrUpdate[];\n};\n\nexport interface GetValuesForEntityAutoCompleteRequest extends SiteAdminCommandRequestBase {\n command: 'getValuesForEntityAutoComplete';\n valueProvidedByUser: string;\n chatAppId?: string;\n type?: 'internal-user' | 'external-user';\n}\n\n/**\n * Request to get display values for a list of entity IDs\n * @since 0.12.0\n */\nexport interface GetValuesForEntityListRequest extends SiteAdminCommandRequestBase {\n command: 'getValuesForEntityList';\n entityIds: string[];\n chatAppId?: string;\n}\n\nexport interface GetValuesForUserAutoCompleteRequest extends SiteAdminCommandRequestBase {\n command: 'getValuesForUserAutoComplete';\n valueProvidedByUser: string;\n}\n\nexport interface GetInitialDataRequest extends SiteAdminCommandRequestBase {\n command: 'getInitialData';\n}\n\nexport interface RefreshChatAppRequest extends SiteAdminCommandRequestBase {\n command: 'refreshChatApp';\n chatAppId: string;\n}\n\nexport interface CreateOrUpdateChatAppOverrideRequest extends SiteAdminCommandRequestBase {\n command: 'createOrUpdateChatAppOverride';\n chatAppId: string;\n override: ChatAppOverrideForCreateOrUpdate;\n}\n\nexport interface DeleteChatAppOverrideRequest extends SiteAdminCommandRequestBase {\n command: 'deleteChatAppOverride';\n chatAppId: string;\n}\n\nexport interface ClearConverseLambdaCacheRequest extends SiteAdminCommandRequestBase {\n command: 'clearConverseLambdaCache';\n cacheType: ClearConverseLambdaCacheType;\n chatAppId?: string;\n agentId?: string;\n}\n\nexport interface ClearSvelteKitCachesRequest extends SiteAdminCommandRequestBase {\n command: 'clearSvelteKitCaches';\n cacheType: ClearSvelteKitCacheType;\n chatAppId?: string; // Only used for chatAppCache when clearing specific chat app\n}\n\nexport const ClearSvelteKitCacheTypes = ['chatAppCache', 'tagDefinitionsCache', 'instructionAssistanceConfigCache', 'encryptionKeysCache', 'all'] as const;\nexport type ClearSvelteKitCacheType = (typeof ClearSvelteKitCacheTypes)[number];\n\nexport interface GetInstructionAssistanceConfigFromSsmRequest extends SiteAdminCommandRequestBase {\n command: 'getInstructionAssistanceConfigFromSsm';\n}\n\nexport interface GetInstructionAssistanceConfigFromSsmResponse extends SiteAdminCommandResponseBase {\n config: InstructionAssistanceConfig;\n}\n\nexport interface GetAllChatAppsAdminResponse extends SiteAdminCommandResponseBase {\n chatApps: ChatApp[];\n}\n\nexport interface GetAllAgentsAdminResponse extends SiteAdminCommandResponseBase {\n agents: AgentDefinition[];\n}\n\nexport interface GetAllToolsAdminResponse extends SiteAdminCommandResponseBase {\n tools: ToolDefinition[];\n}\n\nexport interface GetAllMemoryRecordsAdminResponse extends SiteAdminCommandResponseBase {\n memoryRecords: PagedRecordsResult;\n}\n\nexport interface GetInstructionsAddedForUserMemoryAdminResponse extends SiteAdminCommandResponseBase {\n instructions: string;\n}\n\nexport type SiteAdminResponse =\n | GetAgentResponse\n | GetInitialDataResponse\n | RefreshChatAppResponse\n | CreateOrUpdateChatAppOverrideResponse\n | DeleteChatAppOverrideResponse\n | GetValuesForEntityAutoCompleteResponse\n | GetValuesForEntityListResponse\n | GetValuesForUserAutoCompleteResponse\n | ClearConverseLambdaCacheResponse\n | ClearSvelteKitCachesResponse\n | AddChatSessionFeedbackResponse\n | UpdateChatSessionFeedbackResponse\n | SessionSearchResponse\n | GetChatMessagesAsAdminResponse\n | GetInstructionAssistanceConfigFromSsmResponse\n | GetAllChatAppsAdminResponse\n | GetAllAgentsAdminResponse\n | GetAllToolsAdminResponse\n | GetAllMemoryRecordsAdminResponse\n | GetInstructionsAddedForUserMemoryAdminResponse;\n\nexport interface SiteAdminCommandResponseBase {\n success: boolean;\n error?: string;\n}\n\nexport interface GetChatMessagesAsAdminResponse extends SiteAdminCommandResponseBase {\n messages: ChatMessage[];\n}\n\nexport interface ClearConverseLambdaCacheResponse extends SiteAdminCommandResponseBase {}\n\nexport interface ClearSvelteKitCachesResponse extends SiteAdminCommandResponseBase {\n clearedCount?: number;\n cacheType: string;\n}\n\nexport interface GetValuesForEntityAutoCompleteResponse extends SiteAdminCommandResponseBase {\n data: SimpleOption[] | undefined;\n}\n\n/**\n * Response containing display values for entity IDs\n * @since 0.12.0\n */\nexport interface GetValuesForEntityListResponse extends SiteAdminCommandResponseBase {\n data: SimpleOption[] | undefined;\n}\n\nexport interface GetValuesForUserAutoCompleteResponse extends SiteAdminCommandResponseBase {\n data: ChatUserLite[] | undefined;\n}\n\nexport interface GetInitialDataResponse extends SiteAdminCommandResponseBase {\n chatApps: ChatApp[];\n siteFeatures: SiteFeatures;\n}\n\nexport interface RefreshChatAppResponse extends SiteAdminCommandResponseBase {\n chatApp: ChatApp;\n}\n\nexport interface CreateOrUpdateChatAppOverrideResponse extends SiteAdminCommandResponseBase {\n chatAppOverride: ChatAppOverride;\n}\n\nexport interface DeleteChatAppOverrideResponse extends SiteAdminCommandResponseBase {}\n\nexport type ContentAdminRequest = ViewContentForUserRequest | StopViewingContentForUserRequest | GetValuesForContentAdminAutoCompleteRequest;\nexport type ContentAdminResponse = ViewContentForUserResponse | StopViewingContentForUserResponse | GetValuesForContentAdminAutoCompleteResponse;\n\nexport const ContentAdminCommand = ['viewContentForUser', 'stopViewingContentForUser', 'getValuesForAutoComplete'] as const;\nexport type ContentAdminCommand = (typeof ContentAdminCommand)[number];\n\nexport interface ContentAdminCommandRequestBase {\n command: ContentAdminCommand;\n chatAppId: string;\n}\n\nexport interface ViewContentForUserRequest extends ContentAdminCommandRequestBase {\n command: 'viewContentForUser';\n user: ChatUserLite;\n chatAppId: string;\n}\n\nexport interface StopViewingContentForUserRequest extends ContentAdminCommandRequestBase {\n command: 'stopViewingContentForUser';\n}\n\nexport interface GetValuesForContentAdminAutoCompleteRequest extends ContentAdminCommandRequestBase {\n command: 'getValuesForAutoComplete';\n valueProvidedByUser: string;\n}\n\nexport interface ContentAdminCommandResponseBase {\n success: boolean;\n error?: string;\n}\n\nexport interface GetValuesForContentAdminAutoCompleteResponse extends ContentAdminCommandResponseBase {\n data: ChatUserLite[] | undefined;\n}\n\nexport interface ViewContentForUserResponse extends ContentAdminCommandResponseBase {\n data: ChatUserLite | undefined;\n}\n\nexport interface StopViewingContentForUserResponse extends ContentAdminCommandResponseBase {}\n\nexport interface GetViewingContentForUserResponse extends ContentAdminCommandResponseBase {\n data: ChatUserLite[] | undefined;\n}\n\nexport const UserOverrideDataCommand = ['getInitialDialogData', 'getValuesForAutoComplete', 'saveUserOverrideData', 'clearUserOverrideData'] as const;\nexport type UserOverrideDataCommand = (typeof UserOverrideDataCommand)[number];\n\nexport type UserOverrideDataCommandRequest = GetInitialDialogDataRequest | GetValuesForAutoCompleteRequest | SaveUserOverrideDataRequest | ClearUserOverrideDataRequest;\nexport type UserOverrideDataCommandResponse = GetInitialDialogDataResponse | GetValuesForAutoCompleteResponse | SaveUserOverrideDataResponse | ClearUserOverrideDataResponse;\n\nexport interface UserOverrideDataCommandRequestBase {\n command: UserOverrideDataCommand;\n chatAppId: string;\n}\n\nexport interface GetInitialDialogDataRequest extends UserOverrideDataCommandRequestBase {\n command: 'getInitialDialogData';\n}\n\nexport interface GetValuesForAutoCompleteRequest extends UserOverrideDataCommandRequestBase {\n command: 'getValuesForAutoComplete';\n componentName: string;\n valueProvidedByUser: string;\n}\n\nexport interface SaveUserOverrideDataRequest extends UserOverrideDataCommandRequestBase {\n command: 'saveUserOverrideData';\n data: unknown | undefined;\n}\n\nexport interface ClearUserOverrideDataRequest extends UserOverrideDataCommandRequestBase {\n command: 'clearUserOverrideData';\n}\n\nexport interface UserOverrideDataCommandResponseBase {\n success: boolean;\n error?: string;\n}\n\nexport interface GetInitialDialogDataResponse extends UserOverrideDataCommandResponseBase {\n data: unknown | undefined;\n}\n\nexport interface GetValuesForAutoCompleteResponse extends UserOverrideDataCommandResponseBase {\n data: unknown[] | undefined;\n}\n\nexport interface SaveUserOverrideDataResponse extends UserOverrideDataCommandResponseBase {\n data: RecordOrUndef;\n}\n\nexport interface ClearUserOverrideDataResponse extends UserOverrideDataCommandResponseBase {}\n\n/**\n * This is the type used to persist the user data override data to a cookie if provided.\n */\nexport interface UserOverrideData {\n /** The outer key is the chatAppId and the inner key is the user data override data. */\n data: Record<string, RecordOrUndef>;\n}\n\nexport interface ContentAdminData {\n /** The outer key is the chatAppId and the inner key is the user data override data. */\n data: Record<string, ChatUserLite>;\n}\n\n/**\n * A base interface for features that can be turned on/off for certain users.\n */\nexport interface AccessRules {\n /** Whether the feature is turned on at all. If false, then the feature is turned off for all users regardless of the userTypes and userRoles settings. */\n enabled: boolean;\n\n /**\n * The user types that are allowed to use the feature. If neither this nor userRoles are provided,\n * then no access is granted (secure by default).\n */\n userTypes?: UserType[];\n\n /**\n * The user roles that are allowed to use the feature. If neither this nor userTypes are provided,\n * then no access is granted (secure by default).\n */\n userRoles?: UserRole[];\n\n /**\n * The logic to apply the userTypes and userRoles settings. If not provided, defaults to `and`\n * meaning that the user must be in the userTypes array and have the userRoles to use the feature.\n */\n applyRulesAs?: ApplyRulesAs;\n}\n\n/**\n * For rules that apply to multiple settings, this is the logic to apply the settings.\n */\nexport type ApplyRulesAs = 'and' | 'or';\n\n/**\n * The classifications of the response from the LLM. Used with the Verify Response feature.\n */\nexport const Accurate = 'A';\n\n/**\n * The response is accurate but contains stated assumptions\n */\nexport const AccurateWithStatedAssumptions = 'B';\n\n/**\n * The response is accurate but contains unstated assumptions\n */\nexport const AccurateWithUnstatedAssumptions = 'C';\n\n/**\n * The response is inaccurate or contains made up information\n */\nexport const Inaccurate = 'F';\n\n/**\n * The response was not classified\n */\nexport const Unclassified = 'U';\n\n/**\n * Do not change the order of these. The order is used to determine the severity of the classification.\n */\nexport const VerifyResponseClassifications = [Accurate, AccurateWithStatedAssumptions, AccurateWithUnstatedAssumptions, Inaccurate, Unclassified] as const;\n\n/**\n * The classification of the response from the LLM. Used with the Verify Response feature.\n */\nexport type VerifyResponseClassification = (typeof VerifyResponseClassifications)[number];\n\n/**\n * Do not change the order of these. The order is used to determine the severity of the classification.\n */\nexport const RetryableVerifyResponseClassifications = [AccurateWithStatedAssumptions, AccurateWithUnstatedAssumptions, Inaccurate] as const;\n\n/**\n * The classifications that can be retried by the agent.\n */\nexport type RetryableVerifyResponseClassification = (typeof RetryableVerifyResponseClassifications)[number];\n\nexport interface VerifyResponseClassificationDescription {\n classification: VerifyResponseClassification;\n label: string;\n description: string;\n}\n\nexport type VerifyResponseRetryableClassificationDescription = VerifyResponseClassificationDescription & {\n classification: RetryableVerifyResponseClassification;\n};\n\nexport const VerifyResponseClassificationDescriptions: Record<VerifyResponseClassification, VerifyResponseClassificationDescription> = {\n [Accurate]: { classification: Accurate as VerifyResponseClassification, label: 'Accurate', description: 'The response is completely accurate.' },\n [AccurateWithStatedAssumptions]: {\n classification: AccurateWithStatedAssumptions,\n label: 'Accurate with stated assumptions',\n description: 'The response is accurate but contains clearly stated assumptions'\n },\n [AccurateWithUnstatedAssumptions]: {\n classification: AccurateWithUnstatedAssumptions,\n label: 'Accurate with unstated assumptions',\n description: 'The response is accurate but contains assumptions that are not explicitly stated'\n },\n [Inaccurate]: { classification: Inaccurate, label: 'Inaccurate', description: 'The response is inaccurate or contains made up information' },\n [Unclassified]: { classification: Unclassified, label: 'Unclassified', description: 'The response was not given a classification' }\n};\n\nexport const VerifyResponseRetryableClassificationDescriptions: Record<RetryableVerifyResponseClassification, VerifyResponseRetryableClassificationDescription> = {\n [AccurateWithStatedAssumptions]: {\n classification: AccurateWithStatedAssumptions,\n label: 'Accurate with stated assumptions',\n description: 'The response is accurate but contains clearly stated assumptions'\n },\n [AccurateWithUnstatedAssumptions]: {\n classification: AccurateWithUnstatedAssumptions,\n label: 'Accurate with unstated assumptions',\n description: 'The response is accurate but contains assumptions that are not explicitly stated'\n },\n [Inaccurate]: { classification: Inaccurate, label: 'Inaccurate', description: 'The response is inaccurate or contains made up information' }\n};\n\n/**\n * The result of the authentication process.\n *\n * If both authenticatedUser and redirectTo are present, we set cookie to indiate logged in and redirect to the URL specified.\n * If only authenticatedUser is present, we are authenticated and can continue with the request whatever the URL currently is.\n * If neither are present, we are not authenticated and we willredirect to the login page.\n */\nexport interface AuthenticateResult<T extends RecordOrUndef = undefined, U extends RecordOrUndef = undefined> {\n /** If present, we are authenticated and can continue with the request. */\n authenticatedUser?: AuthenticatedUser<T, U>;\n /** If present, we need to redirect to the URL specified. */\n redirectTo?: Response;\n}\n\nexport interface CustomDataUiRepresentation {\n /** The name you want to show in the UI to represent this custom data: e.g. \"Account Name\" */\n title: string;\n /** The value you want to show in the UI to represent this custom data: e.g. \"Acme, Inc.\" */\n value: string;\n}\n\n/**\n * This is the type that is stored in the chat-app table with a chatAppId of `${chatAppId}:override`.\n */\nexport interface ChatAppOverrideDdb extends ChatAppOverride {\n chatAppId: string;\n}\n\n/**\n * If present, this overrides all access settings on chatApp: userTypes, userRoles, applyRulesAs.\n *\n * It also allows you to override whether the chat app is shown on the home page.\n *\n * Each ChatApp itself controls whether it is accessible to internal or external users. That may be overridden\n * here (stored in dynamodb table). If userType has a value, it is used over whatever was provided in the ChatApp itself.\n *\n * These are stored in the chat-app table with a chatAppId of `${chatAppId}:override`.\n *\n * The order of precedence for these rules is:\n *\n * 1. enabled: If present, overrides the chatApp.enabled setting. If not enabled, no one can access the chat app.\n * 2. exclusiveUserIdAccessControl: If provided, only allow these userIds to access the chat app, whether internal or external, doesn't matter. All other access rules are ignored.\n * 3. exlusive user typeaccess control\n * exclusiveInternalAccessControl: If provided, only allow these entities to access the chat app for internal users.\n * exclusiveExternalAccessControl: If provided, only allow these entities to access the chat app for external users.\n * 4. userTypes/userRoles/applyRulesAs: If provided, only allow these user types to access the chat app (internal-user and/or external-user), otherwise falls back to chatApp.userTypes.\n *\n * If none of these are provided, then the chat app's access settings saved when the chat app\n * was deployed will be used to determine access: userTypes, userRoles, applyRulesAs.\n */\nexport interface ChatAppOverride extends AccessRules {\n /**\n * Each forked instance of pika can provide their own custom data on a User object using the AuthProvider\n * they implement. Each user can thus have custom data associated with him. It is common for example for\n * a user to have an accountId or companyId associated with him by the AuthProvider and stored in the custom data.\n *\n * Let's say you want to control which external accounts or companies (the users associated with the account or company) that can access a chat app.\n * You would populate this list then with whatever is needed to identify the entities that are allowed to access the chat app.\n *\n * If you have even a single entry in this list, then the chat app will only be accessible to external users associated with those entities.\n *\n * The AuthProvider has a method that we will call to do the comparison of data from the user object and this list of entities.\n */\n exclusiveExternalAccessControl?: string[];\n\n /**\n * Each forked instance of pika can provide their own custom data on a User object using the AuthProvider\n * they implement. Each user can thus have custom data associated with him. It is common for example for\n * a user to have an accountId or companyId associated with him by the AuthProvider and stored in the custom data.\n *\n * Let's say you want to control which external accounts or companies (the users associated with the account or company) that can access a chat app.\n * You would populate this list then with whatever is needed to identify the entities that are allowed to access the chat app.\n *\n * If you have even a single entry in this list, then the chat app will only be accessible to internal users associated with those entities.\n *\n * The AuthProvider has a method that we will call to do the comparison of data from the user object and this list of entities.\n */\n exclusiveInternalAccessControl?: string[];\n\n /**\n * If provided, only allow these userIds to access the chat app, whether internal or external, doesn't matter.\n */\n exclusiveUserIdAccessControl?: string[];\n\n /**\n * If provided, this will govern whether the chat app is shown on the home page. This overrides the config in the siteFeatures.homePage.linksToChatApps.userChatAppRules.\n * If not provided, we will fall back to the config in the siteFeatures.homePage.linksToChatApps.userChatAppRules..\n */\n homePageFilterRules?: UserChatAppRule[];\n\n /** Overrides the title of the chat app (human readable) */\n title?: string;\n\n /** Overrides the description */\n description?: string;\n\n /** Any feature not explicitly defined and turned on is turned off by default. */\n features?: Partial<Record<FeatureIdType, ChatAppFeature>>;\n\n /** If true, this app isn't cached in various server-side layers. */\n dontCacheThis?: boolean;\n\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate?: string;\n\n /** ISO 8601 formatted timestamp of the last session update */\n lastUpdate?: string;\n\n /** The user who created this override */\n createdByUserId?: string;\n\n /** The user who last updated this override */\n updatedByUserId?: string;\n}\n\nexport type ChatAppOverrideForCreateOrUpdate = Omit<ChatAppOverride, 'createDate' | 'lastUpdate' | 'createdByUserId' | 'updatedByUserId'>;\n\nexport type UpdateableChatAppOverrideFields = Extract<\n keyof ChatAppOverride,\n | 'enabled'\n | 'userTypes'\n | 'userRoles'\n | 'applyRulesAs'\n | 'exclusiveExternalAccessControl'\n | 'exclusiveInternalAccessControl'\n | 'exclusiveUserIdAccessControl'\n | 'showOnHomePage'\n | 'title'\n | 'description'\n | 'features'\n | 'dontCacheThis'\n>;\n\nexport interface PikaConfig {\n pika: PikaStack;\n pikaChat: BaseStackConfig;\n weather?: BaseStackConfig;\n\n /** Features that are turned on/configured site-wide. */\n siteFeatures?: SiteFeatures;\n}\n\n/**\n * Features that are turned on/configured site-wide. They are configured in the <root>/pika-config.ts file.\n */\nexport interface SiteFeatures {\n /** Configure whether chat apps are shown on the home page. */\n homePage?: HomePageSiteFeature;\n\n /**\n * If this is provided then you intend to use the entity feature which means that you will be associating an\n * entity (such as an account or a company or organization) with a user and saving that information in the\n * chatUser.customData object. This tells us that you intend to do that and that gives us attributes\n * we can use to display and filter by the entity.\n */\n entity?: EntitySiteFeature;\n\n /** Configure whether users can override their user data. */\n userDataOverrides?: UserDataOverridesSiteFeature;\n\n /** Configure whether a content admin can view chat sessions and messages. */\n contentAdmin?: ContentAdminSiteFeature;\n\n /** Configure whether traces are shown in the chat app as \"reasoning traces\". */\n traces?: TracesFeature;\n\n /** Configure whether a disclaimer notice is shown in the chat app. */\n chatDisclaimerNotice?: ChatDisclaimerNoticeFeature;\n\n /** Configure whether the response from the LLM is verified and auto-reprompted if needed. */\n verifyResponse?: VerifyResponseFeature;\n\n /** Configure whether the user can logout of the chat app. */\n logout?: LogoutFeature;\n\n /** Configure whether the site admin website feature is enabled. */\n siteAdmin?: SiteAdminFeature;\n\n /** Configure whether the file upload feature is enabled. */\n fileUpload?: FileUploadFeature;\n\n /** Configure whether the suggestions feature is enabled. */\n suggestions?: SuggestionsFeature;\n\n /** Configure whether the prompt input field label feature is enabled. */\n promptInputFieldLabel?: PromptInputFieldLabelFeature;\n\n /** Configure whether the UI customization feature is enabled. */\n uiCustomization?: UiCustomizationFeature;\n\n /** Configure whether the session insights feature is enabled. */\n sessionInsights?: SessionInsightsFeature;\n\n /** Configure which tag definitions are enabled by default at the site level. */\n tags?: TagsSiteFeature;\n\n /** Configure whether the agent instruction assistance feature is enabled. */\n agentInstructionAssistance?: AgentInstructionAssistanceFeature;\n\n /** Configure whether the instruction augmentation feature is enabled. */\n instructionAugmentation?: InstructionAugmentationFeature;\n\n /** Configure whether the user memory feature is enabled. */\n userMemory?: UserMemoryFeature;\n}\n\n/**\n * Configure whether the user memory feature is enabled.\n *\n * When turned on, we will create a global memory space that will be used to store the user's memory\n * and then we will automatically store memory evnents based on the strategies turned on and the\n * queries made by the user. Then, we will query the memory to augment the prompt given to the LLM.\n */\nexport interface UserMemoryFeature {\n enabled: boolean;\n\n /** The maximum number of memory recrods to enrich a single prompt with. Defaults to 25. */\n maxMemoryRecordsPerPrompt?: number;\n\n /** The maximum number of top matches to consider per strategy. Defaults to 5. */\n maxKMatchesPerStrategy?: number;\n}\n\nexport interface UserMemoryFeatureWithMemoryInfo extends UserMemoryFeature {\n memoryId: string;\n strategies: UserMemoryStrategy[];\n maxMemoryRecordsPerPrompt: number;\n maxKMatchesPerStrategy: number;\n}\n\nexport const UserMemoryStrategies = ['preferences', 'semantic', 'summary'] as const;\nexport type UserMemoryStrategy = (typeof UserMemoryStrategies)[number];\n\n// Define the types of content we store in memory\nexport interface UserMessageContent {\n type: 'user_message';\n text: string;\n}\n\nexport interface AssistantMessageContent {\n type: 'assistant_message';\n text: string;\n}\n\nexport interface AssistantRationaleContent {\n type: 'assistant_rationale';\n text: string;\n}\n\nexport interface ToolInvocationContent {\n type: 'tool_invocation';\n invocation: {\n actionGroupInvocationInput?: any;\n knowledgeBaseLookupInput?: any;\n agentCollaboratorInvocationInput?: any;\n codeInterpreterInvocationInput?: any;\n };\n}\n\n// Union type for all possible memory content\nexport type MemoryContent = UserMessageContent | AssistantMessageContent | AssistantRationaleContent | ToolInvocationContent;\n\nexport type TypedContentWithRole = { content: MemoryContent; role: Role };\n\nexport interface MemoryQueryOptions {\n /** natural-language query for semantic search, default to '*' if not sure what to provide */\n query: string;\n /** how many highest-scoring hits to consider (server-side); we still cap with `maxResults` */\n maxResults: number;\n /** if you are paging, you can provide the nextToken from the previous response */\n nextToken?: string;\n /** how many highest-scoring hits to consider (server-side); we still cap with `maxResults` */\n topK?: number;\n}\n\n// What we get back when retrieving memory (either parsed JSON or raw text)\nexport type RetrievedMemoryContent = MemoryContent | string;\n\n// Memory record summary with parsed content\nexport interface RetrievedMemoryRecordSummary {\n memoryRecordId: string | undefined;\n content: RetrievedMemoryContent | undefined;\n memoryStrategyId: string | undefined;\n namespaces: string[] | undefined;\n createdAt: Date | undefined;\n score?: number | undefined;\n}\n\nexport type PagedRecordsResult = {\n records: RetrievedMemoryRecordSummary[];\n nextToken?: string;\n};\n\nexport interface SearchAllMyMemoryRecordsRequest {\n strategy: UserMemoryStrategy;\n nextToken?: string;\n}\n\nexport interface SearchAllMyMemoryRecordsResponse {\n success: boolean;\n error?: string;\n results: PagedRecordsResult;\n}\n\nexport interface SearchAllMemoryRecordsRequest {\n userId: string;\n strategy: UserMemoryStrategy;\n nextToken?: string;\n}\n\nexport interface SearchAllMemoryRecordsResponse {\n success: boolean;\n error?: string;\n results: PagedRecordsResult;\n}\n\nexport interface GetInstructionsAddedForUserMemoryRequest {\n userId: string;\n strategies: UserMemoryStrategy[];\n maxMemoryRecordsPerPrompt: number;\n maxKMatchesPerStrategy: number;\n prompt: string;\n}\nexport interface GetInstructionsAddedForUserMemoryResponse {\n success: boolean;\n error?: string;\n instructions: string;\n}\n\n/**\n * Sometimes you need to augment the prompt you will give to the LLM with additional information.\n * Currently, only one type of augmentation is supported: llm semantic search. This uses the scope of the\n * agent invocation (chat app ID, agent ID, entity ID) to search for semantic directives in a database\n * of canned semantic directives that match the scope of the agent invocation. Then, those semantic\n * directives are added to the prompt to be used by the LLM. The LLM then takes the end user's message\n * and the semantic directives and uses them to determine if any of the semantic directives should be\n * included in the prompt. If they should be included, then the semantic directive instruction is added to the prompt.\n *\n * Note that by default the feature is turned off. To turn it on, you must set the `enabled` property to `true` or\n * it will not be turned on. Then, all agents will have the type of augmentation chosen.\n *\n * Setting this as a site wide feature sets the default instruction augmentation type used, if turned on. Individual chat apps\n * may override this behavior, turning off the feature or changing the augmentation type.\n *\n * Note that today we only support one type of augmentation: llm semantic directive search. This is a light-weight\n * approach with a good balance of engineer velocity (don't have to ingest and index embeddings into a knowledge base),\n * performance and cost.\n */\nexport interface InstructionAugmentationFeature {\n enabled: boolean;\n type?: InstructionAugmentationType;\n}\n\nexport const InstructionAugmentationTypes = ['llm-semantic-directive-search'] as const;\nexport type InstructionAugmentationType = (typeof InstructionAugmentationTypes)[number];\n\nexport const InstructionAugmentationTypeDisplayNames = {\n 'llm-semantic-directive-search': 'LLM Semantic Directive Search'\n} as const;\nexport type InstructionAugmentationTypeDisplayName = (typeof InstructionAugmentationTypeDisplayNames)[keyof typeof InstructionAugmentationTypeDisplayNames];\n\nexport const InstructionAugmentationScopeTypes = ['chatapp', 'agent', 'tool', 'entity', 'agent-entity'] as const;\nexport type InstructionAugmentationScopeType = (typeof InstructionAugmentationScopeTypes)[number];\n\nexport const InstructionAugmentationScopeTypeDisplayNames = {\n chatapp: 'Chat App',\n agent: 'Agent',\n tool: 'Tool',\n entity: 'Entity',\n 'agent-entity': 'Agent and Entity'\n} as const;\nexport type InstructionAugmentationScopeTypeDisplayName = (typeof InstructionAugmentationScopeTypeDisplayNames)[keyof typeof InstructionAugmentationScopeTypeDisplayNames];\n\n/**\n * This is used to take the actual chatapp, agent, tools, and entity values used in a given agent invocation and use them\n * to go search for the matching semantic directives in the database.\n */\nexport type InvocationScopes = Partial<Record<InstructionAugmentationScopeType, (string | number | Record<string, string | number>)[] | undefined>>;\n\n/**\n * A semantic directive is a special case or additional instruction paragraph that you might want the LLM to have included\n * in its context when responding to a user's question but that doesn't belong in the main prompt. So, the LLM will\n * be given the semantic directives in the context of the user's question and will decide if any of them should be\n * included in the prompt. If they should be included, then the semantic directive instruction is added to the prompt.\n *\n * One of the main use cases for this is when you have a tool with certain inputs and most of the time the LLM can\n * craft the correct inputs to your tool based on the question from an end user. But, occasionally, you might wish to give\n * the LLM special instructions on certain details that are specific to a certain situation.\n *\n * Semantic directives are stored in a database and are associated with a scope. The scope is used to narrow down which\n * directives we will give to the light-weight LLM to consider for inclusion in your prompt. We first search the\n * database based on chat app, agent, tool and entity to get the set of directives that match the scope and then have the\n * LLM tell us if we should include them in the prompt.\n *\n * IMPORTANT: when you see us refer to 'entity' in a scope, it means that the entity is the entity that is associated with the user,\n * assuming you have turned on the entity feature. The value of the entity is entityFeature.attributeName.\n *\n * In your pika-config.ts file, you can turn on the entity feature by setting the entity feature to true.\n */\nexport interface SemanticDirective {\n /**\n * You don't set this value directly. Instead, you set the scopeType and scopeValue from which we will construct the scope.\n *\n * Remember that we might have a database full of these semantic directives. The scope then narrows down which\n * directives we will give to the light-weight LLM to consider for inclusion in your prompt. We first search the\n * database based on chat app, agent, tool and entity to get the set of directives that match the scope and then have the\n * LLM tell us if we should include them in the prompt.\n *\n * We support the following scopes at present:\n * - chatapp: The ID of the chat app this semantic directive is associated with.\n * - agent: The ID of the agent this semantic directive is associated with.\n * - tool: the ID of the tool this semantic directive is associated with.\n * - entity: The ID of the entity this semantic directive is associated with. Of course, if your pika instance\n * doesn't turn on the uses of entities, then this scope will not be used.\n *\n * We support only the following compound scopes at present:\n * - agent#{agent-id}#entity#{entity-id}\n *\n * Examples:\n *\n * - `chatapp#weather-chat-app`\n * - `agent#weather-agent`\n * - `tool#weather-tool`\n * - `entity#account-123`\n * - `agent#weather-agent#entity#account-123` // matches only for queries by account-123 to the weather agent\n */\n scope: string;\n\n /**\n * The type of scope this semantic directive is associated with. This tells us what\n * the value in `scopeValue` is.\n */\n scopeType: InstructionAugmentationScopeType;\n\n /**\n * The value of the scope this semantic directive is associated with. This is a string or an object\n * depending on the value of `scopeType`.\n *\n * If `scopeType` is `agent` then this will be the agent ID.\n * If `scopeType` is `tool` then this will be the tool ID.\n * If `scopeType` is `entity` then this will be the entity ID (entityFeature.attributeName from user.customData).\n * If `scopeType` is `agent-entity` then this will be {agent: string, entity: string}.\n */\n scopeValue: string | number | Record<string, string | number>;\n\n /**\n * This plus scope must be unique across all semantic directives.\n *\n * Just a human-readable ID for the semantic directive. Consider it a variable name: may use dashes and underscores\n * and should start with a letter (no spaces or special characters). E.g. \"account-details\", \"customer-support\", \"order-status\", etc.\n * Used for db queries and to help engineers identify the semantic directive easily in a UI or DB.\n */\n id: string;\n\n /**\n * Used internally to group semantic directives created by a custom cloudformation resource. You shouldn't use this.\n * For example, a specific agent in a given stack may include CDK to define its semantic directives. Pika needs to\n * know the complete set of semantic directives that exist for that group so that the agent author can have the\n * freedom to modify semantic directive scope values. This groupId then is how the pika platform will be able\n * to query for all the semantic directives created as a \"group\" by the agent author and know which semantic directives\n * should be deleted because they are no longer present in the CDK stack.\n *\n * Don't set this value directly. Instead, let the custom cloudformation resource set it for you using the\n * `event.StackName` of the stack that created the semantic directive.\n */\n groupId?: string;\n\n /**\n * This is what the light-weight LLM will use to decide if the question asked by the end user means that\n * this semantic directive should be included in the prompt to ensure the final LLM gives a correct response.\n */\n description: string;\n\n /**\n * If the light-weight LLM determines that this semantic directive should be included in the prompt, then these\n * instructions will be included in the final prompt to the final LLM to guide its response.\n */\n instructions: string;\n\n /** If true, the semantic directive will not be used to augment the prompt. */\n disabled?: boolean;\n\n /** ISO 8601 formatted timestamp of when the semantic directive was created */\n createDate: string;\n\n /** User who created the semantic directive */\n createdBy: string;\n\n /** User who last updated the semantic directive */\n lastUpdatedBy: string;\n\n /** ISO 8601 formatted timestamp of the last semantic directive update */\n lastUpdate: string;\n}\n\nexport interface SemanticDirectiveForCreateOrUpdate extends Omit<SemanticDirective, 'scope' | 'createDate' | 'lastUpdate'> {\n createdBy: string;\n lastUpdatedBy: string;\n}\n\nexport interface SemanticDirectiveCreateOrUpdateRequest {\n semanticDirective: SemanticDirectiveForCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\nexport interface SemanticDirectiveCreateOrUpdateResponse {\n success: boolean;\n semanticDirective: SemanticDirective;\n}\n\nexport interface SemanticDirectiveScope {\n scopeType: InstructionAugmentationScopeType;\n scopeValue: string | number | Record<string, string | number>;\n}\n\n/**\n * Search request for semantic directives. Supports multiple search patterns based on our DynamoDB table design:\n * - If findOne is provided, then we will return the first directive that matches the scopeType, scopeValue and id.\n * - Query by specific scopes (main table access pattern)\n * - Query by creator and date range (GSI1: createdBy + createDate)\n * - Query by directive ID(s) across scopes (GSI2: id + scope)\n * - Date range filtering (created or updated)\n *\n * If no search criteria provided, returns all directives with pagination.\n */\nexport interface SearchSemanticDirectivesRequest {\n findOne?: {\n scopeType: InstructionAugmentationScopeType;\n scopeValue: string | number | Record<string, string | number>;\n id: string;\n };\n\n /**\n * Search for directives within specific scopes.\n * Uses parallel DynamoDB queries against the main table (PK = scope).\n */\n scopes?: SemanticDirectiveScope[];\n\n /** Will be used by the custom cloudformation resource to query for all semantic directives created as a \"group\" by the agent author. */\n groupId?: string;\n\n /**\n * Search for directives created by a specific user.\n * When provided, results are automatically sorted by createDate (newest first by default).\n *\n * Uses GSI1: createdBy + createDate\n */\n createdBy?: string;\n\n /**\n * Search for directives by specific IDs.\n * Returns directives matching any of the provided IDs across all scopes.\n *\n * Uses GSI2: id + scope\n */\n directiveIds?: string[];\n\n /**\n * Filter directives created after this ISO 8601 timestamp.\n * Can be combined with other filters.\n * Example: \"2024-01-15T00:00:00Z\"\n */\n createdAfter?: string;\n\n /**\n * Filter directives created before this ISO 8601 timestamp.\n * Can be combined with other filters.\n * Example: \"2024-01-31T23:59:59Z\"\n */\n createdBefore?: string;\n\n /**\n * Filter directives updated after this ISO 8601 timestamp.\n * Can be combined with other filters.\n */\n updatedAfter?: string;\n\n /**\n * Filter directives updated before this ISO 8601 timestamp.\n * Can be combined with other filters.\n */\n updatedBefore?: string;\n\n /**\n * Sort order for results when using createdBy search or no specific search criteria.\n * - 'asc': Oldest first\n * - 'desc': Newest first (default)\n */\n sortOrder?: 'asc' | 'desc';\n\n /**\n * Maximum number of directives to return per page.\n * Default: 50, Max: 100\n */\n limit?: number;\n\n /**\n * Pagination token from previous search response.\n * Include your original search criteria when using pagination.\n */\n paginationToken?: Record<string, any>;\n\n /**\n * If true, includes the full directive instructions in response.\n * If false, returns directive metadata only (scope, id, description, dates, etc).\n * Default: false (to save bandwidth)\n */\n includeInstructions?: boolean;\n\n /**\n * If true, excludes disabled directives in the response.\n * Default: false\n */\n excludeDisabled?: boolean;\n}\n\nexport interface SearchSemanticDirectivesResponse {\n success: boolean;\n\n /** Array of semantic directives matching the search criteria */\n semanticDirectives: SemanticDirective[];\n\n /** Total count of directives found (may be larger than returned array due to pagination) */\n totalCount?: number;\n\n /** If present, there are more results available. Pass this token back in the next request. */\n paginationToken?: Record<string, any>;\n}\n\nexport interface SemanticDirectiveDeleteRequest {\n semanticDirective: {\n scope: string;\n id: string;\n };\n\n /**\n * If you are deleting one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the deletion and we ask that you prepend it with 'cloudformation/'\n * so we understand it was deleted by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\nexport interface SemanticDirectiveDeleteResponse {\n success: boolean;\n}\n\nexport interface TagsSiteFeature {\n /**\n * Whether to enable the tags feature. If this is turned off you will lost a lot of the functionality of the chat app.\n */\n enabled: boolean;\n\n /**\n * The tag definitions that are enabled by default. If not provided, then no tag definitions are enabled.\n * Each chat app can override this list by providing its own list of tagsEnabled in its chat app config.\n */\n tagsEnabled?: TagDefinitionLite[];\n\n /**\n * Global tags are enabled by default. Turn them off here if you don't want them.\n */\n tagsDisabled?: TagDefinitionLite[];\n}\n\n/**\n * Configure whether the session insights feature is enabled. When turned on, Pika will\n * automatically collect session insights for each chat session. If you want to view these\n * insights, then you need to turn it on in the site admin website.\n */\nexport interface SessionInsightsFeature {\n enabled: boolean;\n\n /**\n * The string is the stage that the session config applies to. If you provide a stage named\n * `default` then any stage not found in your map will use the default config.\n *\n *\n * If you don't provide this, here are the default settings.\n */\n openSearchConfig?: Record<string, SessionInsightsOpenSearchConfig>;\n}\n\nexport interface SessionInsightsOpenSearchConfig {\n dedicatedMasterEnabled: boolean;\n\n /** Ignored if dedicatedMasterEnabled is false. Defaults to 1 if not provided. Recommend >= 3 in production for quorum */\n dedicatedMasterCount?: number;\n\n /** Ignored if dedicatedMasterEnabled is false. Defaults to m5.large.search if not provided. */\n masterNodeInstanceType?: string;\n\n /** Defaults to m5.large.search if not provided. */\n dataNodeInstanceType?: string;\n\n /** The number of data nodes to use. Defaults to 1 if not provided. */\n dataNodeCount?: number;\n\n /** Defaults to false if not provided. */\n zoneAwarenessEnabled: boolean;\n\n /** Ignored if zoneAwarenessEnabled is false. Defaults to 1 if not provided. */\n availabilityZoneCount?: number;\n\n /** Unit is gigs. Defaults to 10 gig if not provided. */\n volumeSize?: number;\n\n /** Defaults to gp3 if not provided. */\n volumeType?: string;\n}\n\nexport interface TagsFeatureForChatApp extends Feature {\n featureId: 'tags';\n\n /**\n * The tag definitions that are explicitly enabled for this chat app.\n * These are chat-app specific tags (usageMode='chat-app') that must be explicitly enabled.\n * Global tags (usageMode='global') are automatically included unless listed in tagsDisabled.\n */\n tagsEnabled?: TagDefinitionLite[];\n\n /**\n * Global tag definitions that should be disabled for this chat app.\n * Only applies to global tags (usageMode='global').\n * Use this to exclude specific global tags that you don't want available.\n */\n tagsDisabled?: TagDefinitionLite[];\n}\n\nexport interface SessionInsightsFeatureForChatApp extends Feature {\n featureId: 'sessionInsights';\n}\n\n/**\n * The user data override feature may be enabled at the site level. If enabled, then individual chat apps\n * may choose to disable the feature. Why would they do this? Perhaps they don't need the data\n * that may be overridden and don't want to prompt users to provide the data which may add friction\n * and confusion.\n */\nexport interface UserDataOverrideFeatureForChatApp extends Feature {\n featureId: 'userDataOverrides';\n}\n\n/**\n * A content admin is a user that can use the UI to select any user of the system and view their chat\n * sessions and messages in each for the purpose of debugging and troubleshooting. By default,\n * this feature is turned off. To turn it on, you must set the `enabled` property to `true`.\n *\n * Further, you will have to go into the DynamoDB table named `chat-users-${your-stack-name}` and\n * add the `pika:content-admin` role to the user.\n */\nexport interface ContentAdminSiteFeature {\n enabled: boolean;\n}\n\n/**\n * If this is provided then you intend to use the entity feature which means that you will be associating an\n * entity (such as an account or a company or organization) with a user and saving that information in the\n * chatUser.customData object. This tells us that you intend to do that and that gives us attributes\n * we can use to display and filter by the entity.\n *\n * This won't affect anything an external customer sees or interacts with since presumably an external customer\n * is a specific account or company and so this feature is only intended for internal users and admins\n * to be able to act on behalf of a specific account or company and in the admin UI to filter by entity.\n */\nexport interface EntitySiteFeature {\n enabled: boolean;\n\n /**\n * The attribute name in the chatUser.customData object that contains the entity value: e.g. \"accountId\".\n * So, you might have a user object that looks like this returned by your AuthProvider:\n * ```ts\n * {\n * customData: {\n * accountId: '123'\n * }\n * }\n * ```\n * If not provided this feature will not work. */\n attributeName: string;\n\n /** The placeholder text for the search input. */\n searchPlaceholderText: string;\n\n /** The singular name of the entity. */\n displayNameSingular: string;\n\n /** The plural name of the entity. */\n displayNamePlural: string;\n\n /** The title of the column header in the entity table as in Account ID. */\n tableColumnHeaderTitle: string;\n}\n\n/**\n * When turned on, the front end will allow users to override user values set by the auth provider\n * in `ChatUser.customData`. For example, perhaps an internal user needs the ability to choose an account\n * to act as. This feature then allows them to set the accountId perhaps on `ChatUser.customData.accountId`.\n * using a UI component that you the developer will provide. @see <root>/docs/developer/user-overrides\n */\nexport interface UserDataOverridesSiteFeature {\n /** Whether to enable the user overrides feature. */\n enabled: boolean;\n\n /**\n * The user types that are allowed to use the user overrides feature. If not provided, defaults to `['internal-user']`\n * meaning that if the feature is enabled, only internal users will be able to use it.\n */\n userTypes?: UserType[];\n\n /**\n * The title of the menu item that will be displayed to authorized users that when clicked will\n * open the dialog allowing them to override user data. Defaults to \"Override User Data\".\n */\n menuItemTitle?: string;\n\n /**\n * The title of the dialog that will be displayed when the user clicks the menu item. Defaults to \"Override User Data\".\n */\n dialogTitle?: string;\n\n /**\n * The description that appears benath the title in the dialog window. Defaults to\n * \"Override user data values to use with this chat app. This override will persist until you\n * login again or clear the override.\"\n */\n dialogDescription?: string;\n\n /**\n * The description that appears benath the title in the dialog window when the user needs to provide data overrides.\n * Defaults to the same as dialogDescription. Use this to say something like, \"You need to provide data overrides to use this chat app.\"\n */\n dialogDescriptionWhenUserNeedsToProvideDataOverrides?: string;\n\n /**\n * Whether to prompt the user if their user object's customData object is missing any of the custom user\n * data attributes that are required for the chat app. If any of these attributes is missing and the user\n * is allowed to use the user data overrides feature, the user will be prompted to enter the missing attributes\n * when they open the chat app. If not provided, defaults to false.\n *\n * So, when they open a chat app and they are allowed to use the user data overrides feature, and\n * any of these attributes are missing on the users's customData attribute provided by the auth provider\n * then the user will be prompted to enter the missing attributes and will not be able to use the chat app\n * until they have provided the data overrides that presumably will be used to fill in the missing attributes.\n *\n * Note, you can use dot notation to specify nested attributes. For example, if you want to prompt the user\n * if the user object's customData object is missing the attribute \"address.street\", you can specify\n * \"address.street\" in the array. The root of the attibute path is the user.customData object itself.\n *\n * So, if your customData object was this and you needed to prompt the user if the companyName or companyId\n * attributes were missing, you would specify \"companyName\" or \"companyId\" in the array.\n *\n * ```ts\n * export interface MyCustomUserData {\n * companyName: string;\n * companyId: string;\n * }\n * ```\n *\n * The prompt will be shown if the data is missing each time they come to chat app and if they dismiss the prompt,\n * the prompt will be shown if they try to submit a message to the agent instead of sending the message.\n */\n promptUserIfAnyOfTheseCustomUserDataAttributesAreMissing?: string[];\n}\n\n/** Used in front end to pass settings from server to client. */\nexport type UserDataOverrideSettings = Omit<UserDataOverridesSiteFeature, 'userTypes' | 'promptUserIfAnyOfTheseCustomUserDataAttributesAreMissing'> & {\n userNeedsToProvideDataOverrides: boolean;\n};\n\nexport interface HomePageSiteFeature {\n /**\n * The title of the home page. If not provided, the default title will be used. This is used\n * to describe the home page to the user and in navigation.\n */\n homePageTitle?: string;\n\n /**\n * The welcome message to display on the home page. If not provided, the default welcome message will be used.\n * This is used to describe the home page to the user and in navigation.\n */\n welcomeMessage?: string;\n\n //TODO: add icon support\n\n /**\n * Whether to have the chat app home page show links to registered chat apps. If none of the\n * userChatAppRules match the user, then the user will not see any links to chat apps on the home page.\n */\n linksToChatApps?: HomePageLinksToChatAppsSiteFeature;\n}\n\n/**\n * Whether to have the chat app home page show links to registered chat apps. If none of the\n * userChatAppRules match the user, then the user will not see any links to chat apps on the home page.\n *\n * This is a site-wide feature and is not associated with a specific chat app. You define this config\n * in the chat app config in <root>/pik-config.json\n */\nexport interface HomePageLinksToChatAppsSiteFeature {\n /**\n * Which users are able to get links to which chat apps on the home page. You must have at least one rule to enable this feature.\n *\n * ```ts\n * {\n * siteFeatures: {\n * homePageLinksToChatApps: {\n * userChatAppRules: [\n * // External users can only see links to external chat apps\n * {\n * userTypes: ['external-user'],\n * chatAppUserTypes: ['external-user']\n * },\n * // Internal users can see links to internal and external chat apps\n * {\n * userTypes: ['internal-user'],\n * chatAppUserTypes: ['internal-user', 'external-user']\n * }\n * ]\n * }\n * }\n * }\n * ```\n */\n userChatAppRules: UserChatAppRule[];\n}\n\nexport interface BaseStackConfig {\n projNameL: string; // All lowercase no stage name e.g. pika\n projNameKebabCase: string; // Kebab case no stage name e.g. pika\n projNameTitleCase: string; // Title case no stage name e.g. Pika\n projNameCamel: string; // Camel case no stage name e.g. pika\n projNameHuman: string; // Human readable no stage name e.g. Pika\n}\n\nexport interface PikaStack extends BaseStackConfig {\n viteConfig?: {\n server?: ViteServerConfig;\n preview?: VitePreviewConfig;\n };\n}\n\nexport interface ViteServerConfig {\n host?: string;\n port?: number;\n strictPort?: boolean;\n https?: {\n key: string; // Path to key file\n cert: string; // Path to cert file\n };\n}\n\nexport interface VitePreviewConfig {\n host?: string;\n port?: number;\n strictPort?: boolean;\n}\n\nexport interface SimpleOption {\n value: string;\n label?: string;\n secondaryLabel?: string;\n}\n\nexport interface FeatureError {\n desc: string;\n\n /** THis is set to true when the parent features component already checks for and handles this kind of error. */\n parentShouldIgnore?: boolean;\n}\n\nexport interface NameValuePair<T> {\n name: string;\n value: T;\n}\n\nexport interface NameValueDescTriple<T> {\n name: string;\n value: T;\n desc?: string;\n}\n\n/**\n * A component that renders a tag is expected to have a tag definition that defines the tag and the instructions for how to render it.\n *\n */\nexport interface ComponentTagDefinition<T extends TagDefinitionWidget> {\n definition: TagDefinition<T>;\n}\n\nexport const TAG_DEFINITION_STATUSES = ['enabled', 'disabled', 'retired'] as const;\nexport type TagDefinitionStatus = (typeof TAG_DEFINITION_STATUSES)[number];\n\nexport interface SpotlightContextConfig {\n enabled: boolean;\n isDefault?: boolean;\n displayOrder?: number;\n /** If true (default), only one instance of this widget can exist in spotlight at a time */\n singleton?: boolean;\n /** If false, widget won't appear in unpinned menu. Default: true. Use false for base widgets that only create instances */\n showInUnpinnedMenu?: boolean;\n}\n\nexport interface InlineContextConfig {\n enabled: boolean;\n}\n\nexport interface DialogContextConfig {\n enabled: boolean;\n size?: 'small' | 'medium' | 'large' | 'fullscreen';\n}\n\nexport interface CanvasContextConfig {\n enabled: boolean;\n}\n\n/**\n * Tag definition for widgets that have static context enabled.\n * Static widgets can run initialization code (like registering title bar actions)\n * when the chat app loads. They can also have other rendering contexts for visual UI.\n */\nexport type StaticWidgetTagDefinition = TagDefinition<TagDefinitionWidgetWebComponent> & {\n renderingContexts: {\n static: StaticContextConfig;\n spotlight?: SpotlightContextConfig;\n inline?: InlineContextConfig;\n dialog?: DialogContextConfig;\n canvas?: CanvasContextConfig;\n };\n};\n\n/**\n * The static context is used to render a static component that doesn't render visually but is used to run code that needs to be run once.\n * For example, you might want to run a code snippet that puts an icon in the title bar of the chat app.\n */\nexport interface StaticContextConfig {\n enabled: boolean;\n /**\n * If provided, the static context container will be removed from the DOM after this many milliseconds.\n * If not provided, the container stays in the DOM (hidden) indefinitely.\n *\n * Use this when the static component only needs to run initialization code and doesn't need to\n * persist in the DOM afterwards.\n *\n * Example: 1000 (remove after 1 second)\n */\n shutDownAfterMs?: number;\n}\n\nexport const WIDGET_RENDERING_CONTEXT_TYPES = ['spotlight', 'inline', 'dialog', 'canvas', 'static'] as const;\nexport type WidgetRenderingContextType = (typeof WIDGET_RENDERING_CONTEXT_TYPES)[number];\n\nexport interface WidgetRenderingContexts {\n spotlight?: SpotlightContextConfig;\n inline?: InlineContextConfig;\n dialog?: DialogContextConfig;\n canvas?: CanvasContextConfig;\n static?: StaticContextConfig;\n}\n\n/**\n * Represents a tracked widget instance with its DOM element and metadata.\n */\nexport interface WidgetInstance {\n /** Unique instance ID */\n instanceId: string;\n /** The actual DOM element */\n element: HTMLElement;\n /** Tag identifier (scope.tag) */\n tagId: string;\n /** Custom element name */\n customElementName: string;\n /** Rendering context where this widget appears */\n renderingContext: WidgetRenderingContextType;\n /** Tag definition */\n tagDefinition: TagDefinition<TagDefinitionWidgetWebComponent>;\n /** When this instance was created */\n createdAt: number;\n}\n\n/**\n * Metadata for a persistent spotlight instance (saved via Virtual Tags Pattern)\n */\nexport interface SpotlightInstanceMetadata {\n displayName: string;\n savedAt: string; // ISO-8601\n displayOrder: number;\n parentTag: string; // Base tag without instance suffix\n instanceId: string; // UUID\n}\n\nexport interface TagDefinition<T extends TagDefinitionWidget> {\n /**\n * The tag type this definition is for. If the tag is one of the built-in pika tags, then you are overriding the built-in pika tag instructions\n * that will be included in the prompt assistance language.\n *\n * If the tag is a custom tag, then you are adding a new custom tag to the agent prompt definition.\n *\n * Do not include your scope on the tag name, we will add it for you.\n */\n tag: string;\n\n /**\n * We didn't start with the expectation that tags would have a scope that prefixes the tag name. We are now requiring it. However,\n * a few of our initial tags were not scoped and so we are allowing you to provide a legacy alias for the tag. This is not recommended\n * and you should use the scope instead.\n *\n * Here is the complete set of legacy tag aliases: download, chart, prompt, image. If you try to set this to anything but one of these, we will\n * error out and not take your tag definition.\n *\n * We will remove this in the near future. You've been warned.\n */\n legacyTagName?: string;\n\n /**\n * The scope of the tag. This is used to group tags together and prevent collisions with other tags.\n *\n * Inside the system, your tag will be known as `<scope>.<tag>`. For example, the chart tag will be known as `<pika.chart></pika.chart>`.\n *\n * As a result, scope must not include punctuation of any kind to be valid xml and keep things simple. All lower case is recommended but it's up to you.\n * Your aim is to ensure uniqueness of the tag name across all tags in the system and to keep it short and simple to use as few characters as possible within reason.\n *\n * This will be `pika` for built in tags the platform natively supports. If you are adding a custom tag, you should use a\n * scope that is unique to your application, chat app or agent.\n */\n scope: string;\n\n /**\n * This should be a pluralized noun that represents the tag and be capitalized.\n *\n * For example, the chart tag title is \"Charts\". The prompt tag title is \"Follow-up Prompts\". The image tag title is \"Images\".\n *\n * Do not use markdown in this title.\n */\n tagTitle: string;\n\n /**\n * This should be a short example of the tag structure. It may be used in the prompt assistance language injected into your prompt in a quick list of tags available for the LLM to generate.\n *\n * For example, the chart tag structure example is `<pika.chart></pika.chart>`. The prompt tag structure example is `<pika.prompt></pika.prompt>`. The image tag structure example is `<pika.image></pika.image>`.\n *\n * Be sure that you use `${scope}.` in front of the tag name.\n *\n * Do not use markdown in this example and don't surround with backticks, just the tag structure itself. Don't include a body to the tag, even if it has one.\n */\n shortTagEx: string;\n\n /**\n * If true, the tag can be generated by the LLM.\n */\n canBeGeneratedByLlm: boolean;\n\n /**\n * If true, the tag will be generated by a tool of an agent.\n */\n canBeGeneratedByTool: boolean;\n\n /**\n * A description of the tag. This will be used to describe the tag in admin-facing UI. Don't use markdown in this description.\n */\n description: string;\n\n /** Cache configuration for testing and debugging, used in lambdas/ecs containers that create LRU caches for tag definitions */\n dontCacheThis?: boolean;\n\n /** You must be explicit about whether this tag is a widget or not and if so what kind. */\n widget: T;\n\n /**\n * Determines how this tag can be used across chat apps.\n * - 'global': Tag is available to all chat apps by default (unless explicitly disabled)\n * - 'chat-app': Tag must be explicitly enabled in a chat app's configuration to be available\n *\n * REQUIRED: Must be explicitly set.\n * Built-in Pika tags (scope='pika') are typically 'global', while custom tags are typically 'chat-app'.\n */\n usageMode: TagDefinitionUsageMode;\n\n /**\n * The status of this tag definition.\n * - 'enabled': Tag is active and available for use\n * - 'disabled': Tag is temporarily disabled\n * - 'retired': Tag is permanently retired/deprecated\n *\n * REQUIRED: Must be explicitly set. If not provided, defaults to 'enabled'.\n * This is critical for the GSI to properly index all records.\n */\n status: TagDefinitionStatus;\n\n /**\n * Rendering contexts this widget supports. Required. Must have at least one context.\n */\n renderingContexts: WidgetRenderingContexts;\n\n /**\n * Indicates this is a mock/demo tag definition for development/testing purposes.\n * Mock tags may be filtered out in production environments.\n */\n isMock?: boolean;\n\n /**\n * If `canBeGeneratedByLlm` is true, you must provide instructions for the LLM to generate the tag since chat app/agent builders can choose\n * to have the instructions injected into the agent instructions prompt for a given tag.\n *\n * When we inject your instructions into the agent instructions prompt, we will do the following:\n *\n * 1. We will use the `tagTitle` as the bullet title for your tag instructions: `- **tagTitle:**`\n * 2. We will wrap your markdown instructions in XML tags to prevent formatting conflicts with the rest of the injected instructions\n *\n * Here's a complete example of what we will generate for you:\n *\n * ```markdown\n * - **Charts:**\n * <tag-instructions type=\"chart\">\n * To include a pika chart, use the `<pika.chart></pika.chart>` tags.\n * The content within the tags MUST be valid Chart.js version 4 JSON, including `type` and `data` properties.\n *\n * **Example:** `<pika.chart>{\"type\":\"line\",\"data\":{\"labels\":[\"May\",\"June\",\"July\",\"August\"],\"datasets\":[{\"label\":\"Avg Temperature (°C)\",\"data\":[2,3,7,12]}]}}</pika.chart>`\n *\n * **Usage:** Include pika charts whenever they can visually represent data, trends, or comparisons effectively.\n * </tag-instructions>\n * ```\n *\n * The markdown you provide should be well-formatted and can use any standard markdown features (lists, bold, code blocks, etc.).\n * The XML wrapper ensures that your formatting doesn't interfere with the overall instruction structure.\n */\n llmInstructionsMd?: string;\n\n /**\n * If the code that backs your tag definition, whether compile in or a separate web component, has need to\n * directly invoke the agent to get assistance from an LLM, then you can create named sets of instructions\n * so when the component makes the request for help from the agent, the agent will know which set of instructions\n * to use. For example, let's say you have a Spotlight component defined as a tag definition that needs to\n * on startup get a list of cities and then make a request to the agent to get the weather for the list of cities.\n * The default agent instructions for the agent probably woudn't return the weather information in a structured\n * manner. So, you'd want to create a new set of instructions for the agent to use, with the same set of tools,\n * that the component code would cause to be used by asking for a direct agent invocation initiated from the\n * code in the browser and that references the name of the instructions to use that will retrieve the\n * weather as structured json let's say and that includes the list of cities you want the weather for.\n *\n * That way, the server side converse lambda function that responds to direct agent invocation requests will know\n * which set of instructions to use. It's not a good idea to allow the client to define the entire set of instructions.\n *\n * It's too risky. So, here's an example of a good set of instructions that you could use. Note that the input value\n * sent from the browser webcomponent in this case would just be a list of locations that we would append to the bottom\n * of the following. Also note that the {{typescript-backed-output-formatting-requirements}} placeholder is used to\n * inject the typescript backed output formatting requirements which are stored in S3.\n *\n * ```markdown\n * You are **WeatherDataLookupAgent**, a highly skilled assistant used to turn a list of locations into weather data.\n * Below you will find the list of locations you need to look up the weather for using the associated tools provided.\n *\n * <output_schema>\n * interface WeatherData {\n * // ISO 8601 date string of when this data was generated\n * date: string;\n *\n * // the weather data itself\n * locations: LocationWeatherInfo[];\n * }\n *\n * interface LocationWeatherInfo {\n * // The name of the location in a human readable format\n * locationName: string;\n *\n * // longitude for the location. Optional just in case you can't get it.\n * lon?: string;\n *\n * // latitude for the location. Optional just in case you can't get it.\n * lat?: string;\n *\n * // The temperature in celsius\n * tempC: string;\n *\n * // The temperature in fahrenheit\n * tempF: string;\n * }\n * </output_schema>\n *\n * {{typescript-backed-output-formatting-requirements}}\n * ```\n *\n * The key in the record is referred to as the \"componentAgentInstructionName\" and the value is the markdown string of the instructions.\n *\n */\n componentAgentInstructionsMd?: Record<string, string>;\n\n /** The user id of the user who created the tag definition */\n createdBy: string;\n\n /** The user id of the user who last updated the tag definition */\n lastUpdatedBy: string;\n\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate: string;\n\n /** ISO 8601 formatted timestamp of the last session update */\n lastUpdate: string;\n}\n\nexport interface TagDefinitionLite {\n tag: string;\n scope: string;\n}\n\n/**\n * Web component definition for create/update operations.\n * The s3Bucket field is omitted because it's filled in by the backend.\n */\nexport interface TagDefinitionWebComponentForCreateOrUpdate extends Omit<TagDefinitionWebComponent, 's3'> {\n s3?: {\n /** Must follow pattern: wc/${scope}/fileName.js.gz */\n s3Key: string;\n };\n}\n\n/**\n * Widget definition for web components in create/update operations.\n * Uses TagDefinitionWebComponentForCreateOrUpdate which omits the backend-managed s3Bucket field.\n */\nexport interface TagDefinitionWidgetWebComponentForCreateOrUpdate extends TagDefinitionWidgetBase {\n type: 'web-component';\n webComponent: TagDefinitionWebComponentForCreateOrUpdate;\n}\n\n/**\n * Union type for all widget types in create/update operations.\n * Uses the specialized web component type that omits backend-managed fields.\n */\nexport type TagDefinitionWidgetForCreateOrUpdate =\n | TagDefinitionWidgetPassThrough\n | TagDefinitionWidgetPikaCompiledIn\n | TagDefinitionWidgetCustomCompiledIn\n | TagDefinitionWidgetWebComponentForCreateOrUpdate;\n\n/**\n * Tag definition for create/update operations.\n * Omits backend-managed fields and uses TagDefinitionWidgetForCreateOrUpdate which excludes\n * backend-managed fields from nested structures (like s3Bucket in web components).\n *\n * The usageMode field is optional and defaults to 'chat-app' if not provided.\n */\nexport type TagDefinitionForCreateOrUpdate<T extends TagDefinitionWidgetForCreateOrUpdate = TagDefinitionWidgetForCreateOrUpdate> = Omit<\n TagDefinition<TagDefinitionWidget>,\n 'createdBy' | 'lastUpdatedBy' | 'createDate' | 'lastUpdate' | 'widget' | 'usageMode'\n> & {\n widget: T;\n usageMode?: TagDefinitionUsageMode;\n};\n\nexport const TAG_DEFINITION_USAGE_MODES = ['global', 'chat-app'] as const;\nexport type TagDefinitionUsageMode = (typeof TAG_DEFINITION_USAGE_MODES)[number];\n\nexport const TAG_DEFINITION_WIDGET_TYPES = ['pass-through', 'pika-compiled-in', 'custom-compiled-in', 'web-component'] as const;\n\n/**\n * Pika compiled-in components are those defined as part of the compiled svelte front end code in `apps/pika-chat/src/lib/client/features/chat/message-segments/default-components/index.ts`.\n *\n * Custom compiled-in components are those defined by the user in their app as a svelte component. They are defined in `apps/pika-chat/src/lib/client/features/chat/message-segments/custom-components/index.ts`.\n *\n * Web components are those that are defined as standalone js files that are uploaded to s3 and then dynamically loaded into the front end.\n * If web-component then the `webComponent` property must be provided.\n *\n * Pass through means we will simply pass this through and not process the tag in any way. This is useful for tags that are not meant to be rendered in the front end.\n */\nexport type TagDefinitionWidgetType = (typeof TAG_DEFINITION_WIDGET_TYPES)[number];\n\nexport interface TagDefinitionWidgetPikaCompiledIn extends TagDefinitionWidgetBase {\n type: 'pika-compiled-in';\n}\n\nexport interface TagDefinitionWidgetCustomCompiledIn extends TagDefinitionWidgetBase {\n type: 'custom-compiled-in';\n}\n\nexport interface TagDefinitionWidgetWebComponent extends TagDefinitionWidgetBase {\n type: 'web-component';\n webComponent: TagDefinitionWebComponent;\n}\n\nexport interface TagDefinitionWidgetPassThrough extends TagDefinitionWidgetBase {\n type: 'pass-through';\n}\n\nexport interface TagDefinitionWidgetBase {\n /**\n * The type of widget that will be used to render this tag.\n */\n type: TagDefinitionWidgetType;\n}\n\nexport type TagDefinitionWidget = TagDefinitionWidgetPassThrough | TagDefinitionWidgetPikaCompiledIn | TagDefinitionWidgetCustomCompiledIn | TagDefinitionWidgetWebComponent;\n\nexport type TagWebComponentEncoding = 'gzip';\n\n/**\n * Preset dialog size options for web component widgets.\n * - 'fullscreen': 95vw x 90vh (default)\n * - 'large': 85vw x 80vh\n * - 'medium': 70vw x 70vh\n * - 'small': 50vw x 50vh\n */\nexport type WidgetDialogSizePreset = 'fullscreen' | 'large' | 'medium' | 'small';\n\n/**\n * Custom dimensions for dialog sizing.\n * Values must be viewport-relative units (vh, vw, vmin, vmax) or percentages.\n * Pixel values are not supported to ensure responsive behavior.\n *\n * Examples:\n * - { width: \"80vw\", height: \"70vh\" }\n * - { width: \"90%\", height: \"85%\" }\n */\nexport interface WidgetDialogSizeCustom {\n /**\n * Dialog width as viewport-relative unit or percentage.\n * Examples: \"80vw\", \"90%\", \"85vw\"\n */\n width?: string;\n\n /**\n * Dialog height as viewport-relative unit or percentage.\n * Examples: \"70vh\", \"80%\", \"60vh\"\n */\n height?: string;\n}\n\n/**\n * Sizing configuration for dialog rendering context.\n * Can be either a preset size or custom dimensions.\n */\nexport type WidgetDialogSizing = WidgetDialogSizePreset | WidgetDialogSizeCustom;\n\n/**\n * Sizing configuration for inline rendering context.\n * Inline widgets appear within the chat message flow.\n */\nexport interface WidgetInlineSizing {\n /**\n * Widget height for inline rendering.\n * Supports any valid CSS height value, or \"auto\" to grow to content height.\n * Defaults to \"400px\" if not specified.\n *\n * Special values:\n * - \"auto\": Widget grows to fit its content height (no fixed height constraint)\n *\n * Fixed height examples: \"400px\", \"50vh\", \"500px\", \"30rem\"\n */\n height?: string;\n\n /**\n * Widget width for inline rendering.\n * Reserved for future use. Currently, inline widgets always fill available width.\n *\n * Examples: \"100%\", \"80vw\", \"600px\"\n */\n width?: string;\n}\n\n/**\n * Sizing configuration for web component widgets across different rendering contexts.\n * Allows widget authors to control how their widget is sized in different visual contexts.\n */\nexport interface WidgetSizing {\n /**\n * Sizing for dialog (modal) rendering context.\n * When a widget is opened in a dialog, this controls its dimensions.\n *\n * Defaults to 'fullscreen' (95vw x 90vh) if not specified.\n */\n dialog?: WidgetDialogSizing;\n\n /**\n * Sizing for inline rendering context.\n * When a widget is rendered inline within a chat message.\n *\n * Defaults to { height: \"400px\" } if not specified.\n */\n inline?: WidgetInlineSizing;\n}\n\nexport interface TagDefinitionWebComponent {\n /**\n * Direct URL to the web component JavaScript file.\n * Use this if the component is hosted externally (CDN, separate server, etc.)\n *\n * Either `url` OR `s3` must be provided, but not both.\n */\n url?: string;\n\n /**\n * S3 location of the web component JavaScript file in the Pika S3 bucket.\n * If provided, the system will serve it via /api/webcomponent/:scope/:tag\n *\n * Either `url` OR `s3` must be provided, but not both.\n */\n s3?: {\n /** Must be the Pika system S3 bucket (retrieved from SSM parameter) */\n s3Bucket: string;\n /** Must follow pattern: wc/${scope}/fileName.js.gz */\n s3Key: string;\n };\n\n /**\n * The actual custom element name that the JavaScript file defines.\n * This is the name used in customElements.define() in the JavaScript file.\n *\n * If not provided, defaults to `${scope}.${tag}` (e.g., \"pika.mock-spotlight-1\").\n *\n * Use this when:\n * - The JavaScript file defines a custom element with a different name than the tag\n * - Multiple tag definitions share the same JavaScript file that defines one custom element\n * - A JavaScript bundle file defines multiple custom elements\n *\n * Examples:\n * - \"hello-world\" for a file that calls customElements.define(\"hello-world\", ...)\n * - \"my-widget\" for a file that calls customElements.define(\"my-widget\", ...)\n */\n customElementName?: string;\n\n /**\n * Optional sizing configuration for this widget across different rendering contexts.\n *\n * If not provided, defaults are:\n * - dialog: 'fullscreen' (95vw x 90vh)\n * - inline: { height: \"400px\" }\n *\n * Examples:\n * ```typescript\n * // Preset dialog size\n * sizing: { dialog: 'medium', inline: { height: '300px' } }\n *\n * // Custom dialog size\n * sizing: { dialog: { width: '80vw', height: '60vh' } }\n *\n * // Only specify inline height\n * sizing: { inline: { height: '500px' } }\n * ```\n */\n sizing?: WidgetSizing;\n\n encoding: TagWebComponentEncoding;\n mediaType: 'application/javascript';\n encodedSizeBytes: number; // size of the stored object (post-encoding)\n\n /**\n * Hash of the GZIPPED file bytes as stored in S3 (NOT the decompressed JavaScript).\n * This hash is used for integrity validation when serving the file from S3.\n * When uploading to S3: hash = SHA256(gzippedBytes).toBase64()\n * When serving: compare stored hash to SHA256(gzippedBytesFromS3).toBase64()\n */\n encodedSha256Base64: string;\n}\n\nexport interface TagDefinitionCreateOrUpdateRequest {\n tagDefinition: TagDefinitionForCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\nexport interface TagDefinitionCreateOrUpdateResponse {\n success: boolean;\n tagDefinition: TagDefinition<TagDefinitionWidget>;\n}\n\n/**\n * Search for tag definitions with two primary modes:\n *\n * MODE 1 - Get specific tags (optionally including globals):\n * - Pass tagsDesired array for specific tags to retrieve\n * - Set includeGlobal=true to also include all global tags\n * - Uses primary key lookup (scope + tag) for specified tags\n * - Uses GSI (scope-status-index) for global tags if includeGlobal=true\n * - Returns requested tags + global tags (if includeGlobal=true)\n *\n * MODE 2 - Get all tags:\n * - Don't pass tagsDesired or includeGlobal\n * - Scans entire table with pagination\n * - Returns all tag definitions\n *\n * If used in admin context, returns all tag definitions (including disabled/retired).\n * If used in chat app context, filters to only 'enabled' status.\n */\nexport interface TagDefinitionSearchRequest {\n /** Specific tags to retrieve by scope+tag */\n tagsDesired?: TagDefinitionLite[];\n\n /** If true, also includes all global tags (usageMode='global') in addition to tagsDesired */\n includeGlobal?: boolean;\n\n /** If not true, instructions will not be returned to save space */\n includeInstructions?: boolean;\n\n /** Pagination token for continued queries */\n paginationToken?: Record<string, any> | undefined;\n}\n\nexport interface TagDefinitionSearchResponse {\n success: boolean;\n tagDefinitions: TagDefinition<TagDefinitionWidget>[];\n\n /** If this is present, there are more records that could be returned. Pass this token in to get the next page with the same request. */\n paginationToken?: Record<string, any> | undefined;\n}\n\nexport interface TagDefinitionDeleteRequest {\n tagDefinition: TagDefinitionLite;\n userId: string;\n}\n\nexport interface TagDefinitionDeleteResponse {\n success: boolean;\n}\n\nexport interface TagDefinitionsJsonFile {\n tagDefs: TagDefInJsonFile[];\n}\n\nexport interface TagDefInJsonFile {\n tag: string;\n scope: string;\n gzippedBase64EncodedString: string;\n}\n\n// ===== SHARING SESSIONS FEATURE TYPES =====\n\n/**\n * SharedSessionVisitHistory tracks user visits to shared sessions\n */\nexport interface SharedSessionVisitHistory {\n shareId: string;\n entityId: string;\n chatAppId: string;\n firstVisitedAt: string;\n lastVisitedAt: string;\n visitCount: number;\n title: string;\n\n /** If set to 'mock', this is a test shared session visit history. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport interface SharedSessionVisitHistoryDynamoDb extends SharedSessionVisitHistory {\n userIdChatAppId: string;\n}\n\n/**\n * PinnedSession represents user-curated sidebar items (both own and shared sessions)\n */\nexport interface PinnedSession {\n shareId?: string; // for shared sessions\n sessionId?: string; // for own sessions\n userId: string; // the user who did the pinning, will be userId of session if pin is for own session\n chatAppId: string;\n pinnedAt: string;\n\n /** If set to 'mock', this is a test pinned session. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport type PinnedSessionDynamoDb = PinnedSession & {\n userIdChatAppId: string;\n sessionOrShareId: string;\n};\n\nexport interface PinnedObjAndChatSession {\n pinnedSession: PinnedSession;\n chatSession: ChatSession<RecordOrUndef>;\n}\n\n// API Request/Response types\n\nexport interface CreateSharedSessionRequest {\n sessionId: string;\n sessionUserId: string;\n chatAppId: string;\n}\n\nexport interface CreateSharedSessionResponse {\n success: boolean;\n shareId: string;\n chatAppId: string;\n error?: string;\n}\n\nexport interface RevokeSharedSessionRequest {\n shareId: string;\n}\n\nexport interface RevokeSharedSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface UnrevokeSharedSessionRequest {\n shareId: string;\n}\n\nexport interface UnrevokeSharedSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface GetRecentSharedRequest {\n chatAppId: string;\n limit?: number; // default 5\n entityId?: string; // entity id to filter by\n nextToken?: string; // pagination token\n}\n\nexport interface GetRecentSharedResponse {\n success: boolean;\n recentShared: SharedSessionVisitHistory[];\n error?: string;\n nextToken?: string; // pagination token\n}\n\nexport interface GetPinnedSessionsRequest {\n chatAppId: string;\n limit?: number; // default 20\n nextToken?: string; // pagination token\n}\n\nexport interface GetPinnedSessionsResponse {\n success: boolean;\n results: PinnedObjAndChatSession[];\n nextToken?: string; // for pagination\n error?: string;\n}\n\nexport interface PinSessionRequest {\n pinnedSession: PinnedSession;\n}\n\nexport interface PinSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface UnpinSessionRequest {\n sessionId?: string; // for own sessions\n shareId?: string; // for shared sessions\n chatAppId: string;\n}\n\nexport interface UnpinSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface ValidateShareAccessRequest {\n shareId: string;\n chatAppId: string;\n entityId?: string;\n}\n\nexport interface ValidateShareAccessResponse {\n success: boolean;\n hasAccess: boolean;\n sessionData?: ChatSession<RecordOrUndef>;\n error?: string;\n}\n\nexport interface RecordShareVisitRequest {\n shareId: string;\n}\n\nexport interface RecordShareVisitResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface ShowToastOptions {\n type: 'success' | 'error' | 'warning' | 'info';\n duration?: number | 'infinite';\n}\n\nexport type ShowToastFn = (message: string, options: ShowToastOptions) => void;\n\nexport const ShareSessionStateList = ['disable-share-feature', 'shared-by-me', 'shared-by-someone-else', 'not-shared'] as const;\nexport type ShareSessionState = (typeof ShareSessionStateList)[number];\n\n/**\n * Options for invokeAgentAsComponent() method\n */\nexport interface InvokeAgentAsComponentOptions {\n /**\n * Callback for streaming traces from the agent\n */\n onTrace?: (trace: any) => void;\n\n /**\n * Callback for progress updates (partial JSON text as it streams)\n */\n onProgress?: (partialText: string) => void;\n\n /**\n * Callback for agent thinking/rationale\n */\n onThinking?: (rationale: string) => void;\n\n /**\n * Callback for tool invocations\n */\n onToolCall?: (toolCall: { name: string; params: any }) => void;\n\n /**\n * Whether to include full traces in callbacks (default: false)\n */\n includeTraces?: boolean;\n\n /**\n * Request timeout in milliseconds (default: 60000)\n */\n timeout?: number;\n\n /**\n * The source of the converse request. Defaults to 'user'. The composite key chat_app_sk looks like this:\n *\n * ${chatAppId}#${source}#${updateDate}\n *\n * The source in the composite key here will only ever be either `user` or `component`. If this attribute's value is missing or is `user` or `component-as-user`,\n * then the composite key will be set to `user` so when we query on behalf of the user, we will get all sessions for that user.\n */\n source: ConverseSource;\n}\n\n/**\n * A single action button that will appear at the top of the chat app in the title bar or\n * that will appear in a button menu that pops up when the user clicks the title bar action button.\n *\n * @example\n * ```js\n * const action: ChatAppAction = {\n * id: 'refresh',\n * title: 'Refresh',\n * iconSvg: '<svg>...</svg>',\n * callback: () => refresh()\n * };\n * ```\n */\nexport interface ChatAppAction {\n /** Unique identifier for this action */\n id: string;\n /** Discriminator for the type */\n type: 'action';\n\n /** Tooltip or menu item description for the action */\n title: string;\n\n /** SVG markup string for the icon (e.g., from extractIconSvg() helper) */\n iconSvg: string;\n\n /** Whether action is currently disabled */\n disabled?: boolean;\n\n /** Handler when clicked */\n callback: () => void | Promise<void>;\n}\n\n/**\n * The only reason to use this is to get a title for the action group.\n */\nexport interface ChatAppActionGroup {\n /** Discriminator for the type */\n type: 'group';\n /** Title of the action group. The whole point of an action group is to get a title above the group. */\n title: string;\n /** Actions to display in the group */\n actions: (ChatAppAction | 'separator')[];\n}\n\n/**\n * The elements that can be displayed in a ChatAppActionMenu.\n */\nexport type ChatAppActionMenuElements = ChatAppActionGroup | ChatAppAction | 'separator';\n\n/**\n * Widgets can register a single icon button or icon button with a menu that will appear at the top of the chat app in the title bar.\n */\nexport interface ChatAppActionMenu {\n /** Unique identifier for this action */\n id: string;\n /** Tooltip/label for the action (also button text in dialog context) */\n title: string;\n /** SVG markup string for the icon (e.g., from extractIconSvg() helper) */\n iconSvg: string;\n /** Whether the action menu is currently disabled */\n disabled?: boolean;\n /**\n * Actions to display in the menu\n * Here are some common examples:\n * - [\n * { type: 'action', id: 'refresh', title: 'Refresh', iconSvg: '<svg>...</svg>', callback: () => refresh() },\n * 'separator',\n * { id: 'settings', title: 'Settings', iconSvg: '<svg>...</svg>', callback: () => showSettings() }\n * ]\n * - [\n * { type: 'group', title: 'Settings', actions: [\n * { type: 'action', id: 'refresh', title: 'Refresh', iconSvg: '<svg>...</svg>', callback: () => refresh() },\n * 'separator',\n * { type: 'action', id: 'settings', title: 'Settings', iconSvg: '<svg>...</svg>', callback: () => showSettings() }\n * ] }\n * ]\n */\n actions: ChatAppActionMenuElements[];\n}\n\nexport interface IUserWidgetDataStoreState {\n readonly initialized: boolean;\n readonly data: UserWidgetData | undefined;\n readonly showToast: ShowToastFn;\n refreshDataFromServer(): Promise<void>;\n getValue<T>(key: string): Promise<T | undefined>;\n setValue(key: string, value: unknown): Promise<void>;\n deleteValue(key: string): Promise<void>;\n}\n\n/**\n * Represents a unit of contextual information that can be considered for inclusion\n * in an LLM prompt when responding to a user's request.\n */\nexport interface LLMContextItem {\n /** A unique identifier for this context item. */\n id: string;\n\n /**\n * A short natural-language summary describing what this context is about.\n * Used by smaller / cheaper LLMs to determine if this item is relevant\n * to the user's current query.\n */\n description: string;\n\n /**\n * The actual contextual content that can be inserted into the LLM prompt\n * if deemed relevant by the model.\n */\n context: unknown;\n\n /** Whether this was added automatically by the component or by the user */\n origin: WidgetContextSourceOrigin;\n\n /** SHA-256 hash of the content, used to detect changes. */\n contentHash: string;\n\n /** ISO-8601 timestamp of when this context was last updated. */\n lastUpdated: string;\n\n /**\n * Optional expiration for the cached context.\n * - `0` means it is always considered \"changed\" (always re-included).\n * - If omitted, re-inclusion depends on hash changes.\n * - If set, after this duration (in ms), the context is considered stale\n * and should be re-fetched or re-included even if the hash is unchanged.\n */\n maxAgeMs?: number;\n}\n\n/**\n * Here is a generic source of context that can be added to the conversation.\n */\nexport interface ContextSourceDef {\n /** A unique identifier for this context source. Must be unique system wide so be sure. Used for caching and tracking. */\n sourceId: string;\n\n /**\n * This is a description that will be given an LLM before the agent is invoked to determine if this context should be included in the prompt.\n * It will be given a list of all contexts that are available, the inquiry from the user and then asked which\n * contexts should be included in the prompt.\n */\n llmInclusionDescription: string;\n\n /** Whether this was added automatically by the component or by the user */\n origin: WidgetContextSourceOrigin;\n\n /** The name of the lucide icon to show the user to represent this context. A default will be used if not provided. */\n lucideIconName?: string;\n\n /** The title of the context. This will be shown to the user as the name of this context. */\n title: string;\n\n /** The description of the context. This will be shown to the user as the description of this context. */\n description: string;\n\n /** The data to include in the context. This will be sent to the agent as the context. */\n data: unknown;\n\n /** Whether to add this context automatically when the component is added to the conversation. */\n addAutomatically?: boolean;\n\n /**\n * Optional expiration for the cached context.\n * - `0` means it is always considered \"changed\" (always re-included).\n * - If omitted, re-inclusion depends on hash changes.\n * - If set, after this duration (in ms), the context is considered stale\n * and should be re-fetched or re-included even if the hash is unchanged.\n */\n maxAgeMs?: number;\n}\n\nexport const WidgetContextSourceOrigins = ['user', 'auto'] as const;\nexport type WidgetContextSourceOrigin = (typeof WidgetContextSourceOrigins)[number];\n\n/**\n * Components that have a getContext method will return a ContextSourceDef\n * object and then Pika will include the instanceId and store it as a\n * WidgetContextSourceDef so it knows the source of the context is\n * a widget.\n */\nexport interface WidgetContextSourceDef extends ContextSourceDef {\n type: 'widget';\n\n /** The web component instance ID that is adding the context. This is used to identify the instance of the component that is adding the context. */\n instanceId: string;\n}\n\n/** These are what get added to the converstaion state as context sources. */\nexport type ContextSource = WidgetContextSourceDef;\n\n/**\n * Session Analytics Types\n * Used for the Session Analytics dashboard to show platform usage metrics, cost analytics, and at-a-glance KPIs.\n */\n\nexport interface SessionAnalyticsRequest {\n /** Date range for the analytics query (ISO 8601 formatted strings) */\n dateRange: {\n start: string;\n end: string;\n };\n /** Optional filter by specific entity ID */\n entityId?: string;\n /** Entity attribute name from siteFeatures, used for entity aggregations */\n entityAttributeName?: string;\n /** Optional filter by specific chat app IDs */\n chatAppIds?: string[];\n /** Optional filter by user types (internal-user, external-user) */\n userTypes?: UserType[];\n /** Optional filter by invocation modes. Defaults to undefined and 'chat-app' (user-initiated only) if not provided. */\n invocationModes?: (ConverseInvocationMode | 'undefined')[];\n /** Time grouping for time series data (day, week, month) */\n groupBy?: 'day' | 'week' | 'month';\n /** Limit for top entities/chat apps results */\n limit?: number;\n}\n\nexport interface SessionAnalyticsResponse {\n /** Whether the request was successful */\n success: boolean;\n /** Error message if success is false */\n error?: string;\n /** Summary metrics across the entire date range */\n summary: SessionAnalyticsSummary;\n /** Time series data points */\n timeSeries: SessionAnalyticsTimeSeriesPoint[];\n /** Top entities by usage (only populated if entityAttributeName was provided) */\n topEntities: SessionAnalyticsEntityUsage[];\n /** Top chat apps by usage */\n topChatApps: SessionAnalyticsChatAppUsage[];\n /** Cost breakdown by invocation mode */\n costByInvocationMode: SessionAnalyticsCostByMode[];\n}\n\nexport interface SessionAnalyticsSummary {\n /** Total number of sessions */\n totalSessions: number;\n /** Number of unique users */\n uniqueUsers: number;\n /** Number of unique entities (only populated if entity feature enabled) */\n uniqueEntities?: number;\n /** Total number of messages across all sessions */\n totalMessages: number;\n /** Total input tokens consumed */\n totalInputTokens: number;\n /** Total output tokens generated */\n totalOutputTokens: number;\n /** Total input cost in USD */\n totalInputCost: number;\n /** Total output cost in USD */\n totalOutputCost: number;\n /** Total cost (input + output) in USD */\n totalCost: number;\n /** Average cost per session in USD */\n avgCostPerSession: number;\n /** Average tokens per session */\n avgTokensPerSession: number;\n}\n\nexport interface SessionAnalyticsTimeSeriesPoint {\n /** ISO 8601 formatted date for this data point */\n date: string;\n /** Number of sessions in this time period */\n sessionCount: number;\n /** Number of unique users in this time period */\n uniqueUserCount: number;\n /** Number of messages in this time period */\n messageCount: number;\n /** Input tokens consumed in this time period */\n inputTokens: number;\n /** Output tokens generated in this time period */\n outputTokens: number;\n /** Input cost in USD for this time period */\n inputCost: number;\n /** Output cost in USD for this time period */\n outputCost: number;\n /** Total cost in USD for this time period */\n totalCost: number;\n}\n\nexport interface SessionAnalyticsEntityUsage {\n /** Entity identifier */\n entityId: string;\n /** Entity name (human-readable) */\n entityName?: string;\n /** Number of sessions for this entity */\n sessionCount: number;\n /** Number of unique users for this entity */\n uniqueUserCount: number;\n /** Number of messages for this entity */\n messageCount: number;\n /** Total cost in USD for this entity */\n totalCost: number;\n /** Input tokens consumed for this entity */\n inputTokens: number;\n /** Output tokens generated for this entity */\n outputTokens: number;\n}\n\nexport interface SessionAnalyticsChatAppUsage {\n /** Chat app identifier */\n chatAppId: string;\n /** Chat app name (human-readable) */\n chatAppName?: string;\n /** Number of sessions for this chat app */\n sessionCount: number;\n /** Number of unique users for this chat app */\n uniqueUserCount: number;\n /** Number of messages for this chat app */\n messageCount: number;\n /** Total cost in USD for this chat app */\n totalCost: number;\n /** Input tokens consumed for this chat app */\n inputTokens: number;\n /** Output tokens generated for this chat app */\n outputTokens: number;\n}\n\nexport interface SessionAnalyticsCostByMode {\n /** Invocation mode (including 'undefined' for missing/undefined mode) */\n invocationMode: string;\n /** Number of sessions for this mode */\n sessionCount: number;\n /** Total cost in USD for this mode */\n totalCost: number;\n /** Input cost in USD for this mode */\n inputCost: number;\n /** Output cost in USD for this mode */\n outputCost: number;\n /** Input tokens consumed for this mode */\n inputTokens: number;\n /** Output tokens generated for this mode */\n outputTokens: number;\n /** Human-readable description of the mode */\n description: string;\n}\n","/**\n * These are utils that should only be used on the server in svelte kit and\n * in lambda functions.\n */\nimport { gunzipSync, gzipSync } from 'zlib';\nimport {\n DEFAULT_MAX_K_MATCHES_PER_STRATEGY,\n DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT,\n type AccessRules,\n type AuthenticatedUser,\n type ChatApp,\n type ChatAppOverridableFeatures,\n type ChatUser,\n type RecordOrUndef,\n type SiteFeatures,\n type TagDefinitionLite\n} from '../types/chatbot/chatbot-types';\n\nexport function gunzipBase64EncodedString(base64EncodedString: string): string {\n const gzippedHexEncodedString = Buffer.from(base64EncodedString, 'base64').toString('hex');\n const gzippedHexDecodedString = gunzipSync(Buffer.from(gzippedHexEncodedString, 'hex')).toString();\n return gzippedHexDecodedString;\n}\n\nexport function gzipAndBase64EncodeString(string: string): string {\n const gzippedHexEncodedString = gzipSync(string).toString('hex');\n const gzippedBase64EncodedString = Buffer.from(gzippedHexEncodedString, 'hex').toString('base64');\n return gzippedBase64EncodedString;\n}\n\n/**\n * Compute what features the user is and isn't allowed to use for this chat app.\n *\n * Feature hierarchy (in order of precedence):\n * 1. Site level (<root>/pika-config.ts) - Controls ultimate availability\n * 2. Chat app level (chatApp.features) - Can override site settings\n * 3. Admin override level (chatApp.override.features) - Can override chat app settings\n *\n * Note that we always return siteAdmin: { websiteEnabled: false } because we only check that for real when they try to access the admin page itself.\n *\n * Override rules:\n * - Site level controls whether a feature can be used at all\n * - Chat apps can override site level (but only to restrict)\n * - Admins can override chat app level completely (but cannot enable features disabled at site level)\n * - When overriding, complete feature configuration must be provided (no merging)\n */\nexport function getOverridableFeatures(siteFeatures: SiteFeatures, chatApp: ChatApp, user: AuthenticatedUser<RecordOrUndef, RecordOrUndef>): ChatAppOverridableFeatures {\n const result: ChatAppOverridableFeatures = {\n entity: {\n enabled: false\n },\n verifyResponse: {\n enabled: false\n },\n traces: {\n enabled: false,\n detailedTraces: false\n },\n fileUpload: {\n mimeTypesAllowed: [] as string[]\n },\n suggestions: {\n suggestions: [] as string[],\n randomize: false,\n randomizeAfter: 0,\n maxToShow: 5\n },\n promptInputFieldLabel: {\n label: undefined\n },\n uiCustomization: {\n showUserRegionInLeftNav: false,\n showChatHistoryInStandaloneMode: false\n },\n chatDisclaimerNotice: undefined,\n logout: {\n enabled: false,\n menuItemTitle: 'Logout',\n dialogTitle: 'Logout',\n dialogDescription: 'Are you sure you want to logout?'\n },\n siteAdmin: {\n websiteEnabled: false\n },\n tags: {\n tagsEnabled: [] as TagDefinitionLite[],\n tagsDisabled: [] as TagDefinitionLite[]\n },\n agentInstructionAssistance: {\n enabled: false,\n includeOutputFormattingRequirements: false,\n includeInstructionsForTags: false,\n completeExampleInstructionEnabled: false,\n completeExampleInstructionLine: undefined,\n jsonOnlyImperativeInstructionEnabled: false,\n jsonOnlyImperativeInstructionLine: undefined,\n includeTypescriptBackedOutputFormattingRequirements: false,\n typescriptBackedOutputFormattingRequirements: undefined\n },\n instructionAugmentation: {\n enabled: false,\n type: undefined\n },\n userMemory: {\n enabled: false,\n maxMemoryRecordsPerPrompt: DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT,\n maxKMatchesPerStrategy: DEFAULT_MAX_K_MATCHES_PER_STRATEGY\n }\n };\n\n // Handle verifyResponse feature\n // Admin override takes precedence over chat app configuration\n const effectiveVerifyResponseFeature = chatApp.override?.features?.verifyResponse || chatApp.features?.verifyResponse;\n result.verifyResponse = handleAccessRuleFeature(\n 'verifyResponse',\n effectiveVerifyResponseFeature,\n siteFeatures?.verifyResponse,\n result.verifyResponse,\n user,\n (feature, enabled) => ({\n enabled,\n autoRepromptThreshold: feature.autoRepromptThreshold\n })\n );\n\n // Handle traces feature (has sub-feature for detailedTraces)\n // Admin override takes precedence over chat app configuration\n const effectiveTracesFeature = chatApp.override?.features?.traces || chatApp.features?.traces;\n result.traces = handleAccessRuleFeature('traces', effectiveTracesFeature, siteFeatures?.traces, result.traces, user, (feature, enabled) => {\n let detailedTraces = false;\n if (enabled && feature.detailedTraces) {\n // Check site-level gating for detailedTraces\n const siteDetailedTracesRule = siteFeatures?.traces?.detailedTraces || { enabled: false };\n if (siteDetailedTracesRule.enabled) {\n detailedTraces = checkUserAccessToFeature(user, feature.detailedTraces as AccessRules);\n }\n } else if (enabled) {\n // No app/admin override for detailedTraces, use site level\n const siteDetailedTracesRule = siteFeatures?.traces?.detailedTraces || { enabled: false };\n detailedTraces = checkUserAccessToFeature(user, siteDetailedTracesRule);\n }\n return {\n enabled,\n detailedTraces\n };\n });\n\n // Handle logout feature\n // Admin override takes precedence over chat app configuration\n const effectiveLogoutFeature = chatApp.override?.features?.logout || chatApp.features?.logout;\n result.logout = handleAccessRuleFeature('logout', effectiveLogoutFeature, siteFeatures?.logout, result.logout, user, (feature, enabled) => ({\n enabled,\n menuItemTitle: feature.menuItemTitle ?? 'Logout',\n dialogTitle: feature.dialogTitle ?? 'Logout',\n dialogDescription: feature.dialogDescription ?? 'Are you sure you want to logout?'\n }));\n\n // Handle fileUpload feature\n // Admin override takes precedence over chat app configuration\n const effectiveFileUploadFeature = chatApp.override?.features?.fileUpload || chatApp.features?.fileUpload;\n result.fileUpload = handleSimpleFeature('fileUpload', effectiveFileUploadFeature, siteFeatures?.fileUpload, result.fileUpload, (feature) => ({\n mimeTypesAllowed: feature.mimeTypesAllowed || []\n }));\n\n // Handle suggestions feature\n // Admin override takes precedence over chat app configuration\n const effectiveSuggestionsFeature = chatApp.override?.features?.suggestions || chatApp.features?.suggestions;\n result.suggestions = handleSimpleFeature('suggestions', effectiveSuggestionsFeature, siteFeatures?.suggestions, result.suggestions, (feature) => ({\n suggestions: feature.suggestions || [],\n randomize: feature.randomize ?? false,\n randomizeAfter: feature.randomizeAfter ?? 0,\n maxToShow: feature.maxToShow ?? 5\n }));\n\n // Handle promptInputFieldLabel feature\n // Admin override takes precedence over chat app configuration\n const effectivePromptInputFieldLabelFeature = chatApp.override?.features?.promptInputFieldLabel || chatApp.features?.promptInputFieldLabel;\n result.promptInputFieldLabel = handleEnabledOnlyFeature(\n 'promptInputFieldLabel',\n effectivePromptInputFieldLabelFeature,\n siteFeatures?.promptInputFieldLabel,\n { label: 'Ready to chat' }, // Default return shape\n (feature, enabled) => ({\n label: enabled ? (feature.promptInputFieldLabel ?? 'Ready to chat') : undefined\n })\n );\n\n // Handle uiCustomization feature\n // Admin override takes precedence over chat app configuration\n const effectiveUiCustomizationFeature = chatApp.override?.features?.uiCustomization || chatApp.features?.uiCustomization;\n result.uiCustomization = handleSimpleFeature('uiCustomization', effectiveUiCustomizationFeature, siteFeatures?.uiCustomization, result.uiCustomization, (feature) => ({\n showUserRegionInLeftNav: feature.showUserRegionInLeftNav ?? false,\n showChatHistoryInStandaloneMode: feature.showChatHistoryInStandaloneMode ?? false\n }));\n\n // Handle chatDisclaimerNotice feature\n // Admin override takes precedence over chat app configuration\n const effectiveChatDisclaimerNoticeFeature = chatApp.override?.features?.chatDisclaimerNotice || chatApp.features?.chatDisclaimerNotice;\n const disclaimerResult = handleEnabledOnlyFeature(\n 'chatDisclaimerNotice',\n effectiveChatDisclaimerNoticeFeature,\n siteFeatures?.chatDisclaimerNotice,\n { notice: undefined },\n (feature, enabled) => ({\n notice: enabled ? feature.notice : undefined\n })\n );\n result.chatDisclaimerNotice = disclaimerResult.notice;\n\n // Handle tags feature\n // Admin override takes precedence over chat app configuration\n const effectiveTagsFeature = chatApp.override?.features?.tags || chatApp.features?.tags;\n result.tags = handleSimpleFeature('tags', effectiveTagsFeature, siteFeatures?.tags, result.tags, (feature) => ({\n tagsEnabled: feature.tagsEnabled ?? [],\n tagsDisabled: feature.tagsDisabled ?? []\n }));\n\n // Handle agentInstructionAssistance feature\n // Admin override takes precedence over chat app configuration\n const effectiveAgentInstructionAssistanceFeature = chatApp.override?.features?.agentInstructionAssistance || chatApp.features?.agentInstructionAssistance;\n result.agentInstructionAssistance = handleSimpleFeature(\n 'agentInstructionAssistance',\n effectiveAgentInstructionAssistanceFeature,\n siteFeatures?.agentInstructionAssistance,\n result.agentInstructionAssistance,\n (feature) => ({\n enabled: feature.enabled ?? false,\n includeOutputFormattingRequirements: feature.includeOutputFormattingRequirements?.enabled ?? false,\n includeInstructionsForTags: feature.includeInstructionsForTags?.enabled ?? false,\n completeExampleInstructionEnabled: feature.completeExampleInstructionLine?.enabled ?? false,\n completeExampleInstructionLine: feature.completeExampleInstructionLine?.mdLine ?? undefined,\n jsonOnlyImperativeInstructionEnabled: feature.jsonOnlyImperativeInstructionLine?.enabled ?? false,\n jsonOnlyImperativeInstructionLine: feature.jsonOnlyImperativeInstructionLine?.line ?? undefined,\n includeTypescriptBackedOutputFormattingRequirements: feature.includeTypescriptBackedOutputFormattingRequirements?.enabled ?? false,\n typescriptBackedOutputFormattingRequirements: feature.typescriptBackedOutputFormattingRequirements ?? undefined\n })\n );\n\n // Handle instructionAugmentation feature\n // Admin override takes precedence over chat app configuration\n const effectiveInstructionAugmentationFeature = chatApp.override?.features?.instructionAugmentation || chatApp.features?.instructionAugmentation;\n result.instructionAugmentation = handleSimpleFeature(\n 'instructionAugmentation',\n effectiveInstructionAugmentationFeature,\n siteFeatures?.instructionAugmentation,\n result.instructionAugmentation,\n (feature) => ({\n enabled: feature.enabled ?? false,\n type: feature.type ?? 'llm-semantic-directive-search'\n })\n );\n\n // Handle userMemory feature\n // Admin override takes precedence over chat app configuration\n const effectiveUserMemoryFeature = chatApp.override?.features?.userMemory || chatApp.features?.userMemory;\n result.userMemory = handleSimpleFeature('userMemory', effectiveUserMemoryFeature, siteFeatures?.userMemory, result.userMemory, (feature) => ({\n enabled: feature.enabled ?? false,\n maxMemoryRecordsPerPrompt: feature.maxMemoryRecordsPerPrompt ?? DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT,\n maxKMatchesPerStrategy: feature.maxKMatchesPerStrategy ?? DEFAULT_MAX_K_MATCHES_PER_STRATEGY\n }));\n\n // Handle entity feature\n // Entity feature is special: it can only be disabled at chat app level, not enabled\n // If site has entity enabled, chat apps can override to disable it\n // Admin override takes precedence over chat app configuration\n const effectiveEntityFeature = chatApp.override?.features?.entity || chatApp.features?.entity;\n if (siteFeatures?.entity?.enabled) {\n // Site has entity enabled, check if chat app or admin has disabled it\n if (effectiveEntityFeature?.enabled === false) {\n result.entity.enabled = false;\n } else {\n // No override to disable, so it's enabled (follows site config)\n result.entity.enabled = true;\n if (!siteFeatures?.entity?.attributeName) {\n throw new Error('Entity feature is enabled at the site level but the site features entity object does not have an attributeName set');\n }\n result.entity.attributeName = siteFeatures.entity.attributeName;\n }\n } else {\n // Site doesn't have entity enabled, so it's disabled regardless of chat app config\n result.entity.enabled = false;\n }\n\n return result;\n}\n\n/**\n * Generic handler for simple features (no access rules).\n *\n * @param featureName - Name of the feature for logging\n * @param appFeature - App-level feature configuration\n * @param siteFeature - Site-level feature configuration\n * @param defaults - Default values for the feature\n * @param propertyExtractor - Function to extract properties from feature config\n * @returns The resolved feature configuration\n */\nfunction handleSimpleFeature<T>(featureName: string, appFeature: any, siteFeature: any, defaults: T, propertyExtractor: (feature: any) => T): T {\n if (isSimpleFeatureOverrideValid(appFeature, featureName) && appFeature) {\n return propertyExtractor(appFeature);\n } else {\n // Use site level or defaults\n const siteRule = siteFeature || defaults;\n return propertyExtractor(siteRule);\n }\n}\n\n/**\n * Generic handler for features with enabled flag but no user access control.\n * If enabled, the feature is on for all users. If disabled, it's off for all users.\n *\n * @param featureName - Name of the feature for logging\n * @param appFeature - App-level feature configuration\n * @param siteFeature - Site-level feature configuration\n * @param defaults - Default values for the feature\n * @param propertyExtractor - Function to extract properties from feature config\n * @returns The resolved feature configuration\n */\nfunction handleEnabledOnlyFeature<T>(featureName: string, appFeature: any, siteFeature: any, defaults: T, propertyExtractor: (feature: any, enabled: boolean) => T): T {\n const overrideStatus = isFeatureOverrideValid(appFeature, featureName);\n\n if (overrideStatus === 'enabled' && appFeature) {\n // Site-level gating: if site is disabled, app can't enable it\n const siteRule = siteFeature || { enabled: false };\n if (siteRule.enabled) {\n return propertyExtractor(appFeature, true);\n }\n return propertyExtractor({}, false); // Pass empty object when disabled\n } else if (overrideStatus === 'disabled') {\n return propertyExtractor({}, false); // Pass empty object when disabled\n } else {\n // Use site level or defaults\n const siteRule = siteFeature || { enabled: true }; // Default enabled for this feature\n return propertyExtractor(siteRule, siteRule.enabled);\n }\n}\n\n/**\n * Validates if a feature override is valid and returns its status.\n *\n * @param appFeature - The app-level feature configuration\n * @param featureName - The name of the feature for error logging\n * @returns The status of the override: 'enabled', 'disabled', 'invalid', or 'none'\n */\nfunction isFeatureOverrideValid(appFeature: any, featureName: string): 'enabled' | 'disabled' | 'invalid' | 'none' {\n if (!appFeature) return 'none';\n\n // Empty object is invalid\n if (Object.keys(appFeature).length === 0) {\n console.error(`Invalid empty feature override for ${featureName}. Falling back to site level.`);\n return 'invalid';\n }\n\n // Must have enabled property to be valid (except for simple features)\n if (!('enabled' in appFeature)) {\n console.error(`Invalid feature override for ${featureName}: missing 'enabled' property. Falling back to site level.`);\n return 'invalid';\n }\n\n return appFeature.enabled ? 'enabled' : 'disabled';\n}\n\n/**\n * Validates if a simple feature override (no access rules) is valid.\n *\n * @param appFeature - The app-level feature configuration\n * @param featureName - The name of the feature for error logging\n * @returns Whether the override is valid\n */\nfunction isSimpleFeatureOverrideValid(appFeature: any, featureName: string): boolean {\n if (!appFeature) return false;\n\n // Empty object is invalid\n if (Object.keys(appFeature).length === 0) {\n console.error(`Invalid empty feature override for ${featureName}. Falling back to site level.`);\n return false;\n }\n\n return true;\n}\n\n/**\n * Generic handler for features with access rules (enabled property + user access control).\n *\n * @param featureName - Name of the feature for logging\n * @param appFeature - App-level feature configuration\n * @param siteFeature - Site-level feature configuration\n * @param defaults - Default values for the feature\n * @param user - The authenticated user\n * @param propertyExtractor - Function to extract properties from feature config\n * @returns The resolved feature configuration\n */\nfunction handleAccessRuleFeature<T>(\n featureName: string,\n appFeature: any,\n siteFeature: any,\n defaults: T,\n user: AuthenticatedUser<RecordOrUndef, RecordOrUndef>,\n propertyExtractor: (feature: any, enabled: boolean) => T\n): T {\n const overrideStatus = isFeatureOverrideValid(appFeature, featureName);\n\n if (overrideStatus === 'enabled' && appFeature) {\n // Site-level gating: if site is disabled, app can't enable it\n const siteRule = siteFeature || { enabled: false };\n if (siteRule.enabled) {\n const enabled = checkUserAccessToFeature(user, appFeature as AccessRules);\n return propertyExtractor(appFeature, enabled);\n }\n return propertyExtractor(defaults, false);\n } else if (overrideStatus === 'disabled') {\n return propertyExtractor(defaults, false);\n } else {\n // Use site level or defaults\n const siteRule = siteFeature || { enabled: false };\n const enabled = checkUserAccessToFeature(user, siteRule);\n return propertyExtractor(siteRule, enabled);\n }\n}\n\n/**\n * Generic function to check if a user has access to a feature based on user types and roles.\n * This implements the same logic used in get for checking user access rules.\n *\n * **Access Control Logic:**\n * - If the feature is disabled (`enabled: false`), no access regardless of other rules\n * - If no userTypes or userRoles are specified, no access is granted (secure by default)\n * - If multiple userTypes are provided, a user need only have one of them to have access (OR logic)\n * - If multiple userRoles are provided, a user need only have one of them to have access (OR logic)\n * - If both userTypes and userRoles are provided, the `applyRulesAs` setting determines how they're combined:\n * - `'and'` (default): User must match a userType AND have a userRole\n * - `'or'`: User must match a userType OR have a userRole\n *\n * @param user - The authenticated user to check access for\n * @param feature - The feature configuration with user access rules\n * @returns Whether the user has access to the feature\n */\nexport function checkUserAccessToFeature(user: AuthenticatedUser<RecordOrUndef, RecordOrUndef>, feature: AccessRules): boolean {\n let { enabled, userTypes, userRoles, applyRulesAs = 'and' } = feature;\n\n // Normalize empty arrays to undefined for more intuitive access control\n // If userTypes is set but userRoles is empty array, treat userRoles as undefined\n if (userTypes && userTypes.length > 0 && userRoles && userRoles.length === 0) {\n userRoles = undefined;\n }\n\n // If userRoles is populated but userTypes is undefined/empty, treat userTypes as undefined\n if (userRoles && userRoles.length > 0 && (!userTypes || userTypes.length === 0)) {\n userTypes = undefined;\n }\n\n // If the feature is disabled, no access regardless of other rules\n if (!enabled) {\n return false;\n }\n\n // If no rules are specified, no access is granted (secure by default)\n if (!userTypes && !userRoles) {\n return false;\n }\n\n // Check user type access\n const userTypeMatches = userTypes ? userTypes.includes(user.userType ?? 'external-user') : true;\n\n // Check user role access\n const userRoleMatches = userRoles ? (user.roles ?? []).some((role) => userRoles.includes(role as any)) : true;\n\n // Apply the rules based on the logic specified\n if (applyRulesAs === 'and') {\n return userTypeMatches && userRoleMatches;\n } else {\n return userTypeMatches || userRoleMatches;\n }\n}\n\nexport function getEntityIdForUser(user: ChatUser<RecordOrUndef>, overrideDataForThisChatApp: RecordOrUndef, entityAttributeName?: string): string | undefined {\n // Choose which data source to use (override takes precedence)\n let customUserData: RecordOrUndef = overrideDataForThisChatApp || user.customData;\n\n // Early exit if no entity attribute name or no custom data\n // This is expected for internal users who may not have entity data\n if (!entityAttributeName || !customUserData) {\n return undefined;\n }\n\n // Note the entityAttributeName could have dots in it and if so we need to dereference the attribute\n // Example: \"user.account.id\" would need to traverse: customUserData.user.account.id\n let currentObject: RecordOrUndef = customUserData;\n const attributeParts = entityAttributeName.split('.');\n let currentValue: string | undefined;\n\n // Traverse through each part of the dotted path\n for (let i = 0; i < attributeParts.length; i++) {\n const part = attributeParts[i];\n\n // Check if the current part exists in the current object\n // If not found, return undefined (expected for internal users)\n if (!(part in currentObject)) {\n return undefined;\n }\n\n // If this is the last part, get the value\n if (i === attributeParts.length - 1) {\n currentValue = currentObject[part];\n } else {\n // Not the last part, so we need to traverse deeper\n if (typeof currentObject[part] === 'object' && currentObject[part] !== null) {\n currentObject = currentObject[part];\n } else {\n // Expected path doesn't exist, return undefined (expected for internal users)\n return undefined;\n }\n }\n }\n\n // Return the value if found, undefined if empty/falsy (expected for internal users)\n return currentValue;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/types/chatbot/chatbot-types.ts","../../src/util/server-utils.ts"],"names":[],"mappings":";;;;;AAKO,IAAM,qCAAA,GAAwC,EAAA;AAC9C,IAAM,kCAAA,GAAqC,CAAA;;;ACY3C,SAAS,0BAA0B,mBAAA,EAAqC;AAC3E,EAAA,MAAM,0BAA0B,MAAA,CAAO,IAAA,CAAK,qBAAqB,QAAQ,CAAA,CAAE,SAAS,KAAK,CAAA;AACzF,EAAA,MAAM,uBAAA,GAA0B,WAAW,MAAA,CAAO,IAAA,CAAK,yBAAyB,KAAK,CAAC,EAAE,QAAA,EAAS;AACjG,EAAA,OAAO,uBAAA;AACX;AAEO,SAAS,0BAA0B,MAAA,EAAwB;AAC9D,EAAA,MAAM,uBAAA,GAA0B,QAAA,CAAS,MAAM,CAAA,CAAE,SAAS,KAAK,CAAA;AAC/D,EAAA,MAAM,6BAA6B,MAAA,CAAO,IAAA,CAAK,yBAAyB,KAAK,CAAA,CAAE,SAAS,QAAQ,CAAA;AAChG,EAAA,OAAO,0BAAA;AACX;AAkBO,SAAS,sBAAA,CAAuB,YAAA,EAA4B,OAAA,EAAkB,IAAA,EAAmF;AACpK,EAAA,MAAM,MAAA,GAAqC;AAAA,IACvC,MAAA,EAAQ;AAAA,MACJ,OAAA,EAAS;AAAA,KACb;AAAA,IACA,cAAA,EAAgB;AAAA,MACZ,OAAA,EAAS;AAAA,KACb;AAAA,IACA,MAAA,EAAQ;AAAA,MACJ,OAAA,EAAS,KAAA;AAAA,MACT,cAAA,EAAgB;AAAA,KACpB;AAAA,IACA,UAAA,EAAY;AAAA,MACR,kBAAkB;AAAC,KACvB;AAAA,IACA,WAAA,EAAa;AAAA,MACT,aAAa,EAAC;AAAA,MACd,SAAA,EAAW,KAAA;AAAA,MACX,cAAA,EAAgB,CAAA;AAAA,MAChB,SAAA,EAAW;AAAA,KACf;AAAA,IACA,qBAAA,EAAuB;AAAA,MACnB,KAAA,EAAO;AAAA,KACX;AAAA,IACA,eAAA,EAAiB;AAAA,MACb,uBAAA,EAAyB,KAAA;AAAA,MACzB,+BAAA,EAAiC;AAAA,KACrC;AAAA,IACA,oBAAA,EAAsB,MAAA;AAAA,IACtB,MAAA,EAAQ;AAAA,MACJ,OAAA,EAAS,KAAA;AAAA,MACT,aAAA,EAAe,QAAA;AAAA,MACf,WAAA,EAAa,QAAA;AAAA,MACb,iBAAA,EAAmB;AAAA,KACvB;AAAA,IACA,SAAA,EAAW;AAAA,MACP,cAAA,EAAgB;AAAA,KACpB;AAAA,IACA,IAAA,EAAM;AAAA,MACF,aAAa,EAAC;AAAA,MACd,cAAc;AAAC,KACnB;AAAA,IACA,0BAAA,EAA4B;AAAA,MACxB,OAAA,EAAS,KAAA;AAAA,MACT,mCAAA,EAAqC,KAAA;AAAA,MACrC,0BAAA,EAA4B,KAAA;AAAA,MAC5B,iCAAA,EAAmC,KAAA;AAAA,MACnC,8BAAA,EAAgC,MAAA;AAAA,MAChC,oCAAA,EAAsC,KAAA;AAAA,MACtC,iCAAA,EAAmC,MAAA;AAAA,MACnC,mDAAA,EAAqD,KAAA;AAAA,MACrD,4CAAA,EAA8C;AAAA,KAClD;AAAA,IACA,uBAAA,EAAyB;AAAA,MACrB,OAAA,EAAS,KAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACV;AAAA,IACA,UAAA,EAAY;AAAA,MACR,OAAA,EAAS,KAAA;AAAA,MACT,yBAAA,EAA2B,qCAAA;AAAA,MAC3B,sBAAA,EAAwB;AAAA;AAC5B,GACJ;AAIA,EAAA,MAAM,iCAAiC,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,cAAA,IAAkB,QAAQ,QAAA,EAAU,cAAA;AACvG,EAAA,MAAA,CAAO,cAAA,GAAiB,uBAAA;AAAA,IACpB,gBAAA;AAAA,IACA,8BAAA;AAAA,IACA,YAAA,EAAc,cAAA;AAAA,IACd,MAAA,CAAO,cAAA;AAAA,IACP,IAAA;AAAA,IACA,CAAC,SAAS,OAAA,MAAa;AAAA,MACnB,OAAA;AAAA,MACA,uBAAuB,OAAA,CAAQ;AAAA,KACnC;AAAA,GACJ;AAIA,EAAA,MAAM,yBAAyB,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,MAAA,IAAU,QAAQ,QAAA,EAAU,MAAA;AACvF,EAAA,MAAA,CAAO,MAAA,GAAS,uBAAA,CAAwB,QAAA,EAAU,sBAAA,EAAwB,YAAA,EAAc,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAQ,IAAA,EAAM,CAAC,OAAA,EAAS,OAAA,KAAY;AACvI,IAAA,IAAI,cAAA,GAAiB,KAAA;AACrB,IAAA,IAAI,OAAA,IAAW,QAAQ,cAAA,EAAgB;AAEnC,MAAA,MAAM,yBAAyB,YAAA,EAAc,MAAA,EAAQ,cAAA,IAAkB,EAAE,SAAS,KAAA,EAAM;AACxF,MAAA,IAAI,uBAAuB,OAAA,EAAS;AAChC,QAAA,cAAA,GAAiB,wBAAA,CAAyB,IAAA,EAAM,OAAA,CAAQ,cAA6B,CAAA;AAAA,MACzF;AAAA,IACJ,WAAW,OAAA,EAAS;AAEhB,MAAA,MAAM,yBAAyB,YAAA,EAAc,MAAA,EAAQ,cAAA,IAAkB,EAAE,SAAS,KAAA,EAAM;AACxF,MAAA,cAAA,GAAiB,wBAAA,CAAyB,MAAM,sBAAsB,CAAA;AAAA,IAC1E;AACA,IAAA,OAAO;AAAA,MACH,OAAA;AAAA,MACA;AAAA,KACJ;AAAA,EACJ,CAAC,CAAA;AAID,EAAA,MAAM,yBAAyB,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,MAAA,IAAU,QAAQ,QAAA,EAAU,MAAA;AACvF,EAAA,MAAA,CAAO,MAAA,GAAS,uBAAA,CAAwB,QAAA,EAAU,sBAAA,EAAwB,YAAA,EAAc,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAQ,IAAA,EAAM,CAAC,OAAA,EAAS,OAAA,MAAa;AAAA,IACxI,OAAA;AAAA,IACA,aAAA,EAAe,QAAQ,aAAA,IAAiB,QAAA;AAAA,IACxC,WAAA,EAAa,QAAQ,WAAA,IAAe,QAAA;AAAA,IACpC,iBAAA,EAAmB,QAAQ,iBAAA,IAAqB;AAAA,GACpD,CAAE,CAAA;AAIF,EAAA,MAAM,6BAA6B,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,UAAA,IAAc,QAAQ,QAAA,EAAU,UAAA;AAC/F,EAAA,MAAA,CAAO,UAAA,GAAa,oBAAoB,YAAA,EAAc,0BAAA,EAA4B,cAAc,UAAA,EAAY,MAAA,CAAO,UAAA,EAAY,CAAC,OAAA,MAAa;AAAA,IACzI,gBAAA,EAAkB,OAAA,CAAQ,gBAAA,IAAoB;AAAC,GACnD,CAAE,CAAA;AAIF,EAAA,MAAM,8BAA8B,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,WAAA,IAAe,QAAQ,QAAA,EAAU,WAAA;AACjG,EAAA,MAAA,CAAO,WAAA,GAAc,oBAAoB,aAAA,EAAe,2BAAA,EAA6B,cAAc,WAAA,EAAa,MAAA,CAAO,WAAA,EAAa,CAAC,OAAA,MAAa;AAAA,IAC9I,WAAA,EAAa,OAAA,CAAQ,WAAA,IAAe,EAAC;AAAA,IACrC,SAAA,EAAW,QAAQ,SAAA,IAAa,KAAA;AAAA,IAChC,cAAA,EAAgB,QAAQ,cAAA,IAAkB,CAAA;AAAA,IAC1C,SAAA,EAAW,QAAQ,SAAA,IAAa;AAAA,GACpC,CAAE,CAAA;AAIF,EAAA,MAAM,wCAAwC,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,qBAAA,IAAyB,QAAQ,QAAA,EAAU,qBAAA;AACrH,EAAA,MAAA,CAAO,qBAAA,GAAwB,wBAAA;AAAA,IAC3B,uBAAA;AAAA,IACA,qCAAA;AAAA,IACA,YAAA,EAAc,qBAAA;AAAA,IACd,EAAyB,CAAA;AAAA;AAAA,IACzB,CAAC,SAAS,OAAA,MAAa;AAAA,MACnB,KAAA,EAAO,OAAA,GAAW,OAAA,CAAQ,qBAAA,IAAyB,eAAA,GAAmB;AAAA,KAC1E;AAAA,GACJ;AAIA,EAAA,MAAM,kCAAkC,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,eAAA,IAAmB,QAAQ,QAAA,EAAU,eAAA;AACzG,EAAA,MAAA,CAAO,eAAA,GAAkB,oBAAoB,iBAAA,EAAmB,+BAAA,EAAiC,cAAc,eAAA,EAAiB,MAAA,CAAO,eAAA,EAAiB,CAAC,OAAA,MAAa;AAAA,IAClK,uBAAA,EAAyB,QAAQ,uBAAA,IAA2B,KAAA;AAAA,IAC5D,+BAAA,EAAiC,QAAQ,+BAAA,IAAmC;AAAA,GAChF,CAAE,CAAA;AAIF,EAAA,MAAM,uCAAuC,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,oBAAA,IAAwB,QAAQ,QAAA,EAAU,oBAAA;AACnH,EAAA,MAAM,gBAAA,GAAmB,wBAAA;AAAA,IACrB,sBAAA;AAAA,IACA,oCAAA;AAAA,IACA,YAAA,EAAc,oBAAA;AAAA,IACd,EAAoB,CAAA;AAAA,IACpB,CAAC,SAAS,OAAA,MAAa;AAAA,MACnB,MAAA,EAAQ,OAAA,GAAU,OAAA,CAAQ,MAAA,GAAS;AAAA,KACvC;AAAA,GACJ;AACA,EAAA,MAAA,CAAO,uBAAuB,gBAAA,CAAiB,MAAA;AAI/C,EAAA,MAAM,uBAAuB,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,IAAA,IAAQ,QAAQ,QAAA,EAAU,IAAA;AACnF,EAAA,MAAA,CAAO,IAAA,GAAO,oBAAoB,MAAA,EAAQ,oBAAA,EAAsB,cAAc,IAAA,EAAM,MAAA,CAAO,IAAA,EAAM,CAAC,OAAA,MAAa;AAAA,IAC3G,WAAA,EAAa,OAAA,CAAQ,WAAA,IAAe,EAAC;AAAA,IACrC,YAAA,EAAc,OAAA,CAAQ,YAAA,IAAgB;AAAC,GAC3C,CAAE,CAAA;AAIF,EAAA,MAAM,6CAA6C,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,0BAAA,IAA8B,QAAQ,QAAA,EAAU,0BAAA;AAC/H,EAAA,MAAA,CAAO,0BAAA,GAA6B,mBAAA;AAAA,IAChC,4BAAA;AAAA,IACA,0CAAA;AAAA,IACA,YAAA,EAAc,0BAAA;AAAA,IACd,MAAA,CAAO,0BAAA;AAAA,IACP,CAAC,OAAA,MAAa;AAAA,MACV,OAAA,EAAS,QAAQ,OAAA,IAAW,KAAA;AAAA,MAC5B,mCAAA,EAAqC,OAAA,CAAQ,mCAAA,EAAqC,OAAA,IAAW,KAAA;AAAA,MAC7F,0BAAA,EAA4B,OAAA,CAAQ,0BAAA,EAA4B,OAAA,IAAW,KAAA;AAAA,MAC3E,iCAAA,EAAmC,OAAA,CAAQ,8BAAA,EAAgC,OAAA,IAAW,KAAA;AAAA,MACtF,8BAAA,EAAgC,OAAA,CAAQ,8BAAA,EAAgC,MAAA,IAAU,MAAA;AAAA,MAClF,oCAAA,EAAsC,OAAA,CAAQ,iCAAA,EAAmC,OAAA,IAAW,KAAA;AAAA,MAC5F,iCAAA,EAAmC,OAAA,CAAQ,iCAAA,EAAmC,IAAA,IAAQ,MAAA;AAAA,MACtF,mDAAA,EAAqD,OAAA,CAAQ,mDAAA,EAAqD,OAAA,IAAW,KAAA;AAAA,MAC7H,4CAAA,EAA8C,QAAQ,4CAAA,IAAgD;AAAA,KAC1G;AAAA,GACJ;AAIA,EAAA,MAAM,0CAA0C,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,uBAAA,IAA2B,QAAQ,QAAA,EAAU,uBAAA;AACzH,EAAA,MAAA,CAAO,uBAAA,GAA0B,mBAAA;AAAA,IAC7B,yBAAA;AAAA,IACA,uCAAA;AAAA,IACA,YAAA,EAAc,uBAAA;AAAA,IACd,MAAA,CAAO,uBAAA;AAAA,IACP,CAAC,OAAA,MAAa;AAAA,MACV,OAAA,EAAS,QAAQ,OAAA,IAAW,KAAA;AAAA,MAC5B,IAAA,EAAM,QAAQ,IAAA,IAAQ;AAAA,KAC1B;AAAA,GACJ;AAIA,EAAA,MAAM,6BAA6B,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,UAAA,IAAc,QAAQ,QAAA,EAAU,UAAA;AAC/F,EAAA,MAAA,CAAO,UAAA,GAAa,oBAAoB,YAAA,EAAc,0BAAA,EAA4B,cAAc,UAAA,EAAY,MAAA,CAAO,UAAA,EAAY,CAAC,OAAA,MAAa;AAAA,IACzI,OAAA,EAAS,QAAQ,OAAA,IAAW,KAAA;AAAA,IAC5B,yBAAA,EAA2B,QAAQ,yBAAA,IAA6B,qCAAA;AAAA,IAChE,sBAAA,EAAwB,QAAQ,sBAAA,IAA0B;AAAA,GAC9D,CAAE,CAAA;AAMF,EAAA,MAAM,yBAAyB,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,MAAA,IAAU,QAAQ,QAAA,EAAU,MAAA;AACvF,EAAA,IAAI,YAAA,EAAc,QAAQ,OAAA,EAAS;AAE/B,IAAA,IAAI,sBAAA,EAAwB,YAAY,KAAA,EAAO;AAC3C,MAAA,MAAA,CAAO,OAAO,OAAA,GAAU,KAAA;AAAA,IAC5B,CAAA,MAAO;AAEH,MAAA,MAAA,CAAO,OAAO,OAAA,GAAU,IAAA;AACxB,MAAA,IAAI,CAAC,YAAA,EAAc,MAAA,EAAQ,aAAA,EAAe;AACtC,QAAA,MAAM,IAAI,MAAM,oHAAoH,CAAA;AAAA,MACxI;AACA,MAAA,MAAA,CAAO,MAAA,CAAO,aAAA,GAAgB,YAAA,CAAa,MAAA,CAAO,aAAA;AAAA,IACtD;AAAA,EACJ,CAAA,MAAO;AAEH,IAAA,MAAA,CAAO,OAAO,OAAA,GAAU,KAAA;AAAA,EAC5B;AAEA,EAAA,OAAO,MAAA;AACX;AAYA,SAAS,mBAAA,CAAuB,WAAA,EAAqB,UAAA,EAAiB,WAAA,EAAkB,UAAa,iBAAA,EAA2C;AAC5I,EAAA,IAAI,4BAAA,CAA6B,UAAA,EAAY,WAAW,CAAA,IAAK,UAAA,EAAY;AACrE,IAAA,OAAO,kBAAkB,UAAU,CAAA;AAAA,EACvC,CAAA,MAAO;AAEH,IAAA,MAAM,WAAW,WAAA,IAAe,QAAA;AAChC,IAAA,OAAO,kBAAkB,QAAQ,CAAA;AAAA,EACrC;AACJ;AAaA,SAAS,wBAAA,CAA4B,WAAA,EAAqB,UAAA,EAAiB,WAAA,EAAkB,UAAa,iBAAA,EAA6D;AACnK,EAAA,MAAM,cAAA,GAAiB,sBAAA,CAAuB,UAAA,EAAY,WAAW,CAAA;AAErE,EAAA,IAAI,cAAA,KAAmB,aAAa,UAAA,EAAY;AAE5C,IAAA,MAAM,QAAA,GAAW,WAAA,IAAe,EAAE,OAAA,EAAS,KAAA,EAAM;AACjD,IAAA,IAAI,SAAS,OAAA,EAAS;AAClB,MAAA,OAAO,iBAAA,CAAkB,YAAY,IAAI,CAAA;AAAA,IAC7C;AACA,IAAA,OAAO,iBAAA,CAAkB,EAAC,EAAG,KAAK,CAAA;AAAA,EACtC,CAAA,MAAA,IAAW,mBAAmB,UAAA,EAAY;AACtC,IAAA,OAAO,iBAAA,CAAkB,EAAC,EAAG,KAAK,CAAA;AAAA,EACtC,CAAA,MAAO;AAEH,IAAA,MAAM,QAAA,GAAW,WAAA,IAAe,EAAE,OAAA,EAAS,IAAA,EAAK;AAChD,IAAA,OAAO,iBAAA,CAAkB,QAAA,EAAU,QAAA,CAAS,OAAO,CAAA;AAAA,EACvD;AACJ;AASA,SAAS,sBAAA,CAAuB,YAAiB,WAAA,EAAkE;AAC/G,EAAA,IAAI,CAAC,YAAY,OAAO,MAAA;AAGxB,EAAA,IAAI,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,WAAW,CAAA,EAAG;AACtC,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,mCAAA,EAAsC,WAAW,CAAA,6BAAA,CAA+B,CAAA;AAC9F,IAAA,OAAO,SAAA;AAAA,EACX;AAGA,EAAA,IAAI,EAAE,aAAa,UAAA,CAAA,EAAa;AAC5B,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,6BAAA,EAAgC,WAAW,CAAA,yDAAA,CAA2D,CAAA;AACpH,IAAA,OAAO,SAAA;AAAA,EACX;AAEA,EAAA,OAAO,UAAA,CAAW,UAAU,SAAA,GAAY,UAAA;AAC5C;AASA,SAAS,4BAAA,CAA6B,YAAiB,WAAA,EAA8B;AACjF,EAAA,IAAI,CAAC,YAAY,OAAO,KAAA;AAGxB,EAAA,IAAI,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA,CAAE,WAAW,CAAA,EAAG;AACtC,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,mCAAA,EAAsC,WAAW,CAAA,6BAAA,CAA+B,CAAA;AAC9F,IAAA,OAAO,KAAA;AAAA,EACX;AAEA,EAAA,OAAO,IAAA;AACX;AAaA,SAAS,wBACL,WAAA,EACA,UAAA,EACA,WAAA,EACA,QAAA,EACA,MACA,iBAAA,EACC;AACD,EAAA,MAAM,cAAA,GAAiB,sBAAA,CAAuB,UAAA,EAAY,WAAW,CAAA;AAErE,EAAA,IAAI,cAAA,KAAmB,aAAa,UAAA,EAAY;AAE5C,IAAA,MAAM,QAAA,GAAW,WAAA,IAAe,EAAE,OAAA,EAAS,KAAA,EAAM;AACjD,IAAA,IAAI,SAAS,OAAA,EAAS;AAClB,MAAA,MAAM,OAAA,GAAU,wBAAA,CAAyB,IAAA,EAAM,UAAyB,CAAA;AACxE,MAAA,OAAO,iBAAA,CAAkB,YAAY,OAAO,CAAA;AAAA,IAChD;AACA,IAAA,OAAO,iBAAA,CAAkB,UAAU,KAAK,CAAA;AAAA,EAC5C,CAAA,MAAA,IAAW,mBAAmB,UAAA,EAAY;AACtC,IAAA,OAAO,iBAAA,CAAkB,UAAU,KAAK,CAAA;AAAA,EAC5C,CAAA,MAAO;AAEH,IAAA,MAAM,QAAA,GAAW,WAAA,IAAe,EAAE,OAAA,EAAS,KAAA,EAAM;AACjD,IAAA,MAAM,OAAA,GAAU,wBAAA,CAAyB,IAAA,EAAM,QAAQ,CAAA;AACvD,IAAA,OAAO,iBAAA,CAAkB,UAAU,OAAO,CAAA;AAAA,EAC9C;AACJ;AAmBO,SAAS,wBAAA,CAAyB,MAAuD,OAAA,EAA+B;AAC3H,EAAA,IAAI,EAAE,OAAA,EAAS,SAAA,EAAW,SAAA,EAAW,YAAA,GAAe,OAAM,GAAI,OAAA;AAI9D,EAAA,IAAI,aAAa,SAAA,CAAU,MAAA,GAAS,KAAK,SAAA,IAAa,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1E,IAAA,SAAA,GAAY,MAAA;AAAA,EAChB;AAGA,EAAA,IAAI,SAAA,IAAa,UAAU,MAAA,GAAS,CAAA,KAAM,CAAC,SAAA,IAAa,SAAA,CAAU,WAAW,CAAA,CAAA,EAAI;AAC7E,IAAA,SAAA,GAAY,MAAA;AAAA,EAChB;AAGA,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA,OAAO,KAAA;AAAA,EACX;AAGA,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,SAAA,EAAW;AAC1B,IAAA,OAAO,KAAA;AAAA,EACX;AAGA,EAAA,MAAM,kBAAkB,SAAA,GAAY,SAAA,CAAU,SAAS,IAAA,CAAK,QAAA,IAAY,eAAe,CAAA,GAAI,IAAA;AAG3F,EAAA,MAAM,eAAA,GAAkB,SAAA,GAAA,CAAa,IAAA,CAAK,KAAA,IAAS,EAAC,EAAG,IAAA,CAAK,CAAC,IAAA,KAAS,SAAA,CAAU,QAAA,CAAS,IAAW,CAAC,CAAA,GAAI,IAAA;AAGzG,EAAA,IAAI,iBAAiB,KAAA,EAAO;AACxB,IAAA,OAAO,eAAA,IAAmB,eAAA;AAAA,EAC9B,CAAA,MAAO;AACH,IAAA,OAAO,eAAA,IAAmB,eAAA;AAAA,EAC9B;AACJ;AAEO,SAAS,kBAAA,CAAmB,IAAA,EAA+B,0BAAA,EAA2C,mBAAA,EAAkD;AAE3J,EAAA,IAAI,cAAA,GAAgC,8BAA8B,IAAA,CAAK,UAAA;AAIvE,EAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,cAAA,EAAgB;AACzC,IAAA,OAAO,MAAA;AAAA,EACX;AAIA,EAAA,IAAI,aAAA,GAA+B,cAAA;AACnC,EAAA,MAAM,cAAA,GAAiB,mBAAA,CAAoB,KAAA,CAAM,GAAG,CAAA;AACpD,EAAA,IAAI,YAAA;AAGJ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,cAAA,CAAe,QAAQ,CAAA,EAAA,EAAK;AAC5C,IAAA,MAAM,IAAA,GAAO,eAAe,CAAC,CAAA;AAI7B,IAAA,IAAI,EAAE,QAAQ,aAAA,CAAA,EAAgB;AAC1B,MAAA,OAAO,MAAA;AAAA,IACX;AAGA,IAAA,IAAI,CAAA,KAAM,cAAA,CAAe,MAAA,GAAS,CAAA,EAAG;AACjC,MAAA,YAAA,GAAe,cAAc,IAAI,CAAA;AAAA,IACrC,CAAA,MAAO;AAEH,MAAA,IAAI,OAAO,cAAc,IAAI,CAAA,KAAM,YAAY,aAAA,CAAc,IAAI,MAAM,IAAA,EAAM;AACzE,QAAA,aAAA,GAAgB,cAAc,IAAI,CAAA;AAAA,MACtC,CAAA,MAAO;AAEH,QAAA,OAAO,MAAA;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;AAGA,EAAA,OAAO,YAAA;AACX","file":"server-utils.mjs","sourcesContent":["import type { ActionGroupInvocationInput, AgentCollaboration, FunctionDefinition, RetrievalFilter, Trace } from '@aws-sdk/client-bedrock-agent-runtime';\nimport type { Role } from '@aws-sdk/client-bedrock-agentcore';\n\nexport type CompanyType = 'retailer' | 'supplier';\n\nexport const DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT = 25;\nexport const DEFAULT_MAX_K_MATCHES_PER_STRATEGY = 5;\nexport const DEFAULT_MEMORY_STRATEGIES: UserMemoryStrategy[] = ['preferences', 'semantic'];\nexport const DEFAULT_EVENT_EXPIRY_DURATION = 7;\n\n/**\n * Data persisted by Bedrock Agent for each session, set\n * by calling the `initSession` function for a lambda\n * action group.\n */\nexport interface SessionData {\n /** Unique identifier for the session */\n sessionId: string;\n /** The company id for the session */\n companyId: string;\n /** Type of company participating in the session */\n companyType: CompanyType;\n /** Current date in ISO 8601 format */\n date: string;\n /** The agent id for the session */\n agentId: string;\n}\n\n/**\n * Represents a context item that was sent to the LLM in this session.\n * Used to track which contexts have been sent to avoid redundant transmission.\n */\nexport interface SentContextRecord {\n /** The sourceId of the context that was sent */\n sourceId: string;\n /** Array of message IDs where this context was sent (tracks all occurrences) */\n messageIds: string[];\n /** The content hash of the context when it was sent */\n contentHash: string;\n /** ISO 8601 timestamp of the last time this context was sent */\n lastSentAt: string;\n /** The origin of the context (user or auto) */\n origin: WidgetContextSourceOrigin;\n}\n\n/**\n * Represents a chat session between a user and an agent. A session is a sequential\n * collection of messages between a user and an agent. The most recent message is\n * lastMessageId.\n */\nexport interface ChatSession<T extends RecordOrUndef = undefined> {\n /**\n * Unique identifier for this chat session\n *\n * Note this is a time-based key so you can use it to lexicographically sort the sessions and to compare them\n * as in sessionId1 < sessionId2 if sessionId1 is before sessionId2.\n */\n sessionId: string;\n /** Unique identifier of the user participating in the session */\n userId: string;\n /**\n * The type of user who created this session. Used for filtering sessions by internal vs external users\n * in session insights. Defaults to 'external-user' if not provided.\n */\n userType?: UserType;\n /** Identifier for the specific agent instance */\n agentId: string;\n /** Identifier for the chat app */\n chatAppId: string;\n /** Unique identifier for the user's identity */\n identityId: string;\n /** Mode of the invocation of the agent */\n invocationMode: ConverseInvocationMode;\n /** Title or name of the chat session */\n title?: string;\n /** ID of the most recent message in the session */\n lastMessageId?: string;\n /** Additional session-specific attributes */\n sessionAttributes: SessionDataWithChatUserCustomDataSpreadIn<T>;\n /** Cost of processing input tokens in USD */\n inputCost?: number;\n /** Number of tokens processed in input messages */\n inputTokens?: number;\n /** Cost of generating output tokens in USD */\n outputCost?: number;\n /** Number of tokens generated in output messages */\n outputTokens?: number;\n /** Total cost of the session (input + output) in USD */\n totalCost?: number;\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate: string;\n /** ISO 8601 formatted timestamp of the last session update */\n lastUpdate: string;\n\n /**\n * If the entity feature is enabled, this is the entity ID of the user who created the session at the moment of creation.\n *\n * If the site wide entity feature is not enabled or if the associated chat app has disabled the entity feature or\n * if this session is being created in the context of a direct invocation (no chat app involved) then this is the string\n * \"chat-app-global\" indicating that if the user chooses to share this session, it will be accessible to anyone with access to the chat app who has the link.\n * Otherwise, only those who have access to the chat app and are associated with the same entity ID as the session owner will be able to access the session.\n */\n entityId: string;\n\n /**\n * Last Message that has been analyzed by the system for insights, this lets us detect if the user came back to\n * the chat after the session is believed to be complete and added another message that we should analyze again.\n *\n * Note this is a time-based key so you can use it to lexicographically sort the messages and compare message IDs\n * as in messageId1 < messageId2 if messageId1 is before messageId2.\n *\n * If present and insightsS3Url is not present then this is a bug.\n *\n * If lastAnalyzedMessageId is not the same as lastMessageId then this means the user has added another message\n * to the session since we computed insights and we need to recompute them.\n */\n lastAnalyzedMessageId?: string;\n\n /**\n * If present, this is the url to the s3 object that contains the insights for the session. If not present,\n * then the insights are not yet computed. If this is present and lastAnalyzedMessageId is not present, then\n * this is a bug.\n *\n * The url to the s3 object in this form:\n *\n * s3://<bucket-name>/<session-id>/insights.json\n */\n insightsS3Url?: string;\n\n /**\n * Insights for the session computed after the session is believed to be complete.\n *\n * This is not persisted in dynamodb, it's only in S3 and then added to the chat session in opensearch.\n */\n insights?: SessionInsights;\n\n /**\n * Feedback for the session.\n *\n * This is persisted in a separate dynamodb table (chat-session-feedback)and then added to the chat session in opensearch.\n */\n feedback?: ChatSessionFeedback[];\n\n /**\n * Expiration date of the message in Unix seconds. Internally used in dynamodb. Don't expect that this will\n * be set as it never will be made available to apps. That's why it's in snake case when nothing else is.\n */\n exp_date_unix_seconds?: number;\n\n /**\n * This is used to those sessions that we need to recompute the insights for.\n *\n * It will be set to NEEDS_INSIGHTS_ANALYSIS when we first create a session. Then we will have a lambda wake up\n * periodically and check if the session is ready to be analyzed (it's been some time since the last message was added).\n * We will then compute the insights and set lastAnalyzedMessageId and insightsS3Url. We will not put the insights\n * on the session object as it is stored in dynamodb, too big. It will go into opensearch on the session however.\n *\n * The actual computation will not be done until there is a messageId that is at last X old (message ID is really a\n * date UUID v7) where X is whatever we set (probably an hour or two). This is to avoid recomputing the insights\n * for every message.\n *\n * Also, if we detect that the lastMessageId is not equal to lastAnalyzedMessageId then we will once again set\n * insight_status_partition_key to NEEDS_INSIGHTS_ANALYSIS so that we can recompute the insights after enough time\n * goes by since the new last message was added.\n *\n * We will unset this value once we have computed the insights and set lastAnalyzedMessageId and insightsS3Url.\n *\n * Note that the GSI that governs this will not include a session record unless NEEDS_INSIGHTS_ANALYSIS is set\n * (insightStatus is the partition key)and lastMessageId is set (the sort key). There could be a short gap between\n * when the session is created and when the last message ID is added. This should be fine.\n */\n insightStatus?: InsightStatusNeedsInsightsAnalysis | undefined;\n\n /**\n * Tracks context items that have been sent to the LLM in this session.\n * Keyed by sourceId to allow efficient lookups when determining if a context has changed or needs to be resent.\n *\n * This is used to:\n * - Avoid sending the same context multiple times\n * - Detect when context has changed (via contentHash comparison)\n * - Track which message included each piece of context\n */\n sentContexts?: Record<string, SentContextRecord>;\n /** The share ID if this session is shared */\n shareId?: string;\n /** User ID of the user who created the share */\n shareCreatedByUserId?: string;\n /** When this session was first shared */\n shareDate?: string;\n /** When this session's share was revoked */\n shareRevokedDate?: string;\n\n /** If set to 'mock', this session is used for integration testing purposes. */\n testType?: 'mock';\n\n /**\n * The source of the converse request. Defaults to 'user'. The composite key chat_app_sk looks like this:\n *\n * ${chatAppId}#${source}#${updateDate}\n *\n * The source in the composite key here will only ever be either `user` or `component`. If this attribute's value is missing or is `user` or `component-as-user`,\n * then the composite key will be set to `user` so when we query on behalf of the user, we will get all sessions for that user.\n */\n source: ConverseSource;\n}\n\n/**\n * Convenience type for updating a session with the last analyzed message id and insights s3 url.\n *\n * Field update behavior:\n * - If a value is null: the field will be REMOVED from the database entirely (using DynamoDB REMOVE expression)\n * - If a value is undefined: the field will not be updated at all (field remains unchanged)\n * - If a value is present: the field will be SET to that value (using DynamoDB SET expression)\n *\n * Note: Setting insightStatus to null removes it from the sparse GSI since the field no longer exists.\n */\nexport interface ChatSessionLiteForUpdate {\n userId: string;\n sessionId: string;\n lastAnalyzedMessageId: string | undefined | null;\n insightStatus: InsightStatusNeedsInsightsAnalysis | undefined | null;\n insightsS3Url: string | undefined | null;\n}\n\nexport interface ChatSessionFeedback {\n /** The session ID of the session that the feedback is about. */\n sessionId: string;\n /** This is a V7 UUID that is date sortable and comparable */\n feedbackId: string;\n /** The user ID of the user who flagged the session. */\n userId: string;\n /** The message ID of the session message that the feedback is about. */\n messageId?: string;\n /** Whether the flag was reported by a human or an AI. */\n reportedByHuman: boolean;\n /** Whether the feedback was created by the customer or the system. */\n createdByCustomer: boolean;\n /** The status of the feedback. */\n status: SessionFeedbackStatus;\n /** The severity of the feedback. */\n severity: SessionFeedbackSeverity;\n /** The type of the feedback. */\n type: SessionFeedbackType;\n /** A comment from the user who flagged the session. Limit to 1000 characters. */\n userComment?: string;\n /** Comments from the internal team. This is stored zipped in dynamodb.*/\n internalComments?: FeedbackInternalComment[];\n /** Attachments to the feedback. */\n attachments?: Attachment[];\n /** The date and time the feedback was created as a string in ISO 8601 format. */\n createdOn: string;\n /** The date and time the feedback was updated as a string in ISO 8601 format. */\n updatedOn: string;\n /** The date and time the feedback will expire as a unix timestamp in seconds. It's snake case because it's never going to be used by the app itself. */\n exp_date_unix_seconds?: number;\n}\n\nexport interface Attachment {\n /**\n * The url to the s3 object in this form:\n *\n * s3://<bucket-name>/<session-id>/<attachment-id>.{extension}\n */\n s3Url: string;\n /** Name of the attachment. */\n name: string;\n /** MIME type of the attachment. */\n mimeType: string;\n}\n\nexport const INSIGHT_STATUS_NEEDS_INSIGHTS_ANALYSIS = 'NEEDS_INSIGHTS_ANALYSIS';\nexport type InsightStatusNeedsInsightsAnalysis = typeof INSIGHT_STATUS_NEEDS_INSIGHTS_ANALYSIS;\n\nexport const SESSION_FEEDBACK_STATUS = ['open', 'in_review', 'resolved', 'closed'] as const;\nexport type SessionFeedbackStatus = (typeof SESSION_FEEDBACK_STATUS)[number];\nexport const SESSION_FEEDBACK_STATUS_VALUES: NameValuePair<SessionFeedbackStatus>[] = [\n { name: 'Open', value: 'open' },\n { name: 'In Review', value: 'in_review' },\n { name: 'Resolved', value: 'resolved' },\n { name: 'Closed', value: 'closed' }\n];\n\nexport const SESSION_FEEDBACK_SEVERITY = ['low', 'medium', 'high', 'critical'] as const;\nexport type SessionFeedbackSeverity = (typeof SESSION_FEEDBACK_SEVERITY)[number];\nexport const SESSION_FEEDBACK_SEVERITY_VALUES: NameValuePair<SessionFeedbackSeverity>[] = [\n { name: 'Low', value: 'low' },\n { name: 'Medium', value: 'medium' },\n { name: 'High', value: 'high' },\n { name: 'Critical', value: 'critical' }\n];\n\nexport const SESSION_FEEDBACK_TYPE = [\n 'user_thumbs_up',\n 'user_thumbs_down',\n 'incorrect_information',\n 'incomplete_information',\n 'off_topic',\n 'hallucination',\n 'confusing_response',\n 'outdated_information',\n 'inappropriate_content',\n 'privacy_concern',\n 'harmful_content',\n 'system_error',\n 'timeout_occurred',\n 'tool_failure',\n 'poor_performance',\n 'training_example',\n 'context_awareness_issue',\n 'goal_misalignment',\n 'tool_capability_gap',\n 'tool_performance_issue',\n 'cost_issue',\n 'high_complexity_session',\n 'low_ai_confidence_level',\n 'critical_issues_present',\n 'user_dissatisfied',\n 'user_question_to_chat_author',\n 'other'\n] as const;\nexport type SessionFeedbackType = (typeof SESSION_FEEDBACK_TYPE)[number];\nexport const SESSION_FEEDBACK_TYPE_VALUES: NameValueDescTriple<SessionFeedbackType>[] = [\n { name: 'Confusing Response', value: 'confusing_response', desc: 'Session was confusing' },\n { name: 'Context Awareness Issue', value: 'context_awareness_issue', desc: 'Session had context awareness issue' },\n { name: 'Cost Issue', value: 'cost_issue', desc: 'Session had cost issue' },\n { name: 'Critical Issues Present', value: 'critical_issues_present', desc: 'Session had critical issues present' },\n { name: 'Goal Misalignment', value: 'goal_misalignment', desc: 'Session had goal misalignment' },\n { name: 'Hallucination', value: 'hallucination', desc: 'Session contained hallucinations' },\n { name: 'Harmful Content', value: 'harmful_content', desc: 'Session contained harmful content' },\n { name: 'High Complexity Session', value: 'high_complexity_session', desc: 'Session was high complexity' },\n { name: 'Inappropriate Content', value: 'inappropriate_content', desc: 'Session contained inappropriate content' },\n { name: 'Incorrect Information', value: 'incorrect_information', desc: 'Session contained incorrect information' },\n { name: 'Incomplete Information', value: 'incomplete_information', desc: 'Session contained incomplete information' },\n { name: 'Low AI Confidence Level', value: 'low_ai_confidence_level', desc: 'Session had low AI confidence level' },\n { name: 'Off Topic', value: 'off_topic', desc: 'Session was off topic' },\n { name: 'Other', value: 'other', desc: 'Session had indeterminate issue' },\n { name: 'Outdated Information', value: 'outdated_information', desc: 'Session contained outdated information' },\n { name: 'Poor Performance', value: 'poor_performance', desc: 'Session experienced poor performance' },\n { name: 'Privacy Concern', value: 'privacy_concern', desc: 'Session contained privacy concern' },\n { name: 'System Error', value: 'system_error', desc: 'Session encountered system error' },\n { name: 'Timeout Occurred', value: 'timeout_occurred', desc: 'Session timed out' },\n { name: 'Tool Capability Gap', value: 'tool_capability_gap', desc: 'Session had tool capability gap' },\n { name: 'Tool Failure', value: 'tool_failure', desc: 'Session encountered tool failure' },\n { name: 'Tool Performance Issue', value: 'tool_performance_issue', desc: 'Session had tool performance issue' },\n { name: 'Training Example', value: 'training_example', desc: 'Session was training example' },\n { name: 'User Dissatisfied', value: 'user_dissatisfied', desc: 'User was dissatisfied with session.' },\n { name: 'User Question to Chat Author', value: 'user_question_to_chat_author', desc: 'User asked question not to AI but to chat app author' },\n { name: 'User Thumbs Down', value: 'user_thumbs_down', desc: 'User gave thumbs down to session' },\n { name: 'User Thumbs Up', value: 'user_thumbs_up', desc: 'User gave thumbs up to session' }\n];\n\nexport type ChatSessionFeedbackForCreate = Omit<ChatSessionFeedback, 'createdOn' | 'updatedOn' | 'internalComments' | 'exp_date_unix_seconds'>;\nexport type ChatSessionFeedbackForUpdate = Omit<\n ChatSessionFeedback,\n 'userId' | 'messageId' | 'reportedByHuman' | 'createdOn' | 'updatedOn' | 'exp_date_unix_seconds' | 'createdByCustomer'\n>;\n\nexport const UPDATEABLE_FEEDBACK_FIELDS = ['status', 'severity', 'type', 'internalComments', 'userComment', 'attachments'] as const;\nexport type UpdateableFeedbackFields = (typeof UPDATEABLE_FEEDBACK_FIELDS)[number];\n\nexport interface FeedbackInternalComment {\n /** This is a V7 UUID that is date sortable and comparable */\n commentId: string;\n /** The user ID of the user who made the comment. */\n userId: string;\n /** The comment. */\n comment: string;\n /** The attachments to the comment. */\n attachments?: Attachment[];\n /** The date and time the comment was made as a string in ISO 8601 format. */\n createdOn: string;\n\n type: FeedbackInternalCommentType;\n\n status: FeedbackInternalCommentStatus;\n}\n\nexport const FEEDBACK_INTERNAL_COMMENT_STATUS = ['open', 'closed'] as const;\nexport type FeedbackInternalCommentStatus = (typeof FEEDBACK_INTERNAL_COMMENT_STATUS)[number];\nexport const FEEDBACK_INTERNAL_COMMENT_STATUS_VALUES: NameValueDescTriple<FeedbackInternalCommentStatus>[] = [\n { name: 'Open', value: 'open', desc: 'The comment is open and is awaiting action.' },\n { name: 'Closed', value: 'closed', desc: 'The comment is closed and has been resolved.' }\n];\n\nexport const FEEDBACK_INTERNAL_COMMENT_TYPE = [\n 'comment',\n 'customer_outreach_recommended',\n 'customer_outreach_made',\n 'technical_action_required',\n 'technical_action_completed'\n] as const;\nexport type FeedbackInternalCommentType = (typeof FEEDBACK_INTERNAL_COMMENT_TYPE)[number];\nexport const FEEDBACK_INTERNAL_COMMENT_TYPE_VALUES: NameValueDescTriple<FeedbackInternalCommentType>[] = [\n { name: 'Comment', value: 'comment', desc: 'A comment about the feedback.' },\n { name: 'Customer Outreach Recommended', value: 'customer_outreach_recommended', desc: 'A recommendation to reach out to the customer.' },\n { name: 'Customer Outreach Made', value: 'customer_outreach_made', desc: 'A record that an outreach was made to the customer.' },\n { name: 'Technical Action Required', value: 'technical_action_required', desc: 'A technical action is required to resolve the feedback.' },\n { name: 'Technical Action Completed', value: 'technical_action_completed', desc: 'A record that a technical action was completed to resolve the feedback.' }\n];\n\nexport interface SessionInsights {\n model: string;\n /** The version of the insights algorithm that was used to compute the insights. */\n version: string;\n usage: SessionInsightUsage;\n scoring: SessionInsightScoring;\n detailMarkdown: string;\n}\n\nexport interface SessionInsightUsage {\n inputTokens: number;\n cacheCreationInputTokens: number;\n cacheReadInputTokens: number;\n outputTokens: number;\n}\n\nexport interface SessionInsightScoring {\n scores: {\n goalAchievement: {\n score: number;\n description: string;\n };\n userSatisfaction: {\n score: number;\n description: string;\n };\n aiPerformance: {\n accuracy: {\n score: number;\n description: string;\n };\n helpfulness: {\n score: number;\n description: string;\n };\n communication: {\n score: number;\n description: string;\n };\n efficiency: {\n score: number;\n description: string;\n };\n overall: {\n score: number;\n description: string;\n };\n };\n interactionQuality: {\n score: number;\n description: string;\n };\n };\n assessments: {\n userSentiment: SessionInsightUserSentiment;\n goalCompletionStatus: SessionInsightGoalCompletionStatus;\n satisfactionLevel: SessionInsightSatisfactionLevel;\n requiresFollowup: boolean;\n criticalIssuesPresent: boolean;\n escalationNeeded: boolean;\n };\n metrics: {\n sessionDurationEstimate: SessionInsightMetricsSessionDurationEstimate;\n complexityLevel: SessionInsightMetricsComplexityLevel;\n userEffortRequired: SessionInsightMetricsUserEffortRequired;\n aiConfidenceLevel: SessionInsightMetricsAiConfidenceLevel;\n };\n}\n\nexport const SESSION_INSIGHT_USER_SENTIMENT = ['positive', 'neutral', 'negative'] as const;\nexport type SessionInsightUserSentiment = (typeof SESSION_INSIGHT_USER_SENTIMENT)[number];\nexport const SESSION_INSIGHT_USER_SENTIMENT_VALUES: NameValueDescTriple<SessionInsightUserSentiment>[] = [\n { name: 'Positive', value: 'positive', desc: 'The user is satisfied with the session.' },\n { name: 'Neutral', value: 'neutral', desc: 'The user is neutral about the session.' },\n { name: 'Negative', value: 'negative', desc: 'The user is dissatisfied with the session.' }\n];\n\nexport const SESSION_INSIGHT_GOAL_COMPLETION_STATUS = ['completed', 'partially_completed', 'not_completed'] as const;\nexport type SessionInsightGoalCompletionStatus = (typeof SESSION_INSIGHT_GOAL_COMPLETION_STATUS)[number];\nexport const SESSION_INSIGHT_GOAL_COMPLETION_STATUS_VALUES: NameValueDescTriple<SessionInsightGoalCompletionStatus>[] = [\n { name: 'Completed', value: 'completed', desc: 'The agent achieved the goal.' },\n { name: 'Partially Completed', value: 'partially_completed', desc: 'The agent partially achieved the goal.' },\n { name: 'Not Completed', value: 'not_completed', desc: 'The agent did not achieve the goal.' }\n];\n\nexport const SESSION_INSIGHT_SATISFACTION_LEVEL = ['satisfied', 'neutral', 'dissatisfied'] as const;\nexport type SessionInsightSatisfactionLevel = (typeof SESSION_INSIGHT_SATISFACTION_LEVEL)[number];\nexport const SESSION_INSIGHT_SATISFACTION_LEVEL_VALUES: NameValueDescTriple<SessionInsightSatisfactionLevel>[] = [\n { name: 'Satisfied', value: 'satisfied', desc: 'The user is satisfied with the overall session.' },\n { name: 'Neutral', value: 'neutral', desc: 'The user is neutral about the overall session.' },\n { name: 'Dissatisfied', value: 'dissatisfied', desc: 'The user is dissatisfied with the overall session.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_SESSION_DURATION_ESTIMATE = ['short', 'medium', 'long'] as const;\nexport type SessionInsightMetricsSessionDurationEstimate = (typeof SESSION_INSIGHT_METRICS_SESSION_DURATION_ESTIMATE)[number];\nexport const SESSION_INSIGHT_METRICS_SESSION_DURATION_ESTIMATE_VALUES: NameValueDescTriple<SessionInsightMetricsSessionDurationEstimate>[] = [\n { name: 'Short', value: 'short', desc: 'The session was short.' },\n { name: 'Medium', value: 'medium', desc: 'The session was medium.' },\n { name: 'Long', value: 'long', desc: 'The session was long.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_COMPLEXITY_LEVEL = ['low', 'medium', 'high'] as const;\nexport type SessionInsightMetricsComplexityLevel = (typeof SESSION_INSIGHT_METRICS_COMPLEXITY_LEVEL)[number];\nexport const SESSION_INSIGHT_METRICS_COMPLEXITY_LEVEL_VALUES: NameValueDescTriple<SessionInsightMetricsComplexityLevel>[] = [\n { name: 'Low', value: 'low', desc: 'The session was low complexity.' },\n { name: 'Medium', value: 'medium', desc: 'The session was medium complexity.' },\n { name: 'High', value: 'high', desc: 'The session was high complexity.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_USER_EFFORT_REQUIRED = ['low', 'medium', 'high'] as const;\nexport type SessionInsightMetricsUserEffortRequired = (typeof SESSION_INSIGHT_METRICS_USER_EFFORT_REQUIRED)[number];\nexport const SESSION_INSIGHT_METRICS_USER_EFFORT_REQUIRED_VALUES: NameValueDescTriple<SessionInsightMetricsUserEffortRequired>[] = [\n { name: 'Low', value: 'low', desc: 'The user required low effort to get the response they wanted.' },\n { name: 'Medium', value: 'medium', desc: 'The user required medium effort to get the response they wanted.' },\n { name: 'High', value: 'high', desc: 'The user required high effort to get the response they wanted.' }\n];\n\nexport const SESSION_INSIGHT_METRICS_AI_CONFIDENCE_LEVEL = ['low', 'medium', 'high'] as const;\nexport type SessionInsightMetricsAiConfidenceLevel = (typeof SESSION_INSIGHT_METRICS_AI_CONFIDENCE_LEVEL)[number];\nexport const SESSION_INSIGHT_METRICS_AI_CONFIDENCE_LEVEL_VALUES: NameValueDescTriple<SessionInsightMetricsAiConfidenceLevel>[] = [\n { name: 'Low', value: 'low', desc: 'The AI was not confident in the response.' },\n { name: 'Medium', value: 'medium', desc: 'The AI was moderately confident in the response.' },\n { name: 'High', value: 'high', desc: 'The AI was highly confident in the response.' }\n];\n\n/**\n * Additional attributes specific to a chat session. This plus ChatUser.customData spreads into the sessionAttributes on a session using the SessionDataWithChatUserCustomDataSpreadIn type.\n */\nexport interface SessionAttributes {\n /** First name of the user participating in the session */\n firstName?: string;\n /** Last name of the user participating in the session */\n lastName?: string;\n /** Timezone of the session in IANA format */\n timezone?: string;\n //TODO: @clint do we need this still?\n /** A session token that can be used to identify the session. This is used to identify the session in the database. */\n token?: string;\n\n //TODO: @clint do we need sessionID still in this?\n\n /** The user's ID */\n userId: string;\n //TODO: this seems stupid, commented out.\n // /** The ID of the session */\n // sessionId: string;\n /** The ID of the chat app */\n chatAppId: string;\n /** The ID of the agent */\n agentId: string;\n /** The current date in ISO 8601 format */\n currentDate: string;\n}\n\n/** Session attributes with spread type T if T is an object. T is the type of ChatUser.customData. If T is undefined, then SessionAttributes is returned. */\nexport type SessionDataWithChatUserCustomDataSpreadIn<T extends RecordOrUndef = undefined> = T extends object ? SessionAttributes & T : SessionAttributes;\n\n/** This is used when creating a new chat session initially, the token will be generated. */\nexport type SessionAttributesWithoutToken<T extends RecordOrUndef = undefined> = Omit<SessionDataWithChatUserCustomDataSpreadIn<T>, 'token'>;\n\n/** This is used when creating a new chat session initially, the omitted fields are generated. */\nexport type ChatSessionForCreate<T extends RecordOrUndef = undefined> = Omit<ChatSession<T>, 'sessionId' | 'createDate' | 'lastUpdate' | 'sessionAttributes'> & {\n sessionAttributes: SessionAttributesWithoutToken<T>;\n};\n\nexport const MessageSource = ['user', 'assistant'] as const;\nexport type MessageSource = (typeof MessageSource)[number];\n\n/**\n * Represents a message in a chat session, containing metadata about the message\n * and its usage statistics.\n */\nexport interface ChatMessage {\n /** Unique identifier of the user who sent/received the message */\n userId: string;\n /** Unique identifier for the chat session this message belongs to */\n sessionId: string;\n /** Unique identifier for this specific message */\n messageId: string;\n /** The message content */\n message: string;\n /** Indicates whether the message originated from a user or the assistant */\n source: MessageSource;\n /** The AI model used to generate the response (if from bot) */\n model?: string;\n /** ISO 8601 formatted timestamp of when the message was created */\n timestamp: string;\n /** Usage statistics for this message */\n usage?: ChatMessageUsage;\n /** Array of AWS Bedrock traces containing detailed information about the model's execution */\n traces?: Trace[];\n /** Duration of the message in milliseconds */\n executionDuration?: number;\n /** Additional data to be stored in the message. Currently used to store any errors that may have occurred during agent invocation*/\n additionalData?: string;\n\n /** Files associated with the message */\n files?: ChatMessageFile[];\n\n /** Expiration date of the message in Unix seconds */\n exp_date_unix_seconds?: number;\n\n /** Verification Classifications */\n verifications?: {\n main: VerifyResponseClassification;\n correction?: VerifyResponseClassification;\n };\n}\n\nexport interface ChatMessageForRendering extends ChatMessage {\n segments: MessageSegment[];\n isStreaming?: boolean;\n}\n\n/** Supported file storage locations */\nexport const ChatMessageFileLocationType = ['s3'] as const;\nexport type ChatMessageFileLocationType = (typeof ChatMessageFileLocationType)[number];\n\n/** Supported file use cases */\nexport const ChatMessageFileUseCase = [\n /** This means the file will be read by the LLM and it will be used to answer the user's question. */\n 'chat',\n /**\n * We will append the following to the user's message before we give it to the LLM:\n *\n * (if the file is of type ChatMessageFileS3)\n * Available S3 files: s3://<s3-bucket-name>/<s3-key>\n *\n * You can be certain the <s3-bucket-name> will always be this value from SSM `/stack/chatbot/${this.stage}/s3/pika_bucket_name` so you\n * can add permissions to allow your lambda tool to have read access to the uploaded files.\n */\n 'pass-through',\n /**\n * This means that the LLM will write and execute Python code to analyze the contents of the file to answer the user's question.\n */\n 'analytics'\n] as const;\nexport type ChatMessageFileUseCase = (typeof ChatMessageFileUseCase)[number];\n\n/** Base properties for message files */\nexport interface ChatMessageFileBase {\n /**\n * Unique identifier for the file\n *\n * In the case of S3 files, this is `s3://<s3-bucket-name>/<s3-key>`\n */\n fileId: string;\n /** The name of the file for display purposes */\n fileName: string;\n /** The size of the file in bytes */\n size: number;\n /** The last modified date of the file in milliseconds since epoch */\n lastModified: number;\n /** The type of the file */\n type: string;\n /** Type of file */\n locationType: ChatMessageFileLocationType;\n /** The use case for the file. Defaults to `pass-through` if not provided. */\n useCase?: ChatMessageFileUseCase;\n}\n\n/** S3-stored message file */\nexport interface ChatMessageFileS3 extends ChatMessageFileBase {\n locationType: 's3';\n s3Bucket: string;\n s3Key: string;\n}\n\n/** Union type for all message file types */\nexport type ChatMessageFile = ChatMessageFileS3;\n\n/**\n * This is used when creating a new chat message, the messageId and timestamp are generated.\n */\nexport type ChatMessageForCreate = Omit<ChatMessage, 'messageId' | 'timestamp'>;\n\nexport const UserTypes = ['internal-user', 'external-user'] as const;\nexport type UserType = (typeof UserTypes)[number];\n\n// A type to differentiate known Pika roles\ntype PikaRoleType<T, B> = T & { __pika: B };\n\n// Define known Pika roles\nexport const PikaUserRoles = [\n // A content admin may choose any user in the system and view his chat sessions and messages\n 'pika:content-admin',\n\n // A site admin may modify access settings for chat apps and assign roles to users\n 'pika:site-admin'\n] as const;\nexport type PikaUserRole = PikaRoleType<(typeof PikaUserRoles)[number], 'PikaUserRole'>;\n\n// User-defined roles can be any string, but PikaUserRole is special\nexport type UserRole = PikaUserRole | (string & { __pika?: never });\n\nexport type RecordOrUndef = Record<string, string | undefined> | undefined;\n\nexport interface UserCognitoIdentity {\n cognitoIdentityId: string;\n cognitoAccessToken: string;\n}\n\nexport interface UserAwsCredentials {\n accessKeyId: string;\n secretKey: string;\n sessionToken: string;\n expiration: string;\n}\n\nexport interface UserAwsCredentialsResponse {\n success: boolean;\n awsCredentials: UserAwsCredentials;\n}\n\n/**\n * Represents a user in the chat system with their associated features and preferences.\n * This is saved in the chat user database.\n *\n * T is the type of customData you want to store in the user object, such as accountId, accountName, accountType, etc. This\n * data will be available to agent tools but not to the agent itself.\n */\nexport interface ChatUser<T extends RecordOrUndef = undefined> {\n /** Unique identifier for the user */\n userId: string;\n /** First name of the user */\n firstName?: string;\n /** Last name of the user */\n lastName?: string;\n /** Custom user data to associate with the user. For example, accountId, accountName, accountType, etc. */\n customData?: T;\n /**\n * If the user is a content admin, this will be set to the user they are viewing content for.\n * This is used to allow content admins to view chat sessions and messages for all users for debugging purposes.\n *\n * The key is the chatAppId and the value is the user they are viewing content for.\n */\n viewingContentFor?: Record<string, ChatUserLite>;\n /**\n * This will be set by the pika infrastructure when we find a user that is allowed to use the user override data\n * feature and actually has used the webapp user override data dialog to choose what values to override.\n *\n * This allows for the user to override `customData` specific to a chat app.\n *\n * It is never persisted to the database, it is saved server side in a secure cookie.\n *\n * The key is the chatAppId and the value is the override data for that chat app.\n */\n overrideData?: Record<string, T>;\n /** ISO 8601 formatted timestamp of when the user was created */\n createDate?: string;\n /** ISO 8601 formatted timestamp of when the user was last updated */\n lastUpdate?: string;\n /** Some chat apps and features are only accessible to internal users. This is used to determine if the user is internal or external. */\n userType?: UserType;\n /** The only role supported right now is 'pika:content-admin'. Pika Content Admin users are allowed to view chat sessions and messages for all users to help with debugging. */\n roles?: (PikaUserRole | string)[];\n /** Map of feature types to their corresponding feature configurations */\n features: {\n [K in FeatureType]: K extends 'instruction' ? InstructionFeature : K extends 'history' ? HistoryFeature : never;\n };\n\n /** If set to 'mock', this user is used for integration testing purposes. */\n testType?: 'mock';\n}\n\nexport interface ChatUserLite {\n userId: string;\n firstName?: string;\n lastName?: string;\n}\n\n/**\n * This includes auth information that is not stored in the chat user database.\n * It is not provided to clients and is used server side.\n *\n * Auth data is data your app needs such as access tokens, refresh tokens, etc.\n *\n * T is the type you want to store in the authData field, if any. This is not stored in the database.\n * U is the type of customData you want to store in the user object.\n */\nexport interface AuthenticatedUser<T extends RecordOrUndef = undefined, U extends RecordOrUndef = undefined> extends ChatUser<U> {\n authData?: T;\n /** ISO 8601 timestamp of when ChatUser data was last refreshed from DynamoDB (the pikaframework sets this) */\n lastChatUserRefresh?: string;\n}\n\n/**\n * This is a simplified version of AuthenticatedUser that is used for auth headers.\n * Note that type T may be the type \"undefined\" indicating that there is no custom user data.\n * The custom user data comes from the ChatUser.customData field provided by the auth provider.\n *\n * Not that JSON.stringify(SimpleAuthenticatedUser) must not be more than 2k in size or you risk\n * getting an erorr when we try to put it in a JWT token and send it as an http header.\n */\nexport interface SimpleAuthenticatedUser<T extends RecordOrUndef = undefined> {\n userId: string;\n customUserData?: T;\n}\n\n/**\n * These are features that are turned on at the site level in the <root>/pika-config.ts file and that may then\n * be overridden by individual chat apps.\n *\n * This is a short hand to store the computation that went into determining if a given user is allowed\n * to use the various features of pika. It is not persisted to the database or in cookies. We use it\n */\nexport interface ChatAppOverridableFeatures {\n /**\n * If enabled, entity-based access control and filtering is active for this chat app.\n * Chat apps can only disable the entity feature, not modify the site-level configuration\n * like attributeName or display settings.\n */\n entity: {\n /**\n * If false, entity features are disabled for this chat app regardless of site settings. This\n * affects the session share feature. If this is false, then a shared session will be\n * accessible to anyone with access to the chat app that the session exists within.\n */\n enabled: boolean;\n\n /**\n * The attribute name in the user's custom data that is used to match against the entity access control lists.\n *\n * This value is copied from the site level entity feature configuration and may not be overridden at the chat app level.\n *\n * It enabled is true and this is not set, then an error will be thrown.\n */\n attributeName?: string;\n };\n\n /**\n *\n * If true then the verify response feature is enabled.\n *\n * With this feature enabled, Pika will attempt to identify the veracity of the response from the LLM to a\n * user message. @see <root>/docs/developer/verify-response-feature.md\n *\n * The logic for turning this on or off is a merging of the site level setting and the chat app level setting.\n */\n verifyResponse: {\n /** If false, we don't verify responses at all. */\n enabled: boolean;\n /** If not defined, we don't auto-reprompt the user's question. */\n autoRepromptThreshold?: VerifyResponseClassification;\n };\n\n /**\n * If enabled, then the traces feature is enabled. If enabled, then the front end will show the traces from\n * the LLM in the chat app except for the detailed traces for the given user. The detailed traces are only\n * shown to the user if the detailedTraces feature is also enabled for the given user.\n *\n * The logic for turning this on or off is a merging of the site level setting and the chat app level setting.\n *\n * @see <root>/docs/developer/traces-feature.md\n */\n traces: {\n enabled: boolean;\n detailedTraces: boolean;\n };\n\n /**\n * The disclaimer notice to show to the user. This is used to inform the user that the chat is not\n * a substitute for human customer support and that the company is not liable for problems caused by\n * relying solely on the chat.\n */\n chatDisclaimerNotice: string | undefined;\n\n /**\n * If true, then the logout feature is enabled. If enabled, then the user will see a logout menu item\n * in the chat app. If the user clicks the logout menu item, then the user will be logged out and\n * redirected.\n */\n logout: {\n enabled: boolean;\n menuItemTitle: string;\n dialogTitle: string;\n dialogDescription: string;\n };\n\n /**\n * If websiteEnabled is true, users with pika:site-admin role will be able to access the site admin features.\n */\n siteAdmin: {\n websiteEnabled: boolean;\n };\n\n /** If no mime types, then the feature is diabled. */\n fileUpload: {\n mimeTypesAllowed: string[];\n };\n\n /** If no suggestions, then the feature is diabled. */\n suggestions: {\n suggestions: string[];\n randomize: boolean;\n randomizeAfter: number;\n maxToShow: number;\n };\n\n /** If no label, then the feature is diabled. */\n promptInputFieldLabel: {\n label: string | undefined;\n };\n\n uiCustomization: {\n showUserRegionInLeftNav: boolean;\n showChatHistoryInStandaloneMode: boolean;\n };\n\n tags?: TagsChatAppOverridableFeature;\n\n agentInstructionAssistance: AgentInstructionChatAppOverridableFeature;\n\n instructionAugmentation: InstructionAugmentationFeature;\n\n userMemory: UserMemoryFeature;\n}\n\nexport interface AgentInstructionChatAppOverridableFeature {\n enabled: boolean;\n includeOutputFormattingRequirements: boolean;\n includeInstructionsForTags: boolean;\n completeExampleInstructionEnabled: boolean;\n completeExampleInstructionLine?: string;\n jsonOnlyImperativeInstructionEnabled: boolean;\n jsonOnlyImperativeInstructionLine?: string;\n includeTypescriptBackedOutputFormattingRequirements: boolean;\n typescriptBackedOutputFormattingRequirements?: string;\n}\n\nexport interface InstructionAssistanceConfig {\n outputFormattingRequirements: string;\n tagInstructions?: string;\n completeExampleInstructionLine: string;\n jsonOnlyImperativeInstructionLine: string;\n typescriptBackedOutputFormattingRequirements: string;\n}\n\nexport interface TagsChatAppOverridableFeature {\n tagsEnabled: TagDefinitionLite[];\n tagsDisabled: TagDefinitionLite[];\n}\n\nexport type ChatAppOverridableFeaturesForConverseFn = Omit<\n ChatAppOverridableFeatures,\n 'chatDisclaimerNotice' | 'traces' | 'logout' | 'suggestions' | 'promptInputFieldLabel' | 'uiCustomization' | 'fileUpload'\n>;\n\n/**\n * By default, content rules exclude anything not explicitly included.\n */\nexport interface UserChatAppRule {\n /**\n * The user types allowed to access the content this rule is applied to.\n *\n * If you support both internal and external users and internal/external chat apps then you should\n * create two ChatAppContentRule objects, one for internal users and one for external users.\n */\n userTypes?: UserType[];\n\n /**\n * The user types allowed to access the chat apps this rule is applied to.\n *\n * If you support both internal and external users and internal/external chat apps then you should\n * create two ChatAppContentRule objects, one for internal users and one for external users.\n */\n chatAppUserTypes?: UserType[];\n}\n\n/** Array of available feature types in the system */\nexport const FeatureTypeArr = ['instruction', 'history'] as const;\n/** Type representing the available feature types */\nexport type FeatureType = (typeof FeatureTypeArr)[number];\n\n/** Union type of all possible feature configurations */\nexport type ChatUserFeature = InstructionFeature | HistoryFeature;\n\n/**\n * Base interface for all feature configurations\n */\nexport interface ChatUserFeatureBase {\n /** Type identifier for the feature */\n type: FeatureType;\n}\n\n/**\n * Configuration for instruction-based features\n */\nexport interface InstructionFeature extends ChatUserFeatureBase {\n type: 'instruction';\n /** The optional additional instructions for the agent */\n instruction: string;\n}\n\n/**\n * Configuration for history-based features\n */\nexport interface HistoryFeature extends ChatUserFeatureBase {\n type: 'history';\n /** Whether history feature is enabled */\n history: boolean;\n}\n\n/**\n * Contains usage statistics for a chat message, including token counts and associated costs.\n */\nexport interface ChatMessageUsage {\n /** Cost of processing the input tokens in USD */\n inputCost: number;\n /** Number of tokens in the input message */\n inputTokens: number;\n /** Cost of generating the output tokens in USD */\n outputCost: number;\n /** Number of tokens in the output message */\n outputTokens: number;\n /** Total cost of processing this message (input + output) in USD */\n totalCost: number;\n}\n\nexport interface BaseRequestData {\n userId: string;\n sessionId?: string;\n chatAppId?: string;\n agentId?: string;\n timezone?: string;\n}\n\nexport interface ConverseRequestWithCommand {\n command: 'clearConverseLambdaCache';\n cacheType: ClearConverseLambdaCacheType;\n agentId?: string;\n userId: string;\n}\n\nexport const ClearConverseLambdaCacheTypes = ['agent', 'tagDefinitions', 'instructionAssistanceConfig', 'all'] as const;\nexport type ClearConverseLambdaCacheType = (typeof ClearConverseLambdaCacheTypes)[number];\n\nexport interface ConverseRequest extends BaseRequestData {\n message: string;\n\n /**\n * The features that are enabled for the user making the request for the chat app this request is tied to.\n */\n features: ChatAppOverridableFeaturesForConverseFn;\n\n files?: ChatMessageFile[];\n\n /**\n * This it the agentID from the agent definition dynamodb table.\n * It allows us to dynamically change the agent used for the conversation.\n */\n agentId: string;\n\n /**\n * This is the attribute name in the user's custom data that is used to match against the entity access control lists.\n * This is only used if the entity feature is enabled and the user has an entity associated with them.\n *\n * @see pika-config.ts#siteFeatures.entity.attributeName\n */\n entityAttributeNameInUserCustomData?: string;\n\n /**\n * If provided, this will be used to determine the invocation mode of the converse request.\n *\n * If 'chat-app', then the converse request is a chat app request.\n *\n * If 'direct-agent-invoke', then the converse request is a direct agent invoke request and is not\n * in the context of a chat app. Since we are adding mode after the fact, if mode is provided\n * and it doesn't match what we expect, we will throw an error (chat-app requires that chatAppId is provided\n * and direct-agent-invoke requires that chatAppId is not provided).\n *\n * If 'chat-app-component', then the converse request is coming from a chat app component and is not\n * being initiated by the end user. This is used to allow the component to invoke the agent directly\n * without the need for the end user to initiate the request. These do not show up as user-created sessions\n * when we query for the users's sessions in this chat app.\n *\n * They are associated with the user and the chat app and the component in question. When this mode is used,\n * the caller must provide the chatAppId and the agentId and the complete \"tag\" that represents the component doing the calling.\n * Tag definitions have both a scope and a tag. Further, the `componentAgentInstructionName` must also provide so we\n * know which set of instructions from the tag definition to use.\n *\n * If invocationMode is not provided, uses the presence or absence of chatAppId to determine the mode (if chatAppId\n * is provided, then it's a chat app request, otherwise it's a direct agent invoke request).\n */\n invocationMode?: ConverseInvocationMode;\n\n /**\n * When invocationMode is 'chat-app-component', then this is the requiredconfiguration for the chat app component invocation.\n */\n chatAppComponentConfig?: ChatAppComponentConfig;\n\n /**\n * The source of the converse request. Defaults to 'user'. The composite key chat_app_sk looks like this:\n *\n * ${chatAppId}#${source}#${updateDate}\n *\n * The source in the composite key here will only ever be either `user` or `component`. If this attribute's value is missing or is `user` or `component-as-user`,\n * then the composite key will be set to `user` so when we query on behalf of the user, we will get all sessions for that user.\n *\n * If 'user', then the converse request is coming from the user.\n * If 'component-as-user', then the converse request is coming from a component acting as a user and thus sessions should show up in the user's sessions list.\n * If 'component', then the converse request is coming from a component.\n */\n source: ConverseSource;\n\n /**\n * The context items to include in the LLM prompt. Before we call the LLM to answer the\n * user's question, we will first use another LLM request to determine which context items are relevant to the user's question.\n * The relevant context items are then appended to the prompt sent to the LLM.\n */\n llmContextItems?: LLMContextItem[];\n}\n\nexport const ConverseSource = ['user', 'component-as-user', 'component'] as const;\nexport type ConverseSource = (typeof ConverseSource)[number];\n/**\n * This is the configuration for a chat app component invocation to the converse lambda function.\n */\nexport interface ChatAppComponentConfig {\n /**\n * The name of the set of instructions to use for the component invocation.\n * This is the key in the `componentAgentInstructionsMd` record in the tag definition as in\n *\n * `tagDef.componentAgentInstructionsMd[componentAgentInstructionName]`\n */\n componentAgentInstructionName: string;\n\n /**\n * The tag definition that represents the component doing the calling. We use this to look up the\n * right tag definition so we can get the correct instructions. Note that you will get an exception\n * if the tag definition isn't associated with this chat app or isn't marked as `chat-app-global`.\n */\n componentTagDefinition: TagDefinitionLite;\n}\n\nexport const ConverseInvocationModes = ['chat-app', 'direct-agent-invoke', 'chat-app-component'] as const;\nexport type ConverseInvocationMode = (typeof ConverseInvocationModes)[number];\n\nexport interface ChatTitleUpdateRequest extends BaseRequestData {\n /** If provided, this will be used as the title for the session */\n title?: string;\n /** The question that was asked in case we need to use bedrock to generate a title */\n userQuestionAsked?: string;\n /** The response that was generated in case we need to use bedrock to generate a title */\n answerToQuestionFromAgent?: string;\n}\n\nexport interface AddChatSessionFeedbackRequest {\n /** Note you need to generate a feedbackId before calling this function as a V7 UUID. */\n feedback: ChatSessionFeedbackForCreate;\n}\n\nexport interface AddChatSessionFeedbackAdminRequest {\n command: 'addChatSessionFeedback';\n /** Note you need to generate a feedbackId before calling this function as a V7 UUID. */\n feedback: ChatSessionFeedbackForCreate;\n}\n\nexport interface UpdateChatSessionFeedbackAdminRequest {\n command: 'updateChatSessionFeedback';\n feedback: ChatSessionFeedbackForUpdate;\n}\n\nexport interface SessionSearchAdminRequest {\n command: 'sessionSearch';\n search: SessionSearchRequest<RecordOrUndef>;\n}\n\nexport interface GetSessionAnalyticsAdminRequest {\n command: 'getSessionAnalytics';\n analyticsRequest: SessionAnalyticsRequest;\n}\n\nexport interface GetAgentRequest {\n command: 'getAgent';\n agentId: string;\n}\n\nexport interface GetAgentResponse {\n success: boolean;\n agent: AgentDefinition | undefined;\n error?: string;\n}\n\nexport interface GetChatSessionFeedbackResponse {\n success: boolean;\n feedback: ChatSessionFeedback[];\n error?: string;\n}\n\nexport interface AddChatSessionFeedbackResponse {\n success: boolean;\n feedback: ChatSessionFeedback;\n error?: string;\n}\n\nexport interface UpdateChatSessionFeedbackRequest {\n feedback: ChatSessionFeedbackForUpdate;\n}\n\nexport interface UpdateChatSessionFeedbackResponse {\n success: boolean;\n feedback: ChatSessionFeedback;\n error?: string;\n}\n\nexport interface ChatUserResponse<T extends RecordOrUndef = undefined> {\n success: boolean;\n user: ChatUser<T> | undefined;\n error?: string;\n}\n\nexport interface ChatUserSearchResponse {\n success: boolean;\n users: ChatUserLite[];\n error?: string;\n}\n\nexport type UserPrefs = Record<string, unknown>;\n\nexport interface GetChatUserPrefsResponse {\n success: boolean;\n userId: string;\n prefs?: UserPrefs;\n error?: string;\n}\n\nexport interface SetChatUserPrefsRequest {\n prefs: UserPrefs;\n\n /**\n * If true, we will first get the existing prefs for the user and then merge them with the new prefs.\n * If false, we will just set the new prefs and overwrite any existing prefs.\n * If you want to delete a pref when doing a partial update, then you should include the pref and set\n * its value expressly to null. When not doing a partial updated, just omit the pref and it will be deleted.\n * To delete all prefs, send in an empty object when not doing a partial update.\n */\n partial?: boolean;\n}\n\nexport interface SetChatUserPrefsResponse {\n success: boolean;\n userId: string;\n\n /** If successful, returns the new complete prefs object. */\n prefs?: UserPrefs;\n error?: string;\n}\n\n/**\n * Arbitrary key-value storage for web component state.\n * Scoped to user + component (scope.tag).\n * Max 400KB per component.\n */\nexport type UserWidgetData = Record<string, unknown>;\n\nexport interface GetUserWidgetDataRequest {\n scope: string;\n tag: string;\n}\n\nexport interface GetUserWidgetDataResponse {\n success: boolean;\n userId: string;\n scope: string;\n tag: string;\n data?: UserWidgetData;\n error?: string;\n}\n\nexport interface SetUserWidgetDataRequest {\n scope: string;\n tag: string;\n data: UserWidgetData;\n partial?: boolean; // If true, merge with existing data\n}\n\nexport interface SetUserWidgetDataResponse {\n success: boolean;\n userId: string;\n scope: string;\n tag: string;\n data: UserWidgetData;\n error?: string;\n}\n\nexport interface DeleteUserWidgetDataRequest {\n scope: string;\n tag: string;\n}\n\nexport interface DeleteUserWidgetDataResponse {\n success: boolean;\n userId: string;\n scope: string;\n tag: string;\n error?: string;\n}\n\nexport interface ChatUserAddOrUpdateResponse {\n success: boolean;\n user: ChatUser<RecordOrUndef>;\n error?: string;\n}\n\nexport interface ChatMessageResponse {\n success: boolean;\n message: ChatMessage;\n error?: string;\n}\n\nexport interface ChatMessagesResponse {\n success: boolean;\n messages: ChatMessage[];\n error?: string;\n}\n\nexport interface ChatSessionResponse {\n success: boolean;\n session: ChatSession<RecordOrUndef>;\n error?: string;\n}\n\nexport interface ChatSessionsResponse {\n success: boolean;\n sessions: ChatSession<RecordOrUndef>[];\n error?: string;\n}\n\n/**\n * If you are already did a search and got back a scrollId, then on the next request all you need to do is provide the scrollId\n * and nothing else. This will get you the next page of results.\n *\n * Otherwise...\n *\n * If you don't provide any search criteria, it just returns all sessions forever orderd by createDate descending unless\n * specified otherwise.\n *\n * If you provide customUserData, then we will filter results to just the sessions whose sessionAttributes includes\n * the attributes you specified in customUserData. So if you provide customUserData.accountId = 'John', then we will filter\n * to just the sessions whose sessionAttributes.accountId = 'John'.\n *\n * We will and together all the search params you provide. So if you provide userId and chatAppId, then we will filter\n * to just the sessions whose userId and chatAppId match the values you provided.\n *\n * The results will be paginated. You may provide a page token to get the next page of results.\n *\n * TODO: the implementation should make sure that the backend query includes a matching sort: [{ startDate: 'desc' }, { sessionId: 'desc' }].\n */\nexport interface SessionSearchRequest<T extends RecordOrUndef = undefined> {\n /** Matches sessions whose userId matches the given value. */\n userId?: string;\n /** Matches sessions whose chatAppId matches the given value. */\n chatAppId?: string;\n /** Matches sessions whose sessionId matches the given value. */\n sessionId?: string;\n /**\n * This must either be an object or undefined. If an object, then its type must be Record<string, string>.\n * We will then filter the sessions to only those whose sessionAttributes includes the attributes you specified in customUserData.\n * So if you provide customUserData.accountId = 'John', then we will filter to just the sessions whose sessionAttributes.accountId = 'John'.\n */\n customUserData?: T;\n\n /**\n * Allows searching for sessions by title (partial match), sessionId (exact match), or userId (exact match).\n * The search will try to match any of these fields.\n */\n query?: string;\n\n /**\n * Filter by date range.\n */\n dateFilter?: SessionSearchDateFilter;\n\n /** Filter by user type (internal-user or external-user). */\n userType?: UserType[];\n\n /** If true, then we will only return sessions that are flagged for human review and if false the converse. */\n flagged?: boolean;\n\n /** If provided, then we will only return sessions that have insights that match the given insights criteria. */\n insights?: InsightsSearchParams;\n\n /**\n * Used for deep pagination via search_after.\n * Provide the scrollId from the previous page response.\n * This contains the encoded query state including sort values.\n */\n scrollId?: string;\n\n /** If provided, we will only return sessions with feedback in one ofthe given status. */\n feedbackInStatus?: SessionFeedbackStatus[];\n\n /** If true, only return sessions with feedback reported by a human and if false, by a computer and undefined both */\n feedbackReportedByHuman?: boolean;\n\n /** If true, only return sessions with feedback created by the customer and if false, by the system and undefined both */\n feedbackCreatedByCustomer?: boolean;\n\n /** If provided, we will only return sessions with feedback with one of the given severities. */\n feedbackSeverity?: SessionFeedbackSeverity[];\n\n /** If provided, we will only return sessions with feedback with one of the given types. */\n feedbackType?: SessionFeedbackType[];\n\n /** If provided, we will only return sessions with feedback from the given user. */\n feedbackUserId?: string;\n\n /** If provided, we will only return sessions with feedback with one of the given internal comment types. */\n feedbackInternalCommentType?: FeedbackInternalCommentType[];\n\n /** If provided, we will only return sessions with feedback with one of the given internal comment statuses. */\n feedbackInternalCommentStatus?: FeedbackInternalCommentStatus[];\n\n /** If provided, we will only return sessions with feedback with one of the given internal comment user ids. */\n feedbackInternalCommentUserId?: string;\n\n /** If true, then we will include the insights in the response. */\n includeInsights?: boolean;\n\n /** If true, then we will include the feedback in the response. */\n includeFeedback?: boolean;\n\n /**\n * The fields to sort by. Determines the shape of pagination tokens.\n *\n * Defaults to [{ createDate: 'desc' }, { sessionId: 'desc' }].\n * Note that we tack on the sessionId to the end of the sort values\n * to make sure that we can get the next page of results correctly.\n * You don't need to provide the sessionId in the sortBy array, it will be added automatically\n * if it's not already there.\n */\n sortBy?: Array<{\n field: SessionSearchSortField;\n order: 'asc' | 'desc';\n }>;\n\n /**\n * Page size (defaulted by backend if not provided).\n */\n size?: number;\n}\n\nexport const SESSION_SEARCH_SORT_FIELDS = ['createDate', 'lastUpdate', 'sessionId', 'inputTokens', 'outputTokens', 'totalCost', 'insightGoalAchievementScore'] as const;\nexport type SessionSearchSortField = (typeof SESSION_SEARCH_SORT_FIELDS)[number];\nexport const SESSION_SEARCH_SORT_FIELDS_VALUES: NameValuePair<SessionSearchSortField>[] = [\n { name: 'Create Date', value: 'createDate' },\n { name: 'Last Update', value: 'lastUpdate' },\n { name: 'Session ID', value: 'sessionId' },\n { name: 'Input Tokens', value: 'inputTokens' },\n { name: 'Output Tokens', value: 'outputTokens' },\n { name: 'Total Cost', value: 'totalCost' },\n { name: 'Insight Goal Achievement Score', value: 'insightGoalAchievementScore' }\n];\n\nexport const SESSION_SEARCH_DATE_TYPES = ['created', 'updated', 'feedback'] as const;\nexport type SessionSearchDateType = (typeof SESSION_SEARCH_DATE_TYPES)[number];\nexport const SESSION_SEARCH_DATE_TYPES_VALUES: NameValuePair<SessionSearchDateType>[] = [\n { name: 'Create Date', value: 'created' },\n { name: 'Last Update', value: 'updated' },\n { name: 'Feedback Created', value: 'feedback' }\n];\n\nexport interface SessionSearchDateFilter {\n dateType: SessionSearchDateType;\n startDate: string;\n endDate?: string;\n}\n\nexport const SESSION_SEARCH_DATE_PRESETS = [\n '1-minute',\n '5-minutes',\n 'last-hour',\n 'last-day',\n 'last-week',\n 'last-month',\n 'last-3months',\n 'last-6-months',\n 'last-year',\n 'last-2-years'\n] as const;\nexport type SessionSearchDatePreset = (typeof SESSION_SEARCH_DATE_PRESETS)[number];\nexport const SESSION_SEARCH_DATE_PRESETS_VALUES: NameValuePair<SessionSearchDatePreset>[] = [\n { name: '1 Minute', value: '1-minute' },\n { name: '5 Minutes', value: '5-minutes' },\n { name: 'Last Hour', value: 'last-hour' },\n { name: 'Last Day', value: 'last-day' },\n { name: 'Last Week', value: 'last-week' },\n { name: 'Last Month', value: 'last-month' },\n { name: 'Last 3 Months', value: 'last-3months' },\n { name: 'Last 6 Months', value: 'last-6-months' },\n { name: 'Last Year', value: 'last-year' },\n { name: 'Last 2 Years', value: 'last-2-years' }\n];\nexport const SESSION_SEARCH_DATE_PRESETS_SHORT_VALUES: NameValuePair<SessionSearchDatePreset>[] = [\n { name: '1 Min', value: '1-minute' },\n { name: '5 Min', value: '5-minutes' },\n { name: 'Hour', value: 'last-hour' },\n { name: 'Day', value: 'last-day' },\n { name: 'Week', value: 'last-week' },\n { name: 'Month', value: 'last-month' },\n { name: '3 Mo', value: 'last-3months' },\n { name: '6 Mo', value: 'last-6-months' },\n { name: 'Year', value: 'last-year' },\n { name: '2 Yrs', value: 'last-2-years' }\n];\n\n/**\n * All of these are anded together. You must at least provide hasInsights.\n */\nexport interface InsightsSearchParams {\n /** If true, then we will only return sessions that have insights and false returns sessions that don't have insights. */\n hasInsights: boolean;\n goalAchievementScore?: ScoreSearchParams;\n userSatisfactionScore?: ScoreSearchParams;\n aiPerformanceOverallScore?: ScoreSearchParams;\n aiPerformanceAccuracyScore?: ScoreSearchParams;\n aiPerformanceEfficiencyScore?: ScoreSearchParams;\n interactionQualityScore?: ScoreSearchParams;\n\n userSentiment?: SessionInsightUserSentiment[]; // Matches documents that have any of these values.\n goalCompletionStatus?: SessionInsightGoalCompletionStatus[]; // Matches documents that have any of these values.\n satisfactionLevel?: SessionInsightSatisfactionLevel[]; // Matches documents that have any of these values.\n sessionDurationEstimate?: SessionInsightMetricsSessionDurationEstimate[]; // Matches documents that have any of these values.\n complexityLevel?: SessionInsightMetricsComplexityLevel[]; // Matches documents that have any of these values.\n userEffortRequired?: SessionInsightMetricsUserEffortRequired[]; // Matches documents that have any of these values.\n aiConfidenceLevel?: SessionInsightMetricsAiConfidenceLevel[]; // Matches documents that have any of these values.\n}\n\nexport interface ScoreSearchParams {\n score: number;\n operator: ScoreSearchOperator;\n}\n\nexport const SCORE_SEARCH_OPERATORS = ['eq', 'gte', 'lte'] as const;\nexport type ScoreSearchOperator = (typeof SCORE_SEARCH_OPERATORS)[number];\nexport const SCORE_SEARCH_OPERATORS_VALUES: NameValuePair<ScoreSearchOperator>[] = [\n { name: '=', value: 'eq' },\n { name: '>=', value: 'gte' },\n { name: '<=', value: 'lte' }\n];\n\nexport interface SessionSearchResponse<T extends RecordOrUndef = undefined> {\n success: boolean;\n sessions: ChatSession<T>[];\n error?: string;\n /**\n * If returned, then there are more pages of results. On the next request, provide this scrollId and nothing else\n * and we will get you the next page of results.\n */\n scrollId?: string;\n\n /** For now, we will always return the total number of hits. */\n total: number;\n\n /** The page size that was used for this request. */\n pageSize: number;\n}\n\n// Agent Definition System Types\n\n/**\n * Access control rule for agents and tools\n */\nexport interface AccessRule {\n /** Condition expression for access control (e.g., \"user.scope IN ['admin', 'user'] AND account.type = 'retailer'\") */\n condition?: string;\n /** Effect of the rule - allow or deny access */\n effect: 'allow' | 'deny';\n /** Order/priority for rule evaluation (lower numbers evaluated first) */\n order?: number;\n /** Optional description of the rule */\n description?: string;\n}\n\n/**\n * Rollout policy configuration for agent definitions\n */\nexport interface RolloutPolicy {\n /** List of beta account IDs that can access this agent */\n betaAccounts?: string[];\n /** List of AWS regions where this agent is available */\n regionRestrictions?: string[];\n /** Tool overrides mapping old tool IDs to new tool IDs */\n toolOverrides?: Record<string, string>;\n}\n\n/**\n * Agent definition representing an LLM agent configuration\n */\nexport interface AgentDefinition {\n /** Unique agent identifier (e.g., 'weather-bot') */\n agentId: string;\n /** Foundation model to use for this agent. */\n foundationModel?: string;\n /** Foundation model to use for verifying the response of this agent. */\n verificationFoundationModel?: string;\n /** System prompt template (can be a handlebars template with placeholders like {{user.email}}) */\n basePrompt: string;\n /** List of access control rules with conditions. If not provided, the agent will be accessible to all users. */\n accessRules?: AccessRule[];\n /** Optional Lambda ARN for augmenting prompt/session context (future feature) */\n runtimeAdapter?: string;\n /** Rollout gating configuration per account/org/region. If not provided, the agent will be accessible to all users. */\n rolloutPolicy?: RolloutPolicy;\n /** Cache configuration for testing and debugging, used in lambdas that create LRU caches for agent definitions */\n dontCacheThis?: boolean;\n\n /** List of collaborator agent IDs that are used to orchestrate this agent. */\n collaborators?: {\n agentId: string;\n instruction: string;\n historyRelay: 'TO_COLLABORATOR' | 'TO_AGENT';\n }[];\n\n /** The collaboration type for this agent. */\n agentCollaboration?: AgentCollaboration;\n\n /** List of tool definitions that this agent uses */\n toolIds: string[];\n /** A list of knowledge bases that are associated with this agent. */\n knowledgeBases?: KnowledgeBase[];\n /** Agent definition version */\n version: number;\n /** User who created the definition */\n createdBy: string;\n /** Last editor user */\n lastModifiedBy: string;\n /** ISO 8601 formatted timestamp of creation */\n createdAt: string;\n /** ISO 8601 formatted timestamp of last update */\n updatedAt: string;\n\n /** If set to 'mock', this is a test agent that will get deleted after 1 day. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport type UpdateableAgentDefinitionFields = Extract<\n keyof AgentDefinition,\n 'basePrompt' | 'toolIds' | 'accessRules' | 'runtimeAdapter' | 'rolloutPolicy' | 'dontCacheThis' | 'knowledgeBases'\n>;\n\nexport type AgentDefinitionForUpdate = Partial<Omit<AgentDefinition, 'version' | 'createdAt' | 'createdBy' | 'updatedAt' | 'lastModifiedBy' | 'test'>> & {\n agentId: string;\n};\n\nexport type AgentDefinitionForCreate = Omit<AgentDefinition, 'version' | 'createdAt' | 'updatedAt'> & {\n agentId?: AgentDefinition['agentId'];\n};\n\n/**\n * This allows you to do an idempotent create or update of an agent and its tools. You can create or modify\n * and its tools. If you specify tools then we will intelligently create or update the tools. If you don't\n * specify tools then we will just create the agent.\n *\n * If you use this you must provide an agentId so we can match up what's there already with what is being provided.\n * If you provide tools then you must provide a toolId for each tool so we can match up what's there already with what is being provided.\n *\n * Three patterns are supported:\n * 1. tools only: Define new tools (create/update)\n * 2. agent.toolIds only: Reference existing tools by ID\n * 3. Both tools AND agent.toolIds: Mixed approach - define new tools while referencing existing ones\n */\nexport interface AgentDataRequest {\n /**\n * Agent must have an ID provided or we will throw an exception since we can't match up what's there already\n * with what is being provided in the custom resource in an idempotent way.\n */\n agent: AgentDefinitionForIdempotentCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n\n /**\n * Tools must have an ID provided or we will throw an exception since we can't match up what's there already\n * with what is being provided in the custom resource in an idempotent way.\n */\n tools?: ToolDefinitionForIdempotentCreateOrUpdate[];\n}\n\n/**\n * In the AgentDataReqest.tools we find that we need to pass in the arn of the lambda function that is the tool.\n * However, at build time you may not have the arn of the lambda function. So, in the Agent custom resource\n * we allow you to pass in a map of toolId to lambdaArn. Then, the custom resource lambda will use this map\n * to replace the lambdaArn with the actual arn of the lambda function.\n *\n * THe key is the toolID and the value is the lambdaArn.\n */\nexport type ToolIdToLambdaArnMap = Record<string, string>;\n\nexport interface AgentAndTools {\n agent: AgentDefinition;\n collaborators?: AgentDefinition[];\n tools?: ToolDefinition[];\n}\n\nexport interface AgentDataResponse {\n success: boolean;\n error?: string;\n agent: AgentDefinition;\n tools?: ToolDefinition[];\n}\n\nexport interface ChatAppDataResponse {\n success: boolean;\n error?: string;\n chatApp: ChatApp;\n}\n\nexport type AgentDefinitionForIdempotentCreateOrUpdate = Omit<AgentDefinition, 'toolIds' | 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n toolIds?: string[];\n};\n/**\n * Execution type for tool definitions. Right now, only lambda is supported.\n */\nexport type ExecutionType = 'lambda' | 'http' | 'inline' | 'mcp';\n\n/**\n * Lifecycle status for tool definitions\n */\nexport type LifecycleStatus = 'enabled' | 'disabled' | 'retired';\n\n/**\n * Lifecycle management configuration for tools\n */\nexport interface ToolLifecycle {\n /** Current status of the tool */\n status: LifecycleStatus;\n /** Optional deprecation date in ISO 8601 format */\n deprecationDate?: string;\n /** Optional migration path to newer tool version */\n migrationPath?: string;\n}\n\n/**\n * Tool definition representing a callable function/service\n */\nexport interface ToolDefinitionBase {\n /** Type of execution (lambda, http, inline) */\n executionType: ExecutionType;\n\n /** Unique tool name/version (e.g., 'weather-basic@1') */\n toolId: string;\n /** Friendly display name */\n displayName: string;\n /** Must not have spaces and no punctuation except _ and - : ([0-9a-zA-Z][_-]?){1,100} */\n name: string;\n /** Description for LLM consumption. MUST BE LESS THAN 500 CHARACTERS */\n description: string;\n /** Timeout in seconds (default: 30) */\n executionTimeout?: number;\n /**\n * List of agent frameworks that this tool supports\n *\n * If you choose to support bedrock, you must provide a functionSchema.\n */\n supportedAgentFrameworks: AgentFramework[];\n /** Bedrock-specific function schema (auto-generated or provided) */\n functionSchema?: FunctionDefinition[];\n /** Tag map for filtering and categorization */\n tags?: Record<string, string>;\n /** Lifecycle management configuration */\n lifecycle?: ToolLifecycle;\n /** Tool version */\n version: number;\n /** List of access control rules */\n accessRules?: AccessRule[];\n /** User who created the tool */\n createdBy: string;\n /** User who last modified the tool */\n lastModifiedBy: string;\n /** ISO 8601 formatted timestamp of creation */\n createdAt: string;\n /** ISO 8601 formatted timestamp of last update */\n updatedAt: string;\n\n /** If set to 'mock', this is a test tool that will get deleted after 1 day. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport interface LambdaToolDefinition extends ToolDefinitionBase {\n executionType: 'lambda';\n /**\n * If executionType is 'lambda', this is the required ARN of the Lambda function.\n * Note that the Lambda function must have an 'agent-tool' tag set to 'true'.\n */\n lambdaArn: string;\n}\n\nexport interface McpToolDefinition extends ToolDefinitionBase {\n executionType: 'mcp';\n url: string;\n auth?: OAuth;\n}\n\nexport interface InlineToolDefinition extends ToolDefinitionBase {\n executionType: 'inline';\n code: string; // This is the code to execute. It is a stringified function.\n handler?: (event: ActionGroupInvocationInput, params: Record<string, any>) => Promise<unknown>;\n}\n\nexport type ToolDefinition = LambdaToolDefinition | McpToolDefinition | InlineToolDefinition;\n\nexport type UpdateableToolDefinitionFields =\n | Extract<\n keyof ToolDefinitionBase,\n 'name' | 'displayName' | 'description' | 'executionType' | 'executionTimeout' | 'supportedAgentFrameworks' | 'functionSchema' | 'tags' | 'lifecycle' | 'accessRules'\n >\n | 'lambdaArn'\n | 'url'\n | 'auth'\n | 'code';\n\nexport type ToolDefinitionForCreate =\n | (Omit<LambdaToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n toolId?: ToolDefinition['toolId'];\n })\n | (Omit<McpToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n toolId?: ToolDefinition['toolId'];\n });\n\nexport type ToolDefinitionForIdempotentCreateOrUpdate =\n | (Omit<LambdaToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n functionSchema: FunctionDefinition[];\n supportedAgentFrameworks: ['bedrock'];\n })\n | (Omit<InlineToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n functionSchema: FunctionDefinition[];\n supportedAgentFrameworks: ['bedrock'];\n })\n | (Omit<McpToolDefinition, 'version' | 'createdAt' | 'updatedAt' | 'lastModifiedBy' | 'createdBy'> & {\n functionSchema: FunctionDefinition[];\n supportedAgentFrameworks: ['bedrock'];\n });\n\nexport interface OAuth {\n clientId: string;\n clientSecret: string;\n tokenUrl: string;\n token?: {\n accessToken: string;\n expires: number;\n };\n}\n\nexport type ToolDefinitionForUpdate =\n | (Partial<Omit<LambdaToolDefinition, 'version' | 'createdAt' | 'createdBy' | 'updatedAt' | 'lastModifiedBy'>> & {\n toolId: string;\n })\n | (Partial<Omit<McpToolDefinition, 'version' | 'createdAt' | 'createdBy' | 'updatedAt' | 'lastModifiedBy'>> & {\n toolId: string;\n });\n\nexport type AgentFramework = 'bedrock';\n\nexport interface CreateAgentRequest {\n agent: AgentDefinitionForCreate;\n existingToolsToAssociate?: string[];\n newToolsToCreate?: ToolDefinitionForCreate[];\n userId: string;\n}\n\nexport interface UpdateAgentRequest {\n agent: AgentDefinitionForUpdate;\n userId: string;\n}\n\nexport interface CreateToolRequest {\n tool: ToolDefinitionForCreate;\n userId: string;\n}\nexport interface GetChatAppsByRulesRequest {\n /** We use this to lookup the user and their userType. */\n userId: string;\n\n /** If this request is to figure out which chat apps to show on the home page, then this will be present. */\n homePageFilterRules?: UserChatAppRule[];\n\n /** If provided, then we will only return this one chat app and then only if the user is allowed to access it. */\n chatAppId?: string;\n\n /**\n * If true, then we will return the list of apps that the user is allowed to see on the home page.\n * Note that this could be different than the list of apps that the user is allowed to access\n * if they don't want to show a given app on the home page.\n */\n chatAppsForHomePage?: boolean;\n\n /**\n * We sometimes need to know if a user's associated \"entity\" (account or company) is allowed to access a chat app.\n * This is the path to the custom data field that is used to match against the entity. Of course,\n * your must have enabled the entity feature in pika-config.ts and set the attributeName to the path to the custom data field\n * attribute name that contains the entity value.\n *\n * For example, if a user is associated with an account and has `customData.accountId` then this might be 'accountId'.\n */\n customDataFieldPathToMatchUsersEntity?: string;\n}\n\nexport interface GetChatAppsByRulesResponse {\n success: boolean;\n chatApps: ChatApp[];\n error?: string;\n}\n\nexport interface UpdateToolRequest {\n tool: ToolDefinitionForUpdate;\n userId: string;\n}\n\nexport interface SearchToolsRequest {\n toolIds: string[];\n userId: string;\n}\n\nexport interface CreateChatAppRequest {\n chatApp: ChatAppForCreate;\n userId: string;\n}\n\nexport interface UpdateChatAppRequest {\n chatApp: ChatAppForUpdate;\n userId: string;\n}\n\nexport interface CreateOrUpdateChatAppOverrideRequest {\n override: ChatAppOverrideForCreateOrUpdate;\n userId: string;\n}\n\nexport interface CreateOrUpdateChatAppOverrideResponse {\n success: boolean;\n chatAppOverride: ChatAppOverride;\n}\n\nexport interface DeleteChatAppOverrideResponse {\n success: boolean;\n}\n\nexport interface DeleteChatAppOverrideRequest {}\n\n// ===== MOCK DATA APIS FOR TESTING =====\n\nexport interface DeleteMockDataRequest {\n userId: string;\n sessions?: {\n sessionId: string;\n sessionUserId: string;\n }[];\n chatApps?: {\n chatAppId: string;\n }[];\n agents?: {\n agentId: string;\n }[];\n tools?: {\n toolId: string;\n }[];\n users?: {\n userId: string;\n }[];\n}\n\nexport interface DeleteMockDataResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockSessionRequest {\n session: ChatSessionForCreate & { test: 'test' };\n userId: string; // admin user creating the mock\n}\n\nexport interface CreateOrUpdateMockSessionResponse {\n success: boolean;\n session: ChatSession<RecordOrUndef>;\n}\n\nexport interface DeleteMockSessionRequest {\n sessionId: string;\n sessionUserId: string; // owner of session\n userId: string; // admin user deleting the mock\n}\n\nexport interface DeleteMockSessionResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockChatAppRequest {\n chatApp: ChatApp & { test: 'test' };\n userId: string;\n}\n\nexport interface CreateOrUpdateMockChatAppResponse {\n success: boolean;\n chatApp: ChatApp;\n}\n\nexport interface DeleteMockChatAppRequest {\n chatAppId: string;\n userId: string;\n}\n\nexport interface DeleteMockChatAppResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockAgentRequest {\n agent: AgentDefinition & { test: 'test' };\n userId: string;\n}\n\nexport interface CreateOrUpdateMockAgentResponse {\n success: boolean;\n agent: AgentDefinition;\n}\n\nexport interface DeleteMockAgentRequest {\n agentId: string;\n userId: string;\n}\n\nexport interface DeleteMockAgentResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockToolRequest {\n tool: ToolDefinition & { test: 'test' };\n userId: string;\n}\n\nexport interface CreateOrUpdateMockToolResponse {\n success: boolean;\n tool: ToolDefinition;\n}\n\nexport interface DeleteMockToolRequest {\n toolId: string;\n userId: string;\n}\n\nexport interface DeleteMockToolResponse {\n success: boolean;\n}\n\nexport interface CreateOrUpdateMockUserRequest {\n user: ChatUser<RecordOrUndef> & { test: 'test' };\n userId: string; // admin user creating the mock\n}\n\nexport interface CreateOrUpdateMockUserResponse {\n success: boolean;\n user: ChatUser<RecordOrUndef>;\n}\n\nexport interface DeleteMockUserRequest {\n mockUserId: string; // userId of the mock user to delete\n userId: string; // admin user deleting the mock\n}\n\nexport interface DeleteMockUserResponse {\n success: boolean;\n}\n\n// ===== GET ALL MOCK DATA APIS =====\n\nexport interface GetAllMockSessionsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockSessionsResponse {\n success: boolean;\n chatSessions: ChatSession<RecordOrUndef>[];\n nextToken?: string;\n}\n\nexport interface GetMockSessionByUserIdAndSessionIdRequest {\n sessionId: string;\n userId: string;\n}\n\nexport interface GetMockSessionByUserIdAndSessionIdResponse {\n success: boolean;\n chatSession?: ChatSession<RecordOrUndef>;\n}\n\nexport interface GetAllMockUsersRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockUsersResponse {\n success: boolean;\n chatUsers: ChatUser<RecordOrUndef>[];\n nextToken?: string;\n}\n\nexport interface GetAllMockAgentsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockAgentsResponse {\n success: boolean;\n agents: AgentDefinition[];\n nextToken?: string;\n}\n\nexport interface GetAllMockToolsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockToolsResponse {\n success: boolean;\n tools: ToolDefinition[];\n nextToken?: string;\n}\n\nexport interface GetAllMockChatAppsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockChatAppsResponse {\n success: boolean;\n chatApps: ChatApp[];\n nextToken?: string;\n}\n\nexport interface GetAllMockSharedSessionVisitsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockSharedSessionVisitsResponse {\n success: boolean;\n sharedSessionVisits: SharedSessionVisitHistory[];\n nextToken?: string;\n}\n\nexport interface GetAllMockPinnedSessionsRequest {\n limit?: number;\n nextToken?: string;\n}\n\nexport interface GetAllMockPinnedSessionsResponse {\n success: boolean;\n pinnedSessions: PinnedSession[];\n nextToken?: string;\n}\n\nexport interface GetAllMockDataRequest {\n limit?: number;\n}\n\nexport interface GetAllMockDataResponse {\n success: boolean;\n data: {\n sessions: ChatSession<RecordOrUndef>[];\n users: ChatUser<RecordOrUndef>[];\n agents: AgentDefinition[];\n tools: ToolDefinition[];\n chatApps: ChatApp[];\n sharedSessionVisits: SharedSessionVisitHistory[];\n pinnedSessions: PinnedSession[];\n };\n}\n\n// ===== DELETE ALL MOCK DATA APIS =====\n\nexport interface DeleteAllMockSessionsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockSessionsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockUsersRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockUsersResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockAgentsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockAgentsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockToolsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockToolsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockChatAppsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockChatAppsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockSharedSessionVisitsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockSharedSessionVisitsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockPinnedSessionsRequest {\n userId: string;\n}\n\nexport interface DeleteAllMockPinnedSessionsResponse {\n success: boolean;\n deletedCount: number;\n}\n\nexport interface DeleteAllMockDataRequest {\n userId: string;\n confirm?: boolean;\n}\n\nexport interface DeleteAllMockDataResponse {\n success: boolean;\n deletedCounts: {\n sessions: number;\n users: number;\n agents: number;\n tools: number;\n chatApps: number;\n sharedSessionVisits: number;\n pinnedSessions: number;\n total: number;\n };\n}\n\nexport type ChatAppMode = 'standalone' | 'embedded';\n\n/**\n * This extends AccessRules so you can enable/disable the chat app for certain users.\n */\nexport interface ChatApp extends AccessRules {\n /**\n * Unique ID for the chat. Only - and _ allowed. Will\n * be used in URL to access the chatbot so keep that in mind\n */\n chatAppId: string;\n\n /**\n * The modes that this chat app supports. If not provided, then all modes are supported.\n * `standalone` means that the chat app can be displayed standalone in a website\n * not embedded in another website as an iframe. `embedded` means that the chat app\n * is embedded in another website as an iframe.\n */\n modesSupported?: ChatAppMode[];\n\n /**\n * Set to true when actively developing so changes are reflected immediately.\n * Various lambdas will cache this data for some minutes (usually 5).\n */\n dontCacheThis?: boolean;\n\n /**\n * The title of the chat app, a human readable name. This is the title that will be displayed in the title bar of the chat app when\n * in standalone mode.\n */\n title: string;\n\n /**\n * A description of the chat app. This is used to describe the chat app to the user and in navigation.\n * Required. Must be less than 300 characters (not currently enforced but will be in the future).\n */\n description: string;\n\n /**\n * The ID of the agent that should be invoked for this chat app (e.g. 'weather-agent').\n * Must be the agentId of an agent that exists in the agent definition table.\n */\n agentId: string;\n\n /**\n * Optional way to override the original access control settings provided when the\n * chat app was deployed. This is not stored on the actual chat app record in the\n * chat-app table. If not provided, falls back to the access control settings set\n * by the chat app when it was deployed.\n *\n * This ChatAppOverride data is stored in a separate record in the chat-app table\n * where the chatAppId is `${chatAppId}:override`. It is stored\n * separately so the list of included entities can grow quite large if needed.\n *\n * When you retrieve a ChatApp using the APIs, this will be populated for you if\n * an override record exists.\n *\n * This is useful so we can modify access control settings without having to redeploy the\n * chat app itself.\n */\n override?: ChatAppOverride;\n\n /** Any feature not explicitly defined and turned on is turned off by default. */\n features?: Partial<Record<FeatureIdType, ChatAppFeature>>;\n\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate: string;\n\n /** ISO 8601 formatted timestamp of the last chat app update */\n lastUpdate: string;\n\n /** If set to 'mock', this is a test chat app that will get deleted after 1 day. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport interface ChatAppLite {\n /**\n * Unique ID for the chat. Only - and _ allowed. Will\n * be used in URL to access the chatbot so keep that in mind\n */\n chatAppId: string;\n\n /**\n * The title of the chat app, a human readable name. This is the title that will be displayed in the title bar of the chat app when\n * in standalone mode.\n */\n title: string;\n\n /**\n * A description of the chat app. This is used to describe the chat app to the user and in navigation.\n * Required. Must be less than 300 characters (not currently enforced but will be in the future).\n */\n description: string;\n\n /**\n * The ID of the agent that should be invoked for this chat app (e.g. 'weather-agent').\n * Must be the agentId of an agent that exists in the agent definition table.\n */\n agentId: string;\n\n /**\n * The user types that are allowed to access this chat app. If not provided, then all user types are allowed.\n */\n userTypes?: UserType[];\n}\n\nexport interface KnowledgeBase {\n /** A unique identifier for the knowledge base */\n id: string;\n\n /** The agent frameworks that this knowledge base supports */\n supportedAgentFrameworks: AgentFramework[];\n\n /** A description of the knowledge base */\n description: string;\n\n /**\n * This is the filter values that will be used to filter the knowledge base to restrict the set of\n * documents that are searched as part of the retrieve operation.\n *\n * When you have a file to ingest into the knowledge base in s3, you can include an accompanying metadata file\n * that defines metadata attributes and values applicable to the file.\n *\n * Note that each `value` in this filter may contain templated values like this:\n *\n * my-{name}-and-{company}\n *\n * If present, we will try to match the template attribute name to either a user top level attribute\n * name (one of userId, firstName, lastName) or an attribute within the user.customData object. Note that the template value\n * may include dot notation to access a nested attribute. For example, if the user has a customData object\n * with the following structure:\n *\n * {\n * customData: {\n * account: {\n * id: '123'\n * }\n * }\n *\n * Then the template value 'my-{account.id}' would match the value 'my-123'.\n */\n filter?: RetrievalFilter;\n\n /**\n * The number of results to return from the knowledge base. If not provided, the default is a smaller number,\n * probably 5.\n */\n numberOfResults?: number;\n}\n\nexport type UpdateableChatAppFields = Extract<\n keyof ChatApp,\n 'dontCacheThis' | 'title' | 'description' | 'agentId' | 'features' | 'enabled' | 'userTypes' | 'userRoles' | 'modesSupported'\n>;\n\nexport type ChatAppForCreate = Omit<ChatApp, 'createDate' | 'lastUpdate'>;\n\nexport type ChatAppForUpdate = Partial<Omit<ChatApp, 'createDate' | 'lastUpdate'>>;\n\nexport type ChatAppForIdempotentCreateOrUpdate = Omit<ChatApp, 'createDate' | 'lastUpdate'>;\n\n/**\n * This allows you to do an idempotent create or update of a chat app.\n *\n * If you use this you must provide a chatAppId so we can match up what's there already with what is being provided.\n */\nexport interface ChatAppDataRequest {\n /**\n * ChatApp must have an ID provided or we will throw an exception since we can't match up what's there already\n * with what is being provided in the custom resource in an idempotent way.\n */\n chatApp: ChatAppForIdempotentCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\n/**\n * These are the features that are available to be overridden by the chat app.\n */\nexport type ChatAppFeature =\n | FileUploadFeatureForChatApp\n | SuggestionsFeatureForChatApp\n | PromptInputFieldLabelFeatureForChatApp\n | UiCustomizationFeatureForChatApp\n | VerifyResponseFeatureForChatApp\n | TracesFeatureForChatApp\n | ChatDisclaimerNoticeFeatureForChatApp\n | LogoutFeatureForChatApp\n | SessionInsightsFeatureForChatApp\n | UserDataOverrideFeatureForChatApp\n | TagsFeatureForChatApp\n | AgentInstructionAssistanceFeatureForChatApp\n | InstructionAugmentationFeatureForChatApp\n | UserMemoryFeatureForChatApp\n | EntityFeatureForChatApp;\n\nexport interface Feature {\n /**\n * Must be unique, only alphanumeric and - _ allowed, may not start with a number\n *\n * This is used to identify the feature in the database.\n */\n featureId: FeatureIdType;\n\n /** Whether the feature is on or off for the chat app in question. Most features are off by default, see the specific feature for details. */\n enabled: boolean;\n}\n\nexport const FeatureIdList = [\n 'fileUpload',\n 'promptInputFieldLabel',\n 'suggestions',\n 'uiCustomization',\n 'verifyResponse',\n 'traces',\n 'chatDisclaimerNotice',\n 'logout',\n 'sessionInsights',\n 'userDataOverrides',\n 'tags',\n 'agentInstructionAssistance',\n 'instructionAugmentation',\n 'userMemory',\n 'entity'\n] as const;\nexport type FeatureIdType = (typeof FeatureIdList)[number];\n\nexport const EndToEndFeatureIdList = ['verifyResponse', 'traces'] as const;\nexport type EndToEndFeatureIdType = (typeof EndToEndFeatureIdList)[number];\n\nexport const FEATURE_NAMES: Record<FeatureIdType, string> = {\n fileUpload: 'File Upload',\n promptInputFieldLabel: 'Prompt Input Field Label',\n suggestions: 'Suggestions',\n uiCustomization: 'UI Customization',\n verifyResponse: 'Verify Response',\n traces: 'Traces',\n chatDisclaimerNotice: 'Chat Disclaimer Notice',\n logout: 'Logout',\n sessionInsights: 'Session Insights',\n userDataOverrides: 'User Data Override',\n tags: 'Tags',\n agentInstructionAssistance: 'Agent Instruction Assistance',\n instructionAugmentation: 'Instruction Augmentation',\n userMemory: 'User Memory',\n entity: 'Entity'\n};\n\nexport interface SiteAdminFeature {\n websiteEnabled: boolean;\n\n /** Ignored if websiteEnabled is false. */\n supportUserEntityAccessControl?: {\n /**\n * If you turn this on then we expect that you will provide\n */\n enabled: boolean;\n };\n\n /**\n * If turned on, any user with the pika:site-admin role will be able to view session insights\n * for any chat session in the admin website. This is useful for debugging and troubleshooting.\n * This feature will not be enabled unless you have also first enabled the session insights feature\n * at the site level in pika-config.ts. Note that the entity feature must be turned on\n * if you want to display and filter by entity in the session insights UI.\n */\n sessionInsights?: {\n enabled: boolean;\n };\n\n /**\n * Ignored if websiteEnabled is false.\n *\n * If turned on then you may restrict access to a chat app for only specified users.\n */\n supportSpecificUserAccessControl?: {\n enabled: boolean;\n };\n}\n\n/**\n * Why make this a feature? Some enterprises that allow their internal users to act on behalf of other\n * users and accounts for the purpose of debugging and troubleshooting. So, if the user is logged in as\n * one account, they can click a menu item to logout and then log in as another account. The base case\n * for external users is to likely not have this feature as they are piggy backing on auth from\n * another enterprise site or system.\n */\nexport interface LogoutFeature extends AccessRules {\n /**\n * The title of the menu item that will be displayed to authorized users that when clicked will\n * log them out of the chat app. Defaults to \"Logout\".\n */\n menuItemTitle?: string;\n\n /**\n * The title of the dialog that will be displayed when the user clicks the menu item. Defaults to \"Logout\".\n */\n dialogTitle?: string;\n\n /**\n * The description that appears benath the title in the dialog window. Defaults to\n * \"Are you sure you want to logout?\"\n */\n dialogDescription?: string;\n}\n\nexport interface LogoutFeatureForChatApp extends LogoutFeature, Feature {\n featureId: 'logout';\n}\n\n/**\n * If a notice is provided, Pika will display a disclaimer notice to the user.\n *\n * This feature must be enabled at the site level and then individual chat apps can choose to override\n * the notice text.\n */\nexport interface ChatDisclaimerNoticeFeature {\n enabled: boolean;\n\n /** The notice text to display to the user. If not provided, no notice is displayed. */\n notice?: string;\n}\n\nexport interface ChatDisclaimerNoticeFeatureForChatApp extends ChatDisclaimerNoticeFeature, Feature {\n featureId: 'chatDisclaimerNotice';\n}\n\n/**\n * When turned on, Pika will attempt to identify the veracity of the response from the LLM to a user message.\n *\n * This feature must be enabled at the site level and then individual chat apps can choose to turn it off\n * if they do not want it on. So, to function you must go to pika-config.ts and enable the feature.\n *\n * Further, individual chat apps can choose to override which users are allowed to use the feature.\n *\n * Note that enabling this will have no effect if the feature is not enabled at the site level first (@see pika-config.ts)\n * You can only choose to disable the feature at the chat app level if it is enabled at the site level.\n *\n * @see <root>/docs/developer/verify-response-feature.md\n */\nexport interface VerifyResponseFeature extends AccessRules {\n /**\n * The threshold for which response classifications will trigger an auto-reprompt to the LLM to correct the answer.\n *\n * If not defined, we will not automatically reprompt the user's question to the LLM to correct the answer.\n *\n * The classificationsa are currenly A, B, C and F with F being terrible and A being really really good.\n *\n * So, if you set this to F then the Pika will only automatically send the user's question back to the LLM to correct the answer\n * if the response verification is F. If you set it to B then it would do so on B, C and F.\n *\n * Note you cannot set this to A since it is not retryable.\n *\n * Recommended default: 'C'\n */\n autoRepromptThreshold?: RetryableVerifyResponseClassification;\n}\n\nexport interface VerifyResponseFeatureForChatApp extends VerifyResponseFeature, Feature {\n featureId: 'verifyResponse';\n}\n\n/**\n * When turned on, Pika will show the traces from the LLM in the chat app. There are three primary types of traces:\n * - Orchestration traces: these show the fundamental reasoning process of the LLM\n * - Failure traces: these show the reason the LLM failed to answer the user's question\n * - Parameter traces: these show the actual parameters passed from the LLM to the tools it invoked\n *\n * By default, when you turn on the traces feature, detailed traces (meaning the parameter traces) are not shown\n * because they show a lot of detail about how the LLM is working. You must explicitly turn on the detailed traces\n * feature to show them.\n *\n * Individual chat apps can choose to override which users are allowed to use the feature. This is done\n * by setting the detailedTraces property to an AccessRules object. @see <root>/docs/developer/traces-feature.md\n *\n * Note that enabling this will have no effect if the feature is not enabled at the site level first (@see pika-config.ts)\n * You can only choose to disable the feature at the chat app level if it is enabled at the site level.\n */\nexport interface TracesFeature extends AccessRules {\n /**\n * If not provided, then the detailed traces are not shown. If provided, then the detailed traces are shown\n * to the user if the user is allowed to use the detailed traces feature.\n */\n detailedTraces?: AccessRules;\n}\n\nexport interface TracesFeatureForChatApp extends TracesFeature, Feature {\n featureId: 'traces';\n}\n\n/**\n * Whether to support UI customization in the chat app. If true, then the chat app will support UI customization.\n */\nexport interface UiCustomizationFeature {\n enabled: boolean;\n\n /** Whether to show the chat history as left nav in full page mode. Defaults to true. */\n showChatHistoryInStandaloneMode?: boolean;\n\n /** Whether to show the user region in the left nav in full page mode. Defaults to true. */\n showUserRegionInLeftNav?: boolean;\n}\n\nexport interface UiCustomizationFeatureForChatApp extends UiCustomizationFeature, Feature {\n featureId: 'uiCustomization';\n}\n\n/**\n * Whether to support suggestions in the chat app. If true, then the chat app will support suggestions.\n * If false, then the chat app will not support suggestions.\n *\n * Default is false.\n */\nexport interface SuggestionsFeature {\n enabled: boolean;\n\n /**\n * A list of suggestions that will be displayed to the user relevant to the chat app.\n * Will be stored gzipped hex encoded in db. Gzipped compressed value may not be more than 100kb.\n */\n suggestions: string[];\n\n /**\n * The maximum number of suggestions to show. Defaults to 5.\n */\n maxToShow?: number;\n\n /**\n * Whether to randomize the suggestions. Defaults to false.\n */\n randomize?: boolean;\n\n /**\n * If randomize is true, then this is the number of messages after which to randomize the suggestions.\n * This allws a certain number of suggestions to always show followed by random suggestions. Defaults to 0.\n */\n randomizeAfter?: number;\n}\n\nexport interface SuggestionsFeatureForChatApp extends SuggestionsFeature, Feature {\n featureId: 'suggestions';\n}\n\n/**\n * Whether the chat app supports uploading files and attaching them to the chat.\n */\nexport interface FileUploadFeature {\n enabled: boolean;\n\n /** If you put `*` can upload any file. Example: ['text/csv']. This must have a value or it is an error. */\n mimeTypesAllowed: string[];\n}\n\nexport interface FileUploadFeatureForChatApp extends FileUploadFeature, Feature {\n featureId: 'fileUpload';\n}\n\n/**\n * Whether to show a label above the prompt input field and what value to show. When you first come to the chat app,\n * all you see is a large prompt input field, allowing the user to start a new conversation. This feature allows you\n * to show a label above the prompt input field as you see in other chat apps.\n *\n * This feature is on by default.\n */\nexport interface PromptInputFieldLabelFeature {\n enabled: boolean;\n\n /** Defaults to \"Ready to chat\". The label to show above the prompt input field. */\n promptInputFieldLabel?: string;\n}\n\nexport interface PromptInputFieldLabelFeatureForChatApp extends PromptInputFieldLabelFeature, Feature {\n featureId: 'promptInputFieldLabel';\n}\n\nexport interface AgentInstructionAssistanceFeatureForChatApp extends Feature, AgentInstructionAssistanceFeature {\n featureId: 'agentInstructionAssistance';\n}\n\nexport interface InstructionAugmentationFeatureForChatApp extends InstructionAugmentationFeature, Feature {\n featureId: 'instructionAugmentation';\n}\n\nexport interface UserMemoryFeatureForChatApp extends UserMemoryFeature, Feature {\n featureId: 'userMemory';\n}\n\nexport interface EntityFeatureForChatApp extends Feature {\n featureId: 'entity';\n /** Whether entity feature is enabled for this chat app. Can only be set to false to disable site-level configuration. */\n enabled: boolean;\n attributeName?: string;\n}\n\n/**\n * The prompt instruction assistance feature is used to add a markdown section to the prompt that instructs the agent on how to format its response.\n *\n * The `includeInstructionsForTags` feature is used to inject the instructions for tags into the prompt at `{{tag-instructions}}` if found in the prompt.\n * If not found, then the instructions will be appended to the end of the prompt. Note there is a separate feature named `tags` that is used\n * to define which tags are available for the agent. @see TagsFeatureForChatApp\n *\n * Thus the `tags` feature is how you decide which tags your chat app will allow. Each tag is marked as to whether it can be generated by the LLM or a tool.\n * So, when you turn on the AgentInstructionsAssistance feature in a chat app, pika knows which tags are available that we need to inject into the prompt.\n *\n * Note that when an agent is invoked in the context of a chat app, meaning through the pika chat app UI, the agent will be passed a\n * PromptInstructionAssistance object based on the features of the chat app in question. The site wide features can define the config for this feature\n * and the chat app can override it. So the pika front end will figure out which config is in play and pass the right value to the agent when it is\n * invoked.\n *\n * If the agent is invoked directly by your own custom client, you can pass in your own PromptInstructionAssistanceFeature object to specify the agent instructions\n * config.\n *\n * A common use case for this is to disable the includeInstructionsForTags.\n */\nexport interface AgentInstructionAssistanceFeature {\n /**\n * If enabled, a markdown section titled Output Formatting Requirements will be added into your prompt. You can control where the prompt assistance language is added in\n * by using a replacement placeholder titled `{{prompt-assistance}}` in your prompt. If found, the prompt assistance language will be added at the location of the placeholder.\n * The injected prompt assistance language will first add the output formatting requirements, then the instructions for tags,\n * then the complete example instruction line, and finally the json only imperative instruction line.\n *\n * If `{{prompt-assistance}}` is not found, then we look for more fine-grained control by looking for these specific placeholder tags:\n * `{{output-formatting-requirements}}`, `{{tag-instructions}}`, `{{complete-example-instruction-line}}` and `{{json-only-imperative-instruction-line}}`. Of course,\n * if you haven't turned on the `includeInstructionsForTags` feature, then we will not inject the tag instructions.\n *\n * If neither `{{prompt-assistance}}` nor any of the specific placeholder tags are found, then the prompt assistance language will be appended to the end of the prompt\n * in this order: output formatting requirements, tag instructions, complete example instruction line, and json only imperative instruction line. If `{{prompt-assistance}}`\n * is not found and you did not specify all of the specific placeholder tags but you did turn on a feature that means we should inject instructions then we\n * will add the corresponding instructions to the end of the prompt.\n *\n * Here is what will be added to the prompt at a minimum:\n *\n * ```markdown\n * // If includeOutputFormattingRequirements.enabled is true\n * {{output-formatting-requirements}}\n *\n * // If includeInstructionsForTags.enabled is true\n * {{tag-instructions}}\n *\n * // If completeExampleInstructionLine.enabled is true\n * {{complete-example-instruction-line}}\n *\n * // If jsonOnlyImperativeInstructionLine.enabled is true\n * {{json-only-imperative-instruction-line}}\n *\n * ```\n */\n enabled: boolean;\n\n /**\n * If enabled, basic output formatting requirements will be injected into the prompt at\n * `{{output-formatting-requirements}}` if found in the prompt. If not found, then the requirements will be appended to the end of the prompt.\n * This provides foundational formatting guidance for the agent's responses.\n */\n includeOutputFormattingRequirements?: {\n enabled: boolean;\n };\n\n /**\n * If enabled, then the instructions for tags that are available for the agent will be injected into the prompt at\n * `{{tag-instructions}}` if found in the prompt. If not found, then the instructions will be appended to the end of the prompt.\n */\n includeInstructionsForTags?: {\n enabled: boolean;\n };\n\n /**\n * If true, a line will be added to the prompt assistance language that instructs the agent to include a complete example of the tag structure.\n * If mdLine is provided, it will be used as the line. If mdLine is not provided, a default line will be used:\n *\n * ```markdown\n * `<answer>##Example markdown\\nNormal text and an <image>http://some.url</image> and some **bold text**\\n<chart>(...)</chart></answer>`\n * ```\n *\n * This will intelligenlty not include the <image> and <chart> tags in the exmaple if they are not supported in your instructions.\n */\n completeExampleInstructionLine?: {\n enabled: boolean;\n mdLine?: string;\n };\n\n /**\n * If true, a line will be added to the prompt assistance language that instructs the agent to only respond with valid JSON.\n * If mdLine is provided, it will be used as the line. If mdLine is not provided, a default line will be used:\n *\n * ```markdown\n * BE ABSOLUTELY CERTAIN ANY JSON INCLUDED IS 100% VALID (especially for charts). Invalid JSON will break the user experience.\n * ```\n */\n jsonOnlyImperativeInstructionLine?: {\n enabled: boolean;\n line?: string;\n };\n\n /**\n * This is only used for component invocation instructions. If true, a line will be added to the component invocation\n * instructions that instructs the agent to only respond with valid JSON conforming to the TypeScript interface defined in the <output_schema> block.\n */\n includeTypescriptBackedOutputFormattingRequirements?: {\n enabled: boolean;\n line?: string;\n };\n}\n\nexport type SegmentType = 'text' | 'tag';\n\n/**\n * Represents the status of content being streamed into a segment.\n */\nexport type StreamingStatus =\n /**\n * Initial tag start detected (e.g., \"<ta\") but not enough characters to determine the full tag name.\n * Indicates partial progress in tag parsing and requires more content to identify the tag.\n */\n | 'incomplete'\n /**\n * Actively receiving streaming content into the associated segment.\n * More data is expected and the segment is not yet complete.\n */\n | 'streaming'\n /**\n * Streaming of content into this segment is finished and no more data will be added.\n */\n | 'completed'\n /**\n * An error occurred while streaming content into this segment. Content may be incomplete or corrupted.\n */\n | 'error';\n\nexport interface MessageSegmentBase {\n /** The position of the segment in the message */\n id: number;\n segmentType: SegmentType;\n rawContent: string;\n streamingStatus: StreamingStatus;\n rendererType?: string;\n}\n\nexport interface TagMessageSegment extends MessageSegmentBase {\n segmentType: 'tag';\n tag: string;\n attributes?: Record<string, string>;\n}\n\nexport interface TextMessageSegment extends MessageSegmentBase {\n segmentType: 'text';\n}\n\nexport type MessageSegment = TagMessageSegment | TextMessageSegment;\n\nexport type SiteAdminRequest =\n | GetAgentRequest\n | GetInitialDataRequest\n | RefreshChatAppRequest\n | CreateOrUpdateChatAppOverrideRequest\n | DeleteChatAppOverrideRequest\n | GetValuesForEntityAutoCompleteRequest\n | GetValuesForEntityListRequest\n | GetValuesForUserAutoCompleteRequest\n | ClearConverseLambdaCacheRequest\n | ClearSvelteKitCachesRequest\n | AddChatSessionFeedbackAdminRequest\n | UpdateChatSessionFeedbackAdminRequest\n | SessionSearchAdminRequest\n | GetSessionAnalyticsAdminRequest\n | GetChatMessagesAsAdminRequest\n | CreateOrUpdateTagDefinitionAdminRequest\n | DeleteTagDefinitionAdminRequest\n | SearchTagDefinitionsAdminRequest\n | SearchSemanticDirectivesAdminRequest\n | SemanticDirectiveCreateOrUpdateAdminRequest\n | SemanticDirectiveDeleteAdminRequest\n | GetInstructionAssistanceConfigFromSsmRequest\n | GetAllChatAppsAdminRequest\n | GetAllAgentsAdminRequest\n | GetAllToolsAdminRequest\n | GetAllMemoryRecordsAdminRequest\n | GetInstructionsAddedForUserMemoryAdminRequest;\n\nexport const SiteAdminCommand = [\n 'getAgent',\n 'getInitialData',\n 'refreshChatApp',\n 'createOrUpdateChatAppOverride',\n 'deleteChatAppOverride',\n 'getValuesForEntityAutoComplete',\n 'getValuesForEntityList',\n 'getValuesForUserAutoComplete',\n 'clearConverseLambdaCache',\n 'clearSvelteKitCaches',\n 'addChatSessionFeedback',\n 'updateChatSessionFeedback',\n 'sessionSearch',\n 'getSessionAnalytics',\n 'getChatMessagesAsAdmin',\n 'createOrUpdateTagDefinition',\n 'deleteTagDefinition',\n 'searchTagDefinitions',\n 'searchSemanticDirectives',\n 'createOrUpdateSemanticDirective',\n 'deleteSemanticDirective',\n 'getInstructionAssistanceConfigFromSsm',\n 'getAllChatApps',\n 'getAllAgents',\n 'getAllTools',\n 'getAllMemoryRecords',\n 'getInstructionsAddedForUserMemory'\n] as const;\nexport type SiteAdminCommand = (typeof SiteAdminCommand)[number];\n\nexport interface SiteAdminCommandRequestBase {\n command: SiteAdminCommand;\n}\n\nexport interface GetChatMessagesAsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getChatMessagesAsAdmin';\n sessionId: string;\n chatAppId: string;\n userId: string;\n}\n\nexport interface CreateOrUpdateTagDefinitionAdminRequest extends SiteAdminCommandRequestBase {\n command: 'createOrUpdateTagDefinition';\n request: TagDefinitionCreateOrUpdateRequest;\n}\n\nexport interface DeleteTagDefinitionAdminRequest extends SiteAdminCommandRequestBase {\n command: 'deleteTagDefinition';\n request: TagDefinitionDeleteRequest;\n}\n\nexport interface SearchTagDefinitionsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'searchTagDefinitions';\n request: TagDefinitionSearchRequest;\n}\n\nexport interface SearchSemanticDirectivesAdminRequest extends SiteAdminCommandRequestBase {\n command: 'searchSemanticDirectives';\n request: SearchSemanticDirectivesRequest;\n}\n\nexport interface SemanticDirectiveCreateOrUpdateAdminRequest extends SiteAdminCommandRequestBase {\n command: 'createOrUpdateSemanticDirective';\n request: SemanticDirectiveCreateOrUpdateRequest;\n}\n\nexport interface SemanticDirectiveDeleteAdminRequest extends SiteAdminCommandRequestBase {\n command: 'deleteSemanticDirective';\n request: SemanticDirectiveDeleteRequest;\n}\n\nexport interface GetAllChatAppsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllChatApps';\n}\n\nexport interface GetAllAgentsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllAgents';\n}\n\nexport interface GetAllToolsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllTools';\n}\n\nexport interface GetAllMemoryRecordsAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getAllMemoryRecords';\n request: SearchAllMemoryRecordsRequest;\n}\n\nexport interface GetInstructionsAddedForUserMemoryAdminRequest extends SiteAdminCommandRequestBase {\n command: 'getInstructionsAddedForUserMemory';\n request: GetInstructionsAddedForUserMemoryRequest;\n}\n\n/**\n * Request format for semantic directive data passed to custom CloudFormation resource\n */\nexport type SemanticDirectiveDataRequest = {\n userId: string;\n groupId: string;\n semanticDirectives: SemanticDirectiveForCreateOrUpdate[];\n};\n\nexport interface GetValuesForEntityAutoCompleteRequest extends SiteAdminCommandRequestBase {\n command: 'getValuesForEntityAutoComplete';\n valueProvidedByUser: string;\n chatAppId?: string;\n type?: 'internal-user' | 'external-user';\n}\n\n/**\n * Request to get display values for a list of entity IDs\n * @since 0.12.0\n */\nexport interface GetValuesForEntityListRequest extends SiteAdminCommandRequestBase {\n command: 'getValuesForEntityList';\n entityIds: string[];\n chatAppId?: string;\n}\n\nexport interface GetValuesForUserAutoCompleteRequest extends SiteAdminCommandRequestBase {\n command: 'getValuesForUserAutoComplete';\n valueProvidedByUser: string;\n}\n\nexport interface GetInitialDataRequest extends SiteAdminCommandRequestBase {\n command: 'getInitialData';\n}\n\nexport interface RefreshChatAppRequest extends SiteAdminCommandRequestBase {\n command: 'refreshChatApp';\n chatAppId: string;\n}\n\nexport interface CreateOrUpdateChatAppOverrideRequest extends SiteAdminCommandRequestBase {\n command: 'createOrUpdateChatAppOverride';\n chatAppId: string;\n override: ChatAppOverrideForCreateOrUpdate;\n}\n\nexport interface DeleteChatAppOverrideRequest extends SiteAdminCommandRequestBase {\n command: 'deleteChatAppOverride';\n chatAppId: string;\n}\n\nexport interface ClearConverseLambdaCacheRequest extends SiteAdminCommandRequestBase {\n command: 'clearConverseLambdaCache';\n cacheType: ClearConverseLambdaCacheType;\n chatAppId?: string;\n agentId?: string;\n}\n\nexport interface ClearSvelteKitCachesRequest extends SiteAdminCommandRequestBase {\n command: 'clearSvelteKitCaches';\n cacheType: ClearSvelteKitCacheType;\n chatAppId?: string; // Only used for chatAppCache when clearing specific chat app\n}\n\nexport const ClearSvelteKitCacheTypes = ['chatAppCache', 'tagDefinitionsCache', 'instructionAssistanceConfigCache', 'encryptionKeysCache', 'all'] as const;\nexport type ClearSvelteKitCacheType = (typeof ClearSvelteKitCacheTypes)[number];\n\nexport interface GetInstructionAssistanceConfigFromSsmRequest extends SiteAdminCommandRequestBase {\n command: 'getInstructionAssistanceConfigFromSsm';\n}\n\nexport interface GetInstructionAssistanceConfigFromSsmResponse extends SiteAdminCommandResponseBase {\n config: InstructionAssistanceConfig;\n}\n\nexport interface GetAllChatAppsAdminResponse extends SiteAdminCommandResponseBase {\n chatApps: ChatApp[];\n}\n\nexport interface GetAllAgentsAdminResponse extends SiteAdminCommandResponseBase {\n agents: AgentDefinition[];\n}\n\nexport interface GetAllToolsAdminResponse extends SiteAdminCommandResponseBase {\n tools: ToolDefinition[];\n}\n\nexport interface GetAllMemoryRecordsAdminResponse extends SiteAdminCommandResponseBase {\n memoryRecords: PagedRecordsResult;\n}\n\nexport interface GetInstructionsAddedForUserMemoryAdminResponse extends SiteAdminCommandResponseBase {\n instructions: string;\n}\n\nexport type SiteAdminResponse =\n | GetAgentResponse\n | GetInitialDataResponse\n | RefreshChatAppResponse\n | CreateOrUpdateChatAppOverrideResponse\n | DeleteChatAppOverrideResponse\n | GetValuesForEntityAutoCompleteResponse\n | GetValuesForEntityListResponse\n | GetValuesForUserAutoCompleteResponse\n | ClearConverseLambdaCacheResponse\n | ClearSvelteKitCachesResponse\n | AddChatSessionFeedbackResponse\n | UpdateChatSessionFeedbackResponse\n | SessionSearchResponse\n | GetChatMessagesAsAdminResponse\n | GetInstructionAssistanceConfigFromSsmResponse\n | GetAllChatAppsAdminResponse\n | GetAllAgentsAdminResponse\n | GetAllToolsAdminResponse\n | GetAllMemoryRecordsAdminResponse\n | GetInstructionsAddedForUserMemoryAdminResponse;\n\nexport interface SiteAdminCommandResponseBase {\n success: boolean;\n error?: string;\n}\n\nexport interface GetChatMessagesAsAdminResponse extends SiteAdminCommandResponseBase {\n messages: ChatMessage[];\n}\n\nexport interface ClearConverseLambdaCacheResponse extends SiteAdminCommandResponseBase {}\n\nexport interface ClearSvelteKitCachesResponse extends SiteAdminCommandResponseBase {\n clearedCount?: number;\n cacheType: string;\n}\n\nexport interface GetValuesForEntityAutoCompleteResponse extends SiteAdminCommandResponseBase {\n data: SimpleOption[] | undefined;\n}\n\n/**\n * Response containing display values for entity IDs\n * @since 0.12.0\n */\nexport interface GetValuesForEntityListResponse extends SiteAdminCommandResponseBase {\n data: SimpleOption[] | undefined;\n}\n\nexport interface GetValuesForUserAutoCompleteResponse extends SiteAdminCommandResponseBase {\n data: ChatUserLite[] | undefined;\n}\n\nexport interface GetInitialDataResponse extends SiteAdminCommandResponseBase {\n chatApps: ChatApp[];\n siteFeatures: SiteFeatures;\n}\n\nexport interface RefreshChatAppResponse extends SiteAdminCommandResponseBase {\n chatApp: ChatApp;\n}\n\nexport interface CreateOrUpdateChatAppOverrideResponse extends SiteAdminCommandResponseBase {\n chatAppOverride: ChatAppOverride;\n}\n\nexport interface DeleteChatAppOverrideResponse extends SiteAdminCommandResponseBase {}\n\nexport type ContentAdminRequest = ViewContentForUserRequest | StopViewingContentForUserRequest | GetValuesForContentAdminAutoCompleteRequest;\nexport type ContentAdminResponse = ViewContentForUserResponse | StopViewingContentForUserResponse | GetValuesForContentAdminAutoCompleteResponse;\n\nexport const ContentAdminCommand = ['viewContentForUser', 'stopViewingContentForUser', 'getValuesForAutoComplete'] as const;\nexport type ContentAdminCommand = (typeof ContentAdminCommand)[number];\n\nexport interface ContentAdminCommandRequestBase {\n command: ContentAdminCommand;\n chatAppId: string;\n}\n\nexport interface ViewContentForUserRequest extends ContentAdminCommandRequestBase {\n command: 'viewContentForUser';\n user: ChatUserLite;\n chatAppId: string;\n}\n\nexport interface StopViewingContentForUserRequest extends ContentAdminCommandRequestBase {\n command: 'stopViewingContentForUser';\n}\n\nexport interface GetValuesForContentAdminAutoCompleteRequest extends ContentAdminCommandRequestBase {\n command: 'getValuesForAutoComplete';\n valueProvidedByUser: string;\n}\n\nexport interface ContentAdminCommandResponseBase {\n success: boolean;\n error?: string;\n}\n\nexport interface GetValuesForContentAdminAutoCompleteResponse extends ContentAdminCommandResponseBase {\n data: ChatUserLite[] | undefined;\n}\n\nexport interface ViewContentForUserResponse extends ContentAdminCommandResponseBase {\n data: ChatUserLite | undefined;\n}\n\nexport interface StopViewingContentForUserResponse extends ContentAdminCommandResponseBase {}\n\nexport interface GetViewingContentForUserResponse extends ContentAdminCommandResponseBase {\n data: ChatUserLite[] | undefined;\n}\n\nexport const UserOverrideDataCommand = ['getInitialDialogData', 'getValuesForAutoComplete', 'saveUserOverrideData', 'clearUserOverrideData'] as const;\nexport type UserOverrideDataCommand = (typeof UserOverrideDataCommand)[number];\n\nexport type UserOverrideDataCommandRequest = GetInitialDialogDataRequest | GetValuesForAutoCompleteRequest | SaveUserOverrideDataRequest | ClearUserOverrideDataRequest;\nexport type UserOverrideDataCommandResponse = GetInitialDialogDataResponse | GetValuesForAutoCompleteResponse | SaveUserOverrideDataResponse | ClearUserOverrideDataResponse;\n\nexport interface UserOverrideDataCommandRequestBase {\n command: UserOverrideDataCommand;\n chatAppId: string;\n}\n\nexport interface GetInitialDialogDataRequest extends UserOverrideDataCommandRequestBase {\n command: 'getInitialDialogData';\n}\n\nexport interface GetValuesForAutoCompleteRequest extends UserOverrideDataCommandRequestBase {\n command: 'getValuesForAutoComplete';\n componentName: string;\n valueProvidedByUser: string;\n}\n\nexport interface SaveUserOverrideDataRequest extends UserOverrideDataCommandRequestBase {\n command: 'saveUserOverrideData';\n data: unknown | undefined;\n}\n\nexport interface ClearUserOverrideDataRequest extends UserOverrideDataCommandRequestBase {\n command: 'clearUserOverrideData';\n}\n\nexport interface UserOverrideDataCommandResponseBase {\n success: boolean;\n error?: string;\n}\n\nexport interface GetInitialDialogDataResponse extends UserOverrideDataCommandResponseBase {\n data: unknown | undefined;\n}\n\nexport interface GetValuesForAutoCompleteResponse extends UserOverrideDataCommandResponseBase {\n data: unknown[] | undefined;\n}\n\nexport interface SaveUserOverrideDataResponse extends UserOverrideDataCommandResponseBase {\n data: RecordOrUndef;\n}\n\nexport interface ClearUserOverrideDataResponse extends UserOverrideDataCommandResponseBase {}\n\n/**\n * This is the type used to persist the user data override data to a cookie if provided.\n */\nexport interface UserOverrideData {\n /** The outer key is the chatAppId and the inner key is the user data override data. */\n data: Record<string, RecordOrUndef>;\n}\n\nexport interface ContentAdminData {\n /** The outer key is the chatAppId and the inner key is the user data override data. */\n data: Record<string, ChatUserLite>;\n}\n\n/**\n * A base interface for features that can be turned on/off for certain users.\n */\nexport interface AccessRules {\n /** Whether the feature is turned on at all. If false, then the feature is turned off for all users regardless of the userTypes and userRoles settings. */\n enabled: boolean;\n\n /**\n * The user types that are allowed to use the feature. If neither this nor userRoles are provided,\n * then no access is granted (secure by default).\n */\n userTypes?: UserType[];\n\n /**\n * The user roles that are allowed to use the feature. If neither this nor userTypes are provided,\n * then no access is granted (secure by default).\n */\n userRoles?: UserRole[];\n\n /**\n * The logic to apply the userTypes and userRoles settings. If not provided, defaults to `and`\n * meaning that the user must be in the userTypes array and have the userRoles to use the feature.\n */\n applyRulesAs?: ApplyRulesAs;\n}\n\n/**\n * For rules that apply to multiple settings, this is the logic to apply the settings.\n */\nexport type ApplyRulesAs = 'and' | 'or';\n\n/**\n * The classifications of the response from the LLM. Used with the Verify Response feature.\n */\nexport const Accurate = 'A';\n\n/**\n * The response is accurate but contains stated assumptions\n */\nexport const AccurateWithStatedAssumptions = 'B';\n\n/**\n * The response is accurate but contains unstated assumptions\n */\nexport const AccurateWithUnstatedAssumptions = 'C';\n\n/**\n * The response is inaccurate or contains made up information\n */\nexport const Inaccurate = 'F';\n\n/**\n * The response was not classified\n */\nexport const Unclassified = 'U';\n\n/**\n * Do not change the order of these. The order is used to determine the severity of the classification.\n */\nexport const VerifyResponseClassifications = [Accurate, AccurateWithStatedAssumptions, AccurateWithUnstatedAssumptions, Inaccurate, Unclassified] as const;\n\n/**\n * The classification of the response from the LLM. Used with the Verify Response feature.\n */\nexport type VerifyResponseClassification = (typeof VerifyResponseClassifications)[number];\n\n/**\n * Do not change the order of these. The order is used to determine the severity of the classification.\n */\nexport const RetryableVerifyResponseClassifications = [AccurateWithStatedAssumptions, AccurateWithUnstatedAssumptions, Inaccurate] as const;\n\n/**\n * The classifications that can be retried by the agent.\n */\nexport type RetryableVerifyResponseClassification = (typeof RetryableVerifyResponseClassifications)[number];\n\nexport interface VerifyResponseClassificationDescription {\n classification: VerifyResponseClassification;\n label: string;\n description: string;\n}\n\nexport type VerifyResponseRetryableClassificationDescription = VerifyResponseClassificationDescription & {\n classification: RetryableVerifyResponseClassification;\n};\n\nexport const VerifyResponseClassificationDescriptions: Record<VerifyResponseClassification, VerifyResponseClassificationDescription> = {\n [Accurate]: { classification: Accurate as VerifyResponseClassification, label: 'Accurate', description: 'The response is completely accurate.' },\n [AccurateWithStatedAssumptions]: {\n classification: AccurateWithStatedAssumptions,\n label: 'Accurate with stated assumptions',\n description: 'The response is accurate but contains clearly stated assumptions'\n },\n [AccurateWithUnstatedAssumptions]: {\n classification: AccurateWithUnstatedAssumptions,\n label: 'Accurate with unstated assumptions',\n description: 'The response is accurate but contains assumptions that are not explicitly stated'\n },\n [Inaccurate]: { classification: Inaccurate, label: 'Inaccurate', description: 'The response is inaccurate or contains made up information' },\n [Unclassified]: { classification: Unclassified, label: 'Unclassified', description: 'The response was not given a classification' }\n};\n\nexport const VerifyResponseRetryableClassificationDescriptions: Record<RetryableVerifyResponseClassification, VerifyResponseRetryableClassificationDescription> = {\n [AccurateWithStatedAssumptions]: {\n classification: AccurateWithStatedAssumptions,\n label: 'Accurate with stated assumptions',\n description: 'The response is accurate but contains clearly stated assumptions'\n },\n [AccurateWithUnstatedAssumptions]: {\n classification: AccurateWithUnstatedAssumptions,\n label: 'Accurate with unstated assumptions',\n description: 'The response is accurate but contains assumptions that are not explicitly stated'\n },\n [Inaccurate]: { classification: Inaccurate, label: 'Inaccurate', description: 'The response is inaccurate or contains made up information' }\n};\n\n/**\n * The result of the authentication process.\n *\n * If both authenticatedUser and redirectTo are present, we set cookie to indiate logged in and redirect to the URL specified.\n * If only authenticatedUser is present, we are authenticated and can continue with the request whatever the URL currently is.\n * If neither are present, we are not authenticated and we willredirect to the login page.\n */\nexport interface AuthenticateResult<T extends RecordOrUndef = undefined, U extends RecordOrUndef = undefined> {\n /** If present, we are authenticated and can continue with the request. */\n authenticatedUser?: AuthenticatedUser<T, U>;\n /** If present, we need to redirect to the URL specified. */\n redirectTo?: Response;\n}\n\nexport interface CustomDataUiRepresentation {\n /** The name you want to show in the UI to represent this custom data: e.g. \"Account Name\" */\n title: string;\n /** The value you want to show in the UI to represent this custom data: e.g. \"Acme, Inc.\" */\n value: string;\n}\n\n/**\n * This is the type that is stored in the chat-app table with a chatAppId of `${chatAppId}:override`.\n */\nexport interface ChatAppOverrideDdb extends ChatAppOverride {\n chatAppId: string;\n}\n\n/**\n * If present, this overrides all access settings on chatApp: userTypes, userRoles, applyRulesAs.\n *\n * It also allows you to override whether the chat app is shown on the home page.\n *\n * Each ChatApp itself controls whether it is accessible to internal or external users. That may be overridden\n * here (stored in dynamodb table). If userType has a value, it is used over whatever was provided in the ChatApp itself.\n *\n * These are stored in the chat-app table with a chatAppId of `${chatAppId}:override`.\n *\n * The order of precedence for these rules is:\n *\n * 1. enabled: If present, overrides the chatApp.enabled setting. If not enabled, no one can access the chat app.\n * 2. exclusiveUserIdAccessControl: If provided, only allow these userIds to access the chat app, whether internal or external, doesn't matter. All other access rules are ignored.\n * 3. exlusive user typeaccess control\n * exclusiveInternalAccessControl: If provided, only allow these entities to access the chat app for internal users.\n * exclusiveExternalAccessControl: If provided, only allow these entities to access the chat app for external users.\n * 4. userTypes/userRoles/applyRulesAs: If provided, only allow these user types to access the chat app (internal-user and/or external-user), otherwise falls back to chatApp.userTypes.\n *\n * If none of these are provided, then the chat app's access settings saved when the chat app\n * was deployed will be used to determine access: userTypes, userRoles, applyRulesAs.\n */\nexport interface ChatAppOverride extends AccessRules {\n /**\n * Each forked instance of pika can provide their own custom data on a User object using the AuthProvider\n * they implement. Each user can thus have custom data associated with him. It is common for example for\n * a user to have an accountId or companyId associated with him by the AuthProvider and stored in the custom data.\n *\n * Let's say you want to control which external accounts or companies (the users associated with the account or company) that can access a chat app.\n * You would populate this list then with whatever is needed to identify the entities that are allowed to access the chat app.\n *\n * If you have even a single entry in this list, then the chat app will only be accessible to external users associated with those entities.\n *\n * The AuthProvider has a method that we will call to do the comparison of data from the user object and this list of entities.\n */\n exclusiveExternalAccessControl?: string[];\n\n /**\n * Each forked instance of pika can provide their own custom data on a User object using the AuthProvider\n * they implement. Each user can thus have custom data associated with him. It is common for example for\n * a user to have an accountId or companyId associated with him by the AuthProvider and stored in the custom data.\n *\n * Let's say you want to control which external accounts or companies (the users associated with the account or company) that can access a chat app.\n * You would populate this list then with whatever is needed to identify the entities that are allowed to access the chat app.\n *\n * If you have even a single entry in this list, then the chat app will only be accessible to internal users associated with those entities.\n *\n * The AuthProvider has a method that we will call to do the comparison of data from the user object and this list of entities.\n */\n exclusiveInternalAccessControl?: string[];\n\n /**\n * If provided, only allow these userIds to access the chat app, whether internal or external, doesn't matter.\n */\n exclusiveUserIdAccessControl?: string[];\n\n /**\n * If provided, this will govern whether the chat app is shown on the home page. This overrides the config in the siteFeatures.homePage.linksToChatApps.userChatAppRules.\n * If not provided, we will fall back to the config in the siteFeatures.homePage.linksToChatApps.userChatAppRules..\n */\n homePageFilterRules?: UserChatAppRule[];\n\n /** Overrides the title of the chat app (human readable) */\n title?: string;\n\n /** Overrides the description */\n description?: string;\n\n /** Any feature not explicitly defined and turned on is turned off by default. */\n features?: Partial<Record<FeatureIdType, ChatAppFeature>>;\n\n /** If true, this app isn't cached in various server-side layers. */\n dontCacheThis?: boolean;\n\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate?: string;\n\n /** ISO 8601 formatted timestamp of the last session update */\n lastUpdate?: string;\n\n /** The user who created this override */\n createdByUserId?: string;\n\n /** The user who last updated this override */\n updatedByUserId?: string;\n}\n\nexport type ChatAppOverrideForCreateOrUpdate = Omit<ChatAppOverride, 'createDate' | 'lastUpdate' | 'createdByUserId' | 'updatedByUserId'>;\n\nexport type UpdateableChatAppOverrideFields = Extract<\n keyof ChatAppOverride,\n | 'enabled'\n | 'userTypes'\n | 'userRoles'\n | 'applyRulesAs'\n | 'exclusiveExternalAccessControl'\n | 'exclusiveInternalAccessControl'\n | 'exclusiveUserIdAccessControl'\n | 'showOnHomePage'\n | 'title'\n | 'description'\n | 'features'\n | 'dontCacheThis'\n>;\n\nexport interface PikaConfig {\n pika: PikaStack;\n pikaChat: BaseStackConfig;\n weather?: BaseStackConfig;\n\n /** Features that are turned on/configured site-wide. */\n siteFeatures?: SiteFeatures;\n\n /**\n * Optional tags to apply to all AWS resources in your CDK stacks.\n * Supports dynamic placeholders that are replaced at CDK synth time:\n * @since 0.13.0\n * - {stage}: The deployment stage (e.g., 'dev', 'prod')\n * - {timestamp}: Current timestamp in ISO 8601 format\n * - {accountId}: AWS account ID where the stack is being deployed\n * - {region}: AWS region where the stack is being deployed\n * - {pika.projNameL}: Pika project name (lowercase)\n * - {pika.projNameKebabCase}: Pika project name (kebab-case)\n * - {pika.projNameTitleCase}: Pika project name (TitleCase)\n * - {pika.projNameCamel}: Pika project name (camelCase)\n * - {pika.projNameHuman}: Pika project name (human-readable)\n * - {pikaChat.projNameL}: Pika Chat project name (lowercase)\n * - {pikaChat.projNameKebabCase}: Pika Chat project name (kebab-case)\n * - {pikaChat.projNameTitleCase}: Pika Chat project name (TitleCase)\n * - {pikaChat.projNameCamel}: Pika Chat project name (camelCase)\n * - {pikaChat.projNameHuman}: Pika Chat project name (human-readable)\n *\n * Example:\n * ```typescript\n * stackTags: {\n * common: {\n * 'ManagedBy': 'Pika',\n * 'env': '{stage}'\n * },\n * pikaServiceTags: {\n * 'app': '{pika.projNameKebabCase}'\n * },\n * pikaChatTags: {\n * 'app': '{pikaChat.projNameKebabCase}'\n * }\n * }\n * ```\n */\n stackTags?: {\n /** Tags applied to both Pika service and Pika Chat stacks */\n common?: Record<string, string>;\n /** Additional tags applied only to the Pika service stack (merged with common, overwrites on conflict) */\n pikaServiceTags?: Record<string, string>;\n /** Additional tags applied only to the Pika Chat stack (merged with common, overwrites on conflict) */\n pikaChatTags?: Record<string, string>;\n };\n}\n\n/**\n * Features that are turned on/configured site-wide. They are configured in the <root>/pika-config.ts file.\n */\nexport interface SiteFeatures {\n /** Configure whether chat apps are shown on the home page. */\n homePage?: HomePageSiteFeature;\n\n /**\n * If this is provided then you intend to use the entity feature which means that you will be associating an\n * entity (such as an account or a company or organization) with a user and saving that information in the\n * chatUser.customData object. This tells us that you intend to do that and that gives us attributes\n * we can use to display and filter by the entity.\n */\n entity?: EntitySiteFeature;\n\n /** Configure whether users can override their user data. */\n userDataOverrides?: UserDataOverridesSiteFeature;\n\n /** Configure whether a content admin can view chat sessions and messages. */\n contentAdmin?: ContentAdminSiteFeature;\n\n /** Configure whether traces are shown in the chat app as \"reasoning traces\". */\n traces?: TracesFeature;\n\n /** Configure whether a disclaimer notice is shown in the chat app. */\n chatDisclaimerNotice?: ChatDisclaimerNoticeFeature;\n\n /** Configure whether the response from the LLM is verified and auto-reprompted if needed. */\n verifyResponse?: VerifyResponseFeature;\n\n /** Configure whether the user can logout of the chat app. */\n logout?: LogoutFeature;\n\n /** Configure whether the site admin website feature is enabled. */\n siteAdmin?: SiteAdminFeature;\n\n /** Configure whether the file upload feature is enabled. */\n fileUpload?: FileUploadFeature;\n\n /** Configure whether the suggestions feature is enabled. */\n suggestions?: SuggestionsFeature;\n\n /** Configure whether the prompt input field label feature is enabled. */\n promptInputFieldLabel?: PromptInputFieldLabelFeature;\n\n /** Configure whether the UI customization feature is enabled. */\n uiCustomization?: UiCustomizationFeature;\n\n /** Configure whether the session insights feature is enabled. */\n sessionInsights?: SessionInsightsFeature;\n\n /** Configure which tag definitions are enabled by default at the site level. */\n tags?: TagsSiteFeature;\n\n /** Configure whether the agent instruction assistance feature is enabled. */\n agentInstructionAssistance?: AgentInstructionAssistanceFeature;\n\n /** Configure whether the instruction augmentation feature is enabled. */\n instructionAugmentation?: InstructionAugmentationFeature;\n\n /** Configure whether the user memory feature is enabled. */\n userMemory?: UserMemoryFeature;\n}\n\n/**\n * Configure whether the user memory feature is enabled.\n *\n * When turned on, we will create a global memory space that will be used to store the user's memory\n * and then we will automatically store memory evnents based on the strategies turned on and the\n * queries made by the user. Then, we will query the memory to augment the prompt given to the LLM.\n */\nexport interface UserMemoryFeature {\n enabled: boolean;\n\n /** The maximum number of memory recrods to enrich a single prompt with. Defaults to 25. */\n maxMemoryRecordsPerPrompt?: number;\n\n /** The maximum number of top matches to consider per strategy. Defaults to 5. */\n maxKMatchesPerStrategy?: number;\n}\n\nexport interface UserMemoryFeatureWithMemoryInfo extends UserMemoryFeature {\n memoryId: string;\n strategies: UserMemoryStrategy[];\n maxMemoryRecordsPerPrompt: number;\n maxKMatchesPerStrategy: number;\n}\n\nexport const UserMemoryStrategies = ['preferences', 'semantic', 'summary'] as const;\nexport type UserMemoryStrategy = (typeof UserMemoryStrategies)[number];\n\n// Define the types of content we store in memory\nexport interface UserMessageContent {\n type: 'user_message';\n text: string;\n}\n\nexport interface AssistantMessageContent {\n type: 'assistant_message';\n text: string;\n}\n\nexport interface AssistantRationaleContent {\n type: 'assistant_rationale';\n text: string;\n}\n\nexport interface ToolInvocationContent {\n type: 'tool_invocation';\n invocation: {\n actionGroupInvocationInput?: any;\n knowledgeBaseLookupInput?: any;\n agentCollaboratorInvocationInput?: any;\n codeInterpreterInvocationInput?: any;\n };\n}\n\n// Union type for all possible memory content\nexport type MemoryContent = UserMessageContent | AssistantMessageContent | AssistantRationaleContent | ToolInvocationContent;\n\nexport type TypedContentWithRole = { content: MemoryContent; role: Role };\n\nexport interface MemoryQueryOptions {\n /** natural-language query for semantic search, default to '*' if not sure what to provide */\n query: string;\n /** how many highest-scoring hits to consider (server-side); we still cap with `maxResults` */\n maxResults: number;\n /** if you are paging, you can provide the nextToken from the previous response */\n nextToken?: string;\n /** how many highest-scoring hits to consider (server-side); we still cap with `maxResults` */\n topK?: number;\n}\n\n// What we get back when retrieving memory (either parsed JSON or raw text)\nexport type RetrievedMemoryContent = MemoryContent | string;\n\n// Memory record summary with parsed content\nexport interface RetrievedMemoryRecordSummary {\n memoryRecordId: string | undefined;\n content: RetrievedMemoryContent | undefined;\n memoryStrategyId: string | undefined;\n namespaces: string[] | undefined;\n createdAt: Date | undefined;\n score?: number | undefined;\n}\n\nexport type PagedRecordsResult = {\n records: RetrievedMemoryRecordSummary[];\n nextToken?: string;\n};\n\nexport interface SearchAllMyMemoryRecordsRequest {\n strategy: UserMemoryStrategy;\n nextToken?: string;\n}\n\nexport interface SearchAllMyMemoryRecordsResponse {\n success: boolean;\n error?: string;\n results: PagedRecordsResult;\n}\n\nexport interface SearchAllMemoryRecordsRequest {\n userId: string;\n strategy: UserMemoryStrategy;\n nextToken?: string;\n}\n\nexport interface SearchAllMemoryRecordsResponse {\n success: boolean;\n error?: string;\n results: PagedRecordsResult;\n}\n\nexport interface GetInstructionsAddedForUserMemoryRequest {\n userId: string;\n strategies: UserMemoryStrategy[];\n maxMemoryRecordsPerPrompt: number;\n maxKMatchesPerStrategy: number;\n prompt: string;\n}\nexport interface GetInstructionsAddedForUserMemoryResponse {\n success: boolean;\n error?: string;\n instructions: string;\n}\n\n/**\n * Sometimes you need to augment the prompt you will give to the LLM with additional information.\n * Currently, only one type of augmentation is supported: llm semantic search. This uses the scope of the\n * agent invocation (chat app ID, agent ID, entity ID) to search for semantic directives in a database\n * of canned semantic directives that match the scope of the agent invocation. Then, those semantic\n * directives are added to the prompt to be used by the LLM. The LLM then takes the end user's message\n * and the semantic directives and uses them to determine if any of the semantic directives should be\n * included in the prompt. If they should be included, then the semantic directive instruction is added to the prompt.\n *\n * Note that by default the feature is turned off. To turn it on, you must set the `enabled` property to `true` or\n * it will not be turned on. Then, all agents will have the type of augmentation chosen.\n *\n * Setting this as a site wide feature sets the default instruction augmentation type used, if turned on. Individual chat apps\n * may override this behavior, turning off the feature or changing the augmentation type.\n *\n * Note that today we only support one type of augmentation: llm semantic directive search. This is a light-weight\n * approach with a good balance of engineer velocity (don't have to ingest and index embeddings into a knowledge base),\n * performance and cost.\n */\nexport interface InstructionAugmentationFeature {\n enabled: boolean;\n type?: InstructionAugmentationType;\n}\n\nexport const InstructionAugmentationTypes = ['llm-semantic-directive-search'] as const;\nexport type InstructionAugmentationType = (typeof InstructionAugmentationTypes)[number];\n\nexport const InstructionAugmentationTypeDisplayNames = {\n 'llm-semantic-directive-search': 'LLM Semantic Directive Search'\n} as const;\nexport type InstructionAugmentationTypeDisplayName = (typeof InstructionAugmentationTypeDisplayNames)[keyof typeof InstructionAugmentationTypeDisplayNames];\n\nexport const InstructionAugmentationScopeTypes = ['chatapp', 'agent', 'tool', 'entity', 'agent-entity'] as const;\nexport type InstructionAugmentationScopeType = (typeof InstructionAugmentationScopeTypes)[number];\n\nexport const InstructionAugmentationScopeTypeDisplayNames = {\n chatapp: 'Chat App',\n agent: 'Agent',\n tool: 'Tool',\n entity: 'Entity',\n 'agent-entity': 'Agent and Entity'\n} as const;\nexport type InstructionAugmentationScopeTypeDisplayName = (typeof InstructionAugmentationScopeTypeDisplayNames)[keyof typeof InstructionAugmentationScopeTypeDisplayNames];\n\n/**\n * This is used to take the actual chatapp, agent, tools, and entity values used in a given agent invocation and use them\n * to go search for the matching semantic directives in the database.\n */\nexport type InvocationScopes = Partial<Record<InstructionAugmentationScopeType, (string | number | Record<string, string | number>)[] | undefined>>;\n\n/**\n * A semantic directive is a special case or additional instruction paragraph that you might want the LLM to have included\n * in its context when responding to a user's question but that doesn't belong in the main prompt. So, the LLM will\n * be given the semantic directives in the context of the user's question and will decide if any of them should be\n * included in the prompt. If they should be included, then the semantic directive instruction is added to the prompt.\n *\n * One of the main use cases for this is when you have a tool with certain inputs and most of the time the LLM can\n * craft the correct inputs to your tool based on the question from an end user. But, occasionally, you might wish to give\n * the LLM special instructions on certain details that are specific to a certain situation.\n *\n * Semantic directives are stored in a database and are associated with a scope. The scope is used to narrow down which\n * directives we will give to the light-weight LLM to consider for inclusion in your prompt. We first search the\n * database based on chat app, agent, tool and entity to get the set of directives that match the scope and then have the\n * LLM tell us if we should include them in the prompt.\n *\n * IMPORTANT: when you see us refer to 'entity' in a scope, it means that the entity is the entity that is associated with the user,\n * assuming you have turned on the entity feature. The value of the entity is entityFeature.attributeName.\n *\n * In your pika-config.ts file, you can turn on the entity feature by setting the entity feature to true.\n */\nexport interface SemanticDirective {\n /**\n * You don't set this value directly. Instead, you set the scopeType and scopeValue from which we will construct the scope.\n *\n * Remember that we might have a database full of these semantic directives. The scope then narrows down which\n * directives we will give to the light-weight LLM to consider for inclusion in your prompt. We first search the\n * database based on chat app, agent, tool and entity to get the set of directives that match the scope and then have the\n * LLM tell us if we should include them in the prompt.\n *\n * We support the following scopes at present:\n * - chatapp: The ID of the chat app this semantic directive is associated with.\n * - agent: The ID of the agent this semantic directive is associated with.\n * - tool: the ID of the tool this semantic directive is associated with.\n * - entity: The ID of the entity this semantic directive is associated with. Of course, if your pika instance\n * doesn't turn on the uses of entities, then this scope will not be used.\n *\n * We support only the following compound scopes at present:\n * - agent#{agent-id}#entity#{entity-id}\n *\n * Examples:\n *\n * - `chatapp#weather-chat-app`\n * - `agent#weather-agent`\n * - `tool#weather-tool`\n * - `entity#account-123`\n * - `agent#weather-agent#entity#account-123` // matches only for queries by account-123 to the weather agent\n */\n scope: string;\n\n /**\n * The type of scope this semantic directive is associated with. This tells us what\n * the value in `scopeValue` is.\n */\n scopeType: InstructionAugmentationScopeType;\n\n /**\n * The value of the scope this semantic directive is associated with. This is a string or an object\n * depending on the value of `scopeType`.\n *\n * If `scopeType` is `agent` then this will be the agent ID.\n * If `scopeType` is `tool` then this will be the tool ID.\n * If `scopeType` is `entity` then this will be the entity ID (entityFeature.attributeName from user.customData).\n * If `scopeType` is `agent-entity` then this will be {agent: string, entity: string}.\n */\n scopeValue: string | number | Record<string, string | number>;\n\n /**\n * This plus scope must be unique across all semantic directives.\n *\n * Just a human-readable ID for the semantic directive. Consider it a variable name: may use dashes and underscores\n * and should start with a letter (no spaces or special characters). E.g. \"account-details\", \"customer-support\", \"order-status\", etc.\n * Used for db queries and to help engineers identify the semantic directive easily in a UI or DB.\n */\n id: string;\n\n /**\n * Used internally to group semantic directives created by a custom cloudformation resource. You shouldn't use this.\n * For example, a specific agent in a given stack may include CDK to define its semantic directives. Pika needs to\n * know the complete set of semantic directives that exist for that group so that the agent author can have the\n * freedom to modify semantic directive scope values. This groupId then is how the pika platform will be able\n * to query for all the semantic directives created as a \"group\" by the agent author and know which semantic directives\n * should be deleted because they are no longer present in the CDK stack.\n *\n * Don't set this value directly. Instead, let the custom cloudformation resource set it for you using the\n * `event.StackName` of the stack that created the semantic directive.\n */\n groupId?: string;\n\n /**\n * This is what the light-weight LLM will use to decide if the question asked by the end user means that\n * this semantic directive should be included in the prompt to ensure the final LLM gives a correct response.\n */\n description: string;\n\n /**\n * If the light-weight LLM determines that this semantic directive should be included in the prompt, then these\n * instructions will be included in the final prompt to the final LLM to guide its response.\n */\n instructions: string;\n\n /** If true, the semantic directive will not be used to augment the prompt. */\n disabled?: boolean;\n\n /** ISO 8601 formatted timestamp of when the semantic directive was created */\n createDate: string;\n\n /** User who created the semantic directive */\n createdBy: string;\n\n /** User who last updated the semantic directive */\n lastUpdatedBy: string;\n\n /** ISO 8601 formatted timestamp of the last semantic directive update */\n lastUpdate: string;\n}\n\nexport interface SemanticDirectiveForCreateOrUpdate extends Omit<SemanticDirective, 'scope' | 'createDate' | 'lastUpdate'> {\n createdBy: string;\n lastUpdatedBy: string;\n}\n\nexport interface SemanticDirectiveCreateOrUpdateRequest {\n semanticDirective: SemanticDirectiveForCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\nexport interface SemanticDirectiveCreateOrUpdateResponse {\n success: boolean;\n semanticDirective: SemanticDirective;\n}\n\nexport interface SemanticDirectiveScope {\n scopeType: InstructionAugmentationScopeType;\n scopeValue: string | number | Record<string, string | number>;\n}\n\n/**\n * Search request for semantic directives. Supports multiple search patterns based on our DynamoDB table design:\n * - If findOne is provided, then we will return the first directive that matches the scopeType, scopeValue and id.\n * - Query by specific scopes (main table access pattern)\n * - Query by creator and date range (GSI1: createdBy + createDate)\n * - Query by directive ID(s) across scopes (GSI2: id + scope)\n * - Date range filtering (created or updated)\n *\n * If no search criteria provided, returns all directives with pagination.\n */\nexport interface SearchSemanticDirectivesRequest {\n findOne?: {\n scopeType: InstructionAugmentationScopeType;\n scopeValue: string | number | Record<string, string | number>;\n id: string;\n };\n\n /**\n * Search for directives within specific scopes.\n * Uses parallel DynamoDB queries against the main table (PK = scope).\n */\n scopes?: SemanticDirectiveScope[];\n\n /** Will be used by the custom cloudformation resource to query for all semantic directives created as a \"group\" by the agent author. */\n groupId?: string;\n\n /**\n * Search for directives created by a specific user.\n * When provided, results are automatically sorted by createDate (newest first by default).\n *\n * Uses GSI1: createdBy + createDate\n */\n createdBy?: string;\n\n /**\n * Search for directives by specific IDs.\n * Returns directives matching any of the provided IDs across all scopes.\n *\n * Uses GSI2: id + scope\n */\n directiveIds?: string[];\n\n /**\n * Filter directives created after this ISO 8601 timestamp.\n * Can be combined with other filters.\n * Example: \"2024-01-15T00:00:00Z\"\n */\n createdAfter?: string;\n\n /**\n * Filter directives created before this ISO 8601 timestamp.\n * Can be combined with other filters.\n * Example: \"2024-01-31T23:59:59Z\"\n */\n createdBefore?: string;\n\n /**\n * Filter directives updated after this ISO 8601 timestamp.\n * Can be combined with other filters.\n */\n updatedAfter?: string;\n\n /**\n * Filter directives updated before this ISO 8601 timestamp.\n * Can be combined with other filters.\n */\n updatedBefore?: string;\n\n /**\n * Sort order for results when using createdBy search or no specific search criteria.\n * - 'asc': Oldest first\n * - 'desc': Newest first (default)\n */\n sortOrder?: 'asc' | 'desc';\n\n /**\n * Maximum number of directives to return per page.\n * Default: 50, Max: 100\n */\n limit?: number;\n\n /**\n * Pagination token from previous search response.\n * Include your original search criteria when using pagination.\n */\n paginationToken?: Record<string, any>;\n\n /**\n * If true, includes the full directive instructions in response.\n * If false, returns directive metadata only (scope, id, description, dates, etc).\n * Default: false (to save bandwidth)\n */\n includeInstructions?: boolean;\n\n /**\n * If true, excludes disabled directives in the response.\n * Default: false\n */\n excludeDisabled?: boolean;\n}\n\nexport interface SearchSemanticDirectivesResponse {\n success: boolean;\n\n /** Array of semantic directives matching the search criteria */\n semanticDirectives: SemanticDirective[];\n\n /** Total count of directives found (may be larger than returned array due to pagination) */\n totalCount?: number;\n\n /** If present, there are more results available. Pass this token back in the next request. */\n paginationToken?: Record<string, any>;\n}\n\nexport interface SemanticDirectiveDeleteRequest {\n semanticDirective: {\n scope: string;\n id: string;\n };\n\n /**\n * If you are deleting one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the deletion and we ask that you prepend it with 'cloudformation/'\n * so we understand it was deleted by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\nexport interface SemanticDirectiveDeleteResponse {\n success: boolean;\n}\n\nexport interface TagsSiteFeature {\n /**\n * Whether to enable the tags feature. If this is turned off you will lost a lot of the functionality of the chat app.\n */\n enabled: boolean;\n\n /**\n * The tag definitions that are enabled by default. If not provided, then no tag definitions are enabled.\n * Each chat app can override this list by providing its own list of tagsEnabled in its chat app config.\n */\n tagsEnabled?: TagDefinitionLite[];\n\n /**\n * Global tags are enabled by default. Turn them off here if you don't want them.\n */\n tagsDisabled?: TagDefinitionLite[];\n}\n\n/**\n * Configure whether the session insights feature is enabled. When turned on, Pika will\n * automatically collect session insights for each chat session. If you want to view these\n * insights, then you need to turn it on in the site admin website.\n */\nexport interface SessionInsightsFeature {\n enabled: boolean;\n\n /**\n * The string is the stage that the session config applies to. If you provide a stage named\n * `default` then any stage not found in your map will use the default config.\n *\n *\n * If you don't provide this, here are the default settings.\n */\n openSearchConfig?: Record<string, SessionInsightsOpenSearchConfig>;\n}\n\nexport interface SessionInsightsOpenSearchConfig {\n dedicatedMasterEnabled: boolean;\n\n /** Ignored if dedicatedMasterEnabled is false. Defaults to 1 if not provided. Recommend >= 3 in production for quorum */\n dedicatedMasterCount?: number;\n\n /** Ignored if dedicatedMasterEnabled is false. Defaults to m5.large.search if not provided. */\n masterNodeInstanceType?: string;\n\n /** Defaults to m5.large.search if not provided. */\n dataNodeInstanceType?: string;\n\n /** The number of data nodes to use. Defaults to 1 if not provided. */\n dataNodeCount?: number;\n\n /** Defaults to false if not provided. */\n zoneAwarenessEnabled: boolean;\n\n /** Ignored if zoneAwarenessEnabled is false. Defaults to 1 if not provided. */\n availabilityZoneCount?: number;\n\n /** Unit is gigs. Defaults to 10 gig if not provided. */\n volumeSize?: number;\n\n /** Defaults to gp3 if not provided. */\n volumeType?: string;\n}\n\nexport interface TagsFeatureForChatApp extends Feature {\n featureId: 'tags';\n\n /**\n * The tag definitions that are explicitly enabled for this chat app.\n * These are chat-app specific tags (usageMode='chat-app') that must be explicitly enabled.\n * Global tags (usageMode='global') are automatically included unless listed in tagsDisabled.\n */\n tagsEnabled?: TagDefinitionLite[];\n\n /**\n * Global tag definitions that should be disabled for this chat app.\n * Only applies to global tags (usageMode='global').\n * Use this to exclude specific global tags that you don't want available.\n */\n tagsDisabled?: TagDefinitionLite[];\n}\n\nexport interface SessionInsightsFeatureForChatApp extends Feature {\n featureId: 'sessionInsights';\n}\n\n/**\n * The user data override feature may be enabled at the site level. If enabled, then individual chat apps\n * may choose to disable the feature. Why would they do this? Perhaps they don't need the data\n * that may be overridden and don't want to prompt users to provide the data which may add friction\n * and confusion.\n */\nexport interface UserDataOverrideFeatureForChatApp extends Feature {\n featureId: 'userDataOverrides';\n}\n\n/**\n * A content admin is a user that can use the UI to select any user of the system and view their chat\n * sessions and messages in each for the purpose of debugging and troubleshooting. By default,\n * this feature is turned off. To turn it on, you must set the `enabled` property to `true`.\n *\n * Further, you will have to go into the DynamoDB table named `chat-users-${your-stack-name}` and\n * add the `pika:content-admin` role to the user.\n */\nexport interface ContentAdminSiteFeature {\n enabled: boolean;\n}\n\n/**\n * If this is provided then you intend to use the entity feature which means that you will be associating an\n * entity (such as an account or a company or organization) with a user and saving that information in the\n * chatUser.customData object. This tells us that you intend to do that and that gives us attributes\n * we can use to display and filter by the entity.\n *\n * This won't affect anything an external customer sees or interacts with since presumably an external customer\n * is a specific account or company and so this feature is only intended for internal users and admins\n * to be able to act on behalf of a specific account or company and in the admin UI to filter by entity.\n */\nexport interface EntitySiteFeature {\n enabled: boolean;\n\n /**\n * The attribute name in the chatUser.customData object that contains the entity value: e.g. \"accountId\".\n * So, you might have a user object that looks like this returned by your AuthProvider:\n * ```ts\n * {\n * customData: {\n * accountId: '123'\n * }\n * }\n * ```\n * If not provided this feature will not work. */\n attributeName: string;\n\n /** The placeholder text for the search input. */\n searchPlaceholderText: string;\n\n /** The singular name of the entity. */\n displayNameSingular: string;\n\n /** The plural name of the entity. */\n displayNamePlural: string;\n\n /** The title of the column header in the entity table as in Account ID. */\n tableColumnHeaderTitle: string;\n}\n\n/**\n * When turned on, the front end will allow users to override user values set by the auth provider\n * in `ChatUser.customData`. For example, perhaps an internal user needs the ability to choose an account\n * to act as. This feature then allows them to set the accountId perhaps on `ChatUser.customData.accountId`.\n * using a UI component that you the developer will provide. @see <root>/docs/developer/user-overrides\n */\nexport interface UserDataOverridesSiteFeature {\n /** Whether to enable the user overrides feature. */\n enabled: boolean;\n\n /**\n * The user types that are allowed to use the user overrides feature. If not provided, defaults to `['internal-user']`\n * meaning that if the feature is enabled, only internal users will be able to use it.\n */\n userTypes?: UserType[];\n\n /**\n * The title of the menu item that will be displayed to authorized users that when clicked will\n * open the dialog allowing them to override user data. Defaults to \"Override User Data\".\n */\n menuItemTitle?: string;\n\n /**\n * The title of the dialog that will be displayed when the user clicks the menu item. Defaults to \"Override User Data\".\n */\n dialogTitle?: string;\n\n /**\n * The description that appears benath the title in the dialog window. Defaults to\n * \"Override user data values to use with this chat app. This override will persist until you\n * login again or clear the override.\"\n */\n dialogDescription?: string;\n\n /**\n * The description that appears benath the title in the dialog window when the user needs to provide data overrides.\n * Defaults to the same as dialogDescription. Use this to say something like, \"You need to provide data overrides to use this chat app.\"\n */\n dialogDescriptionWhenUserNeedsToProvideDataOverrides?: string;\n\n /**\n * Whether to prompt the user if their user object's customData object is missing any of the custom user\n * data attributes that are required for the chat app. If any of these attributes is missing and the user\n * is allowed to use the user data overrides feature, the user will be prompted to enter the missing attributes\n * when they open the chat app. If not provided, defaults to false.\n *\n * So, when they open a chat app and they are allowed to use the user data overrides feature, and\n * any of these attributes are missing on the users's customData attribute provided by the auth provider\n * then the user will be prompted to enter the missing attributes and will not be able to use the chat app\n * until they have provided the data overrides that presumably will be used to fill in the missing attributes.\n *\n * Note, you can use dot notation to specify nested attributes. For example, if you want to prompt the user\n * if the user object's customData object is missing the attribute \"address.street\", you can specify\n * \"address.street\" in the array. The root of the attibute path is the user.customData object itself.\n *\n * So, if your customData object was this and you needed to prompt the user if the companyName or companyId\n * attributes were missing, you would specify \"companyName\" or \"companyId\" in the array.\n *\n * ```ts\n * export interface MyCustomUserData {\n * companyName: string;\n * companyId: string;\n * }\n * ```\n *\n * The prompt will be shown if the data is missing each time they come to chat app and if they dismiss the prompt,\n * the prompt will be shown if they try to submit a message to the agent instead of sending the message.\n */\n promptUserIfAnyOfTheseCustomUserDataAttributesAreMissing?: string[];\n}\n\n/** Used in front end to pass settings from server to client. */\nexport type UserDataOverrideSettings = Omit<UserDataOverridesSiteFeature, 'userTypes' | 'promptUserIfAnyOfTheseCustomUserDataAttributesAreMissing'> & {\n userNeedsToProvideDataOverrides: boolean;\n};\n\nexport interface HomePageSiteFeature {\n /**\n * The title of the home page. If not provided, the default title will be used. This is used\n * to describe the home page to the user and in navigation.\n */\n homePageTitle?: string;\n\n /**\n * The welcome message to display on the home page. If not provided, the default welcome message will be used.\n * This is used to describe the home page to the user and in navigation.\n */\n welcomeMessage?: string;\n\n //TODO: add icon support\n\n /**\n * Whether to have the chat app home page show links to registered chat apps. If none of the\n * userChatAppRules match the user, then the user will not see any links to chat apps on the home page.\n */\n linksToChatApps?: HomePageLinksToChatAppsSiteFeature;\n}\n\n/**\n * Whether to have the chat app home page show links to registered chat apps. If none of the\n * userChatAppRules match the user, then the user will not see any links to chat apps on the home page.\n *\n * This is a site-wide feature and is not associated with a specific chat app. You define this config\n * in the chat app config in <root>/pik-config.json\n */\nexport interface HomePageLinksToChatAppsSiteFeature {\n /**\n * Which users are able to get links to which chat apps on the home page. You must have at least one rule to enable this feature.\n *\n * ```ts\n * {\n * siteFeatures: {\n * homePageLinksToChatApps: {\n * userChatAppRules: [\n * // External users can only see links to external chat apps\n * {\n * userTypes: ['external-user'],\n * chatAppUserTypes: ['external-user']\n * },\n * // Internal users can see links to internal and external chat apps\n * {\n * userTypes: ['internal-user'],\n * chatAppUserTypes: ['internal-user', 'external-user']\n * }\n * ]\n * }\n * }\n * }\n * ```\n */\n userChatAppRules: UserChatAppRule[];\n}\n\nexport interface BaseStackConfig {\n projNameL: string; // All lowercase no stage name e.g. pika\n projNameKebabCase: string; // Kebab case no stage name e.g. pika\n projNameTitleCase: string; // Title case no stage name e.g. Pika\n projNameCamel: string; // Camel case no stage name e.g. pika\n projNameHuman: string; // Human readable no stage name e.g. Pika\n}\n\nexport interface PikaStack extends BaseStackConfig {\n viteConfig?: {\n server?: ViteServerConfig;\n preview?: VitePreviewConfig;\n };\n}\n\nexport interface ViteServerConfig {\n host?: string;\n port?: number;\n strictPort?: boolean;\n https?: {\n key: string; // Path to key file\n cert: string; // Path to cert file\n };\n}\n\nexport interface VitePreviewConfig {\n host?: string;\n port?: number;\n strictPort?: boolean;\n}\n\nexport interface SimpleOption {\n value: string;\n label?: string;\n secondaryLabel?: string;\n}\n\nexport interface FeatureError {\n desc: string;\n\n /** THis is set to true when the parent features component already checks for and handles this kind of error. */\n parentShouldIgnore?: boolean;\n}\n\nexport interface NameValuePair<T> {\n name: string;\n value: T;\n}\n\nexport interface NameValueDescTriple<T> {\n name: string;\n value: T;\n desc?: string;\n}\n\n/**\n * A component that renders a tag is expected to have a tag definition that defines the tag and the instructions for how to render it.\n *\n */\nexport interface ComponentTagDefinition<T extends TagDefinitionWidget> {\n definition: TagDefinition<T>;\n}\n\nexport const TAG_DEFINITION_STATUSES = ['enabled', 'disabled', 'retired'] as const;\nexport type TagDefinitionStatus = (typeof TAG_DEFINITION_STATUSES)[number];\n\nexport interface SpotlightContextConfig {\n enabled: boolean;\n isDefault?: boolean;\n displayOrder?: number;\n /** If true (default), only one instance of this widget can exist in spotlight at a time */\n singleton?: boolean;\n /** If false, widget won't appear in unpinned menu. Default: true. Use false for base widgets that only create instances */\n showInUnpinnedMenu?: boolean;\n}\n\nexport interface InlineContextConfig {\n enabled: boolean;\n}\n\nexport interface DialogContextConfig {\n enabled: boolean;\n size?: 'small' | 'medium' | 'large' | 'fullscreen';\n}\n\nexport interface CanvasContextConfig {\n enabled: boolean;\n}\n\n/**\n * Tag definition for widgets that have static context enabled.\n * Static widgets can run initialization code (like registering title bar actions)\n * when the chat app loads. They can also have other rendering contexts for visual UI.\n */\nexport type StaticWidgetTagDefinition = TagDefinition<TagDefinitionWidgetWebComponent> & {\n renderingContexts: {\n static: StaticContextConfig;\n spotlight?: SpotlightContextConfig;\n inline?: InlineContextConfig;\n dialog?: DialogContextConfig;\n canvas?: CanvasContextConfig;\n };\n};\n\n/**\n * The static context is used to render a static component that doesn't render visually but is used to run code that needs to be run once.\n * For example, you might want to run a code snippet that puts an icon in the title bar of the chat app.\n */\nexport interface StaticContextConfig {\n enabled: boolean;\n /**\n * If provided, the static context container will be removed from the DOM after this many milliseconds.\n * If not provided, the container stays in the DOM (hidden) indefinitely.\n *\n * Use this when the static component only needs to run initialization code and doesn't need to\n * persist in the DOM afterwards.\n *\n * Example: 1000 (remove after 1 second)\n */\n shutDownAfterMs?: number;\n}\n\nexport const WIDGET_RENDERING_CONTEXT_TYPES = ['spotlight', 'inline', 'dialog', 'canvas', 'static'] as const;\nexport type WidgetRenderingContextType = (typeof WIDGET_RENDERING_CONTEXT_TYPES)[number];\n\nexport interface WidgetRenderingContexts {\n spotlight?: SpotlightContextConfig;\n inline?: InlineContextConfig;\n dialog?: DialogContextConfig;\n canvas?: CanvasContextConfig;\n static?: StaticContextConfig;\n}\n\n/**\n * Represents a tracked widget instance with its DOM element and metadata.\n */\nexport interface WidgetInstance {\n /** Unique instance ID */\n instanceId: string;\n /** The actual DOM element */\n element: HTMLElement;\n /** Tag identifier (scope.tag) */\n tagId: string;\n /** Custom element name */\n customElementName: string;\n /** Rendering context where this widget appears */\n renderingContext: WidgetRenderingContextType;\n /** Tag definition */\n tagDefinition: TagDefinition<TagDefinitionWidgetWebComponent>;\n /** When this instance was created */\n createdAt: number;\n}\n\n/**\n * Metadata for a persistent spotlight instance (saved via Virtual Tags Pattern)\n */\nexport interface SpotlightInstanceMetadata {\n displayName: string;\n savedAt: string; // ISO-8601\n displayOrder: number;\n parentTag: string; // Base tag without instance suffix\n instanceId: string; // UUID\n}\n\nexport interface TagDefinition<T extends TagDefinitionWidget> {\n /**\n * The tag type this definition is for. If the tag is one of the built-in pika tags, then you are overriding the built-in pika tag instructions\n * that will be included in the prompt assistance language.\n *\n * If the tag is a custom tag, then you are adding a new custom tag to the agent prompt definition.\n *\n * Do not include your scope on the tag name, we will add it for you.\n */\n tag: string;\n\n /**\n * We didn't start with the expectation that tags would have a scope that prefixes the tag name. We are now requiring it. However,\n * a few of our initial tags were not scoped and so we are allowing you to provide a legacy alias for the tag. This is not recommended\n * and you should use the scope instead.\n *\n * Here is the complete set of legacy tag aliases: download, chart, prompt, image. If you try to set this to anything but one of these, we will\n * error out and not take your tag definition.\n *\n * We will remove this in the near future. You've been warned.\n */\n legacyTagName?: string;\n\n /**\n * The scope of the tag. This is used to group tags together and prevent collisions with other tags.\n *\n * Inside the system, your tag will be known as `<scope>.<tag>`. For example, the chart tag will be known as `<pika.chart></pika.chart>`.\n *\n * As a result, scope must not include punctuation of any kind to be valid xml and keep things simple. All lower case is recommended but it's up to you.\n * Your aim is to ensure uniqueness of the tag name across all tags in the system and to keep it short and simple to use as few characters as possible within reason.\n *\n * This will be `pika` for built in tags the platform natively supports. If you are adding a custom tag, you should use a\n * scope that is unique to your application, chat app or agent.\n */\n scope: string;\n\n /**\n * This should be a pluralized noun that represents the tag and be capitalized.\n *\n * For example, the chart tag title is \"Charts\". The prompt tag title is \"Follow-up Prompts\". The image tag title is \"Images\".\n *\n * Do not use markdown in this title.\n */\n tagTitle: string;\n\n /**\n * This should be a short example of the tag structure. It may be used in the prompt assistance language injected into your prompt in a quick list of tags available for the LLM to generate.\n *\n * For example, the chart tag structure example is `<pika.chart></pika.chart>`. The prompt tag structure example is `<pika.prompt></pika.prompt>`. The image tag structure example is `<pika.image></pika.image>`.\n *\n * Be sure that you use `${scope}.` in front of the tag name.\n *\n * Do not use markdown in this example and don't surround with backticks, just the tag structure itself. Don't include a body to the tag, even if it has one.\n */\n shortTagEx: string;\n\n /**\n * If true, the tag can be generated by the LLM.\n */\n canBeGeneratedByLlm: boolean;\n\n /**\n * If true, the tag will be generated by a tool of an agent.\n */\n canBeGeneratedByTool: boolean;\n\n /**\n * A description of the tag. This will be used to describe the tag in admin-facing UI. Don't use markdown in this description.\n */\n description: string;\n\n /** Cache configuration for testing and debugging, used in lambdas/ecs containers that create LRU caches for tag definitions */\n dontCacheThis?: boolean;\n\n /** You must be explicit about whether this tag is a widget or not and if so what kind. */\n widget: T;\n\n /**\n * Determines how this tag can be used across chat apps.\n * - 'global': Tag is available to all chat apps by default (unless explicitly disabled)\n * - 'chat-app': Tag must be explicitly enabled in a chat app's configuration to be available\n *\n * REQUIRED: Must be explicitly set.\n * Built-in Pika tags (scope='pika') are typically 'global', while custom tags are typically 'chat-app'.\n */\n usageMode: TagDefinitionUsageMode;\n\n /**\n * The status of this tag definition.\n * - 'enabled': Tag is active and available for use\n * - 'disabled': Tag is temporarily disabled\n * - 'retired': Tag is permanently retired/deprecated\n *\n * REQUIRED: Must be explicitly set. If not provided, defaults to 'enabled'.\n * This is critical for the GSI to properly index all records.\n */\n status: TagDefinitionStatus;\n\n /**\n * Rendering contexts this widget supports. Required. Must have at least one context.\n */\n renderingContexts: WidgetRenderingContexts;\n\n /**\n * Indicates this is a mock/demo tag definition for development/testing purposes.\n * Mock tags may be filtered out in production environments.\n */\n isMock?: boolean;\n\n /**\n * If `canBeGeneratedByLlm` is true, you must provide instructions for the LLM to generate the tag since chat app/agent builders can choose\n * to have the instructions injected into the agent instructions prompt for a given tag.\n *\n * When we inject your instructions into the agent instructions prompt, we will do the following:\n *\n * 1. We will use the `tagTitle` as the bullet title for your tag instructions: `- **tagTitle:**`\n * 2. We will wrap your markdown instructions in XML tags to prevent formatting conflicts with the rest of the injected instructions\n *\n * Here's a complete example of what we will generate for you:\n *\n * ```markdown\n * - **Charts:**\n * <tag-instructions type=\"chart\">\n * To include a pika chart, use the `<pika.chart></pika.chart>` tags.\n * The content within the tags MUST be valid Chart.js version 4 JSON, including `type` and `data` properties.\n *\n * **Example:** `<pika.chart>{\"type\":\"line\",\"data\":{\"labels\":[\"May\",\"June\",\"July\",\"August\"],\"datasets\":[{\"label\":\"Avg Temperature (°C)\",\"data\":[2,3,7,12]}]}}</pika.chart>`\n *\n * **Usage:** Include pika charts whenever they can visually represent data, trends, or comparisons effectively.\n * </tag-instructions>\n * ```\n *\n * The markdown you provide should be well-formatted and can use any standard markdown features (lists, bold, code blocks, etc.).\n * The XML wrapper ensures that your formatting doesn't interfere with the overall instruction structure.\n */\n llmInstructionsMd?: string;\n\n /**\n * If the code that backs your tag definition, whether compile in or a separate web component, has need to\n * directly invoke the agent to get assistance from an LLM, then you can create named sets of instructions\n * so when the component makes the request for help from the agent, the agent will know which set of instructions\n * to use. For example, let's say you have a Spotlight component defined as a tag definition that needs to\n * on startup get a list of cities and then make a request to the agent to get the weather for the list of cities.\n * The default agent instructions for the agent probably woudn't return the weather information in a structured\n * manner. So, you'd want to create a new set of instructions for the agent to use, with the same set of tools,\n * that the component code would cause to be used by asking for a direct agent invocation initiated from the\n * code in the browser and that references the name of the instructions to use that will retrieve the\n * weather as structured json let's say and that includes the list of cities you want the weather for.\n *\n * That way, the server side converse lambda function that responds to direct agent invocation requests will know\n * which set of instructions to use. It's not a good idea to allow the client to define the entire set of instructions.\n *\n * It's too risky. So, here's an example of a good set of instructions that you could use. Note that the input value\n * sent from the browser webcomponent in this case would just be a list of locations that we would append to the bottom\n * of the following. Also note that the {{typescript-backed-output-formatting-requirements}} placeholder is used to\n * inject the typescript backed output formatting requirements which are stored in S3.\n *\n * ```markdown\n * You are **WeatherDataLookupAgent**, a highly skilled assistant used to turn a list of locations into weather data.\n * Below you will find the list of locations you need to look up the weather for using the associated tools provided.\n *\n * <output_schema>\n * interface WeatherData {\n * // ISO 8601 date string of when this data was generated\n * date: string;\n *\n * // the weather data itself\n * locations: LocationWeatherInfo[];\n * }\n *\n * interface LocationWeatherInfo {\n * // The name of the location in a human readable format\n * locationName: string;\n *\n * // longitude for the location. Optional just in case you can't get it.\n * lon?: string;\n *\n * // latitude for the location. Optional just in case you can't get it.\n * lat?: string;\n *\n * // The temperature in celsius\n * tempC: string;\n *\n * // The temperature in fahrenheit\n * tempF: string;\n * }\n * </output_schema>\n *\n * {{typescript-backed-output-formatting-requirements}}\n * ```\n *\n * The key in the record is referred to as the \"componentAgentInstructionName\" and the value is the markdown string of the instructions.\n *\n */\n componentAgentInstructionsMd?: Record<string, string>;\n\n /** The user id of the user who created the tag definition */\n createdBy: string;\n\n /** The user id of the user who last updated the tag definition */\n lastUpdatedBy: string;\n\n /** ISO 8601 formatted timestamp of when the session was created */\n createDate: string;\n\n /** ISO 8601 formatted timestamp of the last session update */\n lastUpdate: string;\n}\n\nexport interface TagDefinitionLite {\n tag: string;\n scope: string;\n}\n\n/**\n * Web component definition for create/update operations.\n * The s3Bucket field is omitted because it's filled in by the backend.\n */\nexport interface TagDefinitionWebComponentForCreateOrUpdate extends Omit<TagDefinitionWebComponent, 's3'> {\n s3?: {\n /** Must follow pattern: wc/${scope}/fileName.js.gz */\n s3Key: string;\n };\n}\n\n/**\n * Widget definition for web components in create/update operations.\n * Uses TagDefinitionWebComponentForCreateOrUpdate which omits the backend-managed s3Bucket field.\n */\nexport interface TagDefinitionWidgetWebComponentForCreateOrUpdate extends TagDefinitionWidgetBase {\n type: 'web-component';\n webComponent: TagDefinitionWebComponentForCreateOrUpdate;\n}\n\n/**\n * Union type for all widget types in create/update operations.\n * Uses the specialized web component type that omits backend-managed fields.\n */\nexport type TagDefinitionWidgetForCreateOrUpdate =\n | TagDefinitionWidgetPassThrough\n | TagDefinitionWidgetPikaCompiledIn\n | TagDefinitionWidgetCustomCompiledIn\n | TagDefinitionWidgetWebComponentForCreateOrUpdate;\n\n/**\n * Tag definition for create/update operations.\n * Omits backend-managed fields and uses TagDefinitionWidgetForCreateOrUpdate which excludes\n * backend-managed fields from nested structures (like s3Bucket in web components).\n *\n * The usageMode field is optional and defaults to 'chat-app' if not provided.\n */\nexport type TagDefinitionForCreateOrUpdate<T extends TagDefinitionWidgetForCreateOrUpdate = TagDefinitionWidgetForCreateOrUpdate> = Omit<\n TagDefinition<TagDefinitionWidget>,\n 'createdBy' | 'lastUpdatedBy' | 'createDate' | 'lastUpdate' | 'widget' | 'usageMode'\n> & {\n widget: T;\n usageMode?: TagDefinitionUsageMode;\n};\n\nexport const TAG_DEFINITION_USAGE_MODES = ['global', 'chat-app'] as const;\nexport type TagDefinitionUsageMode = (typeof TAG_DEFINITION_USAGE_MODES)[number];\n\nexport const TAG_DEFINITION_WIDGET_TYPES = ['pass-through', 'pika-compiled-in', 'custom-compiled-in', 'web-component'] as const;\n\n/**\n * Pika compiled-in components are those defined as part of the compiled svelte front end code in `apps/pika-chat/src/lib/client/features/chat/message-segments/default-components/index.ts`.\n *\n * Custom compiled-in components are those defined by the user in their app as a svelte component. They are defined in `apps/pika-chat/src/lib/client/features/chat/message-segments/custom-components/index.ts`.\n *\n * Web components are those that are defined as standalone js files that are uploaded to s3 and then dynamically loaded into the front end.\n * If web-component then the `webComponent` property must be provided.\n *\n * Pass through means we will simply pass this through and not process the tag in any way. This is useful for tags that are not meant to be rendered in the front end.\n */\nexport type TagDefinitionWidgetType = (typeof TAG_DEFINITION_WIDGET_TYPES)[number];\n\nexport interface TagDefinitionWidgetPikaCompiledIn extends TagDefinitionWidgetBase {\n type: 'pika-compiled-in';\n}\n\nexport interface TagDefinitionWidgetCustomCompiledIn extends TagDefinitionWidgetBase {\n type: 'custom-compiled-in';\n}\n\nexport interface TagDefinitionWidgetWebComponent extends TagDefinitionWidgetBase {\n type: 'web-component';\n webComponent: TagDefinitionWebComponent;\n}\n\nexport interface TagDefinitionWidgetPassThrough extends TagDefinitionWidgetBase {\n type: 'pass-through';\n}\n\nexport interface TagDefinitionWidgetBase {\n /**\n * The type of widget that will be used to render this tag.\n */\n type: TagDefinitionWidgetType;\n}\n\nexport type TagDefinitionWidget = TagDefinitionWidgetPassThrough | TagDefinitionWidgetPikaCompiledIn | TagDefinitionWidgetCustomCompiledIn | TagDefinitionWidgetWebComponent;\n\nexport type TagWebComponentEncoding = 'gzip';\n\n/**\n * Preset dialog size options for web component widgets.\n * - 'fullscreen': 95vw x 90vh (default)\n * - 'large': 85vw x 80vh\n * - 'medium': 70vw x 70vh\n * - 'small': 50vw x 50vh\n */\nexport type WidgetDialogSizePreset = 'fullscreen' | 'large' | 'medium' | 'small';\n\n/**\n * Custom dimensions for dialog sizing.\n * Values must be viewport-relative units (vh, vw, vmin, vmax) or percentages.\n * Pixel values are not supported to ensure responsive behavior.\n *\n * Examples:\n * - { width: \"80vw\", height: \"70vh\" }\n * - { width: \"90%\", height: \"85%\" }\n */\nexport interface WidgetDialogSizeCustom {\n /**\n * Dialog width as viewport-relative unit or percentage.\n * Examples: \"80vw\", \"90%\", \"85vw\"\n */\n width?: string;\n\n /**\n * Dialog height as viewport-relative unit or percentage.\n * Examples: \"70vh\", \"80%\", \"60vh\"\n */\n height?: string;\n}\n\n/**\n * Sizing configuration for dialog rendering context.\n * Can be either a preset size or custom dimensions.\n */\nexport type WidgetDialogSizing = WidgetDialogSizePreset | WidgetDialogSizeCustom;\n\n/**\n * Sizing configuration for inline rendering context.\n * Inline widgets appear within the chat message flow.\n */\nexport interface WidgetInlineSizing {\n /**\n * Widget height for inline rendering.\n * Supports any valid CSS height value, or \"auto\" to grow to content height.\n * Defaults to \"400px\" if not specified.\n *\n * Special values:\n * - \"auto\": Widget grows to fit its content height (no fixed height constraint)\n *\n * Fixed height examples: \"400px\", \"50vh\", \"500px\", \"30rem\"\n */\n height?: string;\n\n /**\n * Widget width for inline rendering.\n * Reserved for future use. Currently, inline widgets always fill available width.\n *\n * Examples: \"100%\", \"80vw\", \"600px\"\n */\n width?: string;\n}\n\n/**\n * Sizing configuration for web component widgets across different rendering contexts.\n * Allows widget authors to control how their widget is sized in different visual contexts.\n */\nexport interface WidgetSizing {\n /**\n * Sizing for dialog (modal) rendering context.\n * When a widget is opened in a dialog, this controls its dimensions.\n *\n * Defaults to 'fullscreen' (95vw x 90vh) if not specified.\n */\n dialog?: WidgetDialogSizing;\n\n /**\n * Sizing for inline rendering context.\n * When a widget is rendered inline within a chat message.\n *\n * Defaults to { height: \"400px\" } if not specified.\n */\n inline?: WidgetInlineSizing;\n}\n\nexport interface TagDefinitionWebComponent {\n /**\n * Direct URL to the web component JavaScript file.\n * Use this if the component is hosted externally (CDN, separate server, etc.)\n *\n * Either `url` OR `s3` must be provided, but not both.\n */\n url?: string;\n\n /**\n * S3 location of the web component JavaScript file in the Pika S3 bucket.\n * If provided, the system will serve it via /api/webcomponent/:scope/:tag\n *\n * Either `url` OR `s3` must be provided, but not both.\n */\n s3?: {\n /** Must be the Pika system S3 bucket (retrieved from SSM parameter) */\n s3Bucket: string;\n /** Must follow pattern: wc/${scope}/fileName.js.gz */\n s3Key: string;\n };\n\n /**\n * The actual custom element name that the JavaScript file defines.\n * This is the name used in customElements.define() in the JavaScript file.\n *\n * If not provided, defaults to `${scope}.${tag}` (e.g., \"pika.mock-spotlight-1\").\n *\n * Use this when:\n * - The JavaScript file defines a custom element with a different name than the tag\n * - Multiple tag definitions share the same JavaScript file that defines one custom element\n * - A JavaScript bundle file defines multiple custom elements\n *\n * Examples:\n * - \"hello-world\" for a file that calls customElements.define(\"hello-world\", ...)\n * - \"my-widget\" for a file that calls customElements.define(\"my-widget\", ...)\n */\n customElementName?: string;\n\n /**\n * Optional sizing configuration for this widget across different rendering contexts.\n *\n * If not provided, defaults are:\n * - dialog: 'fullscreen' (95vw x 90vh)\n * - inline: { height: \"400px\" }\n *\n * Examples:\n * ```typescript\n * // Preset dialog size\n * sizing: { dialog: 'medium', inline: { height: '300px' } }\n *\n * // Custom dialog size\n * sizing: { dialog: { width: '80vw', height: '60vh' } }\n *\n * // Only specify inline height\n * sizing: { inline: { height: '500px' } }\n * ```\n */\n sizing?: WidgetSizing;\n\n encoding: TagWebComponentEncoding;\n mediaType: 'application/javascript';\n encodedSizeBytes: number; // size of the stored object (post-encoding)\n\n /**\n * Hash of the GZIPPED file bytes as stored in S3 (NOT the decompressed JavaScript).\n * This hash is used for integrity validation when serving the file from S3.\n * When uploading to S3: hash = SHA256(gzippedBytes).toBase64()\n * When serving: compare stored hash to SHA256(gzippedBytesFromS3).toBase64()\n */\n encodedSha256Base64: string;\n}\n\nexport interface TagDefinitionCreateOrUpdateRequest {\n tagDefinition: TagDefinitionForCreateOrUpdate;\n\n /**\n * If you are creating one of these objects through the CloudFormation custom resource, then you should set this\n * to be something that is tied to the stack that did the creation/update and we ask that you prepend it with 'cloudformation/'\n * so we understand it was created/updated by cloudformation as in 'cloudformation/my-stack-name'.\n */\n userId: string;\n}\n\nexport interface TagDefinitionCreateOrUpdateResponse {\n success: boolean;\n tagDefinition: TagDefinition<TagDefinitionWidget>;\n}\n\n/**\n * Search for tag definitions with two primary modes:\n *\n * MODE 1 - Get specific tags (optionally including globals):\n * - Pass tagsDesired array for specific tags to retrieve\n * - Set includeGlobal=true to also include all global tags\n * - Uses primary key lookup (scope + tag) for specified tags\n * - Uses GSI (scope-status-index) for global tags if includeGlobal=true\n * - Returns requested tags + global tags (if includeGlobal=true)\n *\n * MODE 2 - Get all tags:\n * - Don't pass tagsDesired or includeGlobal\n * - Scans entire table with pagination\n * - Returns all tag definitions\n *\n * If used in admin context, returns all tag definitions (including disabled/retired).\n * If used in chat app context, filters to only 'enabled' status.\n */\nexport interface TagDefinitionSearchRequest {\n /** Specific tags to retrieve by scope+tag */\n tagsDesired?: TagDefinitionLite[];\n\n /** If true, also includes all global tags (usageMode='global') in addition to tagsDesired */\n includeGlobal?: boolean;\n\n /** If not true, instructions will not be returned to save space */\n includeInstructions?: boolean;\n\n /** Pagination token for continued queries */\n paginationToken?: Record<string, any> | undefined;\n}\n\nexport interface TagDefinitionSearchResponse {\n success: boolean;\n tagDefinitions: TagDefinition<TagDefinitionWidget>[];\n\n /** If this is present, there are more records that could be returned. Pass this token in to get the next page with the same request. */\n paginationToken?: Record<string, any> | undefined;\n}\n\nexport interface TagDefinitionDeleteRequest {\n tagDefinition: TagDefinitionLite;\n userId: string;\n}\n\nexport interface TagDefinitionDeleteResponse {\n success: boolean;\n}\n\nexport interface TagDefinitionsJsonFile {\n tagDefs: TagDefInJsonFile[];\n}\n\nexport interface TagDefInJsonFile {\n tag: string;\n scope: string;\n gzippedBase64EncodedString: string;\n}\n\n// ===== SHARING SESSIONS FEATURE TYPES =====\n\n/**\n * SharedSessionVisitHistory tracks user visits to shared sessions\n */\nexport interface SharedSessionVisitHistory {\n shareId: string;\n entityId: string;\n chatAppId: string;\n firstVisitedAt: string;\n lastVisitedAt: string;\n visitCount: number;\n title: string;\n\n /** If set to 'mock', this is a test shared session visit history. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport interface SharedSessionVisitHistoryDynamoDb extends SharedSessionVisitHistory {\n userIdChatAppId: string;\n}\n\n/**\n * PinnedSession represents user-curated sidebar items (both own and shared sessions)\n */\nexport interface PinnedSession {\n shareId?: string; // for shared sessions\n sessionId?: string; // for own sessions\n userId: string; // the user who did the pinning, will be userId of session if pin is for own session\n chatAppId: string;\n pinnedAt: string;\n\n /** If set to 'mock', this is a test pinned session. This is used for integration testing. */\n testType?: 'mock';\n}\n\nexport type PinnedSessionDynamoDb = PinnedSession & {\n userIdChatAppId: string;\n sessionOrShareId: string;\n};\n\nexport interface PinnedObjAndChatSession {\n pinnedSession: PinnedSession;\n chatSession: ChatSession<RecordOrUndef>;\n}\n\n// API Request/Response types\n\nexport interface CreateSharedSessionRequest {\n sessionId: string;\n sessionUserId: string;\n chatAppId: string;\n}\n\nexport interface CreateSharedSessionResponse {\n success: boolean;\n shareId: string;\n chatAppId: string;\n error?: string;\n}\n\nexport interface RevokeSharedSessionRequest {\n shareId: string;\n}\n\nexport interface RevokeSharedSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface UnrevokeSharedSessionRequest {\n shareId: string;\n}\n\nexport interface UnrevokeSharedSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface GetRecentSharedRequest {\n chatAppId: string;\n limit?: number; // default 5\n entityId?: string; // entity id to filter by\n nextToken?: string; // pagination token\n}\n\nexport interface GetRecentSharedResponse {\n success: boolean;\n recentShared: SharedSessionVisitHistory[];\n error?: string;\n nextToken?: string; // pagination token\n}\n\nexport interface GetPinnedSessionsRequest {\n chatAppId: string;\n limit?: number; // default 20\n nextToken?: string; // pagination token\n}\n\nexport interface GetPinnedSessionsResponse {\n success: boolean;\n results: PinnedObjAndChatSession[];\n nextToken?: string; // for pagination\n error?: string;\n}\n\nexport interface PinSessionRequest {\n pinnedSession: PinnedSession;\n}\n\nexport interface PinSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface UnpinSessionRequest {\n sessionId?: string; // for own sessions\n shareId?: string; // for shared sessions\n chatAppId: string;\n}\n\nexport interface UnpinSessionResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface ValidateShareAccessRequest {\n shareId: string;\n chatAppId: string;\n entityId?: string;\n}\n\nexport interface ValidateShareAccessResponse {\n success: boolean;\n hasAccess: boolean;\n sessionData?: ChatSession<RecordOrUndef>;\n error?: string;\n}\n\nexport interface RecordShareVisitRequest {\n shareId: string;\n}\n\nexport interface RecordShareVisitResponse {\n success: boolean;\n error?: string;\n}\n\nexport interface ShowToastOptions {\n type: 'success' | 'error' | 'warning' | 'info';\n duration?: number | 'infinite';\n}\n\nexport type ShowToastFn = (message: string, options: ShowToastOptions) => void;\n\nexport const ShareSessionStateList = ['disable-share-feature', 'shared-by-me', 'shared-by-someone-else', 'not-shared'] as const;\nexport type ShareSessionState = (typeof ShareSessionStateList)[number];\n\n/**\n * Options for invokeAgentAsComponent() method\n */\nexport interface InvokeAgentAsComponentOptions {\n /**\n * Callback for streaming traces from the agent\n */\n onTrace?: (trace: any) => void;\n\n /**\n * Callback for progress updates (partial JSON text as it streams)\n */\n onProgress?: (partialText: string) => void;\n\n /**\n * Callback for agent thinking/rationale\n */\n onThinking?: (rationale: string) => void;\n\n /**\n * Callback for tool invocations\n */\n onToolCall?: (toolCall: { name: string; params: any }) => void;\n\n /**\n * Whether to include full traces in callbacks (default: false)\n */\n includeTraces?: boolean;\n\n /**\n * Request timeout in milliseconds (default: 60000)\n */\n timeout?: number;\n\n /**\n * The source of the converse request. Defaults to 'user'. The composite key chat_app_sk looks like this:\n *\n * ${chatAppId}#${source}#${updateDate}\n *\n * The source in the composite key here will only ever be either `user` or `component`. If this attribute's value is missing or is `user` or `component-as-user`,\n * then the composite key will be set to `user` so when we query on behalf of the user, we will get all sessions for that user.\n */\n source: ConverseSource;\n}\n\n/**\n * A single action button that will appear at the top of the chat app in the title bar or\n * that will appear in a button menu that pops up when the user clicks the title bar action button.\n *\n * @example\n * ```js\n * const action: ChatAppAction = {\n * id: 'refresh',\n * title: 'Refresh',\n * iconSvg: '<svg>...</svg>',\n * callback: () => refresh()\n * };\n * ```\n */\nexport interface ChatAppAction {\n /** Unique identifier for this action */\n id: string;\n /** Discriminator for the type */\n type: 'action';\n\n /** Tooltip or menu item description for the action */\n title: string;\n\n /** SVG markup string for the icon (e.g., from extractIconSvg() helper) */\n iconSvg: string;\n\n /** Whether action is currently disabled */\n disabled?: boolean;\n\n /** Handler when clicked */\n callback: () => void | Promise<void>;\n}\n\n/**\n * The only reason to use this is to get a title for the action group.\n */\nexport interface ChatAppActionGroup {\n /** Discriminator for the type */\n type: 'group';\n /** Title of the action group. The whole point of an action group is to get a title above the group. */\n title: string;\n /** Actions to display in the group */\n actions: (ChatAppAction | 'separator')[];\n}\n\n/**\n * The elements that can be displayed in a ChatAppActionMenu.\n */\nexport type ChatAppActionMenuElements = ChatAppActionGroup | ChatAppAction | 'separator';\n\n/**\n * Widgets can register a single icon button or icon button with a menu that will appear at the top of the chat app in the title bar.\n */\nexport interface ChatAppActionMenu {\n /** Unique identifier for this action */\n id: string;\n /** Tooltip/label for the action (also button text in dialog context) */\n title: string;\n /** SVG markup string for the icon (e.g., from extractIconSvg() helper) */\n iconSvg: string;\n /** Whether the action menu is currently disabled */\n disabled?: boolean;\n /**\n * Actions to display in the menu\n * Here are some common examples:\n * - [\n * { type: 'action', id: 'refresh', title: 'Refresh', iconSvg: '<svg>...</svg>', callback: () => refresh() },\n * 'separator',\n * { id: 'settings', title: 'Settings', iconSvg: '<svg>...</svg>', callback: () => showSettings() }\n * ]\n * - [\n * { type: 'group', title: 'Settings', actions: [\n * { type: 'action', id: 'refresh', title: 'Refresh', iconSvg: '<svg>...</svg>', callback: () => refresh() },\n * 'separator',\n * { type: 'action', id: 'settings', title: 'Settings', iconSvg: '<svg>...</svg>', callback: () => showSettings() }\n * ] }\n * ]\n */\n actions: ChatAppActionMenuElements[];\n}\n\nexport interface IUserWidgetDataStoreState {\n readonly initialized: boolean;\n readonly data: UserWidgetData | undefined;\n readonly showToast: ShowToastFn;\n refreshDataFromServer(): Promise<void>;\n getValue<T>(key: string): Promise<T | undefined>;\n setValue(key: string, value: unknown): Promise<void>;\n deleteValue(key: string): Promise<void>;\n}\n\n/**\n * Represents a unit of contextual information that can be considered for inclusion\n * in an LLM prompt when responding to a user's request.\n */\nexport interface LLMContextItem {\n /** A unique identifier for this context item. */\n id: string;\n\n /**\n * A short natural-language summary describing what this context is about.\n * Used by smaller / cheaper LLMs to determine if this item is relevant\n * to the user's current query.\n */\n description: string;\n\n /**\n * The actual contextual content that can be inserted into the LLM prompt\n * if deemed relevant by the model.\n */\n context: unknown;\n\n /** Whether this was added automatically by the component or by the user */\n origin: WidgetContextSourceOrigin;\n\n /** SHA-256 hash of the content, used to detect changes. */\n contentHash: string;\n\n /** ISO-8601 timestamp of when this context was last updated. */\n lastUpdated: string;\n\n /**\n * Optional expiration for the cached context.\n * - `0` means it is always considered \"changed\" (always re-included).\n * - If omitted, re-inclusion depends on hash changes.\n * - If set, after this duration (in ms), the context is considered stale\n * and should be re-fetched or re-included even if the hash is unchanged.\n */\n maxAgeMs?: number;\n}\n\n/**\n * Here is a generic source of context that can be added to the conversation.\n */\nexport interface ContextSourceDef {\n /** A unique identifier for this context source. Must be unique system wide so be sure. Used for caching and tracking. */\n sourceId: string;\n\n /**\n * This is a description that will be given an LLM before the agent is invoked to determine if this context should be included in the prompt.\n * It will be given a list of all contexts that are available, the inquiry from the user and then asked which\n * contexts should be included in the prompt.\n */\n llmInclusionDescription: string;\n\n /** Whether this was added automatically by the component or by the user */\n origin: WidgetContextSourceOrigin;\n\n /** The name of the lucide icon to show the user to represent this context. A default will be used if not provided. */\n lucideIconName?: string;\n\n /** The title of the context. This will be shown to the user as the name of this context. */\n title: string;\n\n /** The description of the context. This will be shown to the user as the description of this context. */\n description: string;\n\n /** The data to include in the context. This will be sent to the agent as the context. */\n data: unknown;\n\n /** Whether to add this context automatically when the component is added to the conversation. */\n addAutomatically?: boolean;\n\n /**\n * Optional expiration for the cached context.\n * - `0` means it is always considered \"changed\" (always re-included).\n * - If omitted, re-inclusion depends on hash changes.\n * - If set, after this duration (in ms), the context is considered stale\n * and should be re-fetched or re-included even if the hash is unchanged.\n */\n maxAgeMs?: number;\n}\n\nexport const WidgetContextSourceOrigins = ['user', 'auto'] as const;\nexport type WidgetContextSourceOrigin = (typeof WidgetContextSourceOrigins)[number];\n\n/**\n * Components that have a getContext method will return a ContextSourceDef\n * object and then Pika will include the instanceId and store it as a\n * WidgetContextSourceDef so it knows the source of the context is\n * a widget.\n */\nexport interface WidgetContextSourceDef extends ContextSourceDef {\n type: 'widget';\n\n /** The web component instance ID that is adding the context. This is used to identify the instance of the component that is adding the context. */\n instanceId: string;\n}\n\n/** These are what get added to the converstaion state as context sources. */\nexport type ContextSource = WidgetContextSourceDef;\n\n/**\n * Session Analytics Types\n * Used for the Session Analytics dashboard to show platform usage metrics, cost analytics, and at-a-glance KPIs.\n */\n\nexport interface SessionAnalyticsRequest {\n /** Date range for the analytics query (ISO 8601 formatted strings) */\n dateRange: {\n start: string;\n end: string;\n };\n /** Optional filter by specific entity ID */\n entityId?: string;\n /** Entity attribute name from siteFeatures, used for entity aggregations */\n entityAttributeName?: string;\n /** Optional filter by specific chat app IDs */\n chatAppIds?: string[];\n /** Optional filter by user types (internal-user, external-user) */\n userTypes?: UserType[];\n /** Optional filter by invocation modes. Defaults to undefined and 'chat-app' (user-initiated only) if not provided. */\n invocationModes?: (ConverseInvocationMode | 'undefined')[];\n /** Time grouping for time series data (day, week, month) */\n groupBy?: 'day' | 'week' | 'month';\n /** Limit for top entities/chat apps results */\n limit?: number;\n}\n\nexport interface SessionAnalyticsResponse {\n /** Whether the request was successful */\n success: boolean;\n /** Error message if success is false */\n error?: string;\n /** Summary metrics across the entire date range */\n summary: SessionAnalyticsSummary;\n /** Time series data points */\n timeSeries: SessionAnalyticsTimeSeriesPoint[];\n /** Top entities by usage (only populated if entityAttributeName was provided) */\n topEntities: SessionAnalyticsEntityUsage[];\n /** Top chat apps by usage */\n topChatApps: SessionAnalyticsChatAppUsage[];\n /** Cost breakdown by invocation mode */\n costByInvocationMode: SessionAnalyticsCostByMode[];\n}\n\nexport interface SessionAnalyticsSummary {\n /** Total number of sessions */\n totalSessions: number;\n /** Number of unique users */\n uniqueUsers: number;\n /** Number of unique entities (only populated if entity feature enabled) */\n uniqueEntities?: number;\n /** Total number of messages across all sessions */\n totalMessages: number;\n /** Total input tokens consumed */\n totalInputTokens: number;\n /** Total output tokens generated */\n totalOutputTokens: number;\n /** Total input cost in USD */\n totalInputCost: number;\n /** Total output cost in USD */\n totalOutputCost: number;\n /** Total cost (input + output) in USD */\n totalCost: number;\n /** Average cost per session in USD */\n avgCostPerSession: number;\n /** Average tokens per session */\n avgTokensPerSession: number;\n}\n\nexport interface SessionAnalyticsTimeSeriesPoint {\n /** ISO 8601 formatted date for this data point */\n date: string;\n /** Number of sessions in this time period */\n sessionCount: number;\n /** Number of unique users in this time period */\n uniqueUserCount: number;\n /** Number of messages in this time period */\n messageCount: number;\n /** Input tokens consumed in this time period */\n inputTokens: number;\n /** Output tokens generated in this time period */\n outputTokens: number;\n /** Input cost in USD for this time period */\n inputCost: number;\n /** Output cost in USD for this time period */\n outputCost: number;\n /** Total cost in USD for this time period */\n totalCost: number;\n}\n\nexport interface SessionAnalyticsEntityUsage {\n /** Entity identifier */\n entityId: string;\n /** Entity name (human-readable) */\n entityName?: string;\n /** Number of sessions for this entity */\n sessionCount: number;\n /** Number of unique users for this entity */\n uniqueUserCount: number;\n /** Number of messages for this entity */\n messageCount: number;\n /** Total cost in USD for this entity */\n totalCost: number;\n /** Input tokens consumed for this entity */\n inputTokens: number;\n /** Output tokens generated for this entity */\n outputTokens: number;\n}\n\nexport interface SessionAnalyticsChatAppUsage {\n /** Chat app identifier */\n chatAppId: string;\n /** Chat app name (human-readable) */\n chatAppName?: string;\n /** Number of sessions for this chat app */\n sessionCount: number;\n /** Number of unique users for this chat app */\n uniqueUserCount: number;\n /** Number of messages for this chat app */\n messageCount: number;\n /** Total cost in USD for this chat app */\n totalCost: number;\n /** Input tokens consumed for this chat app */\n inputTokens: number;\n /** Output tokens generated for this chat app */\n outputTokens: number;\n}\n\nexport interface SessionAnalyticsCostByMode {\n /** Invocation mode (including 'undefined' for missing/undefined mode) */\n invocationMode: string;\n /** Number of sessions for this mode */\n sessionCount: number;\n /** Total cost in USD for this mode */\n totalCost: number;\n /** Input cost in USD for this mode */\n inputCost: number;\n /** Output cost in USD for this mode */\n outputCost: number;\n /** Input tokens consumed for this mode */\n inputTokens: number;\n /** Output tokens generated for this mode */\n outputTokens: number;\n /** Human-readable description of the mode */\n description: string;\n}\n\n/**\n * Configuration options for markdown-it renderer\n * @since 0.13.0\n */\nexport interface MarkdownRendererConfig {\n /**\n * Enable HTML tags in source\n * @default true\n */\n html?: boolean;\n /**\n * Autoconvert URL-like text to links\n * @default true\n */\n linkify?: boolean;\n /**\n * Enable some language-neutral replacement + quotes beautification\n * @default true\n */\n typographer?: boolean;\n /**\n * Convert '\\n' in paragraphs into <br>\n * @default true\n */\n breaks?: boolean;\n /**\n * Custom syntax highlighting function for code blocks\n * @param str - The code string to highlight\n * @param lang - The language identifier\n * @returns HTML string with highlighted code\n */\n highlight?: (str: string, lang: string) => string;\n /**\n * Cache key identifier for the highlight function (required if highlight is provided).\n * This allows the factory to cache renderers with different highlight functions.\n * Use a unique string to identify your highlight function (e.g., 'hljs-default', 'prism-custom', etc.)\n */\n highlightCacheKey?: string;\n}\n","/**\n * These are utils that should only be used on the server in svelte kit and\n * in lambda functions.\n */\nimport { gunzipSync, gzipSync } from 'zlib';\nimport {\n DEFAULT_MAX_K_MATCHES_PER_STRATEGY,\n DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT,\n type AccessRules,\n type AuthenticatedUser,\n type ChatApp,\n type ChatAppOverridableFeatures,\n type ChatUser,\n type RecordOrUndef,\n type SiteFeatures,\n type TagDefinitionLite\n} from '../types/chatbot/chatbot-types';\n\nexport function gunzipBase64EncodedString(base64EncodedString: string): string {\n const gzippedHexEncodedString = Buffer.from(base64EncodedString, 'base64').toString('hex');\n const gzippedHexDecodedString = gunzipSync(Buffer.from(gzippedHexEncodedString, 'hex')).toString();\n return gzippedHexDecodedString;\n}\n\nexport function gzipAndBase64EncodeString(string: string): string {\n const gzippedHexEncodedString = gzipSync(string).toString('hex');\n const gzippedBase64EncodedString = Buffer.from(gzippedHexEncodedString, 'hex').toString('base64');\n return gzippedBase64EncodedString;\n}\n\n/**\n * Compute what features the user is and isn't allowed to use for this chat app.\n *\n * Feature hierarchy (in order of precedence):\n * 1. Site level (<root>/pika-config.ts) - Controls ultimate availability\n * 2. Chat app level (chatApp.features) - Can override site settings\n * 3. Admin override level (chatApp.override.features) - Can override chat app settings\n *\n * Note that we always return siteAdmin: { websiteEnabled: false } because we only check that for real when they try to access the admin page itself.\n *\n * Override rules:\n * - Site level controls whether a feature can be used at all\n * - Chat apps can override site level (but only to restrict)\n * - Admins can override chat app level completely (but cannot enable features disabled at site level)\n * - When overriding, complete feature configuration must be provided (no merging)\n */\nexport function getOverridableFeatures(siteFeatures: SiteFeatures, chatApp: ChatApp, user: AuthenticatedUser<RecordOrUndef, RecordOrUndef>): ChatAppOverridableFeatures {\n const result: ChatAppOverridableFeatures = {\n entity: {\n enabled: false\n },\n verifyResponse: {\n enabled: false\n },\n traces: {\n enabled: false,\n detailedTraces: false\n },\n fileUpload: {\n mimeTypesAllowed: [] as string[]\n },\n suggestions: {\n suggestions: [] as string[],\n randomize: false,\n randomizeAfter: 0,\n maxToShow: 5\n },\n promptInputFieldLabel: {\n label: undefined\n },\n uiCustomization: {\n showUserRegionInLeftNav: false,\n showChatHistoryInStandaloneMode: false\n },\n chatDisclaimerNotice: undefined,\n logout: {\n enabled: false,\n menuItemTitle: 'Logout',\n dialogTitle: 'Logout',\n dialogDescription: 'Are you sure you want to logout?'\n },\n siteAdmin: {\n websiteEnabled: false\n },\n tags: {\n tagsEnabled: [] as TagDefinitionLite[],\n tagsDisabled: [] as TagDefinitionLite[]\n },\n agentInstructionAssistance: {\n enabled: false,\n includeOutputFormattingRequirements: false,\n includeInstructionsForTags: false,\n completeExampleInstructionEnabled: false,\n completeExampleInstructionLine: undefined,\n jsonOnlyImperativeInstructionEnabled: false,\n jsonOnlyImperativeInstructionLine: undefined,\n includeTypescriptBackedOutputFormattingRequirements: false,\n typescriptBackedOutputFormattingRequirements: undefined\n },\n instructionAugmentation: {\n enabled: false,\n type: undefined\n },\n userMemory: {\n enabled: false,\n maxMemoryRecordsPerPrompt: DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT,\n maxKMatchesPerStrategy: DEFAULT_MAX_K_MATCHES_PER_STRATEGY\n }\n };\n\n // Handle verifyResponse feature\n // Admin override takes precedence over chat app configuration\n const effectiveVerifyResponseFeature = chatApp.override?.features?.verifyResponse || chatApp.features?.verifyResponse;\n result.verifyResponse = handleAccessRuleFeature(\n 'verifyResponse',\n effectiveVerifyResponseFeature,\n siteFeatures?.verifyResponse,\n result.verifyResponse,\n user,\n (feature, enabled) => ({\n enabled,\n autoRepromptThreshold: feature.autoRepromptThreshold\n })\n );\n\n // Handle traces feature (has sub-feature for detailedTraces)\n // Admin override takes precedence over chat app configuration\n const effectiveTracesFeature = chatApp.override?.features?.traces || chatApp.features?.traces;\n result.traces = handleAccessRuleFeature('traces', effectiveTracesFeature, siteFeatures?.traces, result.traces, user, (feature, enabled) => {\n let detailedTraces = false;\n if (enabled && feature.detailedTraces) {\n // Check site-level gating for detailedTraces\n const siteDetailedTracesRule = siteFeatures?.traces?.detailedTraces || { enabled: false };\n if (siteDetailedTracesRule.enabled) {\n detailedTraces = checkUserAccessToFeature(user, feature.detailedTraces as AccessRules);\n }\n } else if (enabled) {\n // No app/admin override for detailedTraces, use site level\n const siteDetailedTracesRule = siteFeatures?.traces?.detailedTraces || { enabled: false };\n detailedTraces = checkUserAccessToFeature(user, siteDetailedTracesRule);\n }\n return {\n enabled,\n detailedTraces\n };\n });\n\n // Handle logout feature\n // Admin override takes precedence over chat app configuration\n const effectiveLogoutFeature = chatApp.override?.features?.logout || chatApp.features?.logout;\n result.logout = handleAccessRuleFeature('logout', effectiveLogoutFeature, siteFeatures?.logout, result.logout, user, (feature, enabled) => ({\n enabled,\n menuItemTitle: feature.menuItemTitle ?? 'Logout',\n dialogTitle: feature.dialogTitle ?? 'Logout',\n dialogDescription: feature.dialogDescription ?? 'Are you sure you want to logout?'\n }));\n\n // Handle fileUpload feature\n // Admin override takes precedence over chat app configuration\n const effectiveFileUploadFeature = chatApp.override?.features?.fileUpload || chatApp.features?.fileUpload;\n result.fileUpload = handleSimpleFeature('fileUpload', effectiveFileUploadFeature, siteFeatures?.fileUpload, result.fileUpload, (feature) => ({\n mimeTypesAllowed: feature.mimeTypesAllowed || []\n }));\n\n // Handle suggestions feature\n // Admin override takes precedence over chat app configuration\n const effectiveSuggestionsFeature = chatApp.override?.features?.suggestions || chatApp.features?.suggestions;\n result.suggestions = handleSimpleFeature('suggestions', effectiveSuggestionsFeature, siteFeatures?.suggestions, result.suggestions, (feature) => ({\n suggestions: feature.suggestions || [],\n randomize: feature.randomize ?? false,\n randomizeAfter: feature.randomizeAfter ?? 0,\n maxToShow: feature.maxToShow ?? 5\n }));\n\n // Handle promptInputFieldLabel feature\n // Admin override takes precedence over chat app configuration\n const effectivePromptInputFieldLabelFeature = chatApp.override?.features?.promptInputFieldLabel || chatApp.features?.promptInputFieldLabel;\n result.promptInputFieldLabel = handleEnabledOnlyFeature(\n 'promptInputFieldLabel',\n effectivePromptInputFieldLabelFeature,\n siteFeatures?.promptInputFieldLabel,\n { label: 'Ready to chat' }, // Default return shape\n (feature, enabled) => ({\n label: enabled ? (feature.promptInputFieldLabel ?? 'Ready to chat') : undefined\n })\n );\n\n // Handle uiCustomization feature\n // Admin override takes precedence over chat app configuration\n const effectiveUiCustomizationFeature = chatApp.override?.features?.uiCustomization || chatApp.features?.uiCustomization;\n result.uiCustomization = handleSimpleFeature('uiCustomization', effectiveUiCustomizationFeature, siteFeatures?.uiCustomization, result.uiCustomization, (feature) => ({\n showUserRegionInLeftNav: feature.showUserRegionInLeftNav ?? false,\n showChatHistoryInStandaloneMode: feature.showChatHistoryInStandaloneMode ?? false\n }));\n\n // Handle chatDisclaimerNotice feature\n // Admin override takes precedence over chat app configuration\n const effectiveChatDisclaimerNoticeFeature = chatApp.override?.features?.chatDisclaimerNotice || chatApp.features?.chatDisclaimerNotice;\n const disclaimerResult = handleEnabledOnlyFeature(\n 'chatDisclaimerNotice',\n effectiveChatDisclaimerNoticeFeature,\n siteFeatures?.chatDisclaimerNotice,\n { notice: undefined },\n (feature, enabled) => ({\n notice: enabled ? feature.notice : undefined\n })\n );\n result.chatDisclaimerNotice = disclaimerResult.notice;\n\n // Handle tags feature\n // Admin override takes precedence over chat app configuration\n const effectiveTagsFeature = chatApp.override?.features?.tags || chatApp.features?.tags;\n result.tags = handleSimpleFeature('tags', effectiveTagsFeature, siteFeatures?.tags, result.tags, (feature) => ({\n tagsEnabled: feature.tagsEnabled ?? [],\n tagsDisabled: feature.tagsDisabled ?? []\n }));\n\n // Handle agentInstructionAssistance feature\n // Admin override takes precedence over chat app configuration\n const effectiveAgentInstructionAssistanceFeature = chatApp.override?.features?.agentInstructionAssistance || chatApp.features?.agentInstructionAssistance;\n result.agentInstructionAssistance = handleSimpleFeature(\n 'agentInstructionAssistance',\n effectiveAgentInstructionAssistanceFeature,\n siteFeatures?.agentInstructionAssistance,\n result.agentInstructionAssistance,\n (feature) => ({\n enabled: feature.enabled ?? false,\n includeOutputFormattingRequirements: feature.includeOutputFormattingRequirements?.enabled ?? false,\n includeInstructionsForTags: feature.includeInstructionsForTags?.enabled ?? false,\n completeExampleInstructionEnabled: feature.completeExampleInstructionLine?.enabled ?? false,\n completeExampleInstructionLine: feature.completeExampleInstructionLine?.mdLine ?? undefined,\n jsonOnlyImperativeInstructionEnabled: feature.jsonOnlyImperativeInstructionLine?.enabled ?? false,\n jsonOnlyImperativeInstructionLine: feature.jsonOnlyImperativeInstructionLine?.line ?? undefined,\n includeTypescriptBackedOutputFormattingRequirements: feature.includeTypescriptBackedOutputFormattingRequirements?.enabled ?? false,\n typescriptBackedOutputFormattingRequirements: feature.typescriptBackedOutputFormattingRequirements ?? undefined\n })\n );\n\n // Handle instructionAugmentation feature\n // Admin override takes precedence over chat app configuration\n const effectiveInstructionAugmentationFeature = chatApp.override?.features?.instructionAugmentation || chatApp.features?.instructionAugmentation;\n result.instructionAugmentation = handleSimpleFeature(\n 'instructionAugmentation',\n effectiveInstructionAugmentationFeature,\n siteFeatures?.instructionAugmentation,\n result.instructionAugmentation,\n (feature) => ({\n enabled: feature.enabled ?? false,\n type: feature.type ?? 'llm-semantic-directive-search'\n })\n );\n\n // Handle userMemory feature\n // Admin override takes precedence over chat app configuration\n const effectiveUserMemoryFeature = chatApp.override?.features?.userMemory || chatApp.features?.userMemory;\n result.userMemory = handleSimpleFeature('userMemory', effectiveUserMemoryFeature, siteFeatures?.userMemory, result.userMemory, (feature) => ({\n enabled: feature.enabled ?? false,\n maxMemoryRecordsPerPrompt: feature.maxMemoryRecordsPerPrompt ?? DEFAULT_MAX_MEMORY_RECORDS_PER_PROMPT,\n maxKMatchesPerStrategy: feature.maxKMatchesPerStrategy ?? DEFAULT_MAX_K_MATCHES_PER_STRATEGY\n }));\n\n // Handle entity feature\n // Entity feature is special: it can only be disabled at chat app level, not enabled\n // If site has entity enabled, chat apps can override to disable it\n // Admin override takes precedence over chat app configuration\n const effectiveEntityFeature = chatApp.override?.features?.entity || chatApp.features?.entity;\n if (siteFeatures?.entity?.enabled) {\n // Site has entity enabled, check if chat app or admin has disabled it\n if (effectiveEntityFeature?.enabled === false) {\n result.entity.enabled = false;\n } else {\n // No override to disable, so it's enabled (follows site config)\n result.entity.enabled = true;\n if (!siteFeatures?.entity?.attributeName) {\n throw new Error('Entity feature is enabled at the site level but the site features entity object does not have an attributeName set');\n }\n result.entity.attributeName = siteFeatures.entity.attributeName;\n }\n } else {\n // Site doesn't have entity enabled, so it's disabled regardless of chat app config\n result.entity.enabled = false;\n }\n\n return result;\n}\n\n/**\n * Generic handler for simple features (no access rules).\n *\n * @param featureName - Name of the feature for logging\n * @param appFeature - App-level feature configuration\n * @param siteFeature - Site-level feature configuration\n * @param defaults - Default values for the feature\n * @param propertyExtractor - Function to extract properties from feature config\n * @returns The resolved feature configuration\n */\nfunction handleSimpleFeature<T>(featureName: string, appFeature: any, siteFeature: any, defaults: T, propertyExtractor: (feature: any) => T): T {\n if (isSimpleFeatureOverrideValid(appFeature, featureName) && appFeature) {\n return propertyExtractor(appFeature);\n } else {\n // Use site level or defaults\n const siteRule = siteFeature || defaults;\n return propertyExtractor(siteRule);\n }\n}\n\n/**\n * Generic handler for features with enabled flag but no user access control.\n * If enabled, the feature is on for all users. If disabled, it's off for all users.\n *\n * @param featureName - Name of the feature for logging\n * @param appFeature - App-level feature configuration\n * @param siteFeature - Site-level feature configuration\n * @param defaults - Default values for the feature\n * @param propertyExtractor - Function to extract properties from feature config\n * @returns The resolved feature configuration\n */\nfunction handleEnabledOnlyFeature<T>(featureName: string, appFeature: any, siteFeature: any, defaults: T, propertyExtractor: (feature: any, enabled: boolean) => T): T {\n const overrideStatus = isFeatureOverrideValid(appFeature, featureName);\n\n if (overrideStatus === 'enabled' && appFeature) {\n // Site-level gating: if site is disabled, app can't enable it\n const siteRule = siteFeature || { enabled: false };\n if (siteRule.enabled) {\n return propertyExtractor(appFeature, true);\n }\n return propertyExtractor({}, false); // Pass empty object when disabled\n } else if (overrideStatus === 'disabled') {\n return propertyExtractor({}, false); // Pass empty object when disabled\n } else {\n // Use site level or defaults\n const siteRule = siteFeature || { enabled: true }; // Default enabled for this feature\n return propertyExtractor(siteRule, siteRule.enabled);\n }\n}\n\n/**\n * Validates if a feature override is valid and returns its status.\n *\n * @param appFeature - The app-level feature configuration\n * @param featureName - The name of the feature for error logging\n * @returns The status of the override: 'enabled', 'disabled', 'invalid', or 'none'\n */\nfunction isFeatureOverrideValid(appFeature: any, featureName: string): 'enabled' | 'disabled' | 'invalid' | 'none' {\n if (!appFeature) return 'none';\n\n // Empty object is invalid\n if (Object.keys(appFeature).length === 0) {\n console.error(`Invalid empty feature override for ${featureName}. Falling back to site level.`);\n return 'invalid';\n }\n\n // Must have enabled property to be valid (except for simple features)\n if (!('enabled' in appFeature)) {\n console.error(`Invalid feature override for ${featureName}: missing 'enabled' property. Falling back to site level.`);\n return 'invalid';\n }\n\n return appFeature.enabled ? 'enabled' : 'disabled';\n}\n\n/**\n * Validates if a simple feature override (no access rules) is valid.\n *\n * @param appFeature - The app-level feature configuration\n * @param featureName - The name of the feature for error logging\n * @returns Whether the override is valid\n */\nfunction isSimpleFeatureOverrideValid(appFeature: any, featureName: string): boolean {\n if (!appFeature) return false;\n\n // Empty object is invalid\n if (Object.keys(appFeature).length === 0) {\n console.error(`Invalid empty feature override for ${featureName}. Falling back to site level.`);\n return false;\n }\n\n return true;\n}\n\n/**\n * Generic handler for features with access rules (enabled property + user access control).\n *\n * @param featureName - Name of the feature for logging\n * @param appFeature - App-level feature configuration\n * @param siteFeature - Site-level feature configuration\n * @param defaults - Default values for the feature\n * @param user - The authenticated user\n * @param propertyExtractor - Function to extract properties from feature config\n * @returns The resolved feature configuration\n */\nfunction handleAccessRuleFeature<T>(\n featureName: string,\n appFeature: any,\n siteFeature: any,\n defaults: T,\n user: AuthenticatedUser<RecordOrUndef, RecordOrUndef>,\n propertyExtractor: (feature: any, enabled: boolean) => T\n): T {\n const overrideStatus = isFeatureOverrideValid(appFeature, featureName);\n\n if (overrideStatus === 'enabled' && appFeature) {\n // Site-level gating: if site is disabled, app can't enable it\n const siteRule = siteFeature || { enabled: false };\n if (siteRule.enabled) {\n const enabled = checkUserAccessToFeature(user, appFeature as AccessRules);\n return propertyExtractor(appFeature, enabled);\n }\n return propertyExtractor(defaults, false);\n } else if (overrideStatus === 'disabled') {\n return propertyExtractor(defaults, false);\n } else {\n // Use site level or defaults\n const siteRule = siteFeature || { enabled: false };\n const enabled = checkUserAccessToFeature(user, siteRule);\n return propertyExtractor(siteRule, enabled);\n }\n}\n\n/**\n * Generic function to check if a user has access to a feature based on user types and roles.\n * This implements the same logic used in get for checking user access rules.\n *\n * **Access Control Logic:**\n * - If the feature is disabled (`enabled: false`), no access regardless of other rules\n * - If no userTypes or userRoles are specified, no access is granted (secure by default)\n * - If multiple userTypes are provided, a user need only have one of them to have access (OR logic)\n * - If multiple userRoles are provided, a user need only have one of them to have access (OR logic)\n * - If both userTypes and userRoles are provided, the `applyRulesAs` setting determines how they're combined:\n * - `'and'` (default): User must match a userType AND have a userRole\n * - `'or'`: User must match a userType OR have a userRole\n *\n * @param user - The authenticated user to check access for\n * @param feature - The feature configuration with user access rules\n * @returns Whether the user has access to the feature\n */\nexport function checkUserAccessToFeature(user: AuthenticatedUser<RecordOrUndef, RecordOrUndef>, feature: AccessRules): boolean {\n let { enabled, userTypes, userRoles, applyRulesAs = 'and' } = feature;\n\n // Normalize empty arrays to undefined for more intuitive access control\n // If userTypes is set but userRoles is empty array, treat userRoles as undefined\n if (userTypes && userTypes.length > 0 && userRoles && userRoles.length === 0) {\n userRoles = undefined;\n }\n\n // If userRoles is populated but userTypes is undefined/empty, treat userTypes as undefined\n if (userRoles && userRoles.length > 0 && (!userTypes || userTypes.length === 0)) {\n userTypes = undefined;\n }\n\n // If the feature is disabled, no access regardless of other rules\n if (!enabled) {\n return false;\n }\n\n // If no rules are specified, no access is granted (secure by default)\n if (!userTypes && !userRoles) {\n return false;\n }\n\n // Check user type access\n const userTypeMatches = userTypes ? userTypes.includes(user.userType ?? 'external-user') : true;\n\n // Check user role access\n const userRoleMatches = userRoles ? (user.roles ?? []).some((role) => userRoles.includes(role as any)) : true;\n\n // Apply the rules based on the logic specified\n if (applyRulesAs === 'and') {\n return userTypeMatches && userRoleMatches;\n } else {\n return userTypeMatches || userRoleMatches;\n }\n}\n\nexport function getEntityIdForUser(user: ChatUser<RecordOrUndef>, overrideDataForThisChatApp: RecordOrUndef, entityAttributeName?: string): string | undefined {\n // Choose which data source to use (override takes precedence)\n let customUserData: RecordOrUndef = overrideDataForThisChatApp || user.customData;\n\n // Early exit if no entity attribute name or no custom data\n // This is expected for internal users who may not have entity data\n if (!entityAttributeName || !customUserData) {\n return undefined;\n }\n\n // Note the entityAttributeName could have dots in it and if so we need to dereference the attribute\n // Example: \"user.account.id\" would need to traverse: customUserData.user.account.id\n let currentObject: RecordOrUndef = customUserData;\n const attributeParts = entityAttributeName.split('.');\n let currentValue: string | undefined;\n\n // Traverse through each part of the dotted path\n for (let i = 0; i < attributeParts.length; i++) {\n const part = attributeParts[i];\n\n // Check if the current part exists in the current object\n // If not found, return undefined (expected for internal users)\n if (!(part in currentObject)) {\n return undefined;\n }\n\n // If this is the last part, get the value\n if (i === attributeParts.length - 1) {\n currentValue = currentObject[part];\n } else {\n // Not the last part, so we need to traverse deeper\n if (typeof currentObject[part] === 'object' && currentObject[part] !== null) {\n currentObject = currentObject[part];\n } else {\n // Expected path doesn't exist, return undefined (expected for internal users)\n return undefined;\n }\n }\n }\n\n // Return the value if found, undefined if empty/falsy (expected for internal users)\n return currentValue;\n}\n"]}
|