@lota-sdk/core 0.2.3 → 0.3.1
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 +73 -0
- package/infrastructure/schema/02_execution_plan.surql +10 -11
- package/infrastructure/schema/04_runtime_bootstrap.surql +1 -0
- 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 +90 -94
- package/src/db/record-id.ts +21 -21
- package/src/db/service.ts +44 -40
- 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 +24 -21
- 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 +25 -39
- 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} +148 -171
- package/src/services/{workstream-turn.ts → thread-turn.ts} +27 -31
- package/src/services/thread.service.ts +853 -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} +68 -135
- 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/utils/async.ts +6 -7
- 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
|
@@ -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 }
|
|
@@ -10,4 +10,4 @@ export const SUMMARY_ROLLUP_MAX_TOKENS = 80_000
|
|
|
10
10
|
export const CONTEXT_COMPACTION_INCLUDED_TOOL_NAMES = ['userQuestions', 'proceedInOnboarding'] as const
|
|
11
11
|
export const CONTEXT_COMPACTION_INCLUDED_TOOL_PREFIXES = ['linear'] as const
|
|
12
12
|
export const CONTEXT_WINDOW_TOKENS = 200_000
|
|
13
|
-
export const
|
|
13
|
+
export const THREAD_RAW_TAIL_MESSAGES = 6
|
|
@@ -198,7 +198,7 @@ export function buildContextCompactionPrompt(params: ContextCompactionPromptPara
|
|
|
198
198
|
export function buildMemoryBlockCompactionPrompt(params: MemoryBlockCompactionPromptParams): string {
|
|
199
199
|
return [
|
|
200
200
|
'<memory-block-compaction>',
|
|
201
|
-
'Produce a compact replacement summary for the
|
|
201
|
+
'Produce a compact replacement summary for the thread memory block.',
|
|
202
202
|
'Preserve constraints, commitments, unresolved risks, and ownership.',
|
|
203
203
|
'Blend the previous summary with the new raw entries into one updated summary.',
|
|
204
204
|
'Return plain text only.',
|
|
@@ -7,7 +7,7 @@ const EXECUTION_PLAN_AGENT_PROTOCOL_PROMPT = `<execution-plan-protocol>
|
|
|
7
7
|
- The active execution runs in <execution-plan-state> are a summary inventory only. They list runId and title, not node-level state.
|
|
8
8
|
- The runtime executor owns lifecycle truth. Do not claim node completion until the executor confirms.
|
|
9
9
|
- Do not invent or restate run/node lifecycle details that are not present in the prompt or tool results.
|
|
10
|
-
- During plan-triggered turns, use the dedicated result-submission tool.
|
|
10
|
+
- During plan-triggered turns, use the dedicated result-submission tool.
|
|
11
11
|
- Treat the active execution runs in <execution-plan-state> as authoritative for whether a plan already exists.
|
|
12
12
|
- If contracts or criteria materially change, replace the plan.
|
|
13
13
|
</execution-plan-protocol>`
|
package/src/runtime/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export function shouldEnqueueOnboardingPostChatMemory(params: {
|
|
|
11
11
|
return params.userMessageText.trim().length > 0 || params.hasAttachmentContext
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function
|
|
14
|
+
export function shouldEnqueueRegularDigestForThread(params: {
|
|
15
15
|
onboardingActive: boolean
|
|
16
16
|
turnCount?: number
|
|
17
17
|
}): boolean {
|
|
@@ -10,22 +10,22 @@ import {
|
|
|
10
10
|
shouldEnqueueMemoryConsolidation,
|
|
11
11
|
shouldEnqueueMemoryExtraction,
|
|
12
12
|
shouldEnqueueOnboardingPostChatMemory,
|
|
13
|
-
|
|
13
|
+
shouldEnqueueRegularDigestForThread,
|
|
14
14
|
} from '../runtime/memory-digest-policy'
|
|
15
15
|
import { getRuntimeAdapters } from '../runtime/runtime-extensions'
|
|
16
16
|
import { shouldEnqueueSkillExtraction } from '../runtime/skill-extraction-policy'
|
|
17
17
|
import {
|
|
18
|
-
|
|
18
|
+
appendPersistedThreadContextToHistoryMessages,
|
|
19
19
|
buildAgentHistoryMessages,
|
|
20
20
|
buildConversationSummary,
|
|
21
21
|
buildReadableUploadMetadataContext,
|
|
22
22
|
extractMessageText,
|
|
23
23
|
readOptionalString,
|
|
24
24
|
toHistoryMessages,
|
|
25
|
-
} from '../runtime/
|
|
25
|
+
} from '../runtime/thread-chat-helpers'
|
|
26
26
|
import { recentActivityService } from '../services/recent-activity.service'
|
|
27
|
-
import {
|
|
28
|
-
import type {
|
|
27
|
+
import { threadService } from '../services/thread.service'
|
|
28
|
+
import type { NormalizedThread, ThreadRecord } from '../services/thread.types'
|
|
29
29
|
import { safeEnqueue } from '../utils/async'
|
|
30
30
|
import { toIsoDateTimeString } from '../utils/date-time'
|
|
31
31
|
|
|
@@ -41,37 +41,37 @@ function resolveDisplayName(agentId: string, overrides?: Partial<Record<string,
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function buildRecentActivityChatDeepLink(params: {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
thread: NormalizedThread
|
|
45
|
+
threadId: string
|
|
46
46
|
visibleAgentId: string
|
|
47
47
|
}): { route: string; search: Record<string, string> } {
|
|
48
|
-
if (params.
|
|
49
|
-
return { route: 'direct-
|
|
48
|
+
if (params.thread.type === 'default') {
|
|
49
|
+
return { route: 'direct-thread', search: { threadId: params.threadId, agentId: params.visibleAgentId } }
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
return { route: 'group-
|
|
52
|
+
return { route: 'group-thread', search: { threadId: params.threadId } }
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function buildRecentActivityChatSystemTitle(params: {
|
|
56
|
-
|
|
56
|
+
thread: NormalizedThread
|
|
57
57
|
visibleAgentId: string
|
|
58
58
|
agentDisplayNamesById?: Partial<Record<string, string>>
|
|
59
59
|
}): string {
|
|
60
|
-
if (params.
|
|
60
|
+
if (params.thread.type === 'default') {
|
|
61
61
|
return `Conversation with ${resolveDisplayName(params.visibleAgentId, params.agentDisplayNamesById)}`
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
return params.
|
|
64
|
+
return params.thread.title.trim() || 'Thread update'
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
interface PostTurnSideEffectsParams {
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
thread: NormalizedThread
|
|
69
|
+
threadRef: RecordIdRef
|
|
70
70
|
orgRef: RecordIdRef
|
|
71
71
|
userRef: RecordIdRef
|
|
72
72
|
userName?: string | null
|
|
73
73
|
orgIdString: string
|
|
74
|
-
|
|
74
|
+
threadIdString: string
|
|
75
75
|
onboardingActive: boolean
|
|
76
76
|
workspace: unknown
|
|
77
77
|
allAssistantMessages: ChatMessage[]
|
|
@@ -85,19 +85,19 @@ interface PostTurnSideEffectsParams {
|
|
|
85
85
|
storageKey: string
|
|
86
86
|
}>
|
|
87
87
|
memoryBlock: string
|
|
88
|
-
|
|
88
|
+
visibleThreadAgentId: string | null | undefined
|
|
89
89
|
defaultLeadAgentId: string
|
|
90
|
-
|
|
90
|
+
latestThreadRecord: ThreadRecord
|
|
91
91
|
isUserTurn: boolean
|
|
92
92
|
agentDisplayNamesById?: Partial<Record<string, string>>
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams): Promise<void> {
|
|
96
96
|
const recentHistory = await params.loadRecentHistory()
|
|
97
|
-
const turnCount = await
|
|
97
|
+
const turnCount = await threadService.incrementTurnCount(params.threadRef)
|
|
98
98
|
const agentMessages = buildAgentHistoryMessages(params.allAssistantMessages)
|
|
99
|
-
const historyMessagesForMemory =
|
|
100
|
-
compactionSummary: params.
|
|
99
|
+
const historyMessagesForMemory = appendPersistedThreadContextToHistoryMessages(toHistoryMessages(recentHistory), {
|
|
100
|
+
compactionSummary: params.latestThreadRecord.compactionSummary,
|
|
101
101
|
})
|
|
102
102
|
|
|
103
103
|
const userMessageText = params.referenceUserMessage ? extractMessageText(params.referenceUserMessage).trim() : ''
|
|
@@ -120,7 +120,7 @@ export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams):
|
|
|
120
120
|
() =>
|
|
121
121
|
enqueuePostChatMemory({
|
|
122
122
|
orgId: params.orgIdString,
|
|
123
|
-
|
|
123
|
+
threadId: params.threadIdString,
|
|
124
124
|
sourceId: params.referenceUserMessageId,
|
|
125
125
|
onboardStatus: readOptionalString((params.workspace as { onboardStatus?: unknown }).onboardStatus),
|
|
126
126
|
userMessage: memoryUserMessage,
|
|
@@ -139,7 +139,7 @@ export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams):
|
|
|
139
139
|
assistantMessages: params.allAssistantMessages,
|
|
140
140
|
})
|
|
141
141
|
if (conversationSummary) {
|
|
142
|
-
const effectiveAgentId = params.
|
|
142
|
+
const effectiveAgentId = params.visibleThreadAgentId ?? params.defaultLeadAgentId
|
|
143
143
|
const recentActivityResult = await recentActivityService.recordEvent({
|
|
144
144
|
orgId: params.orgRef,
|
|
145
145
|
userId: params.userRef,
|
|
@@ -147,27 +147,27 @@ export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams):
|
|
|
147
147
|
event: {
|
|
148
148
|
sourceEventId: `chat-turn:${params.referenceUserMessageId}`,
|
|
149
149
|
kind: 'chat.turn.completed',
|
|
150
|
-
targetKind: '
|
|
151
|
-
targetId: params.
|
|
152
|
-
mergeKey: `
|
|
150
|
+
targetKind: 'thread',
|
|
151
|
+
targetId: params.threadIdString,
|
|
152
|
+
mergeKey: `thread:${params.threadIdString}`,
|
|
153
153
|
title: buildRecentActivityChatSystemTitle({
|
|
154
|
-
|
|
154
|
+
thread: params.thread,
|
|
155
155
|
visibleAgentId: effectiveAgentId,
|
|
156
156
|
agentDisplayNamesById: params.agentDisplayNamesById,
|
|
157
157
|
}),
|
|
158
158
|
sourceLabel: resolveDisplayName(effectiveAgentId, params.agentDisplayNamesById),
|
|
159
159
|
deepLink: buildRecentActivityChatDeepLink({
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
thread: params.thread,
|
|
161
|
+
threadId: params.threadIdString,
|
|
162
162
|
visibleAgentId: effectiveAgentId,
|
|
163
163
|
}),
|
|
164
164
|
metadata: {
|
|
165
165
|
agentId: effectiveAgentId,
|
|
166
166
|
agentName: resolveDisplayName(effectiveAgentId, params.agentDisplayNamesById),
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
...(params.
|
|
167
|
+
threadId: params.threadIdString,
|
|
168
|
+
threadTitle: params.latestThreadRecord.title ?? params.thread.title,
|
|
169
|
+
threadType: params.thread.type,
|
|
170
|
+
...(params.thread.threadType ? { coreType: params.thread.threadType } : {}),
|
|
171
171
|
userMessageText,
|
|
172
172
|
assistantSummary: conversationSummary,
|
|
173
173
|
messageId: params.referenceUserMessageId,
|
|
@@ -186,7 +186,7 @@ export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams):
|
|
|
186
186
|
|
|
187
187
|
await enqueuePostChatOrgAction({
|
|
188
188
|
orgId: params.orgIdString,
|
|
189
|
-
|
|
189
|
+
threadId: params.threadIdString,
|
|
190
190
|
sourceId: params.referenceUserMessageId,
|
|
191
191
|
sourceCreatedAt,
|
|
192
192
|
conversationSummary,
|
|
@@ -203,7 +203,7 @@ export async function runPostTurnSideEffects(params: PostTurnSideEffectsParams):
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
if (
|
|
206
|
+
if (shouldEnqueueRegularDigestForThread({ onboardingActive: params.onboardingActive, turnCount })) {
|
|
207
207
|
await safeEnqueue(() => enqueueRegularChatMemoryDigest({ orgId: params.orgIdString }), {
|
|
208
208
|
operationName: 'regular chat memory digest enqueue',
|
|
209
209
|
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ToolSet } from 'ai'
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { CoreThreadProfile } from '../config/agent-defaults'
|
|
5
5
|
import type { AgentFactory, AgentRuntimeConfigProvider, AgentToolBuilder } from '../config/agent-types'
|
|
6
|
-
import type {
|
|
6
|
+
import type { LotaThreadConfig, ThreadBootstrapWelcomeConfig } from '../config/thread-defaults'
|
|
7
7
|
import type { RecordIdRef } from '../db/record-id'
|
|
8
8
|
import type { NotificationService } from '../services/notification.service'
|
|
9
9
|
import { isRecord } from '../utils/string'
|
|
@@ -144,24 +144,27 @@ function isSocialChatConfig(value: unknown): value is LotaRuntimeSocialChatConfi
|
|
|
144
144
|
return true
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
buildMessageText: z.custom<
|
|
147
|
+
const threadBootstrapWelcomeConfigSchema = z.object({
|
|
148
|
+
defaultAgentId: z.string().trim().min(1),
|
|
149
|
+
buildMessageText: z.custom<ThreadBootstrapWelcomeConfig['buildMessageText']>(isFunction, {
|
|
150
150
|
error: 'onboardingWelcome.buildMessageText must be a function',
|
|
151
151
|
}),
|
|
152
152
|
})
|
|
153
153
|
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
const threadConfigSchema = z
|
|
155
|
+
.object({
|
|
156
|
+
bootstrap: z
|
|
157
|
+
.object({
|
|
158
|
+
onboardingDefaultAgents: z.array(z.string().trim().min(1)).optional(),
|
|
159
|
+
completedDefaultAgents: z.array(z.string().trim().min(1)).optional(),
|
|
160
|
+
threadTypesAfterOnboarding: z.array(z.string().trim().min(1)).optional(),
|
|
161
|
+
ensureDefaultGroupOnCompleted: z.boolean().optional(),
|
|
162
|
+
onboardingWelcome: threadBootstrapWelcomeConfigSchema.optional(),
|
|
163
|
+
})
|
|
164
|
+
.strict()
|
|
165
|
+
.optional(),
|
|
166
|
+
})
|
|
167
|
+
.strict()
|
|
165
168
|
|
|
166
169
|
const agentsConfigSchema = z
|
|
167
170
|
.object({
|
|
@@ -178,9 +181,9 @@ const agentsConfigSchema = z
|
|
|
178
181
|
.optional(),
|
|
179
182
|
routerModelId: z.string().trim().min(1).optional(),
|
|
180
183
|
teamConsultParticipants: z.array(z.string().trim().min(1)),
|
|
181
|
-
|
|
182
|
-
.custom<(coreType: string) =>
|
|
183
|
-
error: 'agents.
|
|
184
|
+
getCoreThreadProfile: z
|
|
185
|
+
.custom<(coreType: string) => CoreThreadProfile>(isFunction, {
|
|
186
|
+
error: 'agents.getCoreThreadProfile must be a function',
|
|
184
187
|
})
|
|
185
188
|
.optional(),
|
|
186
189
|
createAgent: z
|
|
@@ -249,7 +252,7 @@ export const LotaRuntimeConfigSchema = z.object({
|
|
|
249
252
|
embeddingCacheTtlSeconds: z.coerce.number().int().positive().default(7200),
|
|
250
253
|
})
|
|
251
254
|
.default({ searchK: 6, embeddingCacheTtlSeconds: 7200 }),
|
|
252
|
-
|
|
255
|
+
threads: threadConfigSchema.default({}),
|
|
253
256
|
agents: agentsConfigSchema,
|
|
254
257
|
toolProviders: z.custom<Record<string, unknown>>(isToolProviderRecord).optional(),
|
|
255
258
|
extraSchemaFiles: z.array(z.custom<string | URL>(isStringOrUrl)).optional(),
|
|
@@ -319,4 +322,4 @@ export function parseWorkerBootstrapEnv(env: Record<string, string | undefined>)
|
|
|
319
322
|
return WORKER_BOOTSTRAP_ENV_SCHEMA.parse(env)
|
|
320
323
|
}
|
|
321
324
|
|
|
322
|
-
export type {
|
|
325
|
+
export type { LotaThreadConfig }
|
|
@@ -74,7 +74,7 @@ export interface LotaRuntimeTeamThinkToolsParams {
|
|
|
74
74
|
workspaceId: RecordIdRef
|
|
75
75
|
userId: RecordIdRef
|
|
76
76
|
workspaceIdString: string
|
|
77
|
-
|
|
77
|
+
threadId: RecordIdRef
|
|
78
78
|
githubInstalled: boolean
|
|
79
79
|
provideRepoTool: boolean
|
|
80
80
|
availableUploads: ReadableUploadMetadata[]
|
|
@@ -90,7 +90,7 @@ export interface LotaRuntimePlanEventEnvelope {
|
|
|
90
90
|
nodeSpec?: PlanNodeSpecRecord
|
|
91
91
|
nodeRun?: PlanNodeRunRecord
|
|
92
92
|
organizationId: string
|
|
93
|
-
|
|
93
|
+
threadId: string
|
|
94
94
|
runId: string
|
|
95
95
|
planSpecId: string
|
|
96
96
|
userId?: string
|
|
@@ -102,8 +102,8 @@ export interface LotaRuntimePlanEventAdapter {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
export interface BuildContextParams {
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
thread: unknown
|
|
106
|
+
threadRef: RecordIdRef
|
|
107
107
|
orgRef: RecordIdRef
|
|
108
108
|
userRef: RecordIdRef
|
|
109
109
|
userName?: string | null
|
|
@@ -123,15 +123,15 @@ export interface BuildContextParams {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
export interface AfterTurnParams {
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
thread: unknown
|
|
127
|
+
threadRef: RecordIdRef
|
|
128
128
|
orgRef: RecordIdRef
|
|
129
129
|
userRef: RecordIdRef
|
|
130
130
|
userName?: string | null
|
|
131
131
|
onboardingActive: boolean
|
|
132
132
|
referenceUserMessage: unknown
|
|
133
133
|
assistantMessages: unknown[]
|
|
134
|
-
|
|
134
|
+
latestThreadRecord: unknown
|
|
135
135
|
context: Record<string, unknown> | null
|
|
136
136
|
[key: string]: unknown
|
|
137
137
|
}
|
|
@@ -139,8 +139,8 @@ export interface AfterTurnParams {
|
|
|
139
139
|
export interface ResolveAgentParams {
|
|
140
140
|
agentId: string
|
|
141
141
|
mode: string
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
thread: unknown
|
|
143
|
+
threadRef: RecordIdRef
|
|
144
144
|
orgRef: RecordIdRef
|
|
145
145
|
userRef: RecordIdRef
|
|
146
146
|
userName?: string | null
|
|
@@ -154,8 +154,8 @@ export interface ResolveAgentParams {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
export interface BuildExtraInstructionSectionsParams {
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
thread: unknown
|
|
158
|
+
threadRef: RecordIdRef
|
|
159
159
|
orgRef: RecordIdRef
|
|
160
160
|
userRef: RecordIdRef
|
|
161
161
|
userName?: string | null
|
|
@@ -59,8 +59,8 @@ export function withLoggedSocialToolSet(
|
|
|
59
59
|
|
|
60
60
|
export async function runSocialAgentTurn(params: {
|
|
61
61
|
agentId: string
|
|
62
|
-
mode: '
|
|
63
|
-
|
|
62
|
+
mode: 'fixedThreadMode' | 'threadMode'
|
|
63
|
+
threadType: 'group'
|
|
64
64
|
onboardingActive: boolean
|
|
65
65
|
linearInstalled: boolean
|
|
66
66
|
systemWorkspaceDetails?: string
|
|
@@ -75,7 +75,7 @@ export async function runSocialAgentTurn(params: {
|
|
|
75
75
|
}): Promise<{ text: string; displayName: string }> {
|
|
76
76
|
const runtimeConfig = getAgentRuntimeConfig({
|
|
77
77
|
agentId: params.agentId,
|
|
78
|
-
|
|
78
|
+
threadType: params.threadType,
|
|
79
79
|
mode: params.mode,
|
|
80
80
|
onboardingActive: params.onboardingActive,
|
|
81
81
|
linearInstalled: params.linearInstalled,
|
|
@@ -2,7 +2,7 @@ import { stripSlackToolExecutionNoticeMarkdown } from '@lota-sdk/shared'
|
|
|
2
2
|
import type { Message, Thread } from 'chat'
|
|
3
3
|
|
|
4
4
|
import type { SocialChatHistoryMessage } from '../services/social-chat-history.service'
|
|
5
|
-
import { toHistoryMessages, toOptionalTrimmedString } from './
|
|
5
|
+
import { toHistoryMessages, toOptionalTrimmedString } from './thread-chat-helpers'
|
|
6
6
|
|
|
7
7
|
export function readSlackAuthorName(message: Message): string | undefined {
|
|
8
8
|
return (
|