@lota-sdk/core 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/infrastructure/schema/00_workstream.surql +55 -0
- package/infrastructure/schema/01_memory.surql +47 -0
- package/infrastructure/schema/02_execution_plan.surql +62 -0
- package/infrastructure/schema/03_learned_skill.surql +32 -0
- package/infrastructure/schema/04_runtime_bootstrap.surql +8 -0
- package/package.json +128 -0
- package/src/ai/definitions.ts +308 -0
- package/src/bifrost/bifrost.ts +256 -0
- package/src/config/agent-defaults.ts +99 -0
- package/src/config/constants.ts +33 -0
- package/src/config/env-shapes.ts +122 -0
- package/src/config/logger.ts +29 -0
- package/src/config/model-constants.ts +31 -0
- package/src/config/search.ts +17 -0
- package/src/config/workstream-defaults.ts +68 -0
- package/src/db/base.service.ts +55 -0
- package/src/db/cursor-pagination.ts +73 -0
- package/src/db/memory-query-builder.ts +207 -0
- package/src/db/memory-store.helpers.ts +118 -0
- package/src/db/memory-store.rows.ts +29 -0
- package/src/db/memory-store.ts +974 -0
- package/src/db/memory-types.ts +193 -0
- package/src/db/memory.ts +505 -0
- package/src/db/record-id.ts +78 -0
- package/src/db/service.ts +932 -0
- package/src/db/startup.ts +152 -0
- package/src/db/tables.ts +20 -0
- package/src/document/org-document-chunking.ts +224 -0
- package/src/document/parsing.ts +40 -0
- package/src/embeddings/provider.ts +76 -0
- package/src/index.ts +302 -0
- package/src/queues/context-compaction.queue.ts +82 -0
- package/src/queues/document-processor.queue.ts +118 -0
- package/src/queues/memory-consolidation.queue.ts +65 -0
- package/src/queues/post-chat-memory.queue.ts +128 -0
- package/src/queues/recent-activity-title-refinement.queue.ts +69 -0
- package/src/queues/regular-chat-memory-digest.config.ts +12 -0
- package/src/queues/regular-chat-memory-digest.queue.ts +73 -0
- package/src/queues/skill-extraction.config.ts +9 -0
- package/src/queues/skill-extraction.queue.ts +62 -0
- package/src/redis/connection.ts +176 -0
- package/src/redis/index.ts +30 -0
- package/src/redis/org-memory-lock.ts +43 -0
- package/src/redis/redis-lease-lock.ts +158 -0
- package/src/runtime/agent-contract.ts +1 -0
- package/src/runtime/agent-prompt-context.ts +119 -0
- package/src/runtime/agent-runtime-policy.ts +192 -0
- package/src/runtime/agent-stream-helpers.ts +117 -0
- package/src/runtime/agent-types.ts +22 -0
- package/src/runtime/approval-continuation.ts +16 -0
- package/src/runtime/chat-attachments.ts +46 -0
- package/src/runtime/chat-message.ts +10 -0
- package/src/runtime/chat-request-routing.ts +21 -0
- package/src/runtime/chat-run-orchestration.ts +25 -0
- package/src/runtime/chat-run-registry.ts +20 -0
- package/src/runtime/chat-types.ts +18 -0
- package/src/runtime/context-compaction-constants.ts +11 -0
- package/src/runtime/context-compaction-runtime.ts +86 -0
- package/src/runtime/context-compaction.ts +909 -0
- package/src/runtime/execution-plan.ts +59 -0
- package/src/runtime/helper-model.ts +405 -0
- package/src/runtime/indexed-repositories-policy.ts +28 -0
- package/src/runtime/instruction-sections.ts +8 -0
- package/src/runtime/llm-content.ts +71 -0
- package/src/runtime/memory-block.ts +264 -0
- package/src/runtime/memory-digest-policy.ts +14 -0
- package/src/runtime/memory-format.ts +8 -0
- package/src/runtime/memory-pipeline.ts +570 -0
- package/src/runtime/memory-prompts-fact.ts +47 -0
- package/src/runtime/memory-prompts-parse.ts +3 -0
- package/src/runtime/memory-prompts-update.ts +37 -0
- package/src/runtime/memory-scope.ts +43 -0
- package/src/runtime/plugin-types.ts +10 -0
- package/src/runtime/retrieval-adapters.ts +25 -0
- package/src/runtime/retrieval-pipeline.ts +3 -0
- package/src/runtime/runtime-extensions.ts +154 -0
- package/src/runtime/skill-extraction-policy.ts +3 -0
- package/src/runtime/team-consultation-orchestrator.ts +245 -0
- package/src/runtime/team-consultation-prompts.ts +32 -0
- package/src/runtime/title-helpers.ts +12 -0
- package/src/runtime/turn-lifecycle.ts +28 -0
- package/src/runtime/workstream-chat-helpers.ts +187 -0
- package/src/runtime/workstream-routing-policy.ts +301 -0
- package/src/runtime/workstream-state.ts +261 -0
- package/src/services/attachment.service.ts +159 -0
- package/src/services/chat-attachments.service.ts +17 -0
- package/src/services/chat-run-registry.service.ts +3 -0
- package/src/services/context-compaction-runtime.ts +13 -0
- package/src/services/context-compaction.service.ts +115 -0
- package/src/services/document-chunk.service.ts +141 -0
- package/src/services/execution-plan.service.ts +890 -0
- package/src/services/learned-skill.service.ts +328 -0
- package/src/services/memory-assessment.service.ts +43 -0
- package/src/services/memory.service.ts +807 -0
- package/src/services/memory.utils.ts +84 -0
- package/src/services/mutating-approval.service.ts +110 -0
- package/src/services/recent-activity-title.service.ts +74 -0
- package/src/services/recent-activity.service.ts +397 -0
- package/src/services/workstream-change-tracker.service.ts +313 -0
- package/src/services/workstream-message.service.ts +283 -0
- package/src/services/workstream-title.service.ts +58 -0
- package/src/services/workstream-turn-preparation.ts +1340 -0
- package/src/services/workstream-turn.ts +37 -0
- package/src/services/workstream.service.ts +854 -0
- package/src/services/workstream.types.ts +118 -0
- package/src/storage/attachment-parser.ts +101 -0
- package/src/storage/attachment-storage.service.ts +391 -0
- package/src/storage/attachments.types.ts +11 -0
- package/src/storage/attachments.utils.ts +58 -0
- package/src/storage/generated-document-storage.service.ts +55 -0
- package/src/system-agents/agent-result.ts +27 -0
- package/src/system-agents/context-compacter.agent.ts +46 -0
- package/src/system-agents/delegated-agent-factory.ts +177 -0
- package/src/system-agents/helper-agent-options.ts +20 -0
- package/src/system-agents/memory-reranker.agent.ts +38 -0
- package/src/system-agents/memory.agent.ts +58 -0
- package/src/system-agents/recent-activity-title-refiner.agent.ts +53 -0
- package/src/system-agents/regular-chat-memory-digest.agent.ts +75 -0
- package/src/system-agents/researcher.agent.ts +34 -0
- package/src/system-agents/skill-extractor.agent.ts +88 -0
- package/src/system-agents/skill-manager.agent.ts +80 -0
- package/src/system-agents/title-generator.agent.ts +42 -0
- package/src/system-agents/workstream-tracker.agent.ts +58 -0
- package/src/tools/execution-plan.tool.ts +163 -0
- package/src/tools/fetch-webpage.tool.ts +132 -0
- package/src/tools/firecrawl-client.ts +12 -0
- package/src/tools/memory-block.tool.ts +55 -0
- package/src/tools/read-file-parts.tool.ts +80 -0
- package/src/tools/remember-memory.tool.ts +85 -0
- package/src/tools/research-topic.tool.ts +15 -0
- package/src/tools/search-tools.ts +55 -0
- package/src/tools/search-web.tool.ts +175 -0
- package/src/tools/team-think.tool.ts +125 -0
- package/src/tools/tool-contract.ts +21 -0
- package/src/tools/user-questions.tool.ts +18 -0
- package/src/utils/async.ts +50 -0
- package/src/utils/date-time.ts +34 -0
- package/src/utils/error.ts +10 -0
- package/src/utils/errors.ts +28 -0
- package/src/utils/hono-error-handler.ts +71 -0
- package/src/utils/string.ts +51 -0
- package/src/workers/bootstrap.ts +44 -0
- package/src/workers/memory-consolidation.worker.ts +318 -0
- package/src/workers/regular-chat-memory-digest.helpers.ts +100 -0
- package/src/workers/regular-chat-memory-digest.runner.ts +363 -0
- package/src/workers/regular-chat-memory-digest.worker.ts +22 -0
- package/src/workers/skill-extraction.runner.ts +331 -0
- package/src/workers/skill-extraction.worker.ts +22 -0
- package/src/workers/utils/repo-indexer-chunker.ts +331 -0
- package/src/workers/utils/repo-structure-extractor.ts +645 -0
- package/src/workers/utils/repomix-process-concurrency.ts +65 -0
- package/src/workers/utils/sandbox-error.ts +5 -0
- package/src/workers/worker-utils.ts +182 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { agentDisplayNames, resolveAgentNameAlias } from '../config/agent-defaults'
|
|
2
|
+
import type { ChatMessageLike, ReadableUploadMetadataLike } from './chat-types'
|
|
3
|
+
|
|
4
|
+
export interface WorkstreamHistoryMessage {
|
|
5
|
+
role: 'user' | 'agent'
|
|
6
|
+
content: string
|
|
7
|
+
agentName?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getAgentName(message: ChatMessageLike): string | undefined {
|
|
11
|
+
const metadata = message.metadata
|
|
12
|
+
if (!metadata || typeof metadata !== 'object') return undefined
|
|
13
|
+
const value = (metadata as Record<string, unknown>).agentName
|
|
14
|
+
if (typeof value !== 'string' || !value.trim()) return undefined
|
|
15
|
+
const resolvedAgentName = resolveAgentNameAlias(value)
|
|
16
|
+
return resolvedAgentName ? (agentDisplayNames[resolvedAgentName] ?? value.trim()) : value.trim()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function truncateTrackerText(value: string, maxChars: number): string {
|
|
20
|
+
return value.length <= maxChars ? value : `${value.slice(0, maxChars).trimEnd()}...`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function toTrackerToolLine(part: ChatMessageLike['parts'][number]): string | null {
|
|
24
|
+
if (typeof part !== 'object') return null
|
|
25
|
+
const record = part as Record<string, unknown>
|
|
26
|
+
const type = typeof record.type === 'string' ? record.type : null
|
|
27
|
+
if (!type?.startsWith('tool-')) return null
|
|
28
|
+
|
|
29
|
+
const toolName = type.slice('tool-'.length) || 'unknown'
|
|
30
|
+
const state = typeof record.state === 'string' ? record.state : null
|
|
31
|
+
const input = record.input
|
|
32
|
+
const output = record.output
|
|
33
|
+
|
|
34
|
+
const inputTask =
|
|
35
|
+
input && typeof input === 'object' && typeof (input as Record<string, unknown>).task === 'string'
|
|
36
|
+
? truncateTrackerText(((input as Record<string, unknown>).task as string).trim(), 220)
|
|
37
|
+
: null
|
|
38
|
+
const outputSummary =
|
|
39
|
+
output && typeof output === 'object' && typeof (output as Record<string, unknown>).summary === 'string'
|
|
40
|
+
? truncateTrackerText(((output as Record<string, unknown>).summary as string).trim(), 220)
|
|
41
|
+
: null
|
|
42
|
+
const outputResult =
|
|
43
|
+
output && typeof output === 'object' && typeof (output as Record<string, unknown>).result === 'string'
|
|
44
|
+
? truncateTrackerText(((output as Record<string, unknown>).result as string).trim(), 220)
|
|
45
|
+
: null
|
|
46
|
+
const errorText = typeof record.errorText === 'string' ? truncateTrackerText(record.errorText.trim(), 220) : null
|
|
47
|
+
|
|
48
|
+
if (state === 'output-error') {
|
|
49
|
+
return errorText ? `Tool ${toolName} failed: ${errorText}` : `Tool ${toolName} failed.`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (state !== 'output-available') {
|
|
53
|
+
return inputTask ? `Tool ${toolName} ran for: ${inputTask}` : `Tool ${toolName} ran.`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (outputSummary) return `Tool ${toolName} completed: ${outputSummary}`
|
|
57
|
+
if (inputTask) return `Tool ${toolName} completed for: ${inputTask}`
|
|
58
|
+
if (outputResult) return `Tool ${toolName} completed: ${outputResult}`
|
|
59
|
+
return `Tool ${toolName} completed.`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function extractMessageText(message: ChatMessageLike): string {
|
|
63
|
+
return message.parts
|
|
64
|
+
.flatMap((part) => (part.type === 'text' && typeof part.text === 'string' ? [part.text] : []))
|
|
65
|
+
.join('\n')
|
|
66
|
+
.trim()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function extractTrackerMessageText(message: ChatMessageLike): string {
|
|
70
|
+
const textParts = message.parts.flatMap((part) =>
|
|
71
|
+
part.type === 'text' && typeof part.text === 'string' ? [part.text] : [],
|
|
72
|
+
)
|
|
73
|
+
const toolParts = message.parts
|
|
74
|
+
.map((part) => toTrackerToolLine(part))
|
|
75
|
+
.filter((value): value is string => Boolean(value))
|
|
76
|
+
|
|
77
|
+
return [...textParts, ...toolParts].join('\n').trim()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function toHistoryMessages(messages: ChatMessageLike[], maxItems = 24): WorkstreamHistoryMessage[] {
|
|
81
|
+
return messages
|
|
82
|
+
.map((message): WorkstreamHistoryMessage | null => {
|
|
83
|
+
const content = extractMessageText(message)
|
|
84
|
+
if (!content) return null
|
|
85
|
+
|
|
86
|
+
if (message.role === 'user') {
|
|
87
|
+
return { role: 'user', content }
|
|
88
|
+
}
|
|
89
|
+
if (message.role === 'assistant') {
|
|
90
|
+
const agentName = getAgentName(message)
|
|
91
|
+
return { role: 'agent', content, ...(agentName ? { agentName } : {}) }
|
|
92
|
+
}
|
|
93
|
+
return null
|
|
94
|
+
})
|
|
95
|
+
.filter((message): message is WorkstreamHistoryMessage => message !== null)
|
|
96
|
+
.slice(-maxItems)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function buildConversationSummary(params: {
|
|
100
|
+
userMessageText: string
|
|
101
|
+
assistantMessages: ChatMessageLike[]
|
|
102
|
+
}): string {
|
|
103
|
+
const lines: string[] = []
|
|
104
|
+
if (params.userMessageText.trim()) {
|
|
105
|
+
lines.push(`User: ${params.userMessageText.trim()}`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const message of params.assistantMessages) {
|
|
109
|
+
const content = extractMessageText(message)
|
|
110
|
+
if (!content) continue
|
|
111
|
+
const agentName = getAgentName(message)
|
|
112
|
+
lines.push(agentName ? `${agentName}: ${content}` : `Assistant: ${content}`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return lines.join('\n\n').trim()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function buildAgentHistoryMessages(messages: ChatMessageLike[]): Array<{ content: string; agentName?: string }> {
|
|
119
|
+
return toHistoryMessages(messages)
|
|
120
|
+
.filter((message) => message.role === 'agent')
|
|
121
|
+
.map((message) => ({ content: message.content, ...(message.agentName ? { agentName: message.agentName } : {}) }))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function appendCompactionContextToHistoryMessages(
|
|
125
|
+
historyMessages: WorkstreamHistoryMessage[],
|
|
126
|
+
params: { chatSummary?: string | null; persistedState?: unknown },
|
|
127
|
+
): WorkstreamHistoryMessage[] {
|
|
128
|
+
const nextHistoryMessages = [...historyMessages]
|
|
129
|
+
const chatSummary = typeof params.chatSummary === 'string' ? params.chatSummary.trim() : ''
|
|
130
|
+
if (chatSummary) {
|
|
131
|
+
nextHistoryMessages.push({ role: 'agent', content: `Compacted chat summary:\n${chatSummary}` })
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (params.persistedState !== undefined && params.persistedState !== null) {
|
|
135
|
+
nextHistoryMessages.push({
|
|
136
|
+
role: 'agent',
|
|
137
|
+
content: `Structured workstream state:\n${JSON.stringify(params.persistedState)}`,
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return nextHistoryMessages
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function buildReadableUploadMetadataContext(uploads: ReadableUploadMetadataLike[]): string | undefined {
|
|
145
|
+
if (uploads.length === 0) return undefined
|
|
146
|
+
|
|
147
|
+
return [
|
|
148
|
+
'Uploaded files metadata:',
|
|
149
|
+
...uploads.map((upload) => {
|
|
150
|
+
const sizeSegment = upload.sizeBytes === null ? '' : `, sizeBytes=${upload.sizeBytes}`
|
|
151
|
+
return `- ${upload.filename} (${upload.mediaType}${sizeSegment}) storageKey=${upload.storageKey}`
|
|
152
|
+
}),
|
|
153
|
+
].join('\n')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function toOptionalTrimmedString(value: unknown): string | null {
|
|
157
|
+
if (typeof value !== 'string') return null
|
|
158
|
+
const normalized = value.trim()
|
|
159
|
+
return normalized.length > 0 ? normalized : null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function collectToolOutputErrors(params: {
|
|
163
|
+
responseMessage: ChatMessageLike
|
|
164
|
+
}): Array<{ toolName: string; toolCallId: string; errorText: string }> {
|
|
165
|
+
const errors: Array<{ toolName: string; toolCallId: string; errorText: string }> = []
|
|
166
|
+
|
|
167
|
+
for (const part of params.responseMessage.parts) {
|
|
168
|
+
if (typeof part !== 'object') continue
|
|
169
|
+
if (part.type !== undefined && typeof part.type !== 'string') continue
|
|
170
|
+
if (!part.type?.startsWith('tool-')) continue
|
|
171
|
+
if ((part as Record<string, unknown>).state !== 'output-error') continue
|
|
172
|
+
|
|
173
|
+
const toolName = part.type.slice('tool-'.length) || 'unknown'
|
|
174
|
+
const toolCallId =
|
|
175
|
+
typeof (part as Record<string, unknown>).toolCallId === 'string' && (part as Record<string, unknown>).toolCallId
|
|
176
|
+
? ((part as Record<string, unknown>).toolCallId as string)
|
|
177
|
+
: 'unknown'
|
|
178
|
+
const errorTextRaw = (part as Record<string, unknown>).errorText
|
|
179
|
+
const errorText =
|
|
180
|
+
typeof errorTextRaw === 'string' && errorTextRaw.trim()
|
|
181
|
+
? errorTextRaw.trim()
|
|
182
|
+
: 'Tool execution failed without explicit error text.'
|
|
183
|
+
errors.push({ toolName, toolCallId, errorText })
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return errors
|
|
187
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { extractAgentMentions } from '../config/agent-defaults'
|
|
2
|
+
|
|
3
|
+
export type MessageRoute =
|
|
4
|
+
| { type: 'direct'; agents: [string] }
|
|
5
|
+
| { type: 'mentions'; agents: string[] }
|
|
6
|
+
| { type: 'group-default'; agents: [string] }
|
|
7
|
+
|
|
8
|
+
export type ReasoningProfileName = 'fast' | 'standard' | 'deep'
|
|
9
|
+
|
|
10
|
+
export interface ReasoningProfile {
|
|
11
|
+
name: ReasoningProfileName
|
|
12
|
+
maxSteps: number
|
|
13
|
+
toolCallBudget: number
|
|
14
|
+
maxInputTokensHint: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type HighImpactResponseClass =
|
|
18
|
+
| 'architecture-recommendation'
|
|
19
|
+
| 'gtm-strategy'
|
|
20
|
+
| 'pricing-positioning'
|
|
21
|
+
| 'product-capability-claim'
|
|
22
|
+
| 'community-targeting'
|
|
23
|
+
| 'mutating-operation'
|
|
24
|
+
|
|
25
|
+
export type PolicyClass = 'external-mutation' | 'security-privacy' | 'legal-compliance' | 'financial-decision'
|
|
26
|
+
|
|
27
|
+
export function uniqueMentionOrder(message: string): string[] {
|
|
28
|
+
const ordered: string[] = []
|
|
29
|
+
const seen = new Set<string>()
|
|
30
|
+
for (const mention of extractAgentMentions(message)) {
|
|
31
|
+
const agent = mention.agent
|
|
32
|
+
if (seen.has(agent)) continue
|
|
33
|
+
seen.add(agent)
|
|
34
|
+
ordered.push(agent)
|
|
35
|
+
}
|
|
36
|
+
return ordered
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const GTM_STRONG_INTENT_PATTERNS: RegExp[] = [
|
|
40
|
+
/\bgo[-\s]?to[-\s]?market\b/i,
|
|
41
|
+
/\bgtm\b/i,
|
|
42
|
+
/\bcontent\s+marketing\b/i,
|
|
43
|
+
/\bcontent\s+strategy\b/i,
|
|
44
|
+
/\bdemand\s+generation\b/i,
|
|
45
|
+
/\bdistribution\s+strategy\b/i,
|
|
46
|
+
/\bpositioning\s+strategy\b/i,
|
|
47
|
+
/\blaunch\s+strategy\b/i,
|
|
48
|
+
/\blaunch\s+plan\b/i,
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
const GTM_WEAK_INTENT_PATTERNS: RegExp[] = [/\blaunch\b/i, /\bcommunity\b/i, /\bdistribution\b/i, /\bpositioning\b/i]
|
|
52
|
+
|
|
53
|
+
export function isGtmIntentMessage(message: string): boolean {
|
|
54
|
+
const text = message.trim()
|
|
55
|
+
if (!text) return false
|
|
56
|
+
|
|
57
|
+
if (GTM_STRONG_INTENT_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let weakMatches = 0
|
|
62
|
+
for (const pattern of GTM_WEAK_INTENT_PATTERNS) {
|
|
63
|
+
if (pattern.test(text)) weakMatches += 1
|
|
64
|
+
if (weakMatches >= 2) return true
|
|
65
|
+
}
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const HIGH_IMPACT_CLASS_PATTERNS: Array<{ className: HighImpactResponseClass; patterns: RegExp[] }> = [
|
|
70
|
+
{
|
|
71
|
+
className: 'architecture-recommendation',
|
|
72
|
+
patterns: [
|
|
73
|
+
/\barchitecture\b/i,
|
|
74
|
+
/\btech(?:nical)?\s+stack\b/i,
|
|
75
|
+
/\binfra(?:structure)?\b/i,
|
|
76
|
+
/\brefactor\b/i,
|
|
77
|
+
/\bsystem\s+design\b/i,
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
className: 'gtm-strategy',
|
|
82
|
+
patterns: [
|
|
83
|
+
/\bgo[-\s]?to[-\s]?market\b/i,
|
|
84
|
+
/\bgtm\b/i,
|
|
85
|
+
/\bdistribution\s+strategy\b/i,
|
|
86
|
+
/\blaunch\s+strategy\b/i,
|
|
87
|
+
/\bcontent\s+strategy\b/i,
|
|
88
|
+
/\bdemand\s+gen(?:eration)?\b/i,
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
className: 'pricing-positioning',
|
|
93
|
+
patterns: [/\bpricing\b/i, /\bpositioning\b/i, /\bpackaging\b/i, /\bfreemium\b/i, /\bbilling\b/i],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
className: 'product-capability-claim',
|
|
97
|
+
patterns: [
|
|
98
|
+
/\bdoes\s+it\s+(already\s+)?(support|have|do)\b/i,
|
|
99
|
+
/\bwhat\s+can\s+(it|we)\s+do\b/i,
|
|
100
|
+
/\bis\s+this\s+implemented\b/i,
|
|
101
|
+
/\bcurrent(?:ly)?\s+supports?\b/i,
|
|
102
|
+
/\bcapabilities?\b/i,
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
className: 'community-targeting',
|
|
107
|
+
patterns: [
|
|
108
|
+
/\bwhere\s+to\s+post\b/i,
|
|
109
|
+
/\bcommunity\b/i,
|
|
110
|
+
/\btarget\s+audience\b/i,
|
|
111
|
+
/\bchannels?\b/i,
|
|
112
|
+
/\bdistribution\s+channels?\b/i,
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
className: 'mutating-operation',
|
|
117
|
+
patterns: [
|
|
118
|
+
/\bdelete\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
119
|
+
/\bremove\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
120
|
+
/\bupdate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
121
|
+
/\bcreate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
122
|
+
/\bchange\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
123
|
+
/\barchive\b/i,
|
|
124
|
+
/\bskip\s+onboarding\b/i,
|
|
125
|
+
/\bproceed\s+in\s+onboarding\b/i,
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
const POLICY_CLASS_PATTERNS: Array<{ className: PolicyClass; patterns: RegExp[] }> = [
|
|
131
|
+
{
|
|
132
|
+
className: 'external-mutation',
|
|
133
|
+
patterns: [
|
|
134
|
+
/\bdelete\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
135
|
+
/\bremove\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
136
|
+
/\bupdate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
137
|
+
/\bcreate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
138
|
+
/\bchange\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
139
|
+
/\barchive\b/i,
|
|
140
|
+
/\bskip\s+onboarding\b/i,
|
|
141
|
+
/\bproceed\s+in\s+onboarding\b/i,
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
className: 'security-privacy',
|
|
146
|
+
patterns: [
|
|
147
|
+
/\bsecurity\b/i,
|
|
148
|
+
/\bprivacy\b/i,
|
|
149
|
+
/\bpii\b/i,
|
|
150
|
+
/\bauth(?:entication|orization)?\b/i,
|
|
151
|
+
/\bencrypt(?:ion|ed)?\b/i,
|
|
152
|
+
/\bpermission(?:s)?\b/i,
|
|
153
|
+
/\baccess\s+control\b/i,
|
|
154
|
+
/\bsecret(?:s)?\b/i,
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
className: 'legal-compliance',
|
|
159
|
+
patterns: [
|
|
160
|
+
/\blegal\b/i,
|
|
161
|
+
/\bcompliance\b/i,
|
|
162
|
+
/\bregulation(?:s)?\b/i,
|
|
163
|
+
/\bgdpr\b/i,
|
|
164
|
+
/\bhipaa\b/i,
|
|
165
|
+
/\bsoc\s*2\b/i,
|
|
166
|
+
/\blicense\b/i,
|
|
167
|
+
/\bterms?\b/i,
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
className: 'financial-decision',
|
|
172
|
+
patterns: [
|
|
173
|
+
/\bpricing\b/i,
|
|
174
|
+
/\bbilling\b/i,
|
|
175
|
+
/\brevenue\b/i,
|
|
176
|
+
/\bbudget\b/i,
|
|
177
|
+
/\bburn\s+rate\b/i,
|
|
178
|
+
/\brunway\b/i,
|
|
179
|
+
/\bfundrais(?:e|ing)\b/i,
|
|
180
|
+
/\bcash\s+flow\b/i,
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
const REASONING_PROFILES: Record<ReasoningProfileName, ReasoningProfile> = {
|
|
186
|
+
fast: { name: 'fast', maxSteps: 5, toolCallBudget: 3, maxInputTokensHint: 12_000 },
|
|
187
|
+
standard: { name: 'standard', maxSteps: 10, toolCallBudget: 6, maxInputTokensHint: 24_000 },
|
|
188
|
+
deep: { name: 'deep', maxSteps: 15, toolCallBudget: 10, maxInputTokensHint: 36_000 },
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const STRATEGIC_COMPLEXITY_PATTERNS: RegExp[] = [
|
|
192
|
+
/\bstrategy\b/i,
|
|
193
|
+
/\btrade[-\s]?off\b/i,
|
|
194
|
+
/\bcompare\b/i,
|
|
195
|
+
/\broadmap\b/i,
|
|
196
|
+
/\barchitecture\b/i,
|
|
197
|
+
/\bconstraints?\b/i,
|
|
198
|
+
/\bprioriti(?:y|es)\b/i,
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
const CROSS_SOURCE_COMPLEXITY_PATTERNS: RegExp[] = [
|
|
202
|
+
/\bcitation\b/i,
|
|
203
|
+
/\bevidence\b/i,
|
|
204
|
+
/\bsource\b/i,
|
|
205
|
+
/\bground(?:ed|ing)\b/i,
|
|
206
|
+
/\brepo\b/i,
|
|
207
|
+
/\bmemory\b/i,
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
const STANDARD_FLOOR_INTENT_PATTERNS: RegExp[] = [
|
|
211
|
+
/\bplan(?:ning)?\b/i,
|
|
212
|
+
/\bthink(?:ing)?\b/i,
|
|
213
|
+
/\bcareful(?:ly)?\b/i,
|
|
214
|
+
/\bimportant\b/i,
|
|
215
|
+
/\bcritical(?:ly)?\b/i,
|
|
216
|
+
/\bthorough(?:ly)?\b/i,
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
export function classifyHighImpactResponse(params: { message: string }): { classes: HighImpactResponseClass[] } {
|
|
220
|
+
const message = params.message.trim()
|
|
221
|
+
if (!message) return { classes: [] }
|
|
222
|
+
|
|
223
|
+
const classes: HighImpactResponseClass[] = []
|
|
224
|
+
for (const entry of HIGH_IMPACT_CLASS_PATTERNS) {
|
|
225
|
+
if (entry.patterns.some((pattern) => pattern.test(message))) {
|
|
226
|
+
classes.push(entry.className)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return { classes }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function classifyPolicyClasses(params: { message: string }): { classes: PolicyClass[] } {
|
|
234
|
+
const message = params.message.trim()
|
|
235
|
+
if (!message) return { classes: [] }
|
|
236
|
+
|
|
237
|
+
const classes: PolicyClass[] = []
|
|
238
|
+
for (const entry of POLICY_CLASS_PATTERNS) {
|
|
239
|
+
if (entry.patterns.some((pattern) => pattern.test(message))) {
|
|
240
|
+
classes.push(entry.className)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return { classes }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function resolveReasoningProfile(params: {
|
|
248
|
+
message: string
|
|
249
|
+
forceDeep?: boolean
|
|
250
|
+
explicitProfile?: ReasoningProfileName
|
|
251
|
+
}): ReasoningProfile {
|
|
252
|
+
if (params.explicitProfile) {
|
|
253
|
+
return REASONING_PROFILES[params.explicitProfile]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const text = params.message.trim()
|
|
257
|
+
if (!text) {
|
|
258
|
+
return REASONING_PROFILES.standard
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let score = 0
|
|
262
|
+
if (text.length >= 700) score += 3
|
|
263
|
+
else if (text.length >= 350) score += 2
|
|
264
|
+
else if (text.length >= 180) score += 1
|
|
265
|
+
|
|
266
|
+
const numberedListCount = (text.match(/\n\s*\d+\./g) ?? []).length
|
|
267
|
+
if (numberedListCount >= 3) score += 2
|
|
268
|
+
else if (numberedListCount >= 1) score += 1
|
|
269
|
+
|
|
270
|
+
if (STRATEGIC_COMPLEXITY_PATTERNS.some((pattern) => pattern.test(text))) score += 2
|
|
271
|
+
if (CROSS_SOURCE_COMPLEXITY_PATTERNS.some((pattern) => pattern.test(text))) score += 2
|
|
272
|
+
if (params.forceDeep) score += 2
|
|
273
|
+
if (STANDARD_FLOOR_INTENT_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
274
|
+
score += 3
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (score >= 7) return REASONING_PROFILES.deep
|
|
278
|
+
if (score >= 3) return REASONING_PROFILES.standard
|
|
279
|
+
return REASONING_PROFILES.fast
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function resolveMessageRoute(params: {
|
|
283
|
+
workstreamMode: 'direct' | 'group'
|
|
284
|
+
workstreamAgentId?: string
|
|
285
|
+
message: string
|
|
286
|
+
}): MessageRoute {
|
|
287
|
+
if (params.workstreamMode === 'direct') {
|
|
288
|
+
return { type: 'direct', agents: [params.workstreamAgentId ?? 'chief'] }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const mentions = uniqueMentionOrder(params.message)
|
|
292
|
+
if (mentions.length > 0) {
|
|
293
|
+
return { type: 'mentions', agents: mentions }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (isGtmIntentMessage(params.message)) {
|
|
297
|
+
return { type: 'group-default', agents: ['cmo'] }
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { type: 'group-default', agents: ['chief'] }
|
|
301
|
+
}
|