@lota-sdk/core 0.2.3 → 0.3.0
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_identity.surql +2 -2
- package/infrastructure/schema/00_thread.surql +75 -0
- package/infrastructure/schema/02_execution_plan.surql +10 -11
- package/infrastructure/schema/10_autonomous_job.surql +3 -3
- package/package.json +2 -2
- package/src/ai/definitions.ts +1 -1
- package/src/config/agent-defaults.ts +5 -5
- package/src/config/index.ts +1 -1
- package/src/config/thread-defaults.ts +72 -0
- package/src/create-runtime.ts +89 -93
- package/src/db/tables.ts +3 -3
- package/src/db/{workstream-message-row.ts → thread-message-row.ts} +3 -3
- package/src/queues/context-compaction.queue.ts +6 -6
- package/src/queues/plan-agent-heartbeat.queue.ts +3 -3
- package/src/queues/post-chat-memory.queue.ts +1 -1
- package/src/queues/title-generation.queue.ts +10 -13
- package/src/redis/index.ts +1 -1
- package/src/redis/stream-context.ts +1 -1
- package/src/runtime/agent-identity-overrides.ts +1 -1
- package/src/runtime/agent-runtime-policy.ts +19 -21
- package/src/runtime/chat-request-routing.ts +1 -1
- package/src/runtime/context-compaction-constants.ts +1 -1
- package/src/runtime/context-compaction.ts +1 -1
- package/src/runtime/execution-plan.ts +1 -1
- package/src/runtime/index.ts +1 -1
- package/src/runtime/memory-digest-policy.ts +1 -1
- package/src/runtime/plugin-types.ts +1 -1
- package/src/runtime/post-turn-side-effects.ts +35 -35
- package/src/runtime/runtime-config.ts +12 -12
- package/src/runtime/runtime-extensions.ts +11 -11
- package/src/runtime/social-chat-agent-runner.ts +3 -3
- package/src/runtime/social-chat-history.ts +1 -1
- package/src/runtime/social-chat.ts +6 -6
- package/src/runtime/team-consultation-orchestrator.ts +1 -1
- package/src/runtime/{workstream-chat-helpers.ts → thread-chat-helpers.ts} +7 -7
- package/src/runtime/{workstream-plan-turn.ts → thread-plan-turn.ts} +11 -17
- package/src/runtime/{workstream-turn-context.ts → thread-turn-context.ts} +10 -10
- package/src/services/agent-activity.service.ts +39 -44
- package/src/services/agent-executor.service.ts +17 -19
- package/src/services/attachment.service.ts +4 -8
- package/src/services/autonomous-job.service.ts +29 -28
- package/src/services/context-compaction.service.ts +19 -29
- package/src/services/execution-plan.service.ts +58 -70
- package/src/services/global-orchestrator.service.ts +5 -5
- package/src/services/index.ts +6 -6
- package/src/services/memory.service.ts +1 -1
- package/src/services/monitoring-window.service.ts +2 -2
- package/src/services/mutating-approval.service.ts +7 -10
- package/src/services/node-workspace.service.ts +8 -7
- package/src/services/notification.service.ts +1 -1
- package/src/services/organization.service.ts +9 -9
- package/src/services/ownership-dispatcher.service.ts +13 -19
- package/src/services/plan-agent-heartbeat.service.ts +13 -13
- package/src/services/plan-agent-query.service.ts +7 -7
- package/src/services/plan-artifact.service.ts +1 -2
- package/src/services/plan-coordination.service.ts +4 -4
- package/src/services/plan-cycle.service.ts +7 -7
- package/src/services/plan-deadline.service.ts +4 -4
- package/src/services/plan-event-delivery.service.ts +8 -12
- package/src/services/plan-executor.service.ts +16 -37
- package/src/services/plan-run-data.ts +27 -8
- package/src/services/plan-run.service.ts +7 -9
- package/src/services/plan-scheduler.service.ts +4 -4
- package/src/services/plan-template.service.ts +2 -2
- package/src/services/plan-validator.service.ts +0 -11
- package/src/services/plugin-executor.service.ts +1 -1
- package/src/services/queue-job.service.ts +1 -1
- package/src/services/recent-activity-title.service.ts +1 -1
- package/src/services/recent-activity.service.ts +4 -4
- package/src/services/system-executor.service.ts +2 -2
- package/src/services/{workstream-message.service.ts → thread-message.service.ts} +72 -76
- package/src/services/thread-plan-registry.service.ts +22 -0
- package/src/services/thread-title.service.ts +39 -0
- package/src/services/{workstream-turn-preparation.service.ts → thread-turn-preparation.service.ts} +131 -143
- package/src/services/{workstream-turn.ts → thread-turn.ts} +27 -31
- package/src/services/thread.service.ts +707 -0
- package/src/services/thread.types.ts +17 -0
- package/src/storage/attachment-storage.service.ts +4 -4
- package/src/system-agents/index.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
- package/src/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/researcher.agent.ts +3 -3
- package/src/system-agents/{workstream-router.agent.ts → thread-router.agent.ts} +21 -21
- package/src/system-agents/title-generator.agent.ts +8 -8
- package/src/tools/execution-plan.tool.ts +39 -40
- package/src/tools/memory-block.tool.ts +4 -4
- package/src/tools/research-topic.tool.ts +1 -0
- package/src/tools/search-web.tool.ts +1 -1
- package/src/tools/search.tool.ts +4 -4
- package/src/tools/team-think.tool.ts +9 -9
- package/src/workers/regular-chat-memory-digest.helpers.ts +1 -1
- package/src/workers/regular-chat-memory-digest.runner.ts +43 -43
- package/src/workers/skill-extraction.runner.ts +9 -13
- package/src/workers/utils/{workstream-message-query.ts → thread-message-query.ts} +21 -21
- package/infrastructure/schema/00_workstream.surql +0 -64
- package/src/config/workstream-defaults.ts +0 -72
- package/src/services/workstream-plan-registry.service.ts +0 -22
- package/src/services/workstream-title.service.ts +0 -42
- package/src/services/workstream.service.ts +0 -803
- package/src/services/workstream.types.ts +0 -17
- /package/src/services/{workstream-constants.ts → thread-constants.ts} +0 -0
package/src/create-runtime.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { configureEmbeddingCache } from './ai/embedding-cache'
|
|
|
4
4
|
import { configureAgentFactory, configureAgents } from './config/agent-defaults'
|
|
5
5
|
import { configureBackgroundProcessing } from './config/background-processing'
|
|
6
6
|
import { configureLotaLogger } from './config/logger'
|
|
7
|
-
import {
|
|
7
|
+
import { configureThreads } from './config/thread-defaults'
|
|
8
8
|
import { ensureRecordId } from './db/record-id'
|
|
9
9
|
import { computeSchemaFingerprint } from './db/schema-fingerprint'
|
|
10
10
|
import { LOTA_SDK_DATABASE_NAME } from './db/sdk-database'
|
|
@@ -17,7 +17,7 @@ import { createRedisConnectionManager } from './redis/connection'
|
|
|
17
17
|
import { setRedisConnectionManager } from './redis/index'
|
|
18
18
|
import { closeSharedSubscriber } from './redis/stream-context'
|
|
19
19
|
import type { isApprovalContinuationRequest } from './runtime/approval-continuation'
|
|
20
|
-
import {
|
|
20
|
+
import { routeThreadChatMessages } from './runtime/chat-request-routing'
|
|
21
21
|
import { configureGraphDesigner } from './runtime/graph-designer'
|
|
22
22
|
import type { LotaPlugin, SystemNodeExecutor } from './runtime/plugin-types'
|
|
23
23
|
import { configureRuntimeConfig, LOTA_RUNTIME_ENV_KEYS, parseLotaRuntimeConfig } from './runtime/runtime-config'
|
|
@@ -57,41 +57,41 @@ import {
|
|
|
57
57
|
socialChatHistoryService as socialChatHistoryServiceSingleton,
|
|
58
58
|
} from './services/social-chat-history.service'
|
|
59
59
|
import { getBuiltInSystemExecutors } from './services/system-executor.service'
|
|
60
|
-
import type {
|
|
61
|
-
import {
|
|
62
|
-
import type {
|
|
63
|
-
import {
|
|
64
|
-
import type { workstreamTitleService } from './services/workstream-title.service'
|
|
65
|
-
import { workstreamTitleService as workstreamTitleServiceSingleton } from './services/workstream-title.service'
|
|
60
|
+
import type { threadMessageService } from './services/thread-message.service'
|
|
61
|
+
import { threadMessageService as threadMessageServiceSingleton } from './services/thread-message.service'
|
|
62
|
+
import type { threadTitleService } from './services/thread-title.service'
|
|
63
|
+
import { threadTitleService as threadTitleServiceSingleton } from './services/thread-title.service'
|
|
66
64
|
import type {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
createThreadApprovalContinuationStream,
|
|
66
|
+
createThreadNativeToolApprovalStream,
|
|
67
|
+
createThreadTurnStream,
|
|
68
|
+
runThreadTurnInBackground,
|
|
71
69
|
triggerPlanNodeTurn,
|
|
72
|
-
} from './services/
|
|
70
|
+
} from './services/thread-turn'
|
|
73
71
|
import {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
createThreadApprovalContinuationStream as createThreadApprovalContinuationStreamSingleton,
|
|
73
|
+
createThreadNativeToolApprovalStream as createThreadNativeToolApprovalStreamSingleton,
|
|
74
|
+
createThreadTurnStream as createThreadTurnStreamSingleton,
|
|
77
75
|
isApprovalContinuationRequest as isApprovalContinuationRequestSingleton,
|
|
78
|
-
|
|
76
|
+
runThreadTurnInBackground as runThreadTurnInBackgroundSingleton,
|
|
79
77
|
triggerPlanNodeTurn as triggerPlanNodeTurnSingleton,
|
|
80
|
-
} from './services/
|
|
81
|
-
import type {
|
|
82
|
-
import {
|
|
78
|
+
} from './services/thread-turn'
|
|
79
|
+
import type { threadService } from './services/thread.service'
|
|
80
|
+
import { threadService as threadServiceSingleton } from './services/thread.service'
|
|
81
|
+
import type { userService } from './services/user.service'
|
|
82
|
+
import { userService as userServiceSingleton } from './services/user.service'
|
|
83
83
|
import type { generatedDocumentStorageService } from './storage/generated-document-storage.service'
|
|
84
84
|
import { generatedDocumentStorageService as generatedDocumentStorageServiceSingleton } from './storage/generated-document-storage.service'
|
|
85
85
|
|
|
86
|
-
type
|
|
87
|
-
|
|
86
|
+
type ArchiveSdkThread = (
|
|
87
|
+
threadId: Parameters<typeof threadServiceSingleton.updateStatus>[0],
|
|
88
88
|
status?: 'archived',
|
|
89
|
-
) => ReturnType<typeof
|
|
89
|
+
) => ReturnType<typeof threadServiceSingleton.updateStatus>
|
|
90
90
|
|
|
91
|
-
type
|
|
92
|
-
|
|
91
|
+
type UnarchiveSdkThread = (
|
|
92
|
+
threadId: Parameters<typeof threadServiceSingleton.updateStatus>[0],
|
|
93
93
|
status?: 'regular',
|
|
94
|
-
) => ReturnType<typeof
|
|
94
|
+
) => ReturnType<typeof threadServiceSingleton.updateStatus>
|
|
95
95
|
|
|
96
96
|
let activeRuntimeToken: symbol | null = null
|
|
97
97
|
|
|
@@ -131,14 +131,14 @@ export interface LotaRuntime {
|
|
|
131
131
|
socialChatHistoryService: typeof socialChatHistoryServiceSingleton
|
|
132
132
|
executionPlanService: typeof executionPlanService
|
|
133
133
|
planAgentQueryService: typeof planAgentQueryService
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
threadMessageService: typeof threadMessageService
|
|
135
|
+
threadService: typeof threadService
|
|
136
|
+
threadTitleService: typeof threadTitleService
|
|
137
|
+
createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
|
|
138
|
+
createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
|
|
139
|
+
createThreadTurnStream: typeof createThreadTurnStream
|
|
140
140
|
isApprovalContinuationRequest: typeof isApprovalContinuationRequest
|
|
141
|
-
|
|
141
|
+
runThreadTurnInBackground: typeof runThreadTurnInBackground
|
|
142
142
|
triggerPlanNodeTurn: typeof triggerPlanNodeTurn
|
|
143
143
|
}
|
|
144
144
|
lota: {
|
|
@@ -164,32 +164,32 @@ export interface LotaRuntime {
|
|
|
164
164
|
remove: typeof organizationMemberServiceSingleton.removeMembership
|
|
165
165
|
isMember: typeof organizationMemberServiceSingleton.isMember
|
|
166
166
|
}
|
|
167
|
-
|
|
168
|
-
create: typeof
|
|
169
|
-
list: typeof
|
|
170
|
-
get: typeof
|
|
171
|
-
update: typeof
|
|
172
|
-
archive:
|
|
173
|
-
unarchive:
|
|
174
|
-
delete: typeof
|
|
175
|
-
stop: typeof
|
|
176
|
-
listMessages: typeof
|
|
177
|
-
getMessage: (params: {
|
|
167
|
+
threads: {
|
|
168
|
+
create: typeof threadServiceSingleton.createThread
|
|
169
|
+
list: typeof threadServiceSingleton.listThreads
|
|
170
|
+
get: typeof threadServiceSingleton.getThread
|
|
171
|
+
update: typeof threadServiceSingleton.updateTitle
|
|
172
|
+
archive: ArchiveSdkThread
|
|
173
|
+
unarchive: UnarchiveSdkThread
|
|
174
|
+
delete: typeof threadServiceSingleton.deleteThread
|
|
175
|
+
stop: typeof threadServiceSingleton.stopActiveRun
|
|
176
|
+
listMessages: typeof threadMessageServiceSingleton.listMessageHistoryPage
|
|
177
|
+
getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
|
|
178
178
|
sendMessage: (params: {
|
|
179
|
-
|
|
179
|
+
threadId: string
|
|
180
180
|
organizationId: string
|
|
181
181
|
userId: string
|
|
182
182
|
userName: string
|
|
183
|
-
messages: Parameters<typeof
|
|
184
|
-
}) => Promise<Awaited<ReturnType<typeof
|
|
183
|
+
messages: Parameters<typeof routeThreadChatMessages>[0]
|
|
184
|
+
}) => Promise<Awaited<ReturnType<typeof createThreadTurnStream>>>
|
|
185
185
|
continueApproval: (params: {
|
|
186
|
-
|
|
186
|
+
threadId: string
|
|
187
187
|
organizationId: string
|
|
188
188
|
userId: string
|
|
189
189
|
userName: string
|
|
190
|
-
messages: Parameters<typeof
|
|
191
|
-
}) => Promise<Awaited<ReturnType<typeof
|
|
192
|
-
uploadAttachment: typeof attachmentServiceSingleton.
|
|
190
|
+
messages: Parameters<typeof routeThreadChatMessages>[0]
|
|
191
|
+
}) => Promise<Awaited<ReturnType<typeof createThreadApprovalContinuationStream>>>
|
|
192
|
+
uploadAttachment: typeof attachmentServiceSingleton.uploadThreadAttachment
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
redis: {
|
|
@@ -253,7 +253,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
253
253
|
descriptions: runtimeConfig.agents.descriptions,
|
|
254
254
|
routerModelId: runtimeConfig.agents.routerModelId,
|
|
255
255
|
teamConsultParticipants: runtimeConfig.agents.teamConsultParticipants,
|
|
256
|
-
|
|
256
|
+
getCoreThreadProfile: runtimeConfig.agents.getCoreThreadProfile,
|
|
257
257
|
})
|
|
258
258
|
configureAgentFactory({
|
|
259
259
|
createAgent: runtimeConfig.agents.createAgent,
|
|
@@ -261,7 +261,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
261
261
|
getAgentRuntimeConfig: runtimeConfig.agents.getAgentRuntimeConfig,
|
|
262
262
|
pluginRuntime: runtimeConfig.pluginRuntime,
|
|
263
263
|
})
|
|
264
|
-
|
|
264
|
+
configureThreads({ agentRoster: runtimeConfig.agents.roster, config: runtimeConfig.threads })
|
|
265
265
|
configureNotificationService(runtimeConfig.notificationService ?? null)
|
|
266
266
|
configureRuntimeExtensions({
|
|
267
267
|
adapters: runtimeConfig.runtimeAdapters,
|
|
@@ -311,65 +311,61 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
311
311
|
remove: organizationMemberServiceSingleton.removeMembership.bind(organizationMemberServiceSingleton),
|
|
312
312
|
isMember: organizationMemberServiceSingleton.isMember.bind(organizationMemberServiceSingleton),
|
|
313
313
|
},
|
|
314
|
-
|
|
315
|
-
create:
|
|
316
|
-
list:
|
|
317
|
-
get:
|
|
318
|
-
update:
|
|
319
|
-
archive: async (
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
getMessage: async ({ workstreamId, messageId }) => {
|
|
327
|
-
const messages = await workstreamMessageServiceSingleton.listMessages(
|
|
328
|
-
ensureRecordId(workstreamId, TABLES.WORKSTREAM),
|
|
329
|
-
)
|
|
314
|
+
threads: {
|
|
315
|
+
create: threadServiceSingleton.createThread.bind(threadServiceSingleton),
|
|
316
|
+
list: threadServiceSingleton.listThreads.bind(threadServiceSingleton),
|
|
317
|
+
get: threadServiceSingleton.getThread.bind(threadServiceSingleton),
|
|
318
|
+
update: threadServiceSingleton.updateTitle.bind(threadServiceSingleton),
|
|
319
|
+
archive: async (threadId, status = 'archived') => await threadServiceSingleton.updateStatus(threadId, status),
|
|
320
|
+
unarchive: async (threadId, status = 'regular') => await threadServiceSingleton.updateStatus(threadId, status),
|
|
321
|
+
delete: threadServiceSingleton.deleteThread.bind(threadServiceSingleton),
|
|
322
|
+
stop: threadServiceSingleton.stopActiveRun.bind(threadServiceSingleton),
|
|
323
|
+
listMessages: threadMessageServiceSingleton.listMessageHistoryPage.bind(threadMessageServiceSingleton),
|
|
324
|
+
getMessage: async ({ threadId, messageId }) => {
|
|
325
|
+
const messages = await threadMessageServiceSingleton.listMessages(ensureRecordId(threadId, TABLES.THREAD))
|
|
330
326
|
const message = messages.find((candidate) => candidate.id === messageId)
|
|
331
327
|
if (!message) {
|
|
332
|
-
throw new Error(`
|
|
328
|
+
throw new Error(`Thread message not found: ${messageId}`)
|
|
333
329
|
}
|
|
334
330
|
return message
|
|
335
331
|
},
|
|
336
|
-
sendMessage: async ({
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
const routed =
|
|
332
|
+
sendMessage: async ({ threadId, organizationId, userId, userName, messages }) => {
|
|
333
|
+
const threadRef = ensureRecordId(threadId, TABLES.THREAD)
|
|
334
|
+
const thread = await threadServiceSingleton.getThread(threadRef)
|
|
335
|
+
const routed = routeThreadChatMessages(messages)
|
|
340
336
|
if (routed.kind !== 'turn') {
|
|
341
337
|
throw new Error(routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.')
|
|
342
338
|
}
|
|
343
339
|
|
|
344
|
-
return
|
|
345
|
-
|
|
346
|
-
|
|
340
|
+
return createThreadTurnStreamSingleton({
|
|
341
|
+
thread,
|
|
342
|
+
threadRef,
|
|
347
343
|
orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
|
|
348
344
|
userRef: ensureRecordId(userId, TABLES.USER),
|
|
349
345
|
userName,
|
|
350
346
|
inputMessage: routed.inputMessage,
|
|
351
347
|
})
|
|
352
348
|
},
|
|
353
|
-
continueApproval: async ({
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
const routed =
|
|
349
|
+
continueApproval: async ({ threadId, organizationId, userId, userName, messages }) => {
|
|
350
|
+
const threadRef = ensureRecordId(threadId, TABLES.THREAD)
|
|
351
|
+
const thread = await threadServiceSingleton.getThread(threadRef)
|
|
352
|
+
const routed = routeThreadChatMessages(messages)
|
|
357
353
|
if (routed.kind !== 'approval-continuation') {
|
|
358
354
|
throw new Error(
|
|
359
355
|
routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
|
|
360
356
|
)
|
|
361
357
|
}
|
|
362
358
|
|
|
363
|
-
return
|
|
364
|
-
|
|
365
|
-
|
|
359
|
+
return createThreadApprovalContinuationStreamSingleton({
|
|
360
|
+
thread,
|
|
361
|
+
threadRef,
|
|
366
362
|
orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
|
|
367
363
|
userRef: ensureRecordId(userId, TABLES.USER),
|
|
368
364
|
userName,
|
|
369
365
|
approvalMessages: routed.approvalMessages,
|
|
370
366
|
})
|
|
371
367
|
},
|
|
372
|
-
uploadAttachment: attachmentServiceSingleton.
|
|
368
|
+
uploadAttachment: attachmentServiceSingleton.uploadThreadAttachment.bind(attachmentServiceSingleton),
|
|
373
369
|
},
|
|
374
370
|
} satisfies LotaRuntime['lota']
|
|
375
371
|
|
|
@@ -395,14 +391,14 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
395
391
|
socialChatHistoryService: socialChatHistoryServiceSingleton,
|
|
396
392
|
executionPlanService: executionPlanServiceSingleton,
|
|
397
393
|
planAgentQueryService: planAgentQueryServiceSingleton,
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
394
|
+
threadMessageService: threadMessageServiceSingleton,
|
|
395
|
+
threadService: threadServiceSingleton,
|
|
396
|
+
threadTitleService: threadTitleServiceSingleton,
|
|
397
|
+
createThreadApprovalContinuationStream: createThreadApprovalContinuationStreamSingleton,
|
|
398
|
+
createThreadNativeToolApprovalStream: createThreadNativeToolApprovalStreamSingleton,
|
|
399
|
+
createThreadTurnStream: createThreadTurnStreamSingleton,
|
|
404
400
|
isApprovalContinuationRequest: isApprovalContinuationRequestSingleton,
|
|
405
|
-
|
|
401
|
+
runThreadTurnInBackground: runThreadTurnInBackgroundSingleton,
|
|
406
402
|
triggerPlanNodeTurn: triggerPlanNodeTurnSingleton,
|
|
407
403
|
},
|
|
408
404
|
lota,
|
|
@@ -456,7 +452,7 @@ export async function createLotaRuntime(config: LotaRuntimeConfig): Promise<Lota
|
|
|
456
452
|
function getBuiltInSchemaFiles(): URL[] {
|
|
457
453
|
return [
|
|
458
454
|
new URL('../infrastructure/schema/00_identity.surql', import.meta.url),
|
|
459
|
-
new URL('../infrastructure/schema/
|
|
455
|
+
new URL('../infrastructure/schema/00_thread.surql', import.meta.url),
|
|
460
456
|
new URL('../infrastructure/schema/01_memory.surql', import.meta.url),
|
|
461
457
|
new URL('../infrastructure/schema/02_execution_plan.surql', import.meta.url),
|
|
462
458
|
new URL('../infrastructure/schema/03_learned_skill.surql', import.meta.url),
|
package/src/db/tables.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export const TABLES = {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
THREAD: 'thread',
|
|
3
|
+
THREAD_MESSAGE: 'threadMessage',
|
|
4
|
+
THREAD_ATTACHMENT: 'threadAttachment',
|
|
4
5
|
RUNTIME_BOOTSTRAP: 'runtimeBootstrap',
|
|
5
|
-
WORKSTREAM_ATTACHMENT: 'workstreamAttachment',
|
|
6
6
|
MEMORY: 'memory',
|
|
7
7
|
MEMORY_RELATION: 'memoryRelation',
|
|
8
8
|
MEMORY_HISTORY: 'memoryHistory',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { recordIdSchema } from '@lota-sdk/shared'
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const ThreadMessageRowSchema = z.object({
|
|
5
5
|
id: recordIdSchema,
|
|
6
|
-
|
|
6
|
+
threadId: recordIdSchema,
|
|
7
7
|
messageId: z.string(),
|
|
8
8
|
role: z.enum(['system', 'user', 'assistant']),
|
|
9
9
|
parts: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
@@ -12,4 +12,4 @@ export const WorkstreamMessageRowSchema = z.object({
|
|
|
12
12
|
updatedAt: z.coerce.date().optional(),
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
export type
|
|
15
|
+
export type ThreadMessageRow = z.infer<typeof ThreadMessageRowSchema>
|
|
@@ -4,11 +4,11 @@ import { ensureRecordId } from '../db/record-id'
|
|
|
4
4
|
import { databaseService } from '../db/service'
|
|
5
5
|
import { TABLES } from '../db/tables'
|
|
6
6
|
import { contextCompactionService } from '../services/context-compaction.service'
|
|
7
|
-
import {
|
|
7
|
+
import { threadService } from '../services/thread.service'
|
|
8
8
|
import { createQueueFactory } from './queue-factory'
|
|
9
9
|
|
|
10
10
|
interface ContextCompactionJob {
|
|
11
|
-
domain: '
|
|
11
|
+
domain: 'thread'
|
|
12
12
|
entityId: string
|
|
13
13
|
contextSize?: number
|
|
14
14
|
}
|
|
@@ -17,12 +17,12 @@ async function processContextCompactionJob(job: Job<ContextCompactionJob>): Prom
|
|
|
17
17
|
await databaseService.connect()
|
|
18
18
|
|
|
19
19
|
const { entityId, contextSize } = job.data
|
|
20
|
-
const
|
|
21
|
-
await
|
|
20
|
+
const threadRef = ensureRecordId(entityId, TABLES.THREAD)
|
|
21
|
+
await threadService.setCompacting(threadRef, true)
|
|
22
22
|
try {
|
|
23
|
-
await contextCompactionService.
|
|
23
|
+
await contextCompactionService.compactThreadHistory({ threadId: threadRef, contextSize })
|
|
24
24
|
} finally {
|
|
25
|
-
await
|
|
25
|
+
await threadService.setCompacting(threadRef, false)
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -10,7 +10,7 @@ import { createQueueFactory } from './queue-factory'
|
|
|
10
10
|
export interface PlanAgentHeartbeatWakeJob {
|
|
11
11
|
type: 'wake-node'
|
|
12
12
|
organizationId: string
|
|
13
|
-
|
|
13
|
+
threadId: string
|
|
14
14
|
runId: string
|
|
15
15
|
nodeId: string
|
|
16
16
|
agentId: string
|
|
@@ -58,7 +58,7 @@ const planAgentHeartbeatQueue = createQueueFactory<PlanAgentHeartbeatJob>({
|
|
|
58
58
|
|
|
59
59
|
function buildWakeJobId(params: {
|
|
60
60
|
organizationId: string
|
|
61
|
-
|
|
61
|
+
threadId: string
|
|
62
62
|
runId: string
|
|
63
63
|
nodeId: string
|
|
64
64
|
agentId: string
|
|
@@ -70,7 +70,7 @@ function buildWakeJobId(params: {
|
|
|
70
70
|
|
|
71
71
|
export async function enqueuePlanAgentHeartbeatWake(params: {
|
|
72
72
|
organizationId: string
|
|
73
|
-
|
|
73
|
+
threadId: string
|
|
74
74
|
runId: string
|
|
75
75
|
nodeId: string
|
|
76
76
|
agentId: string
|
|
@@ -3,18 +3,18 @@ import type { Job } from 'bullmq'
|
|
|
3
3
|
import { ensureRecordId } from '../db/record-id'
|
|
4
4
|
import { databaseService } from '../db/service'
|
|
5
5
|
import { recentActivityTitleService } from '../services/recent-activity-title.service'
|
|
6
|
-
import {
|
|
6
|
+
import { threadTitleService } from '../services/thread-title.service'
|
|
7
7
|
import { createQueueFactory } from './queue-factory'
|
|
8
8
|
|
|
9
9
|
export const TITLE_GENERATION_QUEUE = 'title-generation'
|
|
10
10
|
|
|
11
|
-
// This queue merges
|
|
11
|
+
// This queue merges thread title generation and recent-activity title
|
|
12
12
|
// refinement because both are short-lived title synthesis jobs with the same
|
|
13
13
|
// operational shape.
|
|
14
14
|
|
|
15
|
-
interface
|
|
16
|
-
kind: '
|
|
17
|
-
|
|
15
|
+
interface ThreadTitleGenerationJob {
|
|
16
|
+
kind: 'thread-title'
|
|
17
|
+
threadId: string
|
|
18
18
|
sourceText: string
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -23,12 +23,12 @@ interface RecentActivityTitleRefinementJob {
|
|
|
23
23
|
activityId: string
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
type TitleGenerationJob =
|
|
26
|
+
type TitleGenerationJob = ThreadTitleGenerationJob | RecentActivityTitleRefinementJob
|
|
27
27
|
|
|
28
28
|
async function processTitleGenerationJob(job: Job<TitleGenerationJob>): Promise<void> {
|
|
29
29
|
await databaseService.connect()
|
|
30
|
-
if (job.data.kind === '
|
|
31
|
-
await
|
|
30
|
+
if (job.data.kind === 'thread-title') {
|
|
31
|
+
await threadTitleService.generateAndPersistTitle(ensureRecordId(job.data.threadId), job.data.sourceText)
|
|
32
32
|
return
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -45,11 +45,8 @@ const titleGeneration = createQueueFactory<TitleGenerationJob>({
|
|
|
45
45
|
processor: processTitleGenerationJob,
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
export function
|
|
49
|
-
return titleGeneration.enqueue(
|
|
50
|
-
{ kind: 'workstream-title', ...job },
|
|
51
|
-
{ jobId: `workstream-title:${job.workstreamId}` },
|
|
52
|
-
)
|
|
48
|
+
export function enqueueThreadTitleGeneration(job: Omit<ThreadTitleGenerationJob, 'kind'>) {
|
|
49
|
+
return titleGeneration.enqueue({ kind: 'thread-title', ...job }, { jobId: `thread-title:${job.threadId}` })
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
export function enqueueRecentActivityTitleRefinement(job: Omit<RecentActivityTitleRefinementJob, 'kind'>) {
|
package/src/redis/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ export {
|
|
|
9
9
|
} from './connection-accessor'
|
|
10
10
|
export { withOrgMemoryLock } from './org-memory-lock'
|
|
11
11
|
export { LeaseLockLostError, withRedisLeaseLock } from './redis-lease-lock'
|
|
12
|
-
export { closeSharedSubscriber,
|
|
12
|
+
export { closeSharedSubscriber, createThreadResumableContext } from './stream-context'
|
|
13
13
|
|
|
14
14
|
export { createRedisConnectionManager }
|
|
15
15
|
export type { RedisConnectionManager }
|
|
@@ -55,7 +55,7 @@ export async function closeSharedSubscriber(): Promise<void> {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export function
|
|
58
|
+
export function createThreadResumableContext() {
|
|
59
59
|
const redis = getRedisConnection()
|
|
60
60
|
return createResumableStreamContext({
|
|
61
61
|
waitUntil: null,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { agentDisplayNames } from '../config/agent-defaults'
|
|
2
|
-
import { asRecord, readOptionalString } from './
|
|
2
|
+
import { asRecord, readOptionalString } from './thread-chat-helpers'
|
|
3
3
|
|
|
4
4
|
interface RuntimeAgentIdentityOverrides {
|
|
5
5
|
displayNamesById: Partial<Record<string, string>>
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
} from '@lota-sdk/shared'
|
|
8
8
|
|
|
9
9
|
import { getLeadAgentId } from '../config/agent-defaults'
|
|
10
|
-
import { resolveOnboardingOwnerAgentId } from '../config/
|
|
10
|
+
import { resolveOnboardingOwnerAgentId } from '../config/thread-defaults'
|
|
11
11
|
import type { ChatMode } from './agent-types'
|
|
12
12
|
export interface AgentRuntimeConfig<TAgent extends string> {
|
|
13
13
|
id: TAgent
|
|
@@ -73,15 +73,13 @@ function buildOwnershipDispatchArtifactPayload(artifacts: PlanArtifactSubmission
|
|
|
73
73
|
return artifacts.map((artifact) => ({
|
|
74
74
|
name: artifact.name,
|
|
75
75
|
kind: artifact.kind,
|
|
76
|
-
pointer: artifact.pointer,
|
|
77
|
-
...(artifact.schemaRef ? { schemaRef: artifact.schemaRef } : {}),
|
|
78
76
|
...(artifact.description ? { description: artifact.description } : {}),
|
|
79
77
|
...(artifact.payload !== undefined ? { payload: artifact.payload } : {}),
|
|
80
78
|
}))
|
|
81
79
|
}
|
|
82
80
|
|
|
83
|
-
export function toChatMode(
|
|
84
|
-
return
|
|
81
|
+
export function toChatMode(threadType: string): ChatMode {
|
|
82
|
+
return threadType === 'default' ? 'fixedThreadMode' : 'threadMode'
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
function toMemoryBlockSection(memoryBlock: string | undefined): string | undefined {
|
|
@@ -92,13 +90,13 @@ function toMemoryBlockSection(memoryBlock: string | undefined): string | undefin
|
|
|
92
90
|
|
|
93
91
|
export function resolveActiveAgentSkills<TAgent extends string, TSkill extends PropertyKey>(params: {
|
|
94
92
|
agentId: TAgent
|
|
95
|
-
|
|
93
|
+
threadType: string
|
|
96
94
|
mode?: ChatMode
|
|
97
95
|
onboardingActive: boolean
|
|
98
96
|
linearInstalled: boolean
|
|
99
97
|
getAgentSkills: (agentId: TAgent, mode: ChatMode) => TSkill[]
|
|
100
98
|
}): TSkill[] {
|
|
101
|
-
const mode = params.mode ?? toChatMode(params.
|
|
99
|
+
const mode = params.mode ?? toChatMode(params.threadType)
|
|
102
100
|
return params
|
|
103
101
|
.getAgentSkills(params.agentId, mode)
|
|
104
102
|
.filter((skill) => (params.linearInstalled ? true : skill !== ('linear' as TSkill)))
|
|
@@ -107,7 +105,7 @@ export function resolveActiveAgentSkills<TAgent extends string, TSkill extends P
|
|
|
107
105
|
export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends PropertyKey>(params: {
|
|
108
106
|
agentId: TAgent
|
|
109
107
|
displayNameByAgent: Record<TAgent, string>
|
|
110
|
-
|
|
108
|
+
threadType: string
|
|
111
109
|
mode?: ChatMode
|
|
112
110
|
skills?: TSkill[]
|
|
113
111
|
onboardingActive: boolean
|
|
@@ -115,7 +113,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
115
113
|
systemWorkspaceDetails?: string
|
|
116
114
|
preSeededMemoriesSection?: string
|
|
117
115
|
retrievedKnowledgeSection?: string
|
|
118
|
-
|
|
116
|
+
threadMemoryBlock?: string
|
|
119
117
|
responseGuardSection?: string
|
|
120
118
|
learnedSkillsSection?: string
|
|
121
119
|
additionalInstructionSections?: string[]
|
|
@@ -125,7 +123,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
125
123
|
buildSkillInstructionSection: (skills: TSkill[]) => string
|
|
126
124
|
buildOnboardingPromptSection: () => string
|
|
127
125
|
}): AgentRuntimeConfig<TAgent> {
|
|
128
|
-
const mode = params.mode ?? toChatMode(params.
|
|
126
|
+
const mode = params.mode ?? toChatMode(params.threadType)
|
|
129
127
|
const rulesSection = params.buildGlobalRuleInstructionSection(params.ruleOptions)
|
|
130
128
|
const skillsSection =
|
|
131
129
|
params.skills && params.skills.length > 0 ? params.buildSkillInstructionSection(params.skills) : ''
|
|
@@ -138,7 +136,7 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
138
136
|
params.systemWorkspaceDetails?.trim(),
|
|
139
137
|
params.preSeededMemoriesSection?.trim(),
|
|
140
138
|
params.retrievedKnowledgeSection?.trim(),
|
|
141
|
-
toMemoryBlockSection(params.
|
|
139
|
+
toMemoryBlockSection(params.threadMemoryBlock),
|
|
142
140
|
...(params.additionalInstructionSections?.map((section) => section.trim()) ?? []),
|
|
143
141
|
params.responseGuardSection?.trim(),
|
|
144
142
|
params.onboardingActive ? 'Onboarding is active. Keep responses onboarding-focused and concise.' : undefined,
|
|
@@ -154,9 +152,9 @@ export function buildAgentRuntimeConfig<TAgent extends string, TSkill extends Pr
|
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
154
|
|
|
157
|
-
export function
|
|
155
|
+
export function buildThreadAgentToolPolicy<TAgent extends string, TSkill extends PropertyKey>(params: {
|
|
158
156
|
agentId: TAgent
|
|
159
|
-
|
|
157
|
+
threadType: string
|
|
160
158
|
mode?: ChatMode
|
|
161
159
|
onboardingActive: boolean
|
|
162
160
|
linearInstalled: boolean
|
|
@@ -164,11 +162,11 @@ export function buildWorkstreamAgentToolPolicy<TAgent extends string, TSkill ext
|
|
|
164
162
|
provideRepoTool: boolean
|
|
165
163
|
getAgentSkills: (agentId: TAgent, mode: ChatMode) => TSkill[]
|
|
166
164
|
}): AgentToolPolicy<TSkill> {
|
|
167
|
-
const resolvedMode = params.mode ?? toChatMode(params.
|
|
165
|
+
const resolvedMode = params.mode ?? toChatMode(params.threadType)
|
|
168
166
|
const onboardingOwnerAgentId = resolveOnboardingOwnerAgentId(getLeadAgentId()) as TAgent
|
|
169
167
|
const skills = resolveActiveAgentSkills({
|
|
170
168
|
agentId: params.agentId,
|
|
171
|
-
|
|
169
|
+
threadType: params.threadType,
|
|
172
170
|
mode: resolvedMode,
|
|
173
171
|
onboardingActive: params.onboardingActive,
|
|
174
172
|
linearInstalled: params.linearInstalled,
|
|
@@ -203,7 +201,7 @@ export function buildTeamConsultationAgentToolPolicy({
|
|
|
203
201
|
provideRepoTool: boolean
|
|
204
202
|
}): AgentToolPolicy<string> & { blockedToolNames: Set<string> } {
|
|
205
203
|
return {
|
|
206
|
-
resolvedMode: '
|
|
204
|
+
resolvedMode: 'fixedThreadMode',
|
|
207
205
|
skills: [],
|
|
208
206
|
includeMemorySearch: false,
|
|
209
207
|
includeConversationSearch: false,
|
|
@@ -249,9 +247,9 @@ export function buildOwnershipDispatchContextSection(params: {
|
|
|
249
247
|
return [
|
|
250
248
|
'<ownership-dispatch-execution>',
|
|
251
249
|
'You are executing a single isolated execution-plan node.',
|
|
252
|
-
'Do not ask the user questions. Do not reference any hidden or prior
|
|
253
|
-
'Use only the provided node context, resolved input, input artifacts, and upstream
|
|
254
|
-
'Return only the final structured node result that satisfies the required output contract
|
|
250
|
+
'Do not ask the user questions. Do not reference any hidden or prior thread chat history.',
|
|
251
|
+
'Use only the provided node context, resolved input, input artifacts, and upstream summaries.',
|
|
252
|
+
'Return only the final structured node result that satisfies the required output contract.',
|
|
255
253
|
JSON.stringify(payload, null, 2),
|
|
256
254
|
'</ownership-dispatch-execution>',
|
|
257
255
|
].join('\n')
|
|
@@ -268,14 +266,14 @@ export function buildOwnershipDispatchResponseGuard(params: {
|
|
|
268
266
|
return [
|
|
269
267
|
'<ownership-dispatch-result-contract>',
|
|
270
268
|
'Return a single JSON object with this exact shape:',
|
|
271
|
-
'{"structuredOutput"?: object, "artifacts": Array<{ "name": string, "kind": "json"|"markdown"|"file"|"external-ref"|"record", "
|
|
269
|
+
'{"notes": string, "structuredOutput"?: object, "artifacts": Array<{ "name": string, "kind": "json"|"markdown"|"file"|"external-ref"|"record", "description"?: string, "payload"?: object|array }>}',
|
|
272
270
|
'Do not wrap the JSON in markdown or code fences.',
|
|
273
271
|
`Node label: ${params.node.label}`,
|
|
274
272
|
`Required deliverables: ${params.node.deliverables.length > 0 ? params.node.deliverables.map((item) => item.name).join(', ') : 'none'}`,
|
|
275
273
|
...(completionCheckHints.length > 0
|
|
276
274
|
? ['Structured output fields required by completion checks:', ...completionCheckHints]
|
|
277
275
|
: []),
|
|
278
|
-
'
|
|
276
|
+
'notes is required. Include a concise summary of what was done, key decisions, and any context downstream nodes need.',
|
|
279
277
|
'</ownership-dispatch-result-contract>',
|
|
280
278
|
].join('\n')
|
|
281
279
|
}
|
|
@@ -8,7 +8,7 @@ export type RoutedChatRequest =
|
|
|
8
8
|
| { kind: 'turn'; inputMessage: ChatMessage }
|
|
9
9
|
| { kind: 'invalid'; message: string }
|
|
10
10
|
|
|
11
|
-
export function
|
|
11
|
+
export function routeThreadChatMessages(messages: ChatMessage[]): RoutedChatRequest {
|
|
12
12
|
if (isApprovalContinuationRequest(messages)) {
|
|
13
13
|
if (isNativeToolApprovalRequest(messages)) {
|
|
14
14
|
return { kind: 'native-tool-approval', messages }
|