@lota-sdk/core 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -12
- package/src/ai/embedding-cache.ts +96 -22
- package/src/ai-gateway/ai-gateway.ts +766 -223
- package/src/config/agent-defaults.ts +189 -75
- package/src/config/agent-types.ts +54 -4
- package/src/config/background-processing.ts +1 -1
- package/src/config/constants.ts +8 -2
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +299 -19
- package/src/config/thread-defaults.ts +40 -20
- package/src/create-runtime.ts +200 -449
- package/src/db/base.service.ts +52 -28
- package/src/db/cursor-pagination.ts +71 -30
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.helpers.ts +4 -7
- package/src/db/memory-store.ts +868 -601
- package/src/db/memory.ts +396 -280
- package/src/db/record-id.ts +32 -10
- package/src/db/schema-fingerprint.ts +30 -12
- package/src/db/service-normalization.ts +288 -0
- package/src/db/service.ts +912 -779
- package/src/db/startup.ts +153 -68
- package/src/db/transaction-conflict.ts +15 -0
- package/src/effect/awaitable-effect.ts +96 -0
- package/src/effect/errors.ts +121 -0
- package/src/effect/helpers.ts +123 -0
- package/src/effect/index.ts +24 -0
- package/src/effect/layers.ts +238 -0
- package/src/effect/runtime-ref.ts +25 -0
- package/src/effect/runtime.ts +46 -0
- package/src/effect/services.ts +61 -0
- package/src/effect/zod.ts +43 -0
- package/src/embeddings/provider.ts +128 -83
- package/src/index.ts +48 -1
- package/src/openrouter/direct-provider.ts +11 -35
- package/src/queues/autonomous-job.queue.ts +117 -73
- package/src/queues/context-compaction.queue.ts +50 -17
- package/src/queues/delayed-node-promotion.queue.ts +46 -17
- package/src/queues/document-processor.queue.ts +52 -77
- package/src/queues/memory-consolidation.queue.ts +47 -32
- package/src/queues/organization-learning.queue.ts +26 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +71 -24
- package/src/queues/plan-scheduler.queue.ts +97 -33
- package/src/queues/post-chat-memory.queue.ts +56 -26
- package/src/queues/queue-factory.ts +227 -59
- package/src/queues/standalone-worker.ts +39 -0
- package/src/queues/title-generation.queue.ts +45 -11
- package/src/redis/connection.ts +182 -113
- package/src/redis/index.ts +6 -8
- package/src/redis/org-memory-lock.ts +60 -27
- package/src/redis/redis-lease-lock.ts +200 -121
- package/src/redis/runtime-connection.ts +20 -0
- package/src/redis/stream-context.ts +92 -46
- package/src/runtime/agent-identity-overrides.ts +2 -2
- package/src/runtime/agent-runtime-policy.ts +5 -2
- package/src/runtime/agent-stream-helpers.ts +24 -9
- package/src/runtime/chat-run-orchestration.ts +102 -19
- package/src/runtime/chat-run-registry.ts +36 -2
- package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
- package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +161 -94
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/execution-plan-visibility.ts +2 -2
- package/src/runtime/execution-plan.ts +42 -15
- package/src/runtime/graph-designer.ts +16 -4
- package/src/runtime/helper-model.ts +139 -48
- package/src/runtime/index.ts +7 -8
- package/src/runtime/indexed-repositories-policy.ts +3 -3
- package/src/runtime/{memory-block.ts → memory/memory-block.ts} +50 -36
- package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
- package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +54 -67
- package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
- package/src/runtime/memory/memory-scope.ts +53 -0
- package/src/runtime/plugin-resolution.ts +124 -25
- package/src/runtime/plugin-types.ts +9 -1
- package/src/runtime/post-turn-side-effects.ts +177 -130
- package/src/runtime/retrieval-adapters.ts +40 -6
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +150 -61
- package/src/runtime/runtime-extensions.ts +23 -25
- package/src/runtime/runtime-lifecycle.ts +124 -0
- package/src/runtime/runtime-services.ts +386 -0
- package/src/runtime/runtime-token.ts +47 -0
- package/src/runtime/social-chat/social-chat-agent-runner.ts +159 -0
- package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +51 -20
- package/src/runtime/social-chat/social-chat.ts +630 -0
- package/src/runtime/specialist-runner.ts +36 -10
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +433 -0
- package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
- package/src/runtime/thread-chat-helpers.ts +2 -2
- package/src/runtime/thread-plan-turn.ts +2 -1
- package/src/runtime/thread-turn-context.ts +183 -111
- package/src/runtime/turn-lifecycle.ts +93 -27
- package/src/services/agent-activity.service.ts +287 -203
- package/src/services/agent-executor.service.ts +253 -149
- package/src/services/artifact.service.ts +231 -149
- package/src/services/attachment.service.ts +171 -115
- package/src/services/autonomous-job.service.ts +890 -491
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +13 -1
- package/src/services/context-compaction.service.ts +136 -86
- package/src/services/document-chunk.service.ts +151 -88
- package/src/services/execution-plan/execution-plan-approval.ts +26 -0
- package/src/services/execution-plan/execution-plan-context.ts +29 -0
- package/src/services/execution-plan/execution-plan-graph.ts +278 -0
- package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
- package/src/services/execution-plan/execution-plan-spec.ts +75 -0
- package/src/services/execution-plan/execution-plan.service.ts +1041 -0
- package/src/services/feedback-loop.service.ts +132 -76
- package/src/services/global-orchestrator.service.ts +101 -168
- package/src/services/graph-full-routing.ts +193 -0
- package/src/services/index.ts +19 -21
- package/src/services/institutional-memory.service.ts +213 -125
- package/src/services/learned-skill.service.ts +368 -260
- package/src/services/memory/memory-conversation.ts +95 -0
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +50 -0
- package/src/services/memory/memory-preseeded.ts +86 -0
- package/src/services/memory/memory-rerank.ts +297 -0
- package/src/services/{memory-utils.ts → memory/memory-utils.ts} +6 -5
- package/src/services/memory/memory.service.ts +674 -0
- package/src/services/memory/rerank.service.ts +201 -0
- package/src/services/monitoring-window.service.ts +92 -70
- package/src/services/mutating-approval.service.ts +62 -53
- package/src/services/node-workspace.service.ts +141 -98
- package/src/services/notification.service.ts +29 -16
- package/src/services/organization-member.service.ts +120 -66
- package/src/services/organization.service.ts +153 -77
- package/src/services/ownership-dispatcher.service.ts +456 -263
- package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
- package/src/services/plan/plan-agent-query.service.ts +322 -0
- package/src/services/{plan-approval.service.ts → plan/plan-approval.service.ts} +45 -22
- package/src/services/plan/plan-artifact.service.ts +60 -0
- package/src/services/plan/plan-builder.service.ts +76 -0
- package/src/services/plan/plan-checkpoint.service.ts +103 -0
- package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
- package/src/services/plan/plan-completion-side-effects.ts +169 -0
- package/src/services/plan/plan-coordination.service.ts +181 -0
- package/src/services/plan/plan-cycle.service.ts +405 -0
- package/src/services/plan/plan-deadline.service.ts +533 -0
- package/src/services/plan/plan-event-delivery.service.ts +266 -0
- package/src/services/plan/plan-executor-context.ts +35 -0
- package/src/services/plan/plan-executor-graph.ts +522 -0
- package/src/services/plan/plan-executor-helpers.ts +307 -0
- package/src/services/plan/plan-executor-persistence.ts +209 -0
- package/src/services/plan/plan-executor.service.ts +1737 -0
- package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
- package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
- package/src/services/plan/plan-run-serialization.ts +15 -0
- package/src/services/plan/plan-run.service.ts +637 -0
- package/src/services/plan/plan-scheduler.service.ts +379 -0
- package/src/services/plan/plan-template.service.ts +224 -0
- package/src/services/plan/plan-transaction-events.ts +36 -0
- package/src/services/plan/plan-validator.service.ts +907 -0
- package/src/services/plan/plan-workspace.service.ts +131 -0
- package/src/services/plugin-executor.service.ts +102 -68
- package/src/services/quality-metrics.service.ts +112 -94
- package/src/services/queue-job.service.ts +288 -231
- package/src/services/recent-activity-title.service.ts +73 -36
- package/src/services/recent-activity.service.ts +274 -259
- package/src/services/skill-resolver.service.ts +38 -12
- package/src/services/social-chat-history.service.ts +190 -122
- package/src/services/system-executor.service.ts +96 -61
- package/src/services/thread/thread-active-run.ts +203 -0
- package/src/services/thread/thread-bootstrap.ts +385 -0
- package/src/services/thread/thread-listing.ts +199 -0
- package/src/services/thread/thread-memory-block.ts +130 -0
- package/src/services/thread/thread-message.service.ts +379 -0
- package/src/services/thread/thread-record-store.ts +155 -0
- package/src/services/thread/thread-title.service.ts +74 -0
- package/src/services/thread/thread-turn-execution.ts +280 -0
- package/src/services/thread/thread-turn-message-context.ts +73 -0
- package/src/services/thread/thread-turn-preparation.service.ts +1148 -0
- package/src/services/thread/thread-turn-streaming.ts +403 -0
- package/src/services/thread/thread-turn-tracing.ts +35 -0
- package/src/services/thread/thread-turn.ts +376 -0
- package/src/services/thread/thread.service.ts +344 -0
- package/src/services/user.service.ts +82 -32
- package/src/services/write-intent-validator.service.ts +63 -51
- package/src/storage/attachment-parser.ts +69 -27
- package/src/storage/attachment-storage.service.ts +334 -275
- package/src/storage/generated-document-storage.service.ts +66 -34
- package/src/system-agents/agent-result.ts +3 -1
- package/src/system-agents/context-compaction.agent.ts +3 -3
- package/src/system-agents/delegated-agent-factory.ts +159 -90
- package/src/system-agents/helper-agent-options.ts +1 -1
- package/src/system-agents/memory-reranker.agent.ts +3 -3
- package/src/system-agents/memory.agent.ts +3 -3
- package/src/system-agents/recent-activity-title-refiner.agent.ts +3 -3
- package/src/system-agents/regular-chat-memory-digest.agent.ts +3 -3
- package/src/system-agents/skill-extractor.agent.ts +3 -3
- package/src/system-agents/skill-manager.agent.ts +3 -3
- package/src/system-agents/thread-router.agent.ts +157 -113
- package/src/system-agents/title-generator.agent.ts +3 -3
- package/src/tools/execution-plan.tool.ts +241 -171
- package/src/tools/fetch-webpage.tool.ts +29 -18
- package/src/tools/firecrawl-client.ts +26 -6
- package/src/tools/index.ts +1 -0
- package/src/tools/memory-block.tool.ts +14 -6
- package/src/tools/plan-approval.tool.ts +57 -47
- package/src/tools/read-file-parts.tool.ts +44 -33
- package/src/tools/remember-memory.tool.ts +65 -45
- package/src/tools/search-web.tool.ts +33 -22
- package/src/tools/search.tool.ts +41 -29
- package/src/tools/team-think.tool.ts +125 -84
- package/src/tools/user-questions.tool.ts +4 -3
- package/src/tools/web-tool-shared.ts +6 -0
- package/src/utils/async.ts +25 -22
- package/src/utils/crypto.ts +21 -0
- package/src/utils/date-time.ts +40 -1
- package/src/utils/errors.ts +111 -20
- package/src/utils/hono-error-handler.ts +24 -39
- package/src/utils/index.ts +2 -1
- package/src/utils/null-proto-record.ts +41 -0
- package/src/utils/sse-keepalive.ts +124 -21
- package/src/workers/bootstrap.ts +164 -52
- package/src/workers/memory-consolidation.worker.ts +325 -237
- package/src/workers/organization-learning.worker.ts +50 -16
- package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
- package/src/workers/regular-chat-memory-digest.runner.ts +185 -114
- package/src/workers/skill-extraction.runner.ts +176 -93
- package/src/workers/utils/file-section-chunker.ts +8 -10
- package/src/workers/utils/repo-structure-extractor.ts +349 -260
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/thread-message-query.ts +97 -38
- package/src/workers/worker-utils.ts +74 -31
- package/src/config/debug-logger.ts +0 -47
- package/src/config/search.ts +0 -3
- package/src/redis/connection-accessor.ts +0 -26
- package/src/runtime/agent-types.ts +0 -1
- package/src/runtime/context-compaction-runtime.ts +0 -87
- package/src/runtime/memory-scope.ts +0 -43
- package/src/runtime/social-chat-agent-runner.ts +0 -118
- package/src/runtime/social-chat.ts +0 -516
- package/src/runtime/team-consultation-orchestrator.ts +0 -272
- package/src/services/adaptive-playbook.service.ts +0 -152
- package/src/services/artifact-provenance.service.ts +0 -172
- package/src/services/chat-attachments.service.ts +0 -17
- package/src/services/context-compaction-runtime.singleton.ts +0 -13
- package/src/services/execution-plan.service.ts +0 -1118
- package/src/services/memory.service.ts +0 -914
- package/src/services/plan-agent-heartbeat.service.ts +0 -136
- package/src/services/plan-agent-query.service.ts +0 -267
- package/src/services/plan-artifact.service.ts +0 -50
- package/src/services/plan-builder.service.ts +0 -67
- package/src/services/plan-checkpoint.service.ts +0 -81
- package/src/services/plan-completion-side-effects.ts +0 -80
- package/src/services/plan-coordination.service.ts +0 -157
- package/src/services/plan-cycle.service.ts +0 -284
- package/src/services/plan-deadline.service.ts +0 -430
- package/src/services/plan-event-delivery.service.ts +0 -166
- package/src/services/plan-executor.service.ts +0 -1950
- package/src/services/plan-run.service.ts +0 -515
- package/src/services/plan-scheduler.service.ts +0 -240
- package/src/services/plan-template.service.ts +0 -177
- package/src/services/plan-validator.service.ts +0 -818
- package/src/services/plan-workspace.service.ts +0 -83
- package/src/services/rerank.service.ts +0 -156
- package/src/services/thread-message.service.ts +0 -275
- package/src/services/thread-plan-registry.service.ts +0 -22
- package/src/services/thread-title.service.ts +0 -39
- package/src/services/thread-turn-preparation.service.ts +0 -1147
- package/src/services/thread-turn.ts +0 -172
- package/src/services/thread.service.ts +0 -869
- package/src/utils/env.ts +0 -8
- /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
- /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
- /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
- /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
- /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
- /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
- /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
- /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { ConsultTeamArgsSchema, withMessageCreatedAt } from '@lota-sdk/shared'
|
|
2
|
+
import type { ChatMessage, ConsultTeamResultData } from '@lota-sdk/shared'
|
|
3
|
+
import { convertToModelMessages, tool as createTool } from 'ai'
|
|
4
|
+
import { Schema, Deferred, Effect, Exit, Fiber, Queue, Ref, Scope } from 'effect'
|
|
5
|
+
|
|
6
|
+
import { getAgentDisplayNames, getTeamConsultParticipants } from '../../config/agent-defaults'
|
|
7
|
+
import { nowEpochMillis } from '../../utils/date-time'
|
|
8
|
+
import { createTimedAbortSignal } from '../agent-stream-helpers'
|
|
9
|
+
import { buildModelInputMessagesWithUploadMetadata, buildReadableUploadMetadataText } from '../chat-attachments'
|
|
10
|
+
import type { ReadableUploadMetadataLike } from '../chat-attachments'
|
|
11
|
+
import type { RepoSectionName } from '../indexed-repositories-policy'
|
|
12
|
+
import { extractMessageText } from '../thread-chat-helpers'
|
|
13
|
+
import { buildTeamConsultationFailureMessage } from './team-consultation-prompts'
|
|
14
|
+
|
|
15
|
+
export type DefaultRepoSections = RepoSectionName[]
|
|
16
|
+
const TEAM_CONSULTATION_TIMEOUT_MS = 90_000
|
|
17
|
+
|
|
18
|
+
class TeamConsultationError extends Schema.TaggedErrorClass<TeamConsultationError>()('TeamConsultationError', {
|
|
19
|
+
message: Schema.String,
|
|
20
|
+
cause: Schema.optional(Schema.Defect),
|
|
21
|
+
}) {}
|
|
22
|
+
|
|
23
|
+
function buildSnapshot(responses: ConsultTeamResultData['responses']): ConsultTeamResultData {
|
|
24
|
+
return { responses: responses.map((response) => ({ ...response })) }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getConsultTeamOutput(output: unknown): ConsultTeamResultData | undefined {
|
|
28
|
+
if (output && typeof output === 'object' && Array.isArray((output as { responses?: unknown }).responses)) {
|
|
29
|
+
return output as ConsultTeamResultData
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (Array.isArray(output)) {
|
|
33
|
+
for (let index = output.length - 1; index >= 0; index -= 1) {
|
|
34
|
+
const candidate = getConsultTeamOutput(output[index])
|
|
35
|
+
if (candidate) return candidate
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function findLastUserMessage(
|
|
43
|
+
messages: ChatMessage[],
|
|
44
|
+
predicate: (message: ChatMessage) => boolean,
|
|
45
|
+
): ChatMessage | null {
|
|
46
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
47
|
+
const message = messages[index]
|
|
48
|
+
if (predicate(message)) {
|
|
49
|
+
return message
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function selectTeamConsultationContextMessages(messages: ChatMessage[], latestUserMessageId: string): ChatMessage[] {
|
|
57
|
+
const latestUserMessage =
|
|
58
|
+
findLastUserMessage(messages, (message) => message.id === latestUserMessageId && message.role === 'user') ??
|
|
59
|
+
findLastUserMessage(messages, (message) => message.role === 'user')
|
|
60
|
+
|
|
61
|
+
return latestUserMessage ? [latestUserMessage] : []
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ParticipantObserver {
|
|
65
|
+
run<T>(fn: () => T | Promise<T>): Promise<T>
|
|
66
|
+
recordError?: (error: unknown) => void
|
|
67
|
+
recordAbort?: (error: unknown) => void
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface TeamConsultationParticipantRunner {
|
|
71
|
+
buildParticipantAgent(
|
|
72
|
+
agentId: string,
|
|
73
|
+
params: {
|
|
74
|
+
task: string
|
|
75
|
+
systemWorkspaceDetails?: string
|
|
76
|
+
preSeededMemoriesSection?: string
|
|
77
|
+
retrievedKnowledgeSection?: string
|
|
78
|
+
},
|
|
79
|
+
): Promise<{
|
|
80
|
+
agent: {
|
|
81
|
+
generate(params: Record<string, unknown>): Promise<{ text: string }>
|
|
82
|
+
stream(
|
|
83
|
+
params: Record<string, unknown>,
|
|
84
|
+
): Promise<{
|
|
85
|
+
consumeStream(): unknown
|
|
86
|
+
toUIMessageStream(options: Record<string, unknown>): ReadableStream<unknown>
|
|
87
|
+
}>
|
|
88
|
+
}
|
|
89
|
+
observer: ParticipantObserver
|
|
90
|
+
}>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface CreateConsultTeamToolParams {
|
|
94
|
+
historyMessages: ChatMessage[]
|
|
95
|
+
latestUserMessageId: string
|
|
96
|
+
availableUploads: ReadableUploadMetadataLike[]
|
|
97
|
+
defaultRepoSectionsByAgent: Record<string, DefaultRepoSections | undefined>
|
|
98
|
+
systemWorkspaceDetails?: string
|
|
99
|
+
getPreSeededMemoriesSection: (agentId: string) => Promise<string | undefined>
|
|
100
|
+
retrievedKnowledgeSection?: string
|
|
101
|
+
displayNamesById?: Partial<Record<string, string>>
|
|
102
|
+
abortSignal: AbortSignal
|
|
103
|
+
participantRunner: TeamConsultationParticipantRunner
|
|
104
|
+
onReadError?: (agentId: string, error: unknown) => void
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Sentinel pushed into the snapshot queue to signal that all workers are done. */
|
|
108
|
+
const DONE = Symbol('done')
|
|
109
|
+
|
|
110
|
+
type ConsultTeamSnapshotItem = ConsultTeamResultData | typeof DONE
|
|
111
|
+
|
|
112
|
+
interface ConsultTeamStreamResources {
|
|
113
|
+
snapshotQueue: Queue.Queue<ConsultTeamSnapshotItem>
|
|
114
|
+
workerFiber: Fiber.Fiber<unknown, unknown>
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function createConsultTeamStreamResources(params: {
|
|
118
|
+
task: string
|
|
119
|
+
uploadMetadataText: string
|
|
120
|
+
teamConsultParticipants: readonly string[]
|
|
121
|
+
resolveDisplayName: (agentId: string) => string
|
|
122
|
+
historyMessages: ChatMessage[]
|
|
123
|
+
latestUserMessageId: string
|
|
124
|
+
availableUploads: ReadableUploadMetadataLike[]
|
|
125
|
+
systemWorkspaceDetails?: string
|
|
126
|
+
getPreSeededMemoriesSection: (agentId: string) => Promise<string | undefined>
|
|
127
|
+
retrievedKnowledgeSection?: string
|
|
128
|
+
abortSignal: AbortSignal
|
|
129
|
+
participantRunner: TeamConsultationParticipantRunner
|
|
130
|
+
onReadError?: (agentId: string, error: unknown) => void
|
|
131
|
+
}): Effect.Effect<ConsultTeamStreamResources, TeamConsultationError> {
|
|
132
|
+
return Effect.gen(function* () {
|
|
133
|
+
const initialResponses: ConsultTeamResultData['responses'] = params.teamConsultParticipants.map((agentId) => ({
|
|
134
|
+
agentId,
|
|
135
|
+
agentName: params.resolveDisplayName(agentId),
|
|
136
|
+
status: 'running',
|
|
137
|
+
}))
|
|
138
|
+
|
|
139
|
+
const snapshotQueue = yield* Queue.bounded<ConsultTeamSnapshotItem>(params.teamConsultParticipants.length + 2)
|
|
140
|
+
const responsesRef = yield* Ref.make([...initialResponses])
|
|
141
|
+
|
|
142
|
+
const pushSnapshot = Effect.flatMap(Ref.get(responsesRef), (current) =>
|
|
143
|
+
Queue.offer(snapshotQueue, buildSnapshot(current)),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
const runParticipantEffect = (agentId: string, index: number) => {
|
|
147
|
+
const agentName = params.resolveDisplayName(agentId)
|
|
148
|
+
const timedAbort = createTimedAbortSignal(params.abortSignal, TEAM_CONSULTATION_TIMEOUT_MS)
|
|
149
|
+
const toTeamConsultationError = (message: string, cause?: unknown) =>
|
|
150
|
+
new TeamConsultationError({ message, cause })
|
|
151
|
+
|
|
152
|
+
const generateAndRecord = Effect.gen(function* () {
|
|
153
|
+
const preSeededMemoriesSection = yield* Effect.tryPromise({
|
|
154
|
+
try: () => params.getPreSeededMemoriesSection(agentId),
|
|
155
|
+
catch: (error) => toTeamConsultationError(`Failed to load pre-seeded memories for ${agentName}.`, error),
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const { agent, observer } = yield* Effect.tryPromise({
|
|
159
|
+
try: () =>
|
|
160
|
+
params.participantRunner.buildParticipantAgent(agentId, {
|
|
161
|
+
task: params.task,
|
|
162
|
+
systemWorkspaceDetails: params.systemWorkspaceDetails,
|
|
163
|
+
preSeededMemoriesSection,
|
|
164
|
+
retrievedKnowledgeSection: params.retrievedKnowledgeSection,
|
|
165
|
+
}),
|
|
166
|
+
catch: (error) => toTeamConsultationError(`Failed to build team participant agent for ${agentName}.`, error),
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const modelMessages = yield* Effect.tryPromise({
|
|
170
|
+
try: () =>
|
|
171
|
+
convertToModelMessages(
|
|
172
|
+
buildModelInputMessagesWithUploadMetadata({
|
|
173
|
+
messages: selectTeamConsultationContextMessages(params.historyMessages, params.latestUserMessageId),
|
|
174
|
+
latestUserMessageId: params.latestUserMessageId,
|
|
175
|
+
uploadMetadataText: params.uploadMetadataText,
|
|
176
|
+
}),
|
|
177
|
+
{ ignoreIncompleteToolCalls: true },
|
|
178
|
+
),
|
|
179
|
+
catch: (error) => toTeamConsultationError(`Failed to build model messages for ${agentName}.`, error),
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
const result = yield* Effect.tryPromise({
|
|
183
|
+
try: () =>
|
|
184
|
+
observer.run(() =>
|
|
185
|
+
agent.generate({
|
|
186
|
+
messages: modelMessages,
|
|
187
|
+
abortSignal: timedAbort.signal,
|
|
188
|
+
timeout: TEAM_CONSULTATION_TIMEOUT_MS,
|
|
189
|
+
}),
|
|
190
|
+
),
|
|
191
|
+
catch: (error) => {
|
|
192
|
+
if (params.abortSignal.aborted || timedAbort.signal.aborted) {
|
|
193
|
+
observer.recordAbort?.(error)
|
|
194
|
+
} else {
|
|
195
|
+
observer.recordError?.(error)
|
|
196
|
+
}
|
|
197
|
+
return toTeamConsultationError(`Team participant ${agentName} failed.`, error)
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
const responseText = result.text.trim()
|
|
202
|
+
if (!responseText) {
|
|
203
|
+
return yield* new TeamConsultationError({
|
|
204
|
+
message: `Team participant ${agentName} did not produce a response.`,
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const message = withMessageCreatedAt(
|
|
209
|
+
{
|
|
210
|
+
id: Bun.randomUUIDv7(),
|
|
211
|
+
role: 'assistant',
|
|
212
|
+
parts: [{ type: 'text', text: responseText }],
|
|
213
|
+
metadata: { agentId, agentName },
|
|
214
|
+
} satisfies ChatMessage,
|
|
215
|
+
nowEpochMillis(),
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
yield* Ref.update(responsesRef, (prev) => {
|
|
219
|
+
const next = [...prev]
|
|
220
|
+
next[index] = {
|
|
221
|
+
agentId,
|
|
222
|
+
agentName,
|
|
223
|
+
status: 'complete',
|
|
224
|
+
summary: extractMessageText(message).trim() || undefined,
|
|
225
|
+
message,
|
|
226
|
+
}
|
|
227
|
+
return next
|
|
228
|
+
})
|
|
229
|
+
yield* pushSnapshot
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
return generateAndRecord.pipe(
|
|
233
|
+
Effect.catch((error) => {
|
|
234
|
+
// Parent abort is fatal — re-fail so structured concurrency interrupts siblings.
|
|
235
|
+
if (params.abortSignal.aborted) {
|
|
236
|
+
return Effect.fail(error)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return Ref.update(responsesRef, (prev) => {
|
|
240
|
+
const next = [...prev]
|
|
241
|
+
next[index] = {
|
|
242
|
+
agentId,
|
|
243
|
+
agentName,
|
|
244
|
+
status: 'error',
|
|
245
|
+
error: buildTeamConsultationFailureMessage(
|
|
246
|
+
agentName,
|
|
247
|
+
TEAM_CONSULTATION_TIMEOUT_MS,
|
|
248
|
+
timedAbort.didTimeout(),
|
|
249
|
+
error,
|
|
250
|
+
),
|
|
251
|
+
}
|
|
252
|
+
return next
|
|
253
|
+
}).pipe(Effect.andThen(pushSnapshot))
|
|
254
|
+
}),
|
|
255
|
+
Effect.ensuring(Effect.sync(() => timedAbort.dispose())),
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const workersEffect = Effect.forEach(
|
|
260
|
+
params.teamConsultParticipants,
|
|
261
|
+
(agentId, index) => runParticipantEffect(agentId, index),
|
|
262
|
+
{ concurrency: 'unbounded' },
|
|
263
|
+
).pipe(Effect.ensuring(Queue.offer(snapshotQueue, DONE)))
|
|
264
|
+
|
|
265
|
+
yield* pushSnapshot
|
|
266
|
+
const workerFiber = yield* Effect.forkChild(workersEffect)
|
|
267
|
+
|
|
268
|
+
return { snapshotQueue, workerFiber }
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
class ConsultTeamSnapshotIterable implements AsyncIterableIterator<ConsultTeamResultData> {
|
|
273
|
+
private readonly scope: Scope.Closeable
|
|
274
|
+
private readonly resourcesDeferred: Deferred.Deferred<ConsultTeamStreamResources, TeamConsultationError>
|
|
275
|
+
private readonly buildEffect: Effect.Effect<ConsultTeamStreamResources, TeamConsultationError>
|
|
276
|
+
private initStarted = false
|
|
277
|
+
private closed = false
|
|
278
|
+
private completed = false
|
|
279
|
+
|
|
280
|
+
constructor(params: CreateConsultTeamToolParams, task: string) {
|
|
281
|
+
const teamConsultParticipants = getTeamConsultParticipants()
|
|
282
|
+
const uploadMetadataText = buildReadableUploadMetadataText(params.availableUploads)
|
|
283
|
+
const agentDisplayNames = getAgentDisplayNames()
|
|
284
|
+
const resolveDisplayName = (agentId: string) => {
|
|
285
|
+
if (params.displayNamesById && Object.hasOwn(params.displayNamesById, agentId)) {
|
|
286
|
+
const override = params.displayNamesById[agentId]
|
|
287
|
+
if (override !== undefined) {
|
|
288
|
+
return override
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return agentDisplayNames[agentId] ?? agentId
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
this.scope = Scope.makeUnsafe()
|
|
296
|
+
this.resourcesDeferred = Deferred.makeUnsafe<ConsultTeamStreamResources, TeamConsultationError>()
|
|
297
|
+
this.buildEffect = createConsultTeamStreamResources({
|
|
298
|
+
task,
|
|
299
|
+
uploadMetadataText,
|
|
300
|
+
teamConsultParticipants,
|
|
301
|
+
resolveDisplayName,
|
|
302
|
+
historyMessages: params.historyMessages,
|
|
303
|
+
latestUserMessageId: params.latestUserMessageId,
|
|
304
|
+
availableUploads: params.availableUploads,
|
|
305
|
+
systemWorkspaceDetails: params.systemWorkspaceDetails,
|
|
306
|
+
getPreSeededMemoriesSection: params.getPreSeededMemoriesSection,
|
|
307
|
+
retrievedKnowledgeSection: params.retrievedKnowledgeSection,
|
|
308
|
+
abortSignal: params.abortSignal,
|
|
309
|
+
participantRunner: params.participantRunner,
|
|
310
|
+
onReadError: params.onReadError,
|
|
311
|
+
})
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Acquire-release: on first call, build the stream resources and register
|
|
316
|
+
* cleanup as a finalizer in the iterable's scope. Subsequent calls await the
|
|
317
|
+
* cached `Deferred`. If init fails, no finalizer is registered, so closing
|
|
318
|
+
* the scope is a no-op for the leaked-resource path.
|
|
319
|
+
*/
|
|
320
|
+
private acquireResourcesEffect(): Effect.Effect<ConsultTeamStreamResources, TeamConsultationError> {
|
|
321
|
+
if (this.initStarted) {
|
|
322
|
+
return Deferred.await(this.resourcesDeferred)
|
|
323
|
+
}
|
|
324
|
+
this.initStarted = true
|
|
325
|
+
|
|
326
|
+
const acquire = Effect.acquireRelease(this.buildEffect, ({ snapshotQueue, workerFiber }) =>
|
|
327
|
+
Fiber.interrupt(workerFiber).pipe(Effect.andThen(Queue.shutdown(snapshotQueue))),
|
|
328
|
+
).pipe(Scope.provide(this.scope))
|
|
329
|
+
|
|
330
|
+
return acquire.pipe(
|
|
331
|
+
Effect.exit,
|
|
332
|
+
Effect.flatMap((exit) =>
|
|
333
|
+
Deferred.done(this.resourcesDeferred, exit).pipe(Effect.andThen(Deferred.await(this.resourcesDeferred))),
|
|
334
|
+
),
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Close the scope idempotently. Runs cleanup finalizers iff init succeeded. */
|
|
339
|
+
private closeScopeEffect(): Effect.Effect<void, never> {
|
|
340
|
+
return Scope.close(this.scope, Exit.void).pipe(Effect.catchCause(() => Effect.void))
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<ConsultTeamResultData> {
|
|
344
|
+
return this
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
next(): Promise<IteratorResult<ConsultTeamResultData>> {
|
|
348
|
+
if (this.closed) {
|
|
349
|
+
return Promise.resolve({ done: true, value: undefined as never })
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return Effect.runPromise(
|
|
353
|
+
Effect.gen(
|
|
354
|
+
function* (this: ConsultTeamSnapshotIterable) {
|
|
355
|
+
const { snapshotQueue } = yield* this.acquireResourcesEffect()
|
|
356
|
+
|
|
357
|
+
if (this.completed) {
|
|
358
|
+
return { done: true, value: undefined as never }
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const item = yield* Queue.take(snapshotQueue)
|
|
362
|
+
if (item === DONE) {
|
|
363
|
+
this.completed = true
|
|
364
|
+
this.closed = true
|
|
365
|
+
yield* this.closeScopeEffect()
|
|
366
|
+
return { done: true, value: undefined as never }
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return { done: false, value: item }
|
|
370
|
+
}.bind(this),
|
|
371
|
+
).pipe(
|
|
372
|
+
Effect.tapCause(() =>
|
|
373
|
+
Effect.sync(() => {
|
|
374
|
+
this.closed = true
|
|
375
|
+
}).pipe(Effect.andThen(this.closeScopeEffect())),
|
|
376
|
+
),
|
|
377
|
+
),
|
|
378
|
+
)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return(): Promise<IteratorResult<ConsultTeamResultData>> {
|
|
382
|
+
this.closed = true
|
|
383
|
+
return Effect.runPromise(this.closeScopeEffect().pipe(Effect.as({ done: true, value: undefined as never })))
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
throw(error: unknown): Promise<never> {
|
|
387
|
+
this.closed = true
|
|
388
|
+
return Effect.runPromise(this.closeScopeEffect().pipe(Effect.andThen(Effect.fail(error as never))))
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function createConsultTeamTool(params: CreateConsultTeamToolParams) {
|
|
393
|
+
const teamConsultParticipants = getTeamConsultParticipants()
|
|
394
|
+
const agentDisplayNames = getAgentDisplayNames()
|
|
395
|
+
const resolveDisplayName = (agentId: string) => {
|
|
396
|
+
if (params.displayNamesById && Object.hasOwn(params.displayNamesById, agentId)) {
|
|
397
|
+
const override = params.displayNamesById[agentId]
|
|
398
|
+
if (override !== undefined) {
|
|
399
|
+
return override
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return agentDisplayNames[agentId] ?? agentId
|
|
404
|
+
}
|
|
405
|
+
const participantNames = teamConsultParticipants
|
|
406
|
+
.map((agentId) => resolveDisplayName(agentId))
|
|
407
|
+
.filter((value) => value.trim().length > 0)
|
|
408
|
+
const participantSummary =
|
|
409
|
+
participantNames.length > 0 ? participantNames.join(', ') : 'the configured specialist participants'
|
|
410
|
+
|
|
411
|
+
return createTool({
|
|
412
|
+
description: `Consult the specialist team in parallel before replying. Use this when the answer benefits from structured input across ${participantSummary}.`,
|
|
413
|
+
inputSchema: ConsultTeamArgsSchema,
|
|
414
|
+
execute: ({ task }) => new ConsultTeamSnapshotIterable(params, task),
|
|
415
|
+
toModelOutput: ({ output }) => {
|
|
416
|
+
const result = getConsultTeamOutput(output)
|
|
417
|
+
const summaryLines =
|
|
418
|
+
result?.responses
|
|
419
|
+
.map((response) => {
|
|
420
|
+
const summary =
|
|
421
|
+
typeof response.error === 'string' && response.error.trim().length > 0
|
|
422
|
+
? response.error.trim()
|
|
423
|
+
: typeof response.summary === 'string' && response.summary.trim().length > 0
|
|
424
|
+
? response.summary.trim()
|
|
425
|
+
: 'No response.'
|
|
426
|
+
return `${response.agentName}: ${summary}`
|
|
427
|
+
})
|
|
428
|
+
.join('\n') ?? 'Team consultation completed.'
|
|
429
|
+
|
|
430
|
+
return { type: 'text', value: summaryLines }
|
|
431
|
+
},
|
|
432
|
+
})
|
|
433
|
+
}
|
package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts}
RENAMED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAgentDisplayNames, getLeadAgentDisplayName } from '../../config/agent-defaults'
|
|
2
|
+
|
|
3
|
+
function resolveDisplayName(agentId: string): string {
|
|
4
|
+
return getAgentDisplayNames()[agentId] ?? agentId
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export function buildTeamConsultationResponseGuard(params: { agentId: string; task: string }) {
|
|
4
|
-
const agentName =
|
|
8
|
+
const agentName = resolveDisplayName(params.agentId)
|
|
5
9
|
const leadAgentDisplayName = getLeadAgentDisplayName()
|
|
6
10
|
const mentorConstraint =
|
|
7
11
|
params.agentId === 'mentor'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { toTimestamp } from '@lota-sdk/shared'
|
|
2
2
|
import type { ChatMessage } from '@lota-sdk/shared'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getAgentDisplayNames, resolveAgentNameAlias } from '../config/agent-defaults'
|
|
5
5
|
import type { ChatMessageLike, ReadableUploadMetadataLike } from './chat-types'
|
|
6
6
|
|
|
7
7
|
export interface ThreadHistoryMessage {
|
|
@@ -35,7 +35,7 @@ function getAgentName(message: ChatMessageLike): string | undefined {
|
|
|
35
35
|
const value = (metadata as Record<string, unknown>).agentName
|
|
36
36
|
if (typeof value !== 'string' || !value.trim()) return undefined
|
|
37
37
|
const resolvedAgentName = resolveAgentNameAlias(value)
|
|
38
|
-
return resolvedAgentName ? (
|
|
38
|
+
return resolvedAgentName ? (getAgentDisplayNames()[resolvedAgentName] ?? value.trim()) : value.trim()
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export function extractMessageText(message: ChatMessageLike): string {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SUBMIT_PLAN_TURN_RESULT_TOOL_NAME, withMessageCreatedAt } from '@lota-sdk/shared'
|
|
2
2
|
import type { ChatMessage, PlanArtifactSubmission, PlanNodeRunRecord, PlanNodeSpecRecord } from '@lota-sdk/shared'
|
|
3
3
|
|
|
4
|
+
import { nowEpochMillis } from '../utils/date-time'
|
|
4
5
|
import { buildCompletionCheckStructuredOutputHints } from './agent-runtime-policy'
|
|
5
6
|
import { mergeInstructionSections } from './instruction-sections'
|
|
6
7
|
|
|
@@ -125,6 +126,6 @@ export function buildPlanTurnPromptMessage(planTurn: ThreadPlanTurnContext): Cha
|
|
|
125
126
|
],
|
|
126
127
|
metadata: { trigger: 'plan-turn', planRunId: planTurn.runId, planNodeId: planTurn.nodeId },
|
|
127
128
|
},
|
|
128
|
-
|
|
129
|
+
nowEpochMillis(),
|
|
129
130
|
)
|
|
130
131
|
}
|