@lota-sdk/core 0.1.14 → 0.1.16
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 +0 -2
- package/infrastructure/schema/01_memory.surql +1 -1
- package/infrastructure/schema/02_execution_plan.surql +62 -1
- package/infrastructure/schema/03_learned_skill.surql +1 -1
- package/infrastructure/schema/06_playbook.surql +25 -0
- package/infrastructure/schema/07_institutional_memory.surql +13 -0
- package/infrastructure/schema/08_quality_metrics.surql +17 -0
- package/package.json +9 -8
- package/src/ai/definitions.ts +80 -2
- package/src/ai/embedding-cache.ts +7 -6
- package/src/ai/index.ts +0 -1
- package/src/bifrost/bifrost.ts +14 -14
- package/src/config/agent-defaults.ts +32 -22
- package/src/config/agent-types.ts +11 -0
- package/src/config/constants.ts +2 -14
- package/src/config/debug-logger.ts +5 -1
- package/src/config/index.ts +3 -0
- package/src/config/logger.ts +7 -9
- package/src/config/model-constants.ts +16 -34
- package/src/config/search.ts +1 -15
- package/src/create-runtime.ts +453 -0
- package/src/db/cursor-pagination.ts +3 -6
- package/src/db/index.ts +2 -0
- package/src/db/memory-store.rows.ts +7 -7
- package/src/db/memory-store.ts +24 -24
- package/src/db/memory.ts +18 -16
- package/src/db/schema-fingerprint.ts +1 -0
- package/src/db/service.ts +193 -122
- package/src/db/startup.ts +9 -13
- package/src/db/surreal-mutation.ts +43 -0
- package/src/db/tables.ts +7 -0
- package/src/db/workstream-message-row.ts +15 -0
- package/src/embeddings/provider.ts +1 -1
- package/src/index.ts +1 -1
- package/src/queues/context-compaction.queue.ts +17 -52
- package/src/queues/delayed-node-promotion.queue.ts +41 -0
- package/src/queues/document-processor.queue.ts +7 -7
- package/src/queues/index.ts +3 -0
- package/src/queues/memory-consolidation.queue.ts +18 -54
- package/src/queues/plan-scheduler.queue.ts +97 -0
- package/src/queues/post-chat-memory.queue.ts +15 -60
- package/src/queues/queue-factory.ts +100 -0
- package/src/queues/recent-activity-title-refinement.queue.ts +15 -54
- package/src/queues/regular-chat-memory-digest.queue.ts +16 -55
- package/src/queues/skill-extraction.queue.ts +15 -50
- package/src/queues/workstream-title-generation.queue.ts +15 -51
- package/src/redis/connection.ts +12 -3
- package/src/redis/index.ts +2 -1
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +41 -8
- package/src/redis/stream-context.ts +11 -0
- package/src/runtime/agent-runtime-policy.ts +106 -21
- package/src/runtime/agent-stream-helpers.ts +2 -1
- package/src/runtime/approval-continuation.ts +12 -6
- package/src/runtime/context-compaction-constants.ts +1 -1
- package/src/runtime/context-compaction-runtime.ts +7 -5
- package/src/runtime/context-compaction.ts +40 -97
- package/src/runtime/execution-plan.ts +23 -19
- package/src/runtime/graph-designer.ts +15 -0
- package/src/runtime/helper-model.ts +10 -196
- package/src/runtime/index.ts +14 -1
- package/src/runtime/llm-content.ts +1 -1
- package/src/runtime/memory-block.ts +11 -12
- package/src/runtime/memory-pipeline.ts +26 -10
- package/src/runtime/plugin-resolution.ts +35 -0
- package/src/runtime/plugin-types.ts +73 -1
- package/src/runtime/retrieval-adapters.ts +1 -1
- package/src/runtime/runtime-config.ts +25 -12
- package/src/runtime/runtime-extensions.ts +91 -15
- package/src/runtime/runtime-worker-registry.ts +6 -0
- package/src/runtime/team-consultation-orchestrator.ts +45 -28
- package/src/runtime/team-consultation-prompts.ts +11 -2
- package/src/runtime/title-helpers.ts +11 -4
- package/src/runtime/workstream-chat-helpers.ts +6 -7
- package/src/runtime/workstream-routing-policy.ts +0 -30
- package/src/runtime/workstream-state.ts +17 -7
- package/src/services/adaptive-playbook.service.ts +152 -0
- package/src/services/agent-executor.service.ts +293 -0
- package/src/services/artifact-provenance.service.ts +172 -0
- package/src/services/attachment.service.ts +7 -12
- package/src/services/context-compaction.service.ts +75 -58
- package/src/services/context-enrichment.service.ts +33 -0
- package/src/services/coordination-registry.service.ts +117 -0
- package/src/services/document-chunk.service.ts +38 -33
- package/src/services/domain-agent-executor.service.ts +71 -0
- package/src/services/execution-plan.service.ts +271 -50
- package/src/services/feedback-loop.service.ts +96 -0
- package/src/services/global-orchestrator.service.ts +148 -0
- package/src/services/index.ts +26 -0
- package/src/services/institutional-memory.service.ts +145 -0
- package/src/services/learned-skill.service.ts +30 -15
- package/src/services/memory-assessment.service.ts +3 -2
- package/src/services/{memory.utils.ts → memory-utils.ts} +4 -13
- package/src/services/memory.service.ts +55 -69
- package/src/services/monitoring-window.service.ts +86 -0
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +155 -0
- package/src/services/notification.service.ts +39 -0
- package/src/services/organization-member.service.ts +12 -5
- package/src/services/organization.service.ts +5 -5
- package/src/services/ownership-dispatcher.service.ts +403 -0
- package/src/services/plan-approval.service.ts +1 -1
- package/src/services/plan-artifact.service.ts +1 -0
- package/src/services/plan-builder.service.ts +1 -0
- package/src/services/plan-checkpoint.service.ts +30 -2
- package/src/services/plan-compiler.service.ts +5 -0
- package/src/services/plan-coordination.service.ts +152 -0
- package/src/services/plan-cycle.service.ts +284 -0
- package/src/services/plan-deadline.service.ts +287 -0
- package/src/services/plan-executor.service.ts +386 -58
- package/src/services/plan-helpers.ts +15 -0
- package/src/services/plan-run.service.ts +41 -7
- package/src/services/plan-scheduler.service.ts +240 -0
- package/src/services/plan-template.service.ts +117 -0
- package/src/services/plan-validator.service.ts +87 -20
- package/src/services/plan-workspace.service.ts +83 -0
- package/src/services/playbook-registry.service.ts +67 -0
- package/src/services/plugin-executor.service.ts +103 -0
- package/src/services/quality-metrics.service.ts +132 -0
- package/src/services/recent-activity-title.service.ts +3 -10
- package/src/services/recent-activity.service.ts +33 -43
- package/src/services/skill-resolver.service.ts +19 -0
- package/src/services/system-executor.service.ts +105 -0
- package/src/services/workstream-message.service.ts +29 -41
- package/src/services/workstream-plan-registry.service.ts +22 -0
- package/src/services/workstream-title.service.ts +3 -9
- package/src/services/{workstream-turn-preparation.ts → workstream-turn-preparation.service.ts} +428 -373
- package/src/services/workstream-turn.ts +2 -2
- package/src/services/workstream.service.ts +55 -65
- package/src/services/workstream.types.ts +10 -19
- package/src/services/write-intent-validator.service.ts +81 -0
- package/src/storage/attachment-parser.ts +1 -1
- package/src/storage/attachment-storage.service.ts +4 -4
- package/src/storage/{attachments.utils.ts → attachment-utils.ts} +2 -5
- package/src/storage/generated-document-storage.service.ts +3 -2
- package/src/storage/index.ts +2 -2
- package/src/system-agents/{context-compacter.agent.ts → context-compaction.agent.ts} +4 -4
- package/src/system-agents/delegated-agent-factory.ts +5 -2
- package/src/system-agents/index.ts +8 -0
- package/src/system-agents/memory-reranker.agent.ts +1 -1
- package/src/system-agents/memory.agent.ts +1 -1
- package/src/system-agents/recent-activity-title-refiner.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +17 -19
- package/src/tools/fetch-webpage.tool.ts +20 -18
- package/src/tools/index.ts +2 -3
- package/src/tools/read-file-parts.tool.ts +1 -1
- package/src/tools/search-web.tool.ts +18 -15
- package/src/tools/{search-tools.ts → search.tool.ts} +1 -1
- package/src/tools/team-think.tool.ts +14 -8
- package/src/tools/{tool-contract.ts → tool-contracts.ts} +9 -2
- package/src/utils/async.ts +3 -2
- package/src/utils/date-time.ts +4 -32
- package/src/utils/env.ts +8 -0
- package/src/utils/errors.ts +47 -0
- package/src/utils/hono-error-handler.ts +1 -2
- package/src/utils/index.ts +19 -2
- package/src/utils/string.ts +128 -1
- package/src/workers/bootstrap.ts +2 -2
- package/src/workers/index.ts +1 -0
- package/src/workers/memory-consolidation.worker.ts +12 -12
- package/src/workers/regular-chat-memory-digest.helpers.ts +2 -7
- package/src/workers/regular-chat-memory-digest.runner.ts +11 -105
- package/src/workers/skill-extraction.runner.ts +8 -102
- package/src/workers/utils/file-section-chunker.ts +6 -3
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/sandbox-error.ts +11 -2
- package/src/workers/utils/workstream-message-query.ts +97 -0
- package/src/workers/worker-utils.ts +6 -2
- package/src/runtime/retrieval-pipeline.ts +0 -3
- package/src/runtime.ts +0 -387
- package/src/tools/log-hello-world.tool.ts +0 -17
- package/src/utils/error.ts +0 -10
- /package/src/services/{context-compaction-runtime.ts → context-compaction-runtime.singleton.ts} +0 -0
- /package/src/storage/{attachments.types.ts → attachment-types.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ToolSet } from 'ai'
|
|
2
2
|
|
|
3
3
|
import type { RecordIdRef } from '../db/record-id'
|
|
4
|
-
import type { ReadableUploadMetadata } from '../
|
|
4
|
+
import type { ReadableUploadMetadata } from '../storage/attachment-types'
|
|
5
5
|
import type { LotaRuntimeWorkerExtensions } from './runtime-worker-registry'
|
|
6
6
|
|
|
7
7
|
export interface LotaRuntimeBackgroundCursor {
|
|
@@ -34,7 +34,7 @@ export interface LotaRuntimeWorkspaceProvider {
|
|
|
34
34
|
): Promise<LotaRuntimeWorkspaceLifecycleState> | LotaRuntimeWorkspaceLifecycleState
|
|
35
35
|
readProfileProjectionState?(
|
|
36
36
|
workspace: Record<string, unknown>,
|
|
37
|
-
): Promise<LotaRuntimeWorkspaceProjectionState |
|
|
37
|
+
): Promise<LotaRuntimeWorkspaceProjectionState | undefined> | LotaRuntimeWorkspaceProjectionState | undefined
|
|
38
38
|
buildPromptSummary?(workspaceId: RecordIdRef): Promise<string | undefined>
|
|
39
39
|
listRecentDomainEvents?(workspaceId: RecordIdRef, limit?: number): Promise<Array<Record<string, unknown>>>
|
|
40
40
|
hasActiveKnowledgeSources?(workspaceId: string): Promise<boolean>
|
|
@@ -76,11 +76,87 @@ export interface LotaRuntimeTeamThinkToolsParams {
|
|
|
76
76
|
toolProviders?: ToolSet
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
export interface BuildContextParams {
|
|
80
|
+
workstream: unknown
|
|
81
|
+
workstreamRef: RecordIdRef
|
|
82
|
+
orgRef: RecordIdRef
|
|
83
|
+
userRef: RecordIdRef
|
|
84
|
+
userName?: string | null
|
|
85
|
+
workspace: Record<string, unknown>
|
|
86
|
+
onboardingActive: boolean
|
|
87
|
+
messageText: string
|
|
88
|
+
linearInstalled: boolean
|
|
89
|
+
githubInstalled: boolean
|
|
90
|
+
indexedRepoContext: unknown
|
|
91
|
+
promptContext: unknown
|
|
92
|
+
workspaceLifecycleState: unknown
|
|
93
|
+
workspaceProfileState: unknown
|
|
94
|
+
promptSummary: string | undefined
|
|
95
|
+
recentDomainEvents: Array<Record<string, unknown>>
|
|
96
|
+
retrievedKnowledgeSection: string | undefined
|
|
97
|
+
[key: string]: unknown
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface AfterTurnParams {
|
|
101
|
+
workstream: unknown
|
|
102
|
+
workstreamRef: RecordIdRef
|
|
103
|
+
orgRef: RecordIdRef
|
|
104
|
+
userRef: RecordIdRef
|
|
105
|
+
userName?: string | null
|
|
106
|
+
onboardingActive: boolean
|
|
107
|
+
referenceUserMessage: unknown
|
|
108
|
+
assistantMessages: unknown[]
|
|
109
|
+
latestWorkstreamRecord: unknown
|
|
110
|
+
latestPersistedState: unknown
|
|
111
|
+
context: Record<string, unknown> | null
|
|
112
|
+
[key: string]: unknown
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ResolveAgentParams {
|
|
116
|
+
agentId: string
|
|
117
|
+
mode: string
|
|
118
|
+
workstream: unknown
|
|
119
|
+
workstreamRef: RecordIdRef
|
|
120
|
+
orgRef: RecordIdRef
|
|
121
|
+
userRef: RecordIdRef
|
|
122
|
+
userName?: string | null
|
|
123
|
+
onboardingActive: boolean
|
|
124
|
+
linearInstalled: boolean
|
|
125
|
+
githubInstalled: boolean
|
|
126
|
+
reasoningProfile: string
|
|
127
|
+
skills?: string[]
|
|
128
|
+
additionalInstructionSections?: string[]
|
|
129
|
+
context: Record<string, unknown> | null
|
|
130
|
+
[key: string]: unknown
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface BuildExtraInstructionSectionsParams {
|
|
134
|
+
workstream: unknown
|
|
135
|
+
workstreamRef: RecordIdRef
|
|
136
|
+
orgRef: RecordIdRef
|
|
137
|
+
userRef: RecordIdRef
|
|
138
|
+
userName?: string | null
|
|
139
|
+
workspace: Record<string, unknown>
|
|
140
|
+
onboardingActive: boolean
|
|
141
|
+
messageText: string
|
|
142
|
+
linearInstalled: boolean
|
|
143
|
+
githubInstalled: boolean
|
|
144
|
+
indexedRepoContext: unknown
|
|
145
|
+
promptContext: unknown
|
|
146
|
+
workspaceLifecycleState: unknown
|
|
147
|
+
workspaceProfileState: unknown
|
|
148
|
+
promptSummary: string | undefined
|
|
149
|
+
recentDomainEvents: Array<Record<string, unknown>>
|
|
150
|
+
retrievedKnowledgeSection: string | undefined
|
|
151
|
+
context: Record<string, unknown> | null
|
|
152
|
+
[key: string]: unknown
|
|
153
|
+
}
|
|
154
|
+
|
|
79
155
|
export interface LotaRuntimeTurnHooks {
|
|
80
|
-
buildContext?: (params:
|
|
81
|
-
afterTurn?: (params:
|
|
82
|
-
resolveAgent?: (params:
|
|
83
|
-
buildExtraInstructionSections?: (params:
|
|
156
|
+
buildContext?: (params: BuildContextParams) => Promise<Record<string, unknown> | void>
|
|
157
|
+
afterTurn?: (params: AfterTurnParams) => Promise<void>
|
|
158
|
+
resolveAgent?: (params: ResolveAgentParams) => Promise<Record<string, unknown> | void>
|
|
159
|
+
buildExtraInstructionSections?: (params: BuildExtraInstructionSectionsParams) => Promise<string[] | void>
|
|
84
160
|
}
|
|
85
161
|
|
|
86
162
|
export interface LotaRuntimeAdapters {
|
|
@@ -90,8 +166,8 @@ export interface LotaRuntimeAdapters {
|
|
|
90
166
|
buildTeamThinkAgentTools?: (params: LotaRuntimeTeamThinkToolsParams) => Promise<{ tools: ToolSet }>
|
|
91
167
|
}
|
|
92
168
|
queues?: {
|
|
93
|
-
enqueuePostChatOrgAction?: (job: Record<string, unknown>) => Promise<void>
|
|
94
|
-
enqueueOnboardingRepoIndexFollowUp?: (job: Record<string, unknown>) => Promise<void>
|
|
169
|
+
enqueuePostChatOrgAction?: (job: Record<string, unknown>) => Promise<void>
|
|
170
|
+
enqueueOnboardingRepoIndexFollowUp?: (job: Record<string, unknown>) => Promise<void>
|
|
95
171
|
}
|
|
96
172
|
workers?: {
|
|
97
173
|
connectPluginDatabases?: () => Promise<void>
|
|
@@ -115,17 +191,17 @@ let runtimeExtensionsState: RuntimeExtensionsState = {
|
|
|
115
191
|
extraWorkers: {},
|
|
116
192
|
}
|
|
117
193
|
|
|
118
|
-
export function configureRuntimeExtensions(params
|
|
194
|
+
export function configureRuntimeExtensions(params: {
|
|
119
195
|
adapters?: LotaRuntimeAdapters
|
|
120
196
|
turnHooks?: LotaRuntimeTurnHooks
|
|
121
197
|
toolProviders?: ToolSet
|
|
122
198
|
extraWorkers?: LotaRuntimeWorkerExtensions
|
|
123
199
|
}): void {
|
|
124
200
|
runtimeExtensionsState = {
|
|
125
|
-
adapters: params
|
|
126
|
-
turnHooks: params
|
|
127
|
-
toolProviders: params
|
|
128
|
-
extraWorkers: params
|
|
201
|
+
adapters: params.adapters ?? {},
|
|
202
|
+
turnHooks: params.turnHooks ?? {},
|
|
203
|
+
toolProviders: params.toolProviders ?? EMPTY_TOOLS,
|
|
204
|
+
extraWorkers: params.extraWorkers ?? {},
|
|
129
205
|
}
|
|
130
206
|
}
|
|
131
207
|
|
|
@@ -148,8 +224,8 @@ export function getConfiguredPluginDatabaseConnector(): (() => Promise<void>) |
|
|
|
148
224
|
export async function withConfiguredWorkspaceMemoryLock<T>(workspaceId: string, fn: () => Promise<T>): Promise<T> {
|
|
149
225
|
const adapter = runtimeExtensionsState.adapters.workers?.withWorkspaceMemoryLock
|
|
150
226
|
if (!adapter) {
|
|
151
|
-
return
|
|
227
|
+
return fn()
|
|
152
228
|
}
|
|
153
229
|
|
|
154
|
-
return
|
|
230
|
+
return adapter(workspaceId, fn)
|
|
155
231
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { startContextCompactionWorker } from '../queues/context-compaction.queue'
|
|
2
|
+
import { startDelayedNodePromotionWorker } from '../queues/delayed-node-promotion.queue'
|
|
2
3
|
import { scheduleRecurringConsolidation, startMemoryConsolidationWorker } from '../queues/memory-consolidation.queue'
|
|
4
|
+
import { startPlanSchedulerWorker } from '../queues/plan-scheduler.queue'
|
|
3
5
|
import { startPostChatMemoryWorker } from '../queues/post-chat-memory.queue'
|
|
4
6
|
import { startRecentActivityTitleRefinementWorker } from '../queues/recent-activity-title-refinement.queue'
|
|
5
7
|
import { startRegularChatMemoryDigestWorker } from '../queues/regular-chat-memory-digest.queue'
|
|
@@ -8,7 +10,9 @@ import { startWorkstreamTitleGenerationWorker } from '../queues/workstream-title
|
|
|
8
10
|
|
|
9
11
|
export interface LotaRuntimeWorkerStartRegistry {
|
|
10
12
|
contextCompaction: typeof startContextCompactionWorker
|
|
13
|
+
delayedNodePromotion: typeof startDelayedNodePromotionWorker
|
|
11
14
|
memoryConsolidation: typeof startMemoryConsolidationWorker
|
|
15
|
+
planScheduler: typeof startPlanSchedulerWorker
|
|
12
16
|
postChatMemory: typeof startPostChatMemoryWorker
|
|
13
17
|
regularChatMemoryDigest: typeof startRegularChatMemoryDigestWorker
|
|
14
18
|
skillExtraction: typeof startSkillExtractionWorker
|
|
@@ -34,7 +38,9 @@ export function buildRuntimeWorkerRegistry(extraWorkers?: LotaRuntimeWorkerExten
|
|
|
34
38
|
return {
|
|
35
39
|
start: {
|
|
36
40
|
contextCompaction: startContextCompactionWorker,
|
|
41
|
+
delayedNodePromotion: startDelayedNodePromotionWorker,
|
|
37
42
|
memoryConsolidation: startMemoryConsolidationWorker,
|
|
43
|
+
planScheduler: startPlanSchedulerWorker,
|
|
38
44
|
postChatMemory: startPostChatMemoryWorker,
|
|
39
45
|
regularChatMemoryDigest: startRegularChatMemoryDigestWorker,
|
|
40
46
|
skillExtraction: startSkillExtractionWorker,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConsultTeamArgsSchema, withMessageCreatedAt } from '@lota-sdk/shared'
|
|
2
2
|
import type { ChatMessage, ConsultTeamResultData } from '@lota-sdk/shared'
|
|
3
|
-
import { convertToModelMessages,
|
|
3
|
+
import { convertToModelMessages, tool as createTool } from 'ai'
|
|
4
4
|
|
|
5
5
|
import { agentDisplayNames, teamConsultParticipants } from '../config/agent-defaults'
|
|
6
6
|
import { createTimedAbortSignal } from './agent-stream-helpers'
|
|
@@ -33,6 +33,28 @@ function getConsultTeamOutput(output: unknown): ConsultTeamResultData | undefine
|
|
|
33
33
|
return undefined
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function findLastUserMessage(
|
|
37
|
+
messages: ChatMessage[],
|
|
38
|
+
predicate: (message: ChatMessage) => boolean,
|
|
39
|
+
): ChatMessage | null {
|
|
40
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
41
|
+
const message = messages[index]
|
|
42
|
+
if (predicate(message)) {
|
|
43
|
+
return message
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function selectTeamConsultationContextMessages(messages: ChatMessage[], latestUserMessageId: string): ChatMessage[] {
|
|
51
|
+
const latestUserMessage =
|
|
52
|
+
findLastUserMessage(messages, (message) => message.id === latestUserMessageId && message.role === 'user') ??
|
|
53
|
+
findLastUserMessage(messages, (message) => message.role === 'user')
|
|
54
|
+
|
|
55
|
+
return latestUserMessage ? [latestUserMessage] : []
|
|
56
|
+
}
|
|
57
|
+
|
|
36
58
|
interface ParticipantObserver {
|
|
37
59
|
run<T>(fn: () => T | Promise<T>): Promise<T>
|
|
38
60
|
recordError?: (error: unknown) => void
|
|
@@ -51,6 +73,7 @@ export interface TeamConsultationParticipantRunner {
|
|
|
51
73
|
},
|
|
52
74
|
): Promise<{
|
|
53
75
|
agent: {
|
|
76
|
+
generate(params: Record<string, unknown>): Promise<{ text: string }>
|
|
54
77
|
stream(
|
|
55
78
|
params: Record<string, unknown>,
|
|
56
79
|
): Promise<{
|
|
@@ -119,16 +142,22 @@ export function createConsultTeamTool(params: CreateConsultTeamToolParams) {
|
|
|
119
142
|
})
|
|
120
143
|
const modelMessages = await convertToModelMessages(
|
|
121
144
|
buildModelInputMessagesWithUploadMetadata({
|
|
122
|
-
messages: params.historyMessages,
|
|
145
|
+
messages: selectTeamConsultationContextMessages(params.historyMessages, params.latestUserMessageId),
|
|
123
146
|
latestUserMessageId: params.latestUserMessageId,
|
|
124
147
|
uploadMetadataText,
|
|
125
148
|
}),
|
|
126
149
|
{ ignoreIncompleteToolCalls: true },
|
|
127
150
|
)
|
|
128
151
|
|
|
129
|
-
let result: Awaited<ReturnType<typeof agent.
|
|
152
|
+
let result: Awaited<ReturnType<typeof agent.generate>>
|
|
130
153
|
try {
|
|
131
|
-
result = await observer.run(() =>
|
|
154
|
+
result = await observer.run(() =>
|
|
155
|
+
agent.generate({
|
|
156
|
+
messages: modelMessages,
|
|
157
|
+
abortSignal: timedAbort.signal,
|
|
158
|
+
timeout: TEAM_CONSULTATION_TIMEOUT_MS,
|
|
159
|
+
}),
|
|
160
|
+
)
|
|
132
161
|
} catch (error) {
|
|
133
162
|
if (params.abortSignal.aborted || timedAbort.signal.aborted) {
|
|
134
163
|
observer.recordAbort?.(error)
|
|
@@ -138,33 +167,21 @@ export function createConsultTeamTool(params: CreateConsultTeamToolParams) {
|
|
|
138
167
|
throw error
|
|
139
168
|
}
|
|
140
169
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
generateMessageId: () => Bun.randomUUIDv7(),
|
|
144
|
-
sendReasoning: true,
|
|
145
|
-
sendSources: true,
|
|
146
|
-
sendStart: false,
|
|
147
|
-
sendFinish: false,
|
|
148
|
-
}) as ReadableStream<never>,
|
|
149
|
-
onError: (error) => {
|
|
150
|
-
params.onReadError?.(agentId, error)
|
|
151
|
-
},
|
|
152
|
-
})) {
|
|
153
|
-
latestMessage = withMessageCreatedAt(message)
|
|
154
|
-
responses[index] = {
|
|
155
|
-
agentId,
|
|
156
|
-
agentName,
|
|
157
|
-
status: 'running',
|
|
158
|
-
summary: extractMessageText(latestMessage).trim() || undefined,
|
|
159
|
-
message: latestMessage,
|
|
160
|
-
}
|
|
161
|
-
pushSnapshot()
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (!latestMessage) {
|
|
170
|
+
const responseText = result.text.trim()
|
|
171
|
+
if (!responseText) {
|
|
165
172
|
throw new Error(`Team participant ${agentId} did not produce a response.`)
|
|
166
173
|
}
|
|
167
174
|
|
|
175
|
+
latestMessage = withMessageCreatedAt(
|
|
176
|
+
{
|
|
177
|
+
id: Bun.randomUUIDv7(),
|
|
178
|
+
role: 'assistant',
|
|
179
|
+
parts: [{ type: 'text', text: responseText }],
|
|
180
|
+
metadata: { agentId, agentName },
|
|
181
|
+
} satisfies ChatMessage,
|
|
182
|
+
Date.now(),
|
|
183
|
+
)
|
|
184
|
+
|
|
168
185
|
responses[index] = {
|
|
169
186
|
agentId,
|
|
170
187
|
agentName,
|
|
@@ -3,12 +3,21 @@ import { agentDisplayNames, getLeadAgentDisplayName } from '../config/agent-defa
|
|
|
3
3
|
export function buildTeamConsultationResponseGuard(params: { agentId: string; task: string }) {
|
|
4
4
|
const agentName = agentDisplayNames[params.agentId] ?? params.agentId
|
|
5
5
|
const leadAgentDisplayName = getLeadAgentDisplayName()
|
|
6
|
+
const mentorConstraint =
|
|
7
|
+
params.agentId === 'mentor'
|
|
8
|
+
? ['- As Mentor, answer as an experienced operator reviewing launch discipline, not as a coach or therapist.']
|
|
9
|
+
: []
|
|
6
10
|
return [
|
|
7
11
|
'<team-consultation-agent-protocol>',
|
|
8
12
|
`- You are participating in a structured internal team consultation led by ${leadAgentDisplayName}.`,
|
|
9
13
|
`- Your role for this response is ${agentName}.`,
|
|
10
|
-
'-
|
|
11
|
-
'-
|
|
14
|
+
'- Chief is already coordinating this panel. Do not refer the task back to Chief or tell the user to consult another agent.',
|
|
15
|
+
'- Answer only from your role-specific perspective for the task below.',
|
|
16
|
+
'- Do not coach the user, ask follow-up questions, or challenge assumptions in this panel response. Give the recommendation directly.',
|
|
17
|
+
...mentorConstraint,
|
|
18
|
+
'- Return exactly 3 short markdown bullets in this order: recommendation, key risk/tradeoff, next decision.',
|
|
19
|
+
'- Keep the whole response under 120 words.',
|
|
20
|
+
'- Do not use headings, code fences, XML, evidence blocks, gap lists, or preamble text.',
|
|
12
21
|
'',
|
|
13
22
|
'<team-consultation-task>',
|
|
14
23
|
params.task.trim(),
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import { compactWhitespace, truncateText } from '../utils/string'
|
|
2
|
+
|
|
1
3
|
const TITLE_WORD_LIMIT = 5
|
|
2
4
|
|
|
3
5
|
export function limitTitleWords(text: string): string {
|
|
4
|
-
const words = text
|
|
6
|
+
const words = compactWhitespace(text).split(' ').filter(Boolean)
|
|
5
7
|
return words.slice(0, TITLE_WORD_LIMIT).join(' ')
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
export function deriveTitle(text: string): string {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
return truncateText(compactWhitespace(text), 60)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function normalizeTitle(value: string): string {
|
|
15
|
+
const normalized = compactWhitespace(value)
|
|
16
|
+
.replace(/^["'`]+|["'`]+$/g, '')
|
|
17
|
+
.replace(/[.!?,;:]+$/g, '')
|
|
18
|
+
return normalized.length <= 80 ? normalized : normalized.slice(0, 80).trim()
|
|
12
19
|
}
|
|
@@ -77,7 +77,7 @@ export function appendPersistedWorkstreamContextToHistoryMessages(
|
|
|
77
77
|
nextHistoryMessages.push({ role: 'agent', content: `Compacted chat summary:\n${compactionSummary}` })
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
if (params.persistedState !==
|
|
80
|
+
if (params.persistedState !== null && params.persistedState !== undefined) {
|
|
81
81
|
nextHistoryMessages.push({
|
|
82
82
|
role: 'agent',
|
|
83
83
|
content: `Structured workstream state:\n${JSON.stringify(params.persistedState)}`,
|
|
@@ -114,14 +114,13 @@ export function collectToolOutputErrors(params: {
|
|
|
114
114
|
if (typeof part !== 'object') continue
|
|
115
115
|
if (part.type !== undefined && typeof part.type !== 'string') continue
|
|
116
116
|
if (!part.type?.startsWith('tool-')) continue
|
|
117
|
-
|
|
117
|
+
|
|
118
|
+
const p = part as Record<string, unknown>
|
|
119
|
+
if (p.state !== 'output-error') continue
|
|
118
120
|
|
|
119
121
|
const toolName = part.type.slice('tool-'.length) || 'unknown'
|
|
120
|
-
const toolCallId =
|
|
121
|
-
|
|
122
|
-
? ((part as Record<string, unknown>).toolCallId as string)
|
|
123
|
-
: 'unknown'
|
|
124
|
-
const errorTextRaw = (part as Record<string, unknown>).errorText
|
|
122
|
+
const toolCallId = typeof p.toolCallId === 'string' && p.toolCallId ? p.toolCallId : 'unknown'
|
|
123
|
+
const errorTextRaw = p.errorText
|
|
125
124
|
const errorText =
|
|
126
125
|
typeof errorTextRaw === 'string' && errorTextRaw.trim()
|
|
127
126
|
? errorTextRaw.trim()
|
|
@@ -36,36 +36,6 @@ export function uniqueMentionOrder(message: string): string[] {
|
|
|
36
36
|
return ordered
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const GTM_STRONG_INTENT_PATTERNS: RegExp[] = [
|
|
40
|
-
/\bgo[-\s]?to[-\s]?market\b/i,
|
|
41
|
-
/\bgtm\b/i,
|
|
42
|
-
/\bcontent\s+marketing\b/i,
|
|
43
|
-
/\bcontent\s+strategy\b/i,
|
|
44
|
-
/\bdemand\s+generation\b/i,
|
|
45
|
-
/\bdistribution\s+strategy\b/i,
|
|
46
|
-
/\bpositioning\s+strategy\b/i,
|
|
47
|
-
/\blaunch\s+strategy\b/i,
|
|
48
|
-
/\blaunch\s+plan\b/i,
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
const GTM_WEAK_INTENT_PATTERNS: RegExp[] = [/\blaunch\b/i, /\bcommunity\b/i, /\bdistribution\b/i, /\bpositioning\b/i]
|
|
52
|
-
|
|
53
|
-
export function isGtmIntentMessage(message: string): boolean {
|
|
54
|
-
const text = message.trim()
|
|
55
|
-
if (!text) return false
|
|
56
|
-
|
|
57
|
-
if (GTM_STRONG_INTENT_PATTERNS.some((pattern) => pattern.test(text))) {
|
|
58
|
-
return true
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let weakMatches = 0
|
|
62
|
-
for (const pattern of GTM_WEAK_INTENT_PATTERNS) {
|
|
63
|
-
if (pattern.test(text)) weakMatches += 1
|
|
64
|
-
if (weakMatches >= 2) return true
|
|
65
|
-
}
|
|
66
|
-
return false
|
|
67
|
-
}
|
|
68
|
-
|
|
69
39
|
const HIGH_IMPACT_CLASS_PATTERNS: Array<{ className: HighImpactResponseClass; patterns: RegExp[] }> = [
|
|
70
40
|
{
|
|
71
41
|
className: 'architecture-recommendation',
|
|
@@ -238,13 +238,23 @@ export interface CompactionOutput {
|
|
|
238
238
|
stateDelta: WorkstreamStateDelta
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
241
|
+
const WORKSTREAM_STATE_MAX_KEY_DECISIONS = 8
|
|
242
|
+
const WORKSTREAM_STATE_MAX_ACTIVE_CONSTRAINTS = 6
|
|
243
|
+
const WORKSTREAM_STATE_MAX_TASKS = 10
|
|
244
|
+
const WORKSTREAM_STATE_MAX_OPEN_QUESTIONS = 5
|
|
245
|
+
const WORKSTREAM_STATE_MAX_RISKS = 5
|
|
246
|
+
const WORKSTREAM_STATE_MAX_ARTIFACTS = 10
|
|
247
|
+
const WORKSTREAM_STATE_MAX_AGENT_CONTRIBUTIONS = 6
|
|
248
|
+
|
|
249
|
+
export function applyWorkstreamStateCaps(state: WorkstreamState): void {
|
|
250
|
+
state.keyDecisions = state.keyDecisions.slice(-WORKSTREAM_STATE_MAX_KEY_DECISIONS)
|
|
251
|
+
state.activeConstraints = state.activeConstraints.slice(-WORKSTREAM_STATE_MAX_ACTIVE_CONSTRAINTS)
|
|
252
|
+
state.tasks = state.tasks.slice(-WORKSTREAM_STATE_MAX_TASKS)
|
|
253
|
+
state.openQuestions = state.openQuestions.slice(-WORKSTREAM_STATE_MAX_OPEN_QUESTIONS)
|
|
254
|
+
state.risks = state.risks.slice(-WORKSTREAM_STATE_MAX_RISKS)
|
|
255
|
+
state.artifacts = state.artifacts.slice(-WORKSTREAM_STATE_MAX_ARTIFACTS)
|
|
256
|
+
state.agentContributions = state.agentContributions.slice(-WORKSTREAM_STATE_MAX_AGENT_CONTRIBUTIONS)
|
|
257
|
+
}
|
|
248
258
|
|
|
249
259
|
export function createEmptyWorkstreamState(now = Date.now()): WorkstreamState {
|
|
250
260
|
return {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { PlaybookVersion, Recommendation } from '@lota-sdk/shared'
|
|
2
|
+
import { PlaybookSchema, PlaybookVersionSchema } from '@lota-sdk/shared'
|
|
3
|
+
|
|
4
|
+
import { ensureRecordId, recordIdToString } from '../db/record-id'
|
|
5
|
+
import { databaseService } from '../db/service'
|
|
6
|
+
import { TABLES } from '../db/tables'
|
|
7
|
+
|
|
8
|
+
class AdaptivePlaybookService {
|
|
9
|
+
async refineFromCycle(params: {
|
|
10
|
+
playbookId: string
|
|
11
|
+
runId: string
|
|
12
|
+
recommendations: Recommendation[]
|
|
13
|
+
organizationId: string
|
|
14
|
+
}): Promise<PlaybookVersion> {
|
|
15
|
+
const playbook = await databaseService.findOne(
|
|
16
|
+
TABLES.PLAYBOOK,
|
|
17
|
+
{ id: ensureRecordId(params.playbookId, TABLES.PLAYBOOK) },
|
|
18
|
+
PlaybookSchema,
|
|
19
|
+
)
|
|
20
|
+
if (!playbook) {
|
|
21
|
+
throw new Error(`Playbook not found: ${params.playbookId}`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const currentVersion = await databaseService.findOne(
|
|
25
|
+
TABLES.PLAYBOOK_VERSION,
|
|
26
|
+
{
|
|
27
|
+
id: ensureRecordId(
|
|
28
|
+
recordIdToString(playbook.currentVersionId, TABLES.PLAYBOOK_VERSION),
|
|
29
|
+
TABLES.PLAYBOOK_VERSION,
|
|
30
|
+
),
|
|
31
|
+
},
|
|
32
|
+
PlaybookVersionSchema,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const nextVersionNumber = currentVersion ? currentVersion.version + 1 : 1
|
|
36
|
+
const now = new Date()
|
|
37
|
+
|
|
38
|
+
const newVersion = await databaseService.create(
|
|
39
|
+
TABLES.PLAYBOOK_VERSION,
|
|
40
|
+
{
|
|
41
|
+
playbookId: ensureRecordId(params.playbookId, TABLES.PLAYBOOK),
|
|
42
|
+
version: nextVersionNumber,
|
|
43
|
+
parentVersionId: playbook.currentVersionId,
|
|
44
|
+
appliedRecommendations: params.recommendations.map((r) => r.description),
|
|
45
|
+
status: 'testing',
|
|
46
|
+
createdAt: now,
|
|
47
|
+
},
|
|
48
|
+
PlaybookVersionSchema,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
await databaseService.update(
|
|
52
|
+
TABLES.PLAYBOOK,
|
|
53
|
+
ensureRecordId(params.playbookId, TABLES.PLAYBOOK),
|
|
54
|
+
{
|
|
55
|
+
currentVersionId: newVersion.id,
|
|
56
|
+
previousVersionId: playbook.currentVersionId,
|
|
57
|
+
cycleCount: playbook.cycleCount + 1,
|
|
58
|
+
},
|
|
59
|
+
PlaybookSchema,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return newVersion
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
evaluateRegression(params: { currentScore: number; previousScore: number; threshold?: number }): {
|
|
66
|
+
shouldRollback: boolean
|
|
67
|
+
} {
|
|
68
|
+
const threshold = params.threshold ?? 0.9
|
|
69
|
+
if (params.previousScore === 0) return { shouldRollback: false }
|
|
70
|
+
return { shouldRollback: params.currentScore < params.previousScore * threshold }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async rollback(params: {
|
|
74
|
+
playbookId: string
|
|
75
|
+
organizationId: string
|
|
76
|
+
maxLevels?: number
|
|
77
|
+
}): Promise<PlaybookVersion | null> {
|
|
78
|
+
const maxLevels = params.maxLevels ?? 3
|
|
79
|
+
return this.rollbackRecursive(params.playbookId, params.organizationId, maxLevels)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private async rollbackRecursive(
|
|
83
|
+
playbookId: string,
|
|
84
|
+
organizationId: string,
|
|
85
|
+
remainingLevels: number,
|
|
86
|
+
): Promise<PlaybookVersion | null> {
|
|
87
|
+
if (remainingLevels <= 0) return null
|
|
88
|
+
|
|
89
|
+
const playbook = await databaseService.findOne(
|
|
90
|
+
TABLES.PLAYBOOK,
|
|
91
|
+
{ id: ensureRecordId(playbookId, TABLES.PLAYBOOK) },
|
|
92
|
+
PlaybookSchema,
|
|
93
|
+
)
|
|
94
|
+
if (!playbook) return null
|
|
95
|
+
|
|
96
|
+
const currentVersion = await databaseService.findOne(
|
|
97
|
+
TABLES.PLAYBOOK_VERSION,
|
|
98
|
+
{
|
|
99
|
+
id: ensureRecordId(
|
|
100
|
+
recordIdToString(playbook.currentVersionId, TABLES.PLAYBOOK_VERSION),
|
|
101
|
+
TABLES.PLAYBOOK_VERSION,
|
|
102
|
+
),
|
|
103
|
+
},
|
|
104
|
+
PlaybookVersionSchema,
|
|
105
|
+
)
|
|
106
|
+
if (!currentVersion?.parentVersionId) return null
|
|
107
|
+
|
|
108
|
+
// Mark current version as rolled-back
|
|
109
|
+
await databaseService.update(
|
|
110
|
+
TABLES.PLAYBOOK_VERSION,
|
|
111
|
+
ensureRecordId(recordIdToString(currentVersion.id, TABLES.PLAYBOOK_VERSION), TABLES.PLAYBOOK_VERSION),
|
|
112
|
+
{ status: 'rolled-back' },
|
|
113
|
+
PlaybookVersionSchema,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
// Restore parent version as active
|
|
117
|
+
const parentVersion = await databaseService.findOne(
|
|
118
|
+
TABLES.PLAYBOOK_VERSION,
|
|
119
|
+
{
|
|
120
|
+
id: ensureRecordId(
|
|
121
|
+
recordIdToString(currentVersion.parentVersionId, TABLES.PLAYBOOK_VERSION),
|
|
122
|
+
TABLES.PLAYBOOK_VERSION,
|
|
123
|
+
),
|
|
124
|
+
},
|
|
125
|
+
PlaybookVersionSchema,
|
|
126
|
+
)
|
|
127
|
+
if (!parentVersion) return null
|
|
128
|
+
|
|
129
|
+
await databaseService.update(
|
|
130
|
+
TABLES.PLAYBOOK_VERSION,
|
|
131
|
+
ensureRecordId(recordIdToString(parentVersion.id, TABLES.PLAYBOOK_VERSION), TABLES.PLAYBOOK_VERSION),
|
|
132
|
+
{ status: 'active' },
|
|
133
|
+
PlaybookVersionSchema,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
await databaseService.update(
|
|
137
|
+
TABLES.PLAYBOOK,
|
|
138
|
+
ensureRecordId(playbookId, TABLES.PLAYBOOK),
|
|
139
|
+
{ currentVersionId: parentVersion.id, previousVersionId: parentVersion.parentVersionId },
|
|
140
|
+
PlaybookSchema,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
// Check if parent version is also regressed (caller can evaluate and re-invoke)
|
|
144
|
+
if (parentVersion.qualityScore !== undefined && parentVersion.qualityScore < 0.5) {
|
|
145
|
+
return this.rollbackRecursive(playbookId, organizationId, remainingLevels - 1)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return parentVersion
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const adaptivePlaybookService = new AdaptivePlaybookService()
|