@lota-sdk/core 0.1.16 → 0.1.17
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/package.json +6 -3
- package/src/ai/definitions.ts +1 -1
- package/src/ai/embedding-cache.ts +2 -4
- package/src/bifrost/cache-headers.ts +8 -0
- package/src/bifrost/index.ts +1 -0
- package/src/create-runtime.ts +26 -1
- package/src/db/memory-store.helpers.ts +1 -3
- package/src/db/schema-fingerprint.ts +1 -3
- package/src/queues/document-processor.queue.ts +2 -4
- package/src/queues/post-chat-memory.queue.ts +8 -2
- package/src/queues/recent-activity-title-refinement.queue.ts +1 -1
- package/src/queues/skill-extraction.queue.ts +1 -1
- package/src/queues/workstream-title-generation.queue.ts +1 -1
- package/src/redis/redis-lease-lock.ts +1 -2
- package/src/runtime/agent-runtime-policy.ts +3 -14
- package/src/runtime/context-compaction.ts +2 -4
- package/src/runtime/index.ts +1 -1
- package/src/runtime/runtime-config.ts +86 -2
- package/src/runtime/runtime-extensions.ts +0 -1
- package/src/runtime/social-chat.ts +752 -0
- package/src/runtime/team-consultation-orchestrator.ts +0 -4
- package/src/services/agent-executor.service.ts +0 -1
- package/src/services/document-chunk.service.ts +1 -3
- package/src/services/index.ts +1 -0
- package/src/services/memory.service.ts +7 -2
- package/src/services/recent-activity.service.ts +1 -3
- package/src/services/social-chat-history.service.ts +197 -0
- package/src/services/workstream-message.service.ts +1 -3
- package/src/services/workstream-turn-preparation.service.ts +0 -23
- package/src/system-agents/context-compaction.agent.ts +2 -0
- package/src/system-agents/delegated-agent-factory.ts +3 -0
- package/src/system-agents/memory-reranker.agent.ts +4 -2
- package/src/system-agents/memory.agent.ts +2 -0
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -0
- package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -0
- package/src/system-agents/skill-extractor.agent.ts +2 -0
- package/src/system-agents/skill-manager.agent.ts +2 -0
- package/src/system-agents/title-generator.agent.ts +2 -0
- package/src/tools/research-topic.tool.ts +2 -0
- package/src/tools/team-think.tool.ts +0 -3
- package/src/workers/regular-chat-memory-digest.helpers.ts +1 -1
- package/src/workers/regular-chat-memory-digest.runner.ts +43 -10
- package/src/workers/skill-extraction.runner.ts +25 -5
- package/src/workers/utils/repo-structure-extractor.ts +2 -2
- package/src/workers/utils/workstream-message-query.ts +3 -5
- package/src/runtime/workstream-routing-policy.ts +0 -267
|
@@ -14,6 +14,7 @@ import type { RegularChatMemoryDigestJob } from '../queues/regular-chat-memory-d
|
|
|
14
14
|
import { createHelperModelRuntime } from '../runtime/helper-model'
|
|
15
15
|
import { getRuntimeAdapters, withConfiguredWorkspaceMemoryLock } from '../runtime/runtime-extensions'
|
|
16
16
|
import { memoryService } from '../services/memory.service'
|
|
17
|
+
import { socialChatHistoryService } from '../services/social-chat-history.service'
|
|
17
18
|
import { createRegularChatMemoryDigestAgent } from '../system-agents/regular-chat-memory-digest.agent'
|
|
18
19
|
import { compactWhitespace } from '../utils/string'
|
|
19
20
|
import { buildDigestTranscript, resolveWorkspaceBootstrapCutoff } from './regular-chat-memory-digest.helpers'
|
|
@@ -48,6 +49,7 @@ const helperModelRuntime = createHelperModelRuntime()
|
|
|
48
49
|
interface RegularChatDigestRunResult {
|
|
49
50
|
skipped: boolean
|
|
50
51
|
processedWorkstreamMessages: number
|
|
52
|
+
processedSocialMessages: number
|
|
51
53
|
followUpScheduled: boolean
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -152,7 +154,7 @@ export async function runRegularChatMemoryDigest(
|
|
|
152
154
|
const workspaceProvider = getRuntimeAdapters().services?.workspaceProvider
|
|
153
155
|
if (!workspaceProvider) {
|
|
154
156
|
serverLogger.info`Skipping regular chat memory digest for ${orgId}: workspaceProvider is not configured`
|
|
155
|
-
return { skipped: true, processedWorkstreamMessages: 0, followUpScheduled: false }
|
|
157
|
+
return { skipped: true, processedWorkstreamMessages: 0, processedSocialMessages: 0, followUpScheduled: false }
|
|
156
158
|
}
|
|
157
159
|
|
|
158
160
|
return withConfiguredWorkspaceMemoryLock(orgId, async () => {
|
|
@@ -162,14 +164,14 @@ export async function runRegularChatMemoryDigest(
|
|
|
162
164
|
!workspaceProvider.applyProfileProjection
|
|
163
165
|
) {
|
|
164
166
|
serverLogger.info`Skipping regular chat memory digest for ${orgId}: workspaceProvider background/profile methods are incomplete`
|
|
165
|
-
return { skipped: true, processedWorkstreamMessages: 0, followUpScheduled: false }
|
|
167
|
+
return { skipped: true, processedWorkstreamMessages: 0, processedSocialMessages: 0, followUpScheduled: false }
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
const workspace = await workspaceProvider.getWorkspace(orgRef)
|
|
169
171
|
const lifecycleState = await workspaceProvider.getLifecycleState?.(workspace)
|
|
170
172
|
if (lifecycleState?.bootstrapActive ?? false) {
|
|
171
173
|
serverLogger.info`Skipping regular chat memory digest for ${orgId}: onboarding is not completed`
|
|
172
|
-
return { skipped: true, processedWorkstreamMessages: 0, followUpScheduled: false }
|
|
174
|
+
return { skipped: true, processedWorkstreamMessages: 0, processedSocialMessages: 0, followUpScheduled: false }
|
|
173
175
|
}
|
|
174
176
|
const projectionState = await workspaceProvider.readProfileProjectionState?.(workspace)
|
|
175
177
|
|
|
@@ -185,13 +187,23 @@ export async function runRegularChatMemoryDigest(
|
|
|
185
187
|
cursor: existingWorkstreamCursor,
|
|
186
188
|
onboardingCutoff: workstreamOnboardingCutoff,
|
|
187
189
|
})
|
|
190
|
+
const existingSocialCursor = await socialChatHistoryService.getBackgroundCursor('regular-chat-digest', orgId)
|
|
191
|
+
const socialOnboardingCutoff = resolveWorkspaceBootstrapCutoff({
|
|
192
|
+
hasExistingCursor: existingSocialCursor !== null,
|
|
193
|
+
bootstrapCompletedAt: lifecycleState?.bootstrapCompletedAt,
|
|
194
|
+
})
|
|
195
|
+
const socialMessages = await socialChatHistoryService.listWorkspaceMessages({
|
|
196
|
+
workspaceId: orgId,
|
|
197
|
+
cursor: existingSocialCursor,
|
|
198
|
+
onboardingCutoff: socialOnboardingCutoff,
|
|
199
|
+
})
|
|
188
200
|
|
|
189
|
-
if (workstreamMessages.length === 0) {
|
|
201
|
+
if (workstreamMessages.length === 0 && socialMessages.length === 0) {
|
|
190
202
|
serverLogger.info`Skipping regular chat memory digest for ${orgId}: no eligible messages`
|
|
191
|
-
return { skipped: true, processedWorkstreamMessages: 0, followUpScheduled: false }
|
|
203
|
+
return { skipped: true, processedWorkstreamMessages: 0, processedSocialMessages: 0, followUpScheduled: false }
|
|
192
204
|
}
|
|
193
205
|
|
|
194
|
-
const combinedMessages = [...workstreamMessages].sort(compareDigestMessageOrder)
|
|
206
|
+
const combinedMessages = [...workstreamMessages, ...socialMessages].sort(compareDigestMessageOrder)
|
|
195
207
|
const { transcript, involvedAgentNames } = buildDigestTranscript({ messages: combinedMessages })
|
|
196
208
|
const existingMemories = await loadExistingOrganizationMemories(orgId)
|
|
197
209
|
|
|
@@ -219,7 +231,8 @@ export async function runRegularChatMemoryDigest(
|
|
|
219
231
|
throw new Error('Regular chat memory digest returned an empty summaryBlock')
|
|
220
232
|
}
|
|
221
233
|
|
|
222
|
-
const processedWorkstreamCursor = getLastCursor(
|
|
234
|
+
const processedWorkstreamCursor = getLastCursor(workstreamMessages)
|
|
235
|
+
const processedSocialCursor = getLastCursor(socialMessages)
|
|
223
236
|
const digestRunAt = new Date().toISOString()
|
|
224
237
|
|
|
225
238
|
if (synthesis.facts.length > 0) {
|
|
@@ -235,6 +248,12 @@ export async function runRegularChatMemoryDigest(
|
|
|
235
248
|
digestWorkstreamCursorId: processedWorkstreamCursor.id,
|
|
236
249
|
}
|
|
237
250
|
: {}),
|
|
251
|
+
...(processedSocialCursor
|
|
252
|
+
? {
|
|
253
|
+
digestSocialCursorCreatedAt: processedSocialCursor.createdAt.toISOString(),
|
|
254
|
+
digestSocialCursorId: processedSocialCursor.id,
|
|
255
|
+
}
|
|
256
|
+
: {}),
|
|
238
257
|
},
|
|
239
258
|
agentNames: involvedAgentNames,
|
|
240
259
|
acquireLock: false,
|
|
@@ -248,6 +267,9 @@ export async function runRegularChatMemoryDigest(
|
|
|
248
267
|
if (processedWorkstreamCursor) {
|
|
249
268
|
await workspaceProvider.setBackgroundCursor('regular-chat-digest', orgRef, processedWorkstreamCursor)
|
|
250
269
|
}
|
|
270
|
+
if (processedSocialCursor) {
|
|
271
|
+
await socialChatHistoryService.setBackgroundCursor('regular-chat-digest', orgId, processedSocialCursor)
|
|
272
|
+
}
|
|
251
273
|
|
|
252
274
|
const workstreamBoundaryCursor = processedWorkstreamCursor ?? existingWorkstreamCursor
|
|
253
275
|
const hasMoreWorkstreamMessages = await hasNewEligibleWorkstreamMessages({
|
|
@@ -255,15 +277,26 @@ export async function runRegularChatMemoryDigest(
|
|
|
255
277
|
cursor: workstreamBoundaryCursor,
|
|
256
278
|
onboardingCutoff: workstreamBoundaryCursor ? null : workstreamOnboardingCutoff,
|
|
257
279
|
})
|
|
280
|
+
const socialBoundaryCursor = processedSocialCursor ?? existingSocialCursor
|
|
281
|
+
const hasMoreSocialMessages = await socialChatHistoryService.hasWorkspaceMessages({
|
|
282
|
+
workspaceId: orgId,
|
|
283
|
+
cursor: socialBoundaryCursor,
|
|
284
|
+
onboardingCutoff: socialBoundaryCursor ? null : socialOnboardingCutoff,
|
|
285
|
+
})
|
|
258
286
|
|
|
259
|
-
const followUpScheduled = hasMoreWorkstreamMessages
|
|
287
|
+
const followUpScheduled = hasMoreWorkstreamMessages || hasMoreSocialMessages
|
|
260
288
|
if (followUpScheduled) {
|
|
261
289
|
await clearRegularChatMemoryDigestDeduplicationKey(orgId)
|
|
262
290
|
await enqueueRegularChatMemoryDigest({ orgId })
|
|
263
291
|
}
|
|
264
292
|
|
|
265
|
-
serverLogger.info`Regular chat memory digest completed for ${orgId}: workstreamMessages=${workstreamMessages.length}, facts=${synthesis.facts.length}, followUpScheduled=${followUpScheduled}`
|
|
293
|
+
serverLogger.info`Regular chat memory digest completed for ${orgId}: workstreamMessages=${workstreamMessages.length}, socialMessages=${socialMessages.length}, facts=${synthesis.facts.length}, followUpScheduled=${followUpScheduled}`
|
|
266
294
|
|
|
267
|
-
return {
|
|
295
|
+
return {
|
|
296
|
+
skipped: false,
|
|
297
|
+
processedWorkstreamMessages: workstreamMessages.length,
|
|
298
|
+
processedSocialMessages: socialMessages.length,
|
|
299
|
+
followUpScheduled,
|
|
300
|
+
}
|
|
268
301
|
})
|
|
269
302
|
}
|
|
@@ -6,6 +6,7 @@ import type { SkillExtractionJob } from '../queues/skill-extraction.queue'
|
|
|
6
6
|
import { createHelperModelRuntime } from '../runtime/helper-model'
|
|
7
7
|
import { getRuntimeAdapters, withConfiguredWorkspaceMemoryLock } from '../runtime/runtime-extensions'
|
|
8
8
|
import { learnedSkillService } from '../services/learned-skill.service'
|
|
9
|
+
import { socialChatHistoryService } from '../services/social-chat-history.service'
|
|
9
10
|
import { createSkillExtractorAgent, SkillExtractionOutputSchema } from '../system-agents/skill-extractor.agent'
|
|
10
11
|
import type { SkillCandidate } from '../system-agents/skill-extractor.agent'
|
|
11
12
|
import { createSkillManagerAgent, SkillManagerOutputSchema } from '../system-agents/skill-manager.agent'
|
|
@@ -100,9 +101,24 @@ export async function runSkillExtraction(data: SkillExtractionJob): Promise<Skil
|
|
|
100
101
|
hasExistingCursor: existingCursor !== null,
|
|
101
102
|
bootstrapCompletedAt: lifecycleState?.bootstrapCompletedAt,
|
|
102
103
|
})
|
|
104
|
+
const existingSocialCursor = await socialChatHistoryService.getBackgroundCursor('skill-extraction', orgId)
|
|
105
|
+
const socialOnboardingCutoff = resolveWorkspaceBootstrapCutoff({
|
|
106
|
+
hasExistingCursor: existingSocialCursor !== null,
|
|
107
|
+
bootstrapCompletedAt: lifecycleState?.bootstrapCompletedAt,
|
|
108
|
+
})
|
|
103
109
|
|
|
104
110
|
const workstreamIds = await listWorkstreamIdsForOrg(orgRef)
|
|
105
|
-
const
|
|
111
|
+
const workstreamMessages = await listEligibleWorkstreamMessages({
|
|
112
|
+
workstreamIds,
|
|
113
|
+
cursor: existingCursor,
|
|
114
|
+
onboardingCutoff,
|
|
115
|
+
})
|
|
116
|
+
const socialMessages = await socialChatHistoryService.listWorkspaceMessages({
|
|
117
|
+
workspaceId: orgId,
|
|
118
|
+
cursor: existingSocialCursor,
|
|
119
|
+
onboardingCutoff: socialOnboardingCutoff,
|
|
120
|
+
})
|
|
121
|
+
const messages = [...workstreamMessages, ...socialMessages]
|
|
106
122
|
|
|
107
123
|
if (messages.length < MIN_MESSAGE_THRESHOLD) {
|
|
108
124
|
serverLogger.info`Skipping skill extraction for ${orgId}: only ${messages.length} messages (threshold: ${MIN_MESSAGE_THRESHOLD})`
|
|
@@ -225,12 +241,16 @@ export async function runSkillExtraction(data: SkillExtractionJob): Promise<Skil
|
|
|
225
241
|
}
|
|
226
242
|
}
|
|
227
243
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
244
|
+
const lastWorkstreamMessage = workstreamMessages.at(-1)
|
|
245
|
+
const lastSocialMessage = socialMessages.at(-1)
|
|
246
|
+
if (lastWorkstreamMessage) {
|
|
247
|
+
await cursorAwareWorkspaceProvider.setBackgroundCursor('skill-extraction', orgRef, lastWorkstreamMessage.cursor)
|
|
248
|
+
}
|
|
249
|
+
if (lastSocialMessage) {
|
|
250
|
+
await socialChatHistoryService.setBackgroundCursor('skill-extraction', orgId, lastSocialMessage.cursor)
|
|
231
251
|
}
|
|
232
252
|
|
|
233
|
-
serverLogger.info`Skill extraction completed for ${orgId}: messages=${messages.length}, extracted=${extractedSkills}`
|
|
253
|
+
serverLogger.info`Skill extraction completed for ${orgId}: messages=${messages.length}, socialMessages=${socialMessages.length}, extracted=${extractedSkills}`
|
|
234
254
|
|
|
235
255
|
return { skipped: false, processedMessages: messages.length, extractedSkills }
|
|
236
256
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdir
|
|
1
|
+
import { readdir } from 'node:fs/promises'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
4
|
import { RepositoryStructureArtifactSchema, RepositoryStructureSummarySchema } from '@lota-sdk/shared'
|
|
@@ -119,7 +119,7 @@ async function collectRelativeFilePaths(rootDir: string, currentDir = ''): Promi
|
|
|
119
119
|
|
|
120
120
|
async function readPackageJson(rootDir: string, relativePath: string): Promise<PackageJson | null> {
|
|
121
121
|
try {
|
|
122
|
-
const raw = await
|
|
122
|
+
const raw = await Bun.file(path.join(rootDir, relativePath)).text()
|
|
123
123
|
return JSON.parse(raw) as PackageJson
|
|
124
124
|
} catch {
|
|
125
125
|
return null
|
|
@@ -9,14 +9,12 @@ import { TABLES } from '../../db/tables'
|
|
|
9
9
|
import { WorkstreamMessageRowSchema } from '../../db/workstream-message-row'
|
|
10
10
|
import type { WorkstreamMessageRow } from '../../db/workstream-message-row'
|
|
11
11
|
import { normalizeTextBody } from '../../document/parsing'
|
|
12
|
+
import type { LotaRuntimeBackgroundCursor } from '../../runtime/runtime-extensions'
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
-
createdAt: Date
|
|
15
|
-
id: string
|
|
16
|
-
}
|
|
14
|
+
export type DigestCursor = LotaRuntimeBackgroundCursor
|
|
17
15
|
|
|
18
16
|
export interface DigestMessage {
|
|
19
|
-
source: 'workstream'
|
|
17
|
+
source: 'workstream' | 'social'
|
|
20
18
|
sourceId: string
|
|
21
19
|
role: 'system' | 'user' | 'assistant'
|
|
22
20
|
parts: Array<Record<string, unknown>>
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import { extractAgentMentions, getLeadAgentId } 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 HIGH_IMPACT_CLASS_PATTERNS: Array<{ className: HighImpactResponseClass; patterns: RegExp[] }> = [
|
|
40
|
-
{
|
|
41
|
-
className: 'architecture-recommendation',
|
|
42
|
-
patterns: [
|
|
43
|
-
/\barchitecture\b/i,
|
|
44
|
-
/\btech(?:nical)?\s+stack\b/i,
|
|
45
|
-
/\binfra(?:structure)?\b/i,
|
|
46
|
-
/\brefactor\b/i,
|
|
47
|
-
/\bsystem\s+design\b/i,
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
className: 'gtm-strategy',
|
|
52
|
-
patterns: [
|
|
53
|
-
/\bgo[-\s]?to[-\s]?market\b/i,
|
|
54
|
-
/\bgtm\b/i,
|
|
55
|
-
/\bdistribution\s+strategy\b/i,
|
|
56
|
-
/\blaunch\s+strategy\b/i,
|
|
57
|
-
/\bcontent\s+strategy\b/i,
|
|
58
|
-
/\bdemand\s+gen(?:eration)?\b/i,
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
className: 'pricing-positioning',
|
|
63
|
-
patterns: [/\bpricing\b/i, /\bpositioning\b/i, /\bpackaging\b/i, /\bfreemium\b/i, /\bbilling\b/i],
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
className: 'product-capability-claim',
|
|
67
|
-
patterns: [
|
|
68
|
-
/\bdoes\s+it\s+(already\s+)?(support|have|do)\b/i,
|
|
69
|
-
/\bwhat\s+can\s+(it|we)\s+do\b/i,
|
|
70
|
-
/\bis\s+this\s+implemented\b/i,
|
|
71
|
-
/\bcurrent(?:ly)?\s+supports?\b/i,
|
|
72
|
-
/\bcapabilities?\b/i,
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
className: 'community-targeting',
|
|
77
|
-
patterns: [
|
|
78
|
-
/\bwhere\s+to\s+post\b/i,
|
|
79
|
-
/\bcommunity\b/i,
|
|
80
|
-
/\btarget\s+audience\b/i,
|
|
81
|
-
/\bchannels?\b/i,
|
|
82
|
-
/\bdistribution\s+channels?\b/i,
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
className: 'mutating-operation',
|
|
87
|
-
patterns: [
|
|
88
|
-
/\bdelete\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
89
|
-
/\bremove\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
90
|
-
/\bupdate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
91
|
-
/\bcreate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
92
|
-
/\bchange\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
93
|
-
/\barchive\b/i,
|
|
94
|
-
/\bskip\s+onboarding\b/i,
|
|
95
|
-
/\bproceed\s+in\s+onboarding\b/i,
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
]
|
|
99
|
-
|
|
100
|
-
const POLICY_CLASS_PATTERNS: Array<{ className: PolicyClass; patterns: RegExp[] }> = [
|
|
101
|
-
{
|
|
102
|
-
className: 'external-mutation',
|
|
103
|
-
patterns: [
|
|
104
|
-
/\bdelete\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
105
|
-
/\bremove\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
106
|
-
/\bupdate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
107
|
-
/\bcreate\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
108
|
-
/\bchange\s+(issue|comment|task|record|workspace|project)\b/i,
|
|
109
|
-
/\barchive\b/i,
|
|
110
|
-
/\bskip\s+onboarding\b/i,
|
|
111
|
-
/\bproceed\s+in\s+onboarding\b/i,
|
|
112
|
-
],
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
className: 'security-privacy',
|
|
116
|
-
patterns: [
|
|
117
|
-
/\bsecurity\b/i,
|
|
118
|
-
/\bprivacy\b/i,
|
|
119
|
-
/\bpii\b/i,
|
|
120
|
-
/\bauth(?:entication|orization)?\b/i,
|
|
121
|
-
/\bencrypt(?:ion|ed)?\b/i,
|
|
122
|
-
/\bpermission(?:s)?\b/i,
|
|
123
|
-
/\baccess\s+control\b/i,
|
|
124
|
-
/\bsecret(?:s)?\b/i,
|
|
125
|
-
],
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
className: 'legal-compliance',
|
|
129
|
-
patterns: [
|
|
130
|
-
/\blegal\b/i,
|
|
131
|
-
/\bcompliance\b/i,
|
|
132
|
-
/\bregulation(?:s)?\b/i,
|
|
133
|
-
/\bgdpr\b/i,
|
|
134
|
-
/\bhipaa\b/i,
|
|
135
|
-
/\bsoc\s*2\b/i,
|
|
136
|
-
/\blicense\b/i,
|
|
137
|
-
/\bterms?\b/i,
|
|
138
|
-
],
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
className: 'financial-decision',
|
|
142
|
-
patterns: [
|
|
143
|
-
/\bpricing\b/i,
|
|
144
|
-
/\bbilling\b/i,
|
|
145
|
-
/\brevenue\b/i,
|
|
146
|
-
/\bbudget\b/i,
|
|
147
|
-
/\bburn\s+rate\b/i,
|
|
148
|
-
/\brunway\b/i,
|
|
149
|
-
/\bfundrais(?:e|ing)\b/i,
|
|
150
|
-
/\bcash\s+flow\b/i,
|
|
151
|
-
],
|
|
152
|
-
},
|
|
153
|
-
]
|
|
154
|
-
|
|
155
|
-
const REASONING_PROFILES: Record<ReasoningProfileName, ReasoningProfile> = {
|
|
156
|
-
fast: { name: 'fast', maxSteps: 5, toolCallBudget: 3, maxInputTokensHint: 12_000 },
|
|
157
|
-
standard: { name: 'standard', maxSteps: 10, toolCallBudget: 6, maxInputTokensHint: 24_000 },
|
|
158
|
-
deep: { name: 'deep', maxSteps: 15, toolCallBudget: 10, maxInputTokensHint: 36_000 },
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const STRATEGIC_COMPLEXITY_PATTERNS: RegExp[] = [
|
|
162
|
-
/\bstrategy\b/i,
|
|
163
|
-
/\btrade[-\s]?off\b/i,
|
|
164
|
-
/\bcompare\b/i,
|
|
165
|
-
/\broadmap\b/i,
|
|
166
|
-
/\barchitecture\b/i,
|
|
167
|
-
/\bconstraints?\b/i,
|
|
168
|
-
/\bprioriti(?:y|es)\b/i,
|
|
169
|
-
]
|
|
170
|
-
|
|
171
|
-
const CROSS_SOURCE_COMPLEXITY_PATTERNS: RegExp[] = [
|
|
172
|
-
/\bcitation\b/i,
|
|
173
|
-
/\bevidence\b/i,
|
|
174
|
-
/\bsource\b/i,
|
|
175
|
-
/\bground(?:ed|ing)\b/i,
|
|
176
|
-
/\brepo\b/i,
|
|
177
|
-
/\bmemory\b/i,
|
|
178
|
-
]
|
|
179
|
-
|
|
180
|
-
const STANDARD_FLOOR_INTENT_PATTERNS: RegExp[] = [
|
|
181
|
-
/\bplan(?:ning)?\b/i,
|
|
182
|
-
/\bthink(?:ing)?\b/i,
|
|
183
|
-
/\bcareful(?:ly)?\b/i,
|
|
184
|
-
/\bimportant\b/i,
|
|
185
|
-
/\bcritical(?:ly)?\b/i,
|
|
186
|
-
/\bthorough(?:ly)?\b/i,
|
|
187
|
-
]
|
|
188
|
-
|
|
189
|
-
export function classifyHighImpactResponse(params: { message: string }): { classes: HighImpactResponseClass[] } {
|
|
190
|
-
const message = params.message.trim()
|
|
191
|
-
if (!message) return { classes: [] }
|
|
192
|
-
|
|
193
|
-
const classes: HighImpactResponseClass[] = []
|
|
194
|
-
for (const entry of HIGH_IMPACT_CLASS_PATTERNS) {
|
|
195
|
-
if (entry.patterns.some((pattern) => pattern.test(message))) {
|
|
196
|
-
classes.push(entry.className)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return { classes }
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function classifyPolicyClasses(params: { message: string }): { classes: PolicyClass[] } {
|
|
204
|
-
const message = params.message.trim()
|
|
205
|
-
if (!message) return { classes: [] }
|
|
206
|
-
|
|
207
|
-
const classes: PolicyClass[] = []
|
|
208
|
-
for (const entry of POLICY_CLASS_PATTERNS) {
|
|
209
|
-
if (entry.patterns.some((pattern) => pattern.test(message))) {
|
|
210
|
-
classes.push(entry.className)
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return { classes }
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export function resolveReasoningProfile(params: {
|
|
218
|
-
message: string
|
|
219
|
-
forceDeep?: boolean
|
|
220
|
-
explicitProfile?: ReasoningProfileName
|
|
221
|
-
}): ReasoningProfile {
|
|
222
|
-
if (params.explicitProfile) {
|
|
223
|
-
return REASONING_PROFILES[params.explicitProfile]
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const text = params.message.trim()
|
|
227
|
-
if (!text) {
|
|
228
|
-
return REASONING_PROFILES.standard
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
let score = 0
|
|
232
|
-
if (text.length >= 700) score += 3
|
|
233
|
-
else if (text.length >= 350) score += 2
|
|
234
|
-
else if (text.length >= 180) score += 1
|
|
235
|
-
|
|
236
|
-
const numberedListCount = (text.match(/\n\s*\d+\./g) ?? []).length
|
|
237
|
-
if (numberedListCount >= 3) score += 2
|
|
238
|
-
else if (numberedListCount >= 1) score += 1
|
|
239
|
-
|
|
240
|
-
if (STRATEGIC_COMPLEXITY_PATTERNS.some((pattern) => pattern.test(text))) score += 2
|
|
241
|
-
if (CROSS_SOURCE_COMPLEXITY_PATTERNS.some((pattern) => pattern.test(text))) score += 2
|
|
242
|
-
if (params.forceDeep) score += 2
|
|
243
|
-
if (STANDARD_FLOOR_INTENT_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
244
|
-
score += 3
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (score >= 7) return REASONING_PROFILES.deep
|
|
248
|
-
if (score >= 3) return REASONING_PROFILES.standard
|
|
249
|
-
return REASONING_PROFILES.fast
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
export function resolveMessageRoute(params: {
|
|
253
|
-
workstreamMode: 'direct' | 'group'
|
|
254
|
-
workstreamAgentId?: string
|
|
255
|
-
message: string
|
|
256
|
-
}): MessageRoute {
|
|
257
|
-
if (params.workstreamMode === 'direct') {
|
|
258
|
-
return { type: 'direct', agents: [params.workstreamAgentId ?? getLeadAgentId()] }
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const mentions = uniqueMentionOrder(params.message)
|
|
262
|
-
if (mentions.length > 0) {
|
|
263
|
-
return { type: 'mentions', agents: mentions }
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return { type: 'group-default', agents: [getLeadAgentId()] }
|
|
267
|
-
}
|