@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lota-sdk/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"lint": "
|
|
19
|
+
"lint": "bunx oxlint --fix -c ../oxlint.config.ts src",
|
|
20
20
|
"format": "bunx oxfmt src",
|
|
21
21
|
"typecheck": "bunx tsgo --noEmit",
|
|
22
22
|
"test:unit": "bun test ../tests/unit/core",
|
|
@@ -29,12 +29,15 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@ai-sdk/devtools": "^0.0.15",
|
|
31
31
|
"@ai-sdk/openai": "^3.0.48",
|
|
32
|
+
"@chat-adapter/slack": "^4.23.0",
|
|
33
|
+
"@chat-adapter/state-ioredis": "^4.23.0",
|
|
32
34
|
"@logtape/logtape": "^2.0.5",
|
|
33
|
-
"@lota-sdk/shared": "0.1.
|
|
35
|
+
"@lota-sdk/shared": "0.1.17",
|
|
34
36
|
"@mendable/firecrawl-js": "^4.17.0",
|
|
35
37
|
"@surrealdb/node": "^3.0.3",
|
|
36
38
|
"ai": "^6.0.137",
|
|
37
39
|
"bullmq": "^5.71.0",
|
|
40
|
+
"chat": "^4.23.0",
|
|
38
41
|
"cron-parser": "^5.5.0",
|
|
39
42
|
"hono": "^4.12.9",
|
|
40
43
|
"ioredis": "5.9.3",
|
package/src/ai/definitions.ts
CHANGED
|
@@ -283,7 +283,7 @@ export const generalRule = defineRule({
|
|
|
283
283
|
name: 'general',
|
|
284
284
|
instructions: `# General Rules
|
|
285
285
|
|
|
286
|
-
- Be concise and direct.
|
|
286
|
+
- Be concise and direct. Prefer short, direct responses. Do not pad with context the user did not ask for.
|
|
287
287
|
- Follow the user's request and constraints.
|
|
288
288
|
- Ask clarifying questions when necessary.
|
|
289
289
|
- Be formal and professional when tone is unclear.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
|
|
3
1
|
import type IORedis from 'ioredis'
|
|
4
2
|
|
|
5
3
|
import { aiLogger } from '../config/logger'
|
|
6
4
|
|
|
7
|
-
export const DEFAULT_EMBEDDING_CACHE_TTL_SECONDS =
|
|
5
|
+
export const DEFAULT_EMBEDDING_CACHE_TTL_SECONDS = 7200
|
|
8
6
|
const EMBEDDING_CACHE_KEY_PREFIX = 'emb'
|
|
9
7
|
|
|
10
8
|
export class EmbeddingCache {
|
|
@@ -14,7 +12,7 @@ export class EmbeddingCache {
|
|
|
14
12
|
) {}
|
|
15
13
|
|
|
16
14
|
private buildKey(model: string, text: string): string {
|
|
17
|
-
const hash =
|
|
15
|
+
const hash = new Bun.CryptoHasher('sha256').update(text).digest('hex')
|
|
18
16
|
return `${EMBEDDING_CACHE_KEY_PREFIX}:${model}:${hash}`
|
|
19
17
|
}
|
|
20
18
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const BIFROST_CACHE_KEY_HEADER = 'x-bf-cache-key'
|
|
2
|
+
const BIFROST_CACHE_TTL_HEADER = 'x-bf-cache-ttl'
|
|
3
|
+
|
|
4
|
+
export function buildBifrostCacheHeaders(cacheKey: string, ttl?: string): Record<string, string> {
|
|
5
|
+
const headers: Record<string, string> = { [BIFROST_CACHE_KEY_HEADER]: cacheKey }
|
|
6
|
+
if (ttl) headers[BIFROST_CACHE_TTL_HEADER] = ttl
|
|
7
|
+
return headers
|
|
8
|
+
}
|
package/src/bifrost/index.ts
CHANGED
package/src/create-runtime.ts
CHANGED
|
@@ -25,6 +25,8 @@ import type { LotaRuntimeConfig, ResolvedLotaRuntimeConfig } from './runtime/run
|
|
|
25
25
|
import { configureRuntimeExtensions } from './runtime/runtime-extensions'
|
|
26
26
|
import type { LotaRuntimeWorkers } from './runtime/runtime-worker-registry'
|
|
27
27
|
import { buildRuntimeWorkerRegistry } from './runtime/runtime-worker-registry'
|
|
28
|
+
import type { LotaRuntimeSocialChat } from './runtime/social-chat'
|
|
29
|
+
import { createSocialChatRuntime } from './runtime/social-chat'
|
|
28
30
|
import type { attachmentService } from './services/attachment.service'
|
|
29
31
|
import { attachmentService as attachmentServiceSingleton } from './services/attachment.service'
|
|
30
32
|
import { coordinationRegistryService as coordinationRegistryServiceSingleton } from './services/coordination-registry.service'
|
|
@@ -47,6 +49,10 @@ import type { recentActivityTitleService } from './services/recent-activity-titl
|
|
|
47
49
|
import { recentActivityTitleService as recentActivityTitleServiceSingleton } from './services/recent-activity-title.service'
|
|
48
50
|
import type { recentActivityService } from './services/recent-activity.service'
|
|
49
51
|
import { recentActivityService as recentActivityServiceSingleton } from './services/recent-activity.service'
|
|
52
|
+
import {
|
|
53
|
+
configureSocialChatHistory,
|
|
54
|
+
socialChatHistoryService as socialChatHistoryServiceSingleton,
|
|
55
|
+
} from './services/social-chat-history.service'
|
|
50
56
|
import { getBuiltInSystemExecutors } from './services/system-executor.service'
|
|
51
57
|
import type { userService } from './services/user.service'
|
|
52
58
|
import { userService as userServiceSingleton } from './services/user.service'
|
|
@@ -115,6 +121,7 @@ export interface LotaRuntime {
|
|
|
115
121
|
userService: typeof userService
|
|
116
122
|
recentActivityService: typeof recentActivityService
|
|
117
123
|
recentActivityTitleService: typeof recentActivityTitleService
|
|
124
|
+
socialChatHistoryService: typeof socialChatHistoryServiceSingleton
|
|
118
125
|
executionPlanService: typeof executionPlanService
|
|
119
126
|
workstreamMessageService: typeof workstreamMessageService
|
|
120
127
|
workstreamService: typeof workstreamService
|
|
@@ -184,6 +191,7 @@ export interface LotaRuntime {
|
|
|
184
191
|
closeConnection: () => Promise<void>
|
|
185
192
|
}
|
|
186
193
|
workers: LotaRuntimeWorkers
|
|
194
|
+
socialChat: LotaRuntimeSocialChat
|
|
187
195
|
schemaFiles: Array<string | URL>
|
|
188
196
|
contributions: { envKeys: readonly string[]; schemaFiles: Array<string | URL> }
|
|
189
197
|
config: ResolvedLotaRuntimeConfig
|
|
@@ -218,11 +226,21 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
218
226
|
setRedisConnectionManager(redisManager)
|
|
219
227
|
configureEmbeddingCache(redisManager.getConnection(), runtimeConfig.memory.embeddingCacheTtlSeconds)
|
|
220
228
|
configureBackgroundProcessing(runtimeConfig.backgroundProcessing)
|
|
229
|
+
configureSocialChatHistory({ keyPrefix: runtimeConfig.socialChat?.historyRedisKeyPrefix })
|
|
230
|
+
|
|
231
|
+
const socialChatAgentId = runtimeConfig.socialChat?.agentId?.trim() || 'socialChat'
|
|
232
|
+
const socialChatAgentDisplayName = runtimeConfig.socialChat?.agentDisplayName?.trim() || 'Lota'
|
|
233
|
+
if (runtimeConfig.socialChat && !runtimeConfig.agents.roster.includes(socialChatAgentId)) {
|
|
234
|
+
throw new Error(`socialChat.agentId must be present in agents.roster: ${socialChatAgentId}`)
|
|
235
|
+
}
|
|
236
|
+
const agentDisplayNames = runtimeConfig.socialChat
|
|
237
|
+
? { ...runtimeConfig.agents.displayNames, [socialChatAgentId]: socialChatAgentDisplayName }
|
|
238
|
+
: runtimeConfig.agents.displayNames
|
|
221
239
|
|
|
222
240
|
configureAgents({
|
|
223
241
|
roster: runtimeConfig.agents.roster,
|
|
224
242
|
leadAgentId: runtimeConfig.agents.leadAgentId,
|
|
225
|
-
displayNames:
|
|
243
|
+
displayNames: agentDisplayNames,
|
|
226
244
|
shortDisplayNames: runtimeConfig.agents.shortDisplayNames,
|
|
227
245
|
teamConsultParticipants: runtimeConfig.agents.teamConsultParticipants,
|
|
228
246
|
getCoreWorkstreamProfile: runtimeConfig.agents.getCoreWorkstreamProfile,
|
|
@@ -264,6 +282,10 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
264
282
|
const contributionEnvKeys = [...LOTA_RUNTIME_ENV_KEYS, ...pluginContributions.flatMap((plugin) => plugin.envKeys)]
|
|
265
283
|
const connectPluginDatabases = createPluginDatabaseConnector(pluginRuntime)
|
|
266
284
|
const workers = buildRuntimeWorkerRegistry(runtimeConfig.extraWorkers)
|
|
285
|
+
const socialChat = createSocialChatRuntime({
|
|
286
|
+
redisClient: redisManager.getConnection(),
|
|
287
|
+
socialChat: runtimeConfig.socialChat,
|
|
288
|
+
})
|
|
267
289
|
|
|
268
290
|
const lota = {
|
|
269
291
|
organizations: {
|
|
@@ -369,6 +391,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
369
391
|
userService: userServiceSingleton,
|
|
370
392
|
recentActivityService: recentActivityServiceSingleton,
|
|
371
393
|
recentActivityTitleService: recentActivityTitleServiceSingleton,
|
|
394
|
+
socialChatHistoryService: socialChatHistoryServiceSingleton,
|
|
372
395
|
executionPlanService: executionPlanServiceSingleton,
|
|
373
396
|
workstreamMessageService: workstreamMessageServiceSingleton,
|
|
374
397
|
workstreamService: workstreamServiceSingleton,
|
|
@@ -388,6 +411,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
388
411
|
closeConnection: async () => await redisManager.closeConnection(),
|
|
389
412
|
},
|
|
390
413
|
workers,
|
|
414
|
+
socialChat,
|
|
391
415
|
schemaFiles,
|
|
392
416
|
contributions: { envKeys: [...new Set(contributionEnvKeys)], schemaFiles: hostContributionSchemaFiles },
|
|
393
417
|
config: runtimeConfig,
|
|
@@ -412,6 +436,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
412
436
|
disconnected = true
|
|
413
437
|
|
|
414
438
|
try {
|
|
439
|
+
await socialChat.shutdown()
|
|
415
440
|
await closeSharedSubscriber()
|
|
416
441
|
await db.disconnect()
|
|
417
442
|
await redisManager.closeConnection()
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
|
|
3
1
|
import type { BasicSearchRow, SurrealMemoryRow } from './memory-store.rows'
|
|
4
2
|
import type { MemoryRecord, MemorySearchResult } from './memory-types'
|
|
5
3
|
import { recordIdToString } from './record-id'
|
|
@@ -114,5 +112,5 @@ export function processGraphAwareRows<T extends BasicSearchRow>(
|
|
|
114
112
|
}
|
|
115
113
|
|
|
116
114
|
export function hashContent(content: string, scopeId: string, memoryType: string): string {
|
|
117
|
-
return
|
|
115
|
+
return new Bun.CryptoHasher('sha256').update(`${scopeId}:${memoryType}:${content}`).digest('hex')
|
|
118
116
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
|
|
3
1
|
function toSchemaFilePath(value: string | URL): string {
|
|
4
2
|
return value instanceof URL ? value.pathname : value
|
|
5
3
|
}
|
|
6
4
|
|
|
7
5
|
export async function computeSchemaFingerprint(schemaFiles: readonly (string | URL)[]): Promise<string> {
|
|
8
|
-
const hash =
|
|
6
|
+
const hash = new Bun.CryptoHasher('sha256')
|
|
9
7
|
|
|
10
8
|
// Sequential reads required: hash must be computed in deterministic file order
|
|
11
9
|
for (const schemaFile of schemaFiles) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
|
|
3
1
|
import { Queue, Worker } from 'bullmq'
|
|
4
2
|
import type IORedis from 'ioredis'
|
|
5
3
|
|
|
@@ -43,7 +41,7 @@ export function buildDocumentProcessorJobId(
|
|
|
43
41
|
'orgId' | 'source' | 'sourceId' | 'sourceCanonicalKey' | 'sourceVersionKey' | 'title'
|
|
44
42
|
>,
|
|
45
43
|
): string {
|
|
46
|
-
const digest =
|
|
44
|
+
const digest = new Bun.CryptoHasher('sha256')
|
|
47
45
|
.update(
|
|
48
46
|
JSON.stringify({
|
|
49
47
|
orgId: job.orgId,
|
|
@@ -73,7 +71,7 @@ export function createDocumentProcessorQueueRuntime<TJob extends DocumentProcess
|
|
|
73
71
|
} {
|
|
74
72
|
const queueName = params.queueName ?? DEFAULT_DOCUMENT_PROCESSOR_QUEUE
|
|
75
73
|
const workerName = params.workerName ?? DEFAULT_WORKER_NAME
|
|
76
|
-
const concurrency = params.concurrency ??
|
|
74
|
+
const concurrency = params.concurrency ?? 10
|
|
77
75
|
const lockDuration = params.lockDuration ?? 300_000
|
|
78
76
|
const jobName = 'process-document' as Parameters<Queue<TJob, unknown, string>['add']>[0]
|
|
79
77
|
const toQueueData = (job: TJob): Parameters<Queue<TJob, unknown, string>['add']>[1] =>
|
|
@@ -15,6 +15,8 @@ interface PostChatMemoryExtractionJob {
|
|
|
15
15
|
orgId: string
|
|
16
16
|
workstreamId: string
|
|
17
17
|
sourceId: string
|
|
18
|
+
source?: string
|
|
19
|
+
sourceMetadata?: Record<string, unknown>
|
|
18
20
|
onboardStatus?: OrganizationOnboardStatus
|
|
19
21
|
userMessage: string
|
|
20
22
|
historyMessages: PostChatMemoryMessage[]
|
|
@@ -54,6 +56,8 @@ async function processPostChatMemoryJob(job: Job<PostChatMemoryExtractionJob>):
|
|
|
54
56
|
input: userMessage,
|
|
55
57
|
output: joinedOutput,
|
|
56
58
|
sourceId: data.sourceId,
|
|
59
|
+
source: data.source,
|
|
60
|
+
sourceMetadata: data.sourceMetadata,
|
|
57
61
|
onboardStatus: data.onboardStatus,
|
|
58
62
|
...(uniqueAgentNames.length > 0 ? { agentName: uniqueAgentNames[0] } : {}),
|
|
59
63
|
historyMessages: data.historyMessages,
|
|
@@ -67,7 +71,7 @@ const postChatMemory = createQueueFactory<PostChatMemoryExtractionJob>({
|
|
|
67
71
|
name: 'post-chat-memory',
|
|
68
72
|
displayName: 'Post-chat memory',
|
|
69
73
|
jobName: 'extract-memory',
|
|
70
|
-
concurrency:
|
|
74
|
+
concurrency: 10,
|
|
71
75
|
lockDuration: 900_000,
|
|
72
76
|
maxStalledCount: 10,
|
|
73
77
|
stalledInterval: 120_000,
|
|
@@ -75,7 +79,9 @@ const postChatMemory = createQueueFactory<PostChatMemoryExtractionJob>({
|
|
|
75
79
|
processor: processPostChatMemoryJob,
|
|
76
80
|
})
|
|
77
81
|
|
|
78
|
-
export
|
|
82
|
+
export function enqueuePostChatMemory(job: PostChatMemoryExtractionJob, options?: { dedupeKey?: string }) {
|
|
83
|
+
return postChatMemory.enqueue(job, options?.dedupeKey ? { jobId: options.dedupeKey } : undefined)
|
|
84
|
+
}
|
|
79
85
|
export const startPostChatMemoryWorker = postChatMemory.startWorker
|
|
80
86
|
|
|
81
87
|
if (import.meta.main) {
|
|
@@ -17,7 +17,7 @@ const recentActivityTitleRefinement = createQueueFactory<RecentActivityTitleRefi
|
|
|
17
17
|
name: 'recent-activity-title-refinement',
|
|
18
18
|
displayName: 'Recent activity title refinement',
|
|
19
19
|
jobName: 'refine-recent-activity-title',
|
|
20
|
-
concurrency:
|
|
20
|
+
concurrency: 10,
|
|
21
21
|
lockDuration: 300_000,
|
|
22
22
|
defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 2_000 } },
|
|
23
23
|
processor: processRecentActivityTitleRefinementJob,
|
|
@@ -10,7 +10,7 @@ const skillExtraction = createQueueFactory<SkillExtractionJob>({
|
|
|
10
10
|
name: 'skill-extraction',
|
|
11
11
|
displayName: 'Skill extraction',
|
|
12
12
|
jobName: 'run-extraction',
|
|
13
|
-
concurrency:
|
|
13
|
+
concurrency: 10,
|
|
14
14
|
lockDuration: 600_000,
|
|
15
15
|
defaultJobOptions: { attempts: 2, backoff: { type: 'exponential', delay: 5000 } },
|
|
16
16
|
processorPath: getWorkerPath('skill-extraction.worker.ts'),
|
|
@@ -20,7 +20,7 @@ const workstreamTitleGeneration = createQueueFactory<WorkstreamTitleGenerationJo
|
|
|
20
20
|
name: 'workstream-title-generation',
|
|
21
21
|
displayName: 'Workstream title generation',
|
|
22
22
|
jobName: 'generate-workstream-title',
|
|
23
|
-
concurrency:
|
|
23
|
+
concurrency: 10,
|
|
24
24
|
lockDuration: 60_000,
|
|
25
25
|
defaultJobOptions: { attempts: 2, backoff: { type: 'exponential', delay: 2_000 } },
|
|
26
26
|
processor: processWorkstreamTitleGenerationJob,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto'
|
|
2
1
|
import { setTimeout as delay } from 'node:timers/promises'
|
|
3
2
|
|
|
4
3
|
import type IORedis from 'ioredis'
|
|
@@ -147,7 +146,7 @@ export async function withRedisLeaseLock<T>(
|
|
|
147
146
|
const heldInfoThresholdMs = options.heldInfoThresholdMs ?? 5_000
|
|
148
147
|
const label = options.label ?? 'redis lease lock'
|
|
149
148
|
|
|
150
|
-
const lockValue = randomUUID()
|
|
149
|
+
const lockValue = crypto.randomUUID()
|
|
151
150
|
const waitStart = Date.now()
|
|
152
151
|
await acquireLeaseLock({ ...options, lockKey, lockValue, label, retryDelayMs, waitLogIntervalMs, maxWaitMs })
|
|
153
152
|
const waitedMs = Date.now() - waitStart
|
|
@@ -3,18 +3,12 @@ import type { ExecutionMode, PlanArtifactSubmission, PlanNodeSpec } from '@lota-
|
|
|
3
3
|
import { getLeadAgentId } from '../config/agent-defaults'
|
|
4
4
|
import { resolveOnboardingOwnerAgentId } from '../config/workstream-defaults'
|
|
5
5
|
import type { ChatMode } from './agent-types'
|
|
6
|
-
import { resolveReasoningProfile } from './workstream-routing-policy'
|
|
7
|
-
import type { ReasoningProfileName } from './workstream-routing-policy'
|
|
8
|
-
|
|
9
6
|
export interface AgentRuntimeConfig<TAgent extends string> {
|
|
10
7
|
id: TAgent
|
|
11
8
|
displayName: string
|
|
12
9
|
mode: ChatMode
|
|
13
10
|
extraInstructions?: string
|
|
14
11
|
maxSteps: number
|
|
15
|
-
reasoningProfile: ReasoningProfileName
|
|
16
|
-
toolCallBudget: number
|
|
17
|
-
maxInputTokensHint: number
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
export interface AgentToolPolicy<TSkill extends PropertyKey> {
|
|
@@ -100,7 +94,6 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
100
94
|
skills?: TSkill[]
|
|
101
95
|
onboardingActive: boolean
|
|
102
96
|
linearInstalled: boolean
|
|
103
|
-
reasoningProfile?: ReasoningProfileName
|
|
104
97
|
systemWorkspaceDetails?: string
|
|
105
98
|
preSeededMemoriesSection?: string
|
|
106
99
|
retrievedKnowledgeSection?: string
|
|
@@ -115,7 +108,6 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
115
108
|
buildOnboardingPromptSection: () => string
|
|
116
109
|
}): AgentRuntimeConfig<TAgent> {
|
|
117
110
|
const mode = params.mode ?? toChatMode(params.workstreamMode)
|
|
118
|
-
const profile = resolveReasoningProfile({ message: '', explicitProfile: params.reasoningProfile ?? 'standard' })
|
|
119
111
|
const rulesSection = params.buildGlobalRuleInstructionSection()
|
|
120
112
|
const skillsSection =
|
|
121
113
|
params.skills && params.skills.length > 0 ? params.buildSkillInstructionSection(params.skills) : ''
|
|
@@ -141,10 +133,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
141
133
|
displayName: params.displayNameByAgent[params.agentId] ?? params.agentId,
|
|
142
134
|
mode,
|
|
143
135
|
extraInstructions,
|
|
144
|
-
maxSteps:
|
|
145
|
-
reasoningProfile: profile.name,
|
|
146
|
-
toolCallBudget: profile.toolCallBudget,
|
|
147
|
-
maxInputTokensHint: profile.maxInputTokensHint,
|
|
136
|
+
maxSteps: 15,
|
|
148
137
|
}
|
|
149
138
|
}
|
|
150
139
|
|
|
@@ -180,8 +169,8 @@ export function buildWorkstreamAgentToolPolicy<TAgent extends string, TSkill ext
|
|
|
180
169
|
includeReadFileParts: true,
|
|
181
170
|
includeInspectWebsite: params.onboardingActive && params.agentId === onboardingOwnerAgentId,
|
|
182
171
|
includeProceedInOnboarding: params.onboardingActive && params.agentId === onboardingOwnerAgentId,
|
|
183
|
-
includeGithubIntegration: params.
|
|
184
|
-
includeIndexRepositoryByURL: params.
|
|
172
|
+
includeGithubIntegration: params.agentId === onboardingOwnerAgentId,
|
|
173
|
+
includeIndexRepositoryByURL: params.agentId === onboardingOwnerAgentId,
|
|
185
174
|
includeIndexedRepository: params.githubInstalled && params.provideRepoTool,
|
|
186
175
|
}
|
|
187
176
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createHash, randomUUID } from 'node:crypto'
|
|
2
|
-
|
|
3
1
|
import type { ChatMessage } from '@lota-sdk/shared'
|
|
4
2
|
|
|
5
3
|
import { CHARS_PER_TOKEN_ESTIMATE, compactWhitespace, readRecord, readString, stringifyUnknown } from '../utils/string'
|
|
@@ -108,7 +106,7 @@ function createStableId(prefix: string, ...parts: Array<string | number | undefi
|
|
|
108
106
|
.map((part) => (part === undefined ? '' : String(part)))
|
|
109
107
|
.map((part) => compactWhitespace(part))
|
|
110
108
|
.join('|')
|
|
111
|
-
const hash =
|
|
109
|
+
const hash = new Bun.CryptoHasher('sha1').update(`${prefix}|${payload}`).digest('hex').slice(0, 20)
|
|
112
110
|
return `${prefix}_${hash}`
|
|
113
111
|
}
|
|
114
112
|
|
|
@@ -532,7 +530,7 @@ export function createContextCompactionRuntime(
|
|
|
532
530
|
options: CreateContextCompactionRuntimeOptions,
|
|
533
531
|
): ContextCompactionRuntime {
|
|
534
532
|
const now = options.now ?? (() => Date.now())
|
|
535
|
-
const randomId = options.randomId ?? (() => randomUUID())
|
|
533
|
+
const randomId = options.randomId ?? (() => crypto.randomUUID())
|
|
536
534
|
const thresholdRatio = options.thresholdRatio ?? CONTEXT_COMPACTION_THRESHOLD_RATIO
|
|
537
535
|
const outputReserveTokens = options.outputReserveTokens ?? CONTEXT_OUTPUT_RESERVE_TOKENS
|
|
538
536
|
const safetyMarginTokens = options.safetyMarginTokens ?? CONTEXT_SAFETY_MARGIN_TOKENS
|
package/src/runtime/index.ts
CHANGED
|
@@ -20,11 +20,11 @@ export * from './runtime-config'
|
|
|
20
20
|
export * from './runtime-extensions'
|
|
21
21
|
export * from './runtime-worker-registry'
|
|
22
22
|
export * from './skill-extraction-policy'
|
|
23
|
+
export * from './social-chat'
|
|
23
24
|
export * from './team-consultation-orchestrator'
|
|
24
25
|
export * from './team-consultation-prompts'
|
|
25
26
|
export * from './turn-lifecycle'
|
|
26
27
|
export * from './workstream-chat-helpers'
|
|
27
|
-
export * from './workstream-routing-policy'
|
|
28
28
|
export {
|
|
29
29
|
WorkstreamStateSchema,
|
|
30
30
|
type WorkstreamState,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { ToolSet } from 'ai'
|
|
1
2
|
import { z } from 'zod'
|
|
2
3
|
|
|
3
4
|
import type { CoreWorkstreamProfile } from '../config/agent-defaults'
|
|
4
5
|
import type { AgentFactory, AgentRuntimeConfigProvider, AgentToolBuilder } from '../config/agent-types'
|
|
5
6
|
import type { LotaWorkstreamConfig, WorkstreamBootstrapWelcomeConfig } from '../config/workstream-defaults'
|
|
7
|
+
import type { RecordIdRef } from '../db/record-id'
|
|
6
8
|
import type { NotificationService } from '../services/notification.service'
|
|
7
9
|
import { isRecord } from '../utils/string'
|
|
8
10
|
import type { GraphDesigner } from './graph-designer'
|
|
@@ -61,6 +63,87 @@ function isWorkerExtensionRecord(value: unknown): value is LotaRuntimeWorkerExte
|
|
|
61
63
|
return true
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
export interface LotaSocialChatSlackConfig {
|
|
67
|
+
botToken?: string
|
|
68
|
+
signingSecret?: string
|
|
69
|
+
userName?: string
|
|
70
|
+
dedupeTtlMs?: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface LotaSocialChatResolveContextParams {
|
|
74
|
+
platform: 'slack'
|
|
75
|
+
channelId: string
|
|
76
|
+
threadId: string
|
|
77
|
+
messageId: string
|
|
78
|
+
text: string
|
|
79
|
+
authorId?: string
|
|
80
|
+
authorName?: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface LotaSocialChatResolvedContext {
|
|
84
|
+
workspaceId: RecordIdRef
|
|
85
|
+
userId: RecordIdRef
|
|
86
|
+
userName?: string | null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface BuildSocialChatAgentToolsParams {
|
|
90
|
+
agentId: string
|
|
91
|
+
workspaceId: RecordIdRef
|
|
92
|
+
workspaceIdString: string
|
|
93
|
+
userId: RecordIdRef
|
|
94
|
+
userIdString: string
|
|
95
|
+
userName?: string | null
|
|
96
|
+
platform: 'slack'
|
|
97
|
+
channelId: string
|
|
98
|
+
threadId: string
|
|
99
|
+
incomingMessageId: string
|
|
100
|
+
incomingText: string
|
|
101
|
+
memoryBlock: string
|
|
102
|
+
onAppendMemoryBlock: (value: string) => void
|
|
103
|
+
context?: Record<string, unknown> | null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface LotaRuntimeSocialChatConfig {
|
|
107
|
+
agentId?: string
|
|
108
|
+
agentDisplayName?: string
|
|
109
|
+
slack?: LotaSocialChatSlackConfig
|
|
110
|
+
historyRedisKeyPrefix?: string
|
|
111
|
+
stateRedisKeyPrefix?: string
|
|
112
|
+
resolveContext: (
|
|
113
|
+
params: LotaSocialChatResolveContextParams,
|
|
114
|
+
) => LotaSocialChatResolvedContext | Promise<LotaSocialChatResolvedContext>
|
|
115
|
+
buildAgentTools: (params: BuildSocialChatAgentToolsParams) => ToolSet | Promise<ToolSet>
|
|
116
|
+
getConsultParticipants?:
|
|
117
|
+
| ((params: {
|
|
118
|
+
workspaceId: RecordIdRef
|
|
119
|
+
workspaceIdString: string
|
|
120
|
+
platform: 'slack'
|
|
121
|
+
}) => string[] | Promise<string[]>)
|
|
122
|
+
| undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isSlackSocialChatConfig(value: unknown): value is LotaSocialChatSlackConfig {
|
|
126
|
+
if (!isRecord(value)) return false
|
|
127
|
+
if (value.botToken !== undefined && typeof value.botToken !== 'string') return false
|
|
128
|
+
if (value.signingSecret !== undefined && typeof value.signingSecret !== 'string') return false
|
|
129
|
+
if (value.userName !== undefined && typeof value.userName !== 'string') return false
|
|
130
|
+
if (value.dedupeTtlMs !== undefined && typeof value.dedupeTtlMs !== 'number') return false
|
|
131
|
+
return true
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isSocialChatConfig(value: unknown): value is LotaRuntimeSocialChatConfig {
|
|
135
|
+
if (!isRecord(value)) return false
|
|
136
|
+
if (value.agentId !== undefined && typeof value.agentId !== 'string') return false
|
|
137
|
+
if (value.agentDisplayName !== undefined && typeof value.agentDisplayName !== 'string') return false
|
|
138
|
+
if (value.historyRedisKeyPrefix !== undefined && typeof value.historyRedisKeyPrefix !== 'string') return false
|
|
139
|
+
if (value.stateRedisKeyPrefix !== undefined && typeof value.stateRedisKeyPrefix !== 'string') return false
|
|
140
|
+
if (value.slack !== undefined && !isSlackSocialChatConfig(value.slack)) return false
|
|
141
|
+
if (!isFunction(value.resolveContext)) return false
|
|
142
|
+
if (!isFunction(value.buildAgentTools)) return false
|
|
143
|
+
if (value.getConsultParticipants !== undefined && !isFunction(value.getConsultParticipants)) return false
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
|
|
64
147
|
const workstreamBootstrapWelcomeConfigSchema = z.object({
|
|
65
148
|
directAgentId: z.string().trim().min(1),
|
|
66
149
|
buildMessageText: z.custom<WorkstreamBootstrapWelcomeConfig['buildMessageText']>(isFunction, {
|
|
@@ -161,9 +244,9 @@ export const LotaRuntimeConfigSchema = z.object({
|
|
|
161
244
|
memory: z
|
|
162
245
|
.object({
|
|
163
246
|
searchK: z.coerce.number().int().positive().default(6),
|
|
164
|
-
embeddingCacheTtlSeconds: z.coerce.number().int().positive().default(
|
|
247
|
+
embeddingCacheTtlSeconds: z.coerce.number().int().positive().default(7200),
|
|
165
248
|
})
|
|
166
|
-
.default({ searchK: 6, embeddingCacheTtlSeconds:
|
|
249
|
+
.default({ searchK: 6, embeddingCacheTtlSeconds: 7200 }),
|
|
167
250
|
workstreams: workstreamConfigSchema.default({}),
|
|
168
251
|
backgroundProcessing: z
|
|
169
252
|
.object({
|
|
@@ -188,6 +271,7 @@ export const LotaRuntimeConfigSchema = z.object({
|
|
|
188
271
|
runtimeAdapters: z.custom<LotaRuntimeAdapters>(isRecord).optional(),
|
|
189
272
|
turnHooks: z.custom<LotaRuntimeTurnHooks>(isRecord).optional(),
|
|
190
273
|
graphDesigner: z.custom<GraphDesigner>(isGraphDesigner).optional(),
|
|
274
|
+
socialChat: z.custom<LotaRuntimeSocialChatConfig>(isSocialChatConfig).optional(),
|
|
191
275
|
})
|
|
192
276
|
|
|
193
277
|
export type LotaRuntimeConfig = z.input<typeof LotaRuntimeConfigSchema>
|
|
@@ -123,7 +123,6 @@ export interface ResolveAgentParams {
|
|
|
123
123
|
onboardingActive: boolean
|
|
124
124
|
linearInstalled: boolean
|
|
125
125
|
githubInstalled: boolean
|
|
126
|
-
reasoningProfile: string
|
|
127
126
|
skills?: string[]
|
|
128
127
|
additionalInstructionSections?: string[]
|
|
129
128
|
context: Record<string, unknown> | null
|