@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/services/{workstream-turn-preparation.service.ts → thread-turn-preparation.service.ts}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
THREAD,
|
|
3
3
|
dataPartsSchemas,
|
|
4
4
|
messageMetadataSchema,
|
|
5
5
|
PlanNodeResultSubmissionSchema,
|
|
@@ -11,13 +11,13 @@ import type { ChatMessage, MessageMetadata, PlanNodeSpecRecord } from '@lota-sdk
|
|
|
11
11
|
import { convertToModelMessages, stepCountIs, tool as createTool, validateUIMessages } from 'ai'
|
|
12
12
|
import type { PrepareStepFunction, StopCondition, ToolLoopAgent, ToolSet, UIMessageStreamWriter } from 'ai'
|
|
13
13
|
|
|
14
|
-
import type {
|
|
14
|
+
import type { CoreThreadProfile } from '../config/agent-defaults'
|
|
15
15
|
import {
|
|
16
16
|
agentRoster,
|
|
17
17
|
buildAgentTools,
|
|
18
18
|
createAgent,
|
|
19
19
|
getLeadAgentId,
|
|
20
|
-
|
|
20
|
+
getCoreThreadProfile,
|
|
21
21
|
getAgentRuntimeConfig,
|
|
22
22
|
} from '../config/agent-defaults'
|
|
23
23
|
import { lotaDebugLogger } from '../config/debug-logger'
|
|
@@ -26,7 +26,7 @@ import type { RecordIdRef } from '../db/record-id'
|
|
|
26
26
|
import { recordIdToString } from '../db/record-id'
|
|
27
27
|
import { TABLES } from '../db/tables'
|
|
28
28
|
import { enqueueContextCompaction } from '../queues/context-compaction.queue'
|
|
29
|
-
import {
|
|
29
|
+
import { enqueueThreadTitleGeneration } from '../queues/title-generation.queue'
|
|
30
30
|
import { readRuntimeAgentIdentityOverrides, resolveRuntimeAgentDisplayName } from '../runtime/agent-identity-overrides'
|
|
31
31
|
import { OWNERSHIP_DISPATCH_BLOCKED_TOOL_NAMES } from '../runtime/agent-runtime-policy'
|
|
32
32
|
import { createAgentMessageMetadata, createServerRunAbortController } from '../runtime/agent-stream-helpers'
|
|
@@ -39,7 +39,6 @@ import { createExecutionPlanInstructionSectionCache } from '../runtime/execution
|
|
|
39
39
|
import { mergeInstructionSections } from '../runtime/instruction-sections'
|
|
40
40
|
import { runPostTurnSideEffects } from '../runtime/post-turn-side-effects'
|
|
41
41
|
import { getRuntimeAdapters, getToolProviders, getTurnHooks } from '../runtime/runtime-extensions'
|
|
42
|
-
import { finalizeTurnRun } from '../runtime/turn-lifecycle'
|
|
43
42
|
import {
|
|
44
43
|
asRecord,
|
|
45
44
|
collectToolOutputErrors,
|
|
@@ -47,17 +46,18 @@ import {
|
|
|
47
46
|
readInstructionSections,
|
|
48
47
|
readOptionalString,
|
|
49
48
|
toOptionalTrimmedString,
|
|
50
|
-
} from '../runtime/
|
|
49
|
+
} from '../runtime/thread-chat-helpers'
|
|
51
50
|
import {
|
|
52
51
|
buildPlanTurnInstructionSections,
|
|
53
52
|
buildPlanTurnPromptMessage,
|
|
54
53
|
buildPlanTurnSubmitToolDescription,
|
|
55
|
-
} from '../runtime/
|
|
56
|
-
import type {
|
|
57
|
-
import {
|
|
54
|
+
} from '../runtime/thread-plan-turn'
|
|
55
|
+
import type { ThreadPlanTurnContext } from '../runtime/thread-plan-turn'
|
|
56
|
+
import { assembleThreadTurnContext } from '../runtime/thread-turn-context'
|
|
57
|
+
import { finalizeTurnRun } from '../runtime/turn-lifecycle'
|
|
58
58
|
import { chatRunRegistry } from '../services/chat-run-registry.service'
|
|
59
|
-
import type {
|
|
60
|
-
import {
|
|
59
|
+
import type { NormalizedThread, ThreadRecord } from '../services/thread.types'
|
|
60
|
+
import { triageThreadMessage, checkForNextAgent } from '../system-agents/thread-router.agent'
|
|
61
61
|
import { safeEnqueue } from '../utils/async'
|
|
62
62
|
import { AppError } from '../utils/errors'
|
|
63
63
|
import { attachmentService } from './attachment.service'
|
|
@@ -67,8 +67,8 @@ import { executionPlanService } from './execution-plan.service'
|
|
|
67
67
|
import { learnedSkillService } from './learned-skill.service'
|
|
68
68
|
import { memoryService } from './memory.service'
|
|
69
69
|
import { planRunService } from './plan-run.service'
|
|
70
|
-
import {
|
|
71
|
-
import {
|
|
70
|
+
import { threadMessageService } from './thread-message.service'
|
|
71
|
+
import { ActiveThreadRunConflictError, threadService } from './thread.service'
|
|
72
72
|
|
|
73
73
|
type ChatStreamChunk = Parameters<UIMessageStreamWriter<ChatMessage>['write']>[0]
|
|
74
74
|
|
|
@@ -86,22 +86,22 @@ function hasUIMessageStream(value: unknown): value is UIMessageStreamResult {
|
|
|
86
86
|
|
|
87
87
|
const PRESEEDED_MEMORY_LOOKUP_LIMIT = 3
|
|
88
88
|
|
|
89
|
-
async function
|
|
89
|
+
async function waitForThreadCompactionIfNeeded(threadId: RecordIdRef): Promise<ThreadRecord> {
|
|
90
90
|
return waitForCompactionIfNeeded({
|
|
91
|
-
entityId: recordIdToString(
|
|
92
|
-
entityLabel: '
|
|
93
|
-
loadEntity: () =>
|
|
94
|
-
isCompacting: (
|
|
91
|
+
entityId: recordIdToString(threadId, TABLES.THREAD),
|
|
92
|
+
entityLabel: 'Thread',
|
|
93
|
+
loadEntity: () => threadService.getById(threadId),
|
|
94
|
+
isCompacting: (thread) => thread.isCompacting === true,
|
|
95
95
|
})
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
class
|
|
98
|
+
class ThreadTurnError extends AppError {
|
|
99
99
|
constructor(
|
|
100
100
|
message: string,
|
|
101
101
|
readonly statusCode: 400 | 409,
|
|
102
102
|
) {
|
|
103
103
|
super(message, statusCode === 409 ? 'CONFLICT' : 'BAD_REQUEST', statusCode)
|
|
104
|
-
this.name = '
|
|
104
|
+
this.name = 'ThreadTurnError'
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -143,9 +143,9 @@ function applyPlanTurnToolPolicy(tools: ToolSet, nodeSpec: PlanNodeSpecRecord):
|
|
|
143
143
|
)
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
export interface
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
export interface ThreadTurnParams {
|
|
147
|
+
thread: NormalizedThread
|
|
148
|
+
threadRef: RecordIdRef
|
|
149
149
|
orgRef: RecordIdRef
|
|
150
150
|
userRef: RecordIdRef
|
|
151
151
|
userName?: string | null
|
|
@@ -156,9 +156,9 @@ export interface WorkstreamTurnParams {
|
|
|
156
156
|
streamId?: string
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
export interface
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
export interface ThreadApprovalContinuationParams {
|
|
160
|
+
thread: NormalizedThread
|
|
161
|
+
threadRef: RecordIdRef
|
|
162
162
|
orgRef: RecordIdRef
|
|
163
163
|
userRef: RecordIdRef
|
|
164
164
|
userName?: string | null
|
|
@@ -167,20 +167,20 @@ export interface WorkstreamApprovalContinuationParams {
|
|
|
167
167
|
streamId?: string
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
export interface
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
export interface ThreadPlanTurnParams {
|
|
171
|
+
thread: NormalizedThread
|
|
172
|
+
threadRef: RecordIdRef
|
|
173
173
|
orgRef: RecordIdRef
|
|
174
174
|
userRef: RecordIdRef
|
|
175
175
|
userName?: string | null
|
|
176
|
-
planTurn:
|
|
176
|
+
planTurn: ThreadPlanTurnContext
|
|
177
177
|
abortSignal?: AbortSignal
|
|
178
178
|
streamId?: string
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
type
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
type ThreadRunCoreParams = {
|
|
182
|
+
thread: NormalizedThread
|
|
183
|
+
threadRef: RecordIdRef
|
|
184
184
|
orgRef: RecordIdRef
|
|
185
185
|
userRef: RecordIdRef
|
|
186
186
|
userName?: string | null
|
|
@@ -191,15 +191,15 @@ type WorkstreamRunCoreParams = {
|
|
|
191
191
|
| { kind: 'userTurn'; inputMessage: ChatMessage; skipInputMessagePersistence?: boolean }
|
|
192
192
|
| { kind: 'approvalContinuation'; approvalMessages: ChatMessage[] }
|
|
193
193
|
| { kind: 'nativeToolApprovalTurn'; approvalMessages: ChatMessage[] }
|
|
194
|
-
| { kind: 'planTurn'; planTurn:
|
|
194
|
+
| { kind: 'planTurn'; planTurn: ThreadPlanTurnContext }
|
|
195
195
|
)
|
|
196
196
|
|
|
197
|
-
interface
|
|
197
|
+
interface PreparedThreadTurn {
|
|
198
198
|
originalMessages: ChatMessage[]
|
|
199
|
-
run: (writer?: UIMessageStreamWriter<ChatMessage>) => Promise<
|
|
199
|
+
run: (writer?: UIMessageStreamWriter<ChatMessage>) => Promise<PreparedThreadTurnResult>
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
export interface
|
|
202
|
+
export interface PreparedThreadTurnResult {
|
|
203
203
|
inputMessageId?: string
|
|
204
204
|
assistantMessages: ChatMessage[]
|
|
205
205
|
}
|
|
@@ -217,8 +217,8 @@ function upsertChatHistoryMessage(messages: ChatMessage[], nextMessage: ChatMess
|
|
|
217
217
|
|
|
218
218
|
interface StreamAgentResponseContext {
|
|
219
219
|
turnHooks: ReturnType<typeof getTurnHooks>
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
thread: NormalizedThread
|
|
221
|
+
threadRef: RecordIdRef
|
|
222
222
|
orgRef: RecordIdRef
|
|
223
223
|
userRef: RecordIdRef
|
|
224
224
|
userName?: string | null
|
|
@@ -238,7 +238,7 @@ interface StreamAgentResponseContext {
|
|
|
238
238
|
|
|
239
239
|
interface StreamAgentResponseParams {
|
|
240
240
|
agentId: string
|
|
241
|
-
mode: 'direct' | '
|
|
241
|
+
mode: 'direct' | 'fixedThreadMode' | 'threadMode'
|
|
242
242
|
messages: ChatMessage[]
|
|
243
243
|
tools: ToolSet
|
|
244
244
|
observer: {
|
|
@@ -269,8 +269,8 @@ async function streamAgentResponse(
|
|
|
269
269
|
await ctx.turnHooks.resolveAgent?.({
|
|
270
270
|
agentId: streamParams.agentId,
|
|
271
271
|
mode: streamParams.mode,
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
thread: ctx.thread,
|
|
273
|
+
threadRef: ctx.threadRef,
|
|
274
274
|
orgRef: ctx.orgRef,
|
|
275
275
|
userRef: ctx.userRef,
|
|
276
276
|
userName: ctx.userName,
|
|
@@ -306,7 +306,7 @@ async function streamAgentResponse(
|
|
|
306
306
|
resolvedAgentId === 'mentor'
|
|
307
307
|
const config = getAgentRuntimeConfig({
|
|
308
308
|
agentId: resolvedAgentId,
|
|
309
|
-
|
|
309
|
+
threadType: ctx.thread.type,
|
|
310
310
|
mode: streamParams.mode,
|
|
311
311
|
skills: streamParams.skills,
|
|
312
312
|
onboardingActive: ctx.onboardingActive,
|
|
@@ -314,7 +314,7 @@ async function streamAgentResponse(
|
|
|
314
314
|
systemWorkspaceDetails: ctx.promptContext.systemWorkspaceDetails,
|
|
315
315
|
preSeededMemoriesSection,
|
|
316
316
|
retrievedKnowledgeSection: ctx.retrievedKnowledgeSection,
|
|
317
|
-
|
|
317
|
+
threadMemoryBlock: ctx.memoryBlock,
|
|
318
318
|
learnedSkillsSection,
|
|
319
319
|
userMessageText: latestUserMessageText,
|
|
320
320
|
ruleOptions: { includeMemr3Rule: hasRetrievalTools, includeDomainReasoningFallbackRule: hasDomainRoutingSkills },
|
|
@@ -426,15 +426,15 @@ async function streamAgentResponse(
|
|
|
426
426
|
return responseMessage
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
-
export async function
|
|
430
|
-
const {
|
|
429
|
+
export async function prepareThreadRunCore(params: ThreadRunCoreParams): Promise<PreparedThreadTurn> {
|
|
430
|
+
const { thread, threadRef, orgRef, userRef, userName } = params
|
|
431
431
|
const runtimeAdapters = getRuntimeAdapters()
|
|
432
432
|
const turnHooks = getTurnHooks()
|
|
433
433
|
const toolProviders = getToolProviders()
|
|
434
434
|
const workspaceProvider = runtimeAdapters.workspaceProvider
|
|
435
435
|
const orgIdString = recordIdToString(orgRef, TABLES.ORGANIZATION)
|
|
436
436
|
const userIdString = recordIdToString(userRef, TABLES.USER)
|
|
437
|
-
const
|
|
437
|
+
const threadIdString = recordIdToString(threadRef, TABLES.THREAD)
|
|
438
438
|
|
|
439
439
|
const hydrateMessageFileUrls = (message: ChatMessage): ChatMessage => ({
|
|
440
440
|
...message,
|
|
@@ -453,13 +453,13 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
453
453
|
if (params.kind === 'userTurn') {
|
|
454
454
|
inputMessage = hydrateMessageFileUrls(withMessageCreatedAt(params.inputMessage, Date.now()))
|
|
455
455
|
if (inputMessage.role !== 'user') {
|
|
456
|
-
throw new
|
|
456
|
+
throw new ThreadTurnError('Only user messages can be submitted to the thread runtime.', 400)
|
|
457
457
|
}
|
|
458
458
|
if (!hasMessageContent(inputMessage.parts)) {
|
|
459
|
-
throw new
|
|
459
|
+
throw new ThreadTurnError('Thread messages must include text or attachments.', 400)
|
|
460
460
|
}
|
|
461
|
-
if (
|
|
462
|
-
throw new
|
|
461
|
+
if (thread.type === 'default' && !thread.agentId) {
|
|
462
|
+
throw new ThreadTurnError('Default threads require an assigned agent.', 400)
|
|
463
463
|
}
|
|
464
464
|
}
|
|
465
465
|
|
|
@@ -471,17 +471,14 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
471
471
|
? workspaceProvider.getWorkspace(orgRef)
|
|
472
472
|
: Promise.resolve({})
|
|
473
473
|
|
|
474
|
-
const
|
|
474
|
+
const threadRecord = await waitForThreadCompactionIfNeeded(threadRef)
|
|
475
475
|
timer.step('compaction-gate')
|
|
476
476
|
// Plan turns run without the chat lease — they must not block or be blocked by user messages.
|
|
477
477
|
if (params.kind !== 'planTurn') {
|
|
478
|
-
if (
|
|
479
|
-
|
|
480
|
-
toOptionalTrimmedString(workstreamRecord.activeRunId)
|
|
481
|
-
) {
|
|
482
|
-
const clearedStaleRun = await workstreamService.clearStaleActiveRunIfMissingFromRegistry(workstreamRef)
|
|
478
|
+
if ((await threadService.hasActiveRunLease(threadRef)) || toOptionalTrimmedString(threadRecord.activeRunId)) {
|
|
479
|
+
const clearedStaleRun = await threadService.clearStaleActiveRunIfMissingFromRegistry(threadRef)
|
|
483
480
|
if (!clearedStaleRun) {
|
|
484
|
-
throw new
|
|
481
|
+
throw new ThreadTurnError('A chat run is already active.', 409)
|
|
485
482
|
}
|
|
486
483
|
}
|
|
487
484
|
}
|
|
@@ -491,22 +488,19 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
491
488
|
.reverse()
|
|
492
489
|
.find((m) => m.role === 'assistant' && hasApprovalRespondedParts(m))
|
|
493
490
|
if (!approvedAssistantMessage) {
|
|
494
|
-
throw new
|
|
491
|
+
throw new ThreadTurnError('No approval-responded message found.', 400)
|
|
495
492
|
}
|
|
496
|
-
await
|
|
493
|
+
await threadMessageService.upsertMessages({ threadId: threadRef, messages: [approvedAssistantMessage] })
|
|
497
494
|
timer.step('persist-approval-message')
|
|
498
495
|
}
|
|
499
496
|
|
|
500
|
-
const persistedCompactionCursor = toOptionalTrimmedString(
|
|
501
|
-
const persistedLiveHistoryPromise =
|
|
502
|
-
workstreamRef,
|
|
503
|
-
persistedCompactionCursor,
|
|
504
|
-
)
|
|
497
|
+
const persistedCompactionCursor = toOptionalTrimmedString(threadRecord.lastCompactedMessageId) ?? undefined
|
|
498
|
+
const persistedLiveHistoryPromise = threadMessageService.listMessagesAfterCursor(threadRef, persistedCompactionCursor)
|
|
505
499
|
let recentHistoryPromise: Promise<ChatMessage[]> | null = null
|
|
506
500
|
const loadRecentHistory = async (): Promise<ChatMessage[]> => {
|
|
507
501
|
if (!recentHistoryPromise) {
|
|
508
|
-
recentHistoryPromise =
|
|
509
|
-
.listRecentMessages(
|
|
502
|
+
recentHistoryPromise = threadMessageService
|
|
503
|
+
.listRecentMessages(threadRef, 64)
|
|
510
504
|
.then(async (persistedRecentHistory) => {
|
|
511
505
|
if (persistedRecentHistory.length === 0) {
|
|
512
506
|
return [] as ChatMessage[]
|
|
@@ -547,7 +541,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
547
541
|
timer.step('validate+hydrate-history')
|
|
548
542
|
|
|
549
543
|
if (userMessage && shouldPersistInputMessage) {
|
|
550
|
-
await
|
|
544
|
+
await threadMessageService.upsertMessages({ threadId: threadRef, messages: [userMessage] })
|
|
551
545
|
timer.step('persist-user-message')
|
|
552
546
|
}
|
|
553
547
|
|
|
@@ -569,7 +563,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
569
563
|
const respondedBy = recordIdToString(userRef, TABLES.USER)
|
|
570
564
|
if (params.kind === 'approvalContinuation') {
|
|
571
565
|
await executionPlanService.applyApprovalResponseFromMessages({
|
|
572
|
-
|
|
566
|
+
threadId: threadRef,
|
|
573
567
|
approvalMessages: params.approvalMessages,
|
|
574
568
|
respondedBy,
|
|
575
569
|
})
|
|
@@ -580,31 +574,29 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
580
574
|
|
|
581
575
|
if (
|
|
582
576
|
params.kind === 'userTurn' &&
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
workstreamRecord.title === WORKSTREAM.DEFAULT_TITLE &&
|
|
577
|
+
thread.type === 'group' &&
|
|
578
|
+
threadRecord.nameGenerated !== true &&
|
|
579
|
+
threadRecord.title === THREAD.DEFAULT_TITLE &&
|
|
587
580
|
messageText.length > 0
|
|
588
581
|
) {
|
|
589
|
-
void safeEnqueue(
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
)
|
|
582
|
+
void safeEnqueue(() => enqueueThreadTitleGeneration({ threadId: threadIdString, sourceText: messageText }), {
|
|
583
|
+
operationName: 'thread-title-generation',
|
|
584
|
+
})
|
|
593
585
|
}
|
|
594
586
|
|
|
595
|
-
if (
|
|
596
|
-
throw new
|
|
587
|
+
if (thread.type === 'thread' && !thread.threadType) {
|
|
588
|
+
throw new ThreadTurnError('Core threads require a thread type.', 400)
|
|
597
589
|
}
|
|
598
|
-
const
|
|
599
|
-
|
|
590
|
+
const coreThreadProfile: CoreThreadProfile | null =
|
|
591
|
+
thread.type === 'thread' && thread.threadType ? getCoreThreadProfile(thread.threadType) : null
|
|
600
592
|
const defaultLeadAgentId = getLeadAgentId()
|
|
601
|
-
const
|
|
593
|
+
const visibleThreadAgentId =
|
|
602
594
|
params.agentIdOverride ??
|
|
603
|
-
(
|
|
604
|
-
const coreInstructionSections =
|
|
605
|
-
const assembledContext = await
|
|
606
|
-
|
|
607
|
-
|
|
595
|
+
(thread.type === 'default' ? thread.agentId : (coreThreadProfile?.config.agentId ?? defaultLeadAgentId))
|
|
596
|
+
const coreInstructionSections = coreThreadProfile ? [coreThreadProfile.instructions] : undefined
|
|
597
|
+
const assembledContext = await assembleThreadTurnContext({
|
|
598
|
+
thread,
|
|
599
|
+
threadRef,
|
|
608
600
|
orgRef,
|
|
609
601
|
userRef,
|
|
610
602
|
userName,
|
|
@@ -628,11 +620,11 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
628
620
|
hookInstructionSections,
|
|
629
621
|
} = assembledContext
|
|
630
622
|
|
|
631
|
-
let memoryBlock =
|
|
623
|
+
let memoryBlock = threadService.formatMemoryBlockForPrompt(threadRecord)
|
|
632
624
|
const executionPlanInstructionSectionCache = createExecutionPlanInstructionSectionCache({
|
|
633
625
|
disabled: false,
|
|
634
626
|
loadPlans: async () => {
|
|
635
|
-
const runs = await planRunService.getActiveRunRecords(
|
|
627
|
+
const runs = await planRunService.getActiveRunRecords(threadRef)
|
|
636
628
|
return Promise.all(runs.map((run) => planRunService.toSerializablePlan(run, { slim: true })))
|
|
637
629
|
},
|
|
638
630
|
})
|
|
@@ -643,7 +635,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
643
635
|
}
|
|
644
636
|
if (userMessage) {
|
|
645
637
|
const appliedHumanInput = await executionPlanService.applyHumanInputFromUserMessage({
|
|
646
|
-
|
|
638
|
+
threadId: threadRef,
|
|
647
639
|
message: userMessage,
|
|
648
640
|
respondedBy,
|
|
649
641
|
})
|
|
@@ -684,8 +676,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
684
676
|
}
|
|
685
677
|
|
|
686
678
|
const persistedCompactionSummary =
|
|
687
|
-
persistedCompactionCursor && typeof
|
|
688
|
-
?
|
|
679
|
+
persistedCompactionCursor && typeof threadRecord.compactionSummary === 'string'
|
|
680
|
+
? threadRecord.compactionSummary
|
|
689
681
|
: ''
|
|
690
682
|
const messagesForContext = userMessage ? upsertChatHistoryMessage(liveHistory, userMessage) : liveHistory
|
|
691
683
|
let currentMessages = contextCompactionRuntime.prependSummaryMessage(persistedCompactionSummary, messagesForContext)
|
|
@@ -704,7 +696,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
704
696
|
})
|
|
705
697
|
const buildTurnToolParams = (toolParams: {
|
|
706
698
|
agentId: string
|
|
707
|
-
mode: 'direct' | '
|
|
699
|
+
mode: 'direct' | 'fixedThreadMode' | 'threadMode'
|
|
708
700
|
memoryBlock: string
|
|
709
701
|
onAppendMemoryBlock: (value: string) => void
|
|
710
702
|
extraMessages?: ChatMessage[]
|
|
@@ -715,9 +707,9 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
715
707
|
orgId: orgRef,
|
|
716
708
|
userId: userRef,
|
|
717
709
|
userName: userName ?? 'there',
|
|
718
|
-
|
|
710
|
+
threadId: threadRef,
|
|
719
711
|
orgIdString,
|
|
720
|
-
|
|
712
|
+
threadType: thread.type,
|
|
721
713
|
mode: toolParams.mode,
|
|
722
714
|
linearInstalled,
|
|
723
715
|
onboardingActive,
|
|
@@ -738,7 +730,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
738
730
|
return {
|
|
739
731
|
originalMessages,
|
|
740
732
|
run: async (writer?: UIMessageStreamWriter<ChatMessage>) => {
|
|
741
|
-
const executeRun = async (leaseAbortSignal?: AbortSignal): Promise<
|
|
733
|
+
const executeRun = async (leaseAbortSignal?: AbortSignal): Promise<PreparedThreadTurnResult | void> => {
|
|
742
734
|
const agentIdentityOverrides = readRuntimeAgentIdentityOverrides(buildContextResult)
|
|
743
735
|
const runTimer = lotaDebugLogger.timer('run')
|
|
744
736
|
const serverRunId = Bun.randomUUIDv7()
|
|
@@ -751,7 +743,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
751
743
|
}
|
|
752
744
|
// Plan turns run without the chat lease — don't claim the active run slot.
|
|
753
745
|
if (params.kind !== 'planTurn') {
|
|
754
|
-
await
|
|
746
|
+
await threadService.setActiveTurn(threadRef, serverRunId, params.streamId ?? null)
|
|
755
747
|
chatRunRegistry.register(serverRunId, runAbort.controller)
|
|
756
748
|
}
|
|
757
749
|
runTimer.step('set-active-run+stream')
|
|
@@ -794,7 +786,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
794
786
|
Date.now(),
|
|
795
787
|
)
|
|
796
788
|
|
|
797
|
-
await
|
|
789
|
+
await threadMessageService.upsertMessages({ threadId: threadRef, messages: [committed] })
|
|
798
790
|
currentMessages = upsertChatHistoryMessage(currentMessages, committed)
|
|
799
791
|
allAssistantMessages = upsertChatHistoryMessage(allAssistantMessages, committed)
|
|
800
792
|
throwIfRunAborted()
|
|
@@ -804,8 +796,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
804
796
|
|
|
805
797
|
const streamCtx: StreamAgentResponseContext = {
|
|
806
798
|
turnHooks,
|
|
807
|
-
|
|
808
|
-
|
|
799
|
+
thread,
|
|
800
|
+
threadRef,
|
|
809
801
|
orgRef,
|
|
810
802
|
userRef,
|
|
811
803
|
userName,
|
|
@@ -825,7 +817,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
825
817
|
|
|
826
818
|
const runVisibleAgent = async (runParams: {
|
|
827
819
|
agentId: string
|
|
828
|
-
mode: 'direct' | '
|
|
820
|
+
mode: 'direct' | 'fixedThreadMode' | 'threadMode'
|
|
829
821
|
skills?: string[]
|
|
830
822
|
additionalInstructionSections?: string[]
|
|
831
823
|
extraMessages?: ChatMessage[]
|
|
@@ -837,7 +829,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
837
829
|
const visibleTimer = lotaDebugLogger.timer(`visible:${runParams.agentId}`)
|
|
838
830
|
let runMemoryBlock = memoryBlock
|
|
839
831
|
const includeExecutionPlanTools =
|
|
840
|
-
runParams.includeExecutionPlanTools ?? runParams.mode !== '
|
|
832
|
+
runParams.includeExecutionPlanTools ?? runParams.mode !== 'fixedThreadMode'
|
|
841
833
|
const rawTools: ToolSet = {
|
|
842
834
|
...((await buildAgentTools(
|
|
843
835
|
buildTurnToolParams({
|
|
@@ -889,7 +881,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
889
881
|
inputSchema: PlanNodeResultSubmissionSchema,
|
|
890
882
|
execute: async (result) =>
|
|
891
883
|
await executionPlanService.submitPlanTurnResult({
|
|
892
|
-
|
|
884
|
+
threadId: threadRef,
|
|
893
885
|
runId: planTurn.runId,
|
|
894
886
|
nodeId: planTurn.nodeId,
|
|
895
887
|
emittedBy: planTurn.nodeSpec.owner.ref,
|
|
@@ -899,7 +891,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
899
891
|
|
|
900
892
|
await runVisibleAgent({
|
|
901
893
|
agentId: planTurn.nodeSpec.owner.ref,
|
|
902
|
-
mode:
|
|
894
|
+
mode: thread.type === 'default' ? 'direct' : 'threadMode',
|
|
903
895
|
additionalInstructionSections: buildPlanTurnInstructionSections(planTurn),
|
|
904
896
|
extraMessages: [buildPlanTurnPromptMessage(planTurn)],
|
|
905
897
|
includeExecutionPlanTools: false,
|
|
@@ -908,16 +900,16 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
908
900
|
metadataPatch: { trigger: 'plan-turn', planRunId: planTurn.runId, planNodeId: planTurn.nodeId },
|
|
909
901
|
})
|
|
910
902
|
} else {
|
|
911
|
-
if (
|
|
912
|
-
if (!
|
|
913
|
-
throw new
|
|
903
|
+
if (thread.type === 'default') {
|
|
904
|
+
if (!thread.agentId) {
|
|
905
|
+
throw new ThreadTurnError('Direct threads require an assigned agent.', 400)
|
|
914
906
|
}
|
|
915
|
-
await runVisibleAgent({ agentId:
|
|
907
|
+
await runVisibleAgent({ agentId: thread.agentId, mode: 'direct' })
|
|
916
908
|
} else {
|
|
917
|
-
// Multi-agent orchestration for group
|
|
918
|
-
const wsMembers = (
|
|
909
|
+
// Multi-agent orchestration for group threads
|
|
910
|
+
const wsMembers = (thread as { members?: string[] }).members ?? []
|
|
919
911
|
const members = wsMembers.length > 0 ? wsMembers : [...agentRoster]
|
|
920
|
-
const fallbackAgentId =
|
|
912
|
+
const fallbackAgentId = coreThreadProfile?.config.agentId ?? defaultLeadAgentId
|
|
921
913
|
throwIfRunAborted()
|
|
922
914
|
writeMultiAgentEvent(writer, { phase: 'routing', note: 'Routing this turn to the right agent.' })
|
|
923
915
|
|
|
@@ -926,8 +918,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
926
918
|
.map((m) => `${m.role}: ${extractMessageText(m).slice(0, 200)}`)
|
|
927
919
|
.join('\n')
|
|
928
920
|
|
|
929
|
-
const triageResult = await
|
|
930
|
-
|
|
921
|
+
const triageResult = await triageThreadMessage({
|
|
922
|
+
threadTitle: thread.title,
|
|
931
923
|
members,
|
|
932
924
|
messageText,
|
|
933
925
|
recentContext,
|
|
@@ -944,13 +936,13 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
944
936
|
}
|
|
945
937
|
// Multi-agent member protocol: be direct, focus on domain
|
|
946
938
|
additionalSections.push(
|
|
947
|
-
'<multi-agent-protocol>\nYou are responding as part of a multi-agent
|
|
939
|
+
'<multi-agent-protocol>\nYou are responding as part of a multi-agent thread. Focus on your domain expertise. Be direct and concise — another agent may follow up on different aspects.\n</multi-agent-protocol>',
|
|
948
940
|
)
|
|
949
941
|
|
|
950
942
|
return await runVisibleAgent({
|
|
951
943
|
agentId,
|
|
952
|
-
mode: '
|
|
953
|
-
skills:
|
|
944
|
+
mode: 'threadMode',
|
|
945
|
+
skills: coreThreadProfile?.skills ? [...coreThreadProfile.skills] : undefined,
|
|
954
946
|
additionalInstructionSections: additionalSections,
|
|
955
947
|
})
|
|
956
948
|
}
|
|
@@ -973,7 +965,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
973
965
|
while (respondedAgents.length < 3) {
|
|
974
966
|
const lastResponseText = extractMessageText(lastResponse).slice(0, 500)
|
|
975
967
|
const checkResult = await checkForNextAgent({
|
|
976
|
-
|
|
968
|
+
threadTitle: thread.title,
|
|
977
969
|
members,
|
|
978
970
|
messageText,
|
|
979
971
|
respondedAgents,
|
|
@@ -1006,10 +998,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1006
998
|
metadata: { hidden: true, createdAt: Date.now() } as MessageMetadata,
|
|
1007
999
|
}
|
|
1008
1000
|
throwIfRunAborted()
|
|
1009
|
-
await
|
|
1010
|
-
workstreamId: workstreamRef,
|
|
1011
|
-
messages: [bridgeMessage],
|
|
1012
|
-
})
|
|
1001
|
+
await threadMessageService.upsertMessages({ threadId: threadRef, messages: [bridgeMessage] })
|
|
1013
1002
|
currentMessages = upsertChatHistoryMessage(currentMessages, bridgeMessage)
|
|
1014
1003
|
throwIfRunAborted()
|
|
1015
1004
|
|
|
@@ -1033,13 +1022,12 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1033
1022
|
}
|
|
1034
1023
|
} finally {
|
|
1035
1024
|
try {
|
|
1036
|
-
const
|
|
1025
|
+
const latestThreadRecord = await threadService.getById(threadRef)
|
|
1037
1026
|
|
|
1038
1027
|
await finalizeTurnRun({
|
|
1039
1028
|
serverRunId,
|
|
1040
|
-
getEntity: async () =>
|
|
1041
|
-
getUncompactedMessages: (cursor) =>
|
|
1042
|
-
workstreamMessageService.listMessagesAfterCursor(workstreamRef, cursor),
|
|
1029
|
+
getEntity: async () => latestThreadRecord,
|
|
1030
|
+
getUncompactedMessages: (cursor) => threadMessageService.listMessagesAfterCursor(threadRef, cursor),
|
|
1043
1031
|
assessCompaction: (summaryText, messages) =>
|
|
1044
1032
|
contextCompactionRuntime.shouldCompactHistory({
|
|
1045
1033
|
summaryText,
|
|
@@ -1048,34 +1036,34 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1048
1036
|
}),
|
|
1049
1037
|
enqueueCompaction: async () => {
|
|
1050
1038
|
await enqueueContextCompaction({
|
|
1051
|
-
domain: '
|
|
1052
|
-
entityId:
|
|
1039
|
+
domain: 'thread',
|
|
1040
|
+
entityId: threadIdString,
|
|
1053
1041
|
contextSize: CONTEXT_WINDOW_TOKENS,
|
|
1054
1042
|
})
|
|
1055
1043
|
},
|
|
1056
1044
|
unregisterRun: (runId) => chatRunRegistry.unregister(runId),
|
|
1057
1045
|
clearActiveRunId: async (runId) => {
|
|
1058
|
-
const activeStreamId = await
|
|
1059
|
-
await
|
|
1046
|
+
const activeStreamId = await threadService.getActiveStreamId(threadRef)
|
|
1047
|
+
await threadService.clearActiveTurn(threadRef, { runId, streamId: activeStreamId })
|
|
1060
1048
|
},
|
|
1061
1049
|
disposeAbort: () => runAbort.dispose(),
|
|
1062
1050
|
activeStreamId: params.streamId,
|
|
1063
1051
|
clearActiveStreamId: async (streamId) => {
|
|
1064
|
-
const activeRunId = await
|
|
1052
|
+
const activeRunId = await threadService.getActiveRunId(threadRef)
|
|
1065
1053
|
if (!activeRunId) return
|
|
1066
|
-
await
|
|
1054
|
+
await threadService.clearActiveTurn(threadRef, { runId: activeRunId, streamId })
|
|
1067
1055
|
},
|
|
1068
1056
|
})
|
|
1069
1057
|
|
|
1070
1058
|
if (allAssistantMessages.length > 0 && shouldProcessPostRunSideEffects) {
|
|
1071
1059
|
await runPostTurnSideEffects({
|
|
1072
|
-
|
|
1073
|
-
|
|
1060
|
+
thread,
|
|
1061
|
+
threadRef,
|
|
1074
1062
|
orgRef,
|
|
1075
1063
|
userRef,
|
|
1076
1064
|
userName,
|
|
1077
1065
|
orgIdString,
|
|
1078
|
-
|
|
1066
|
+
threadIdString,
|
|
1079
1067
|
onboardingActive,
|
|
1080
1068
|
workspace,
|
|
1081
1069
|
allAssistantMessages,
|
|
@@ -1084,9 +1072,9 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1084
1072
|
loadRecentHistory,
|
|
1085
1073
|
listReadableUploads: () => listReadableUploads(),
|
|
1086
1074
|
memoryBlock,
|
|
1087
|
-
|
|
1075
|
+
visibleThreadAgentId,
|
|
1088
1076
|
defaultLeadAgentId,
|
|
1089
|
-
|
|
1077
|
+
latestThreadRecord,
|
|
1090
1078
|
isUserTurn: params.kind === 'userTurn',
|
|
1091
1079
|
agentDisplayNamesById: agentIdentityOverrides.displayNamesById,
|
|
1092
1080
|
})
|
|
@@ -1094,20 +1082,20 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1094
1082
|
|
|
1095
1083
|
if (allAssistantMessages.length > 0 && params.kind !== 'planTurn') {
|
|
1096
1084
|
await turnHooks.afterTurn?.({
|
|
1097
|
-
|
|
1098
|
-
|
|
1085
|
+
thread,
|
|
1086
|
+
threadRef,
|
|
1099
1087
|
orgRef,
|
|
1100
1088
|
userRef,
|
|
1101
1089
|
userName,
|
|
1102
1090
|
onboardingActive,
|
|
1103
1091
|
referenceUserMessage,
|
|
1104
1092
|
assistantMessages: allAssistantMessages,
|
|
1105
|
-
|
|
1093
|
+
latestThreadRecord,
|
|
1106
1094
|
context: buildContextResult,
|
|
1107
1095
|
})
|
|
1108
1096
|
}
|
|
1109
1097
|
} catch (postRunError) {
|
|
1110
|
-
aiLogger.error`
|
|
1098
|
+
aiLogger.error`Thread post-run cleanup failed: ${postRunError}`
|
|
1111
1099
|
}
|
|
1112
1100
|
}
|
|
1113
1101
|
}
|
|
@@ -1123,7 +1111,7 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1123
1111
|
}
|
|
1124
1112
|
|
|
1125
1113
|
try {
|
|
1126
|
-
return await
|
|
1114
|
+
return await threadService.withActiveRunLease(threadRef, async (leaseAbortSignal) => {
|
|
1127
1115
|
const runResult = await executeRun(leaseAbortSignal)
|
|
1128
1116
|
if (runResult) {
|
|
1129
1117
|
return runResult
|
|
@@ -1132,8 +1120,8 @@ export async function prepareWorkstreamRunCore(params: WorkstreamRunCoreParams):
|
|
|
1132
1120
|
return { inputMessageId: referenceUserMessage?.id, assistantMessages: [...allAssistantMessages] }
|
|
1133
1121
|
})
|
|
1134
1122
|
} catch (error) {
|
|
1135
|
-
if (error instanceof
|
|
1136
|
-
throw new
|
|
1123
|
+
if (error instanceof ActiveThreadRunConflictError) {
|
|
1124
|
+
throw new ThreadTurnError(error.message, 409)
|
|
1137
1125
|
}
|
|
1138
1126
|
throw error
|
|
1139
1127
|
}
|