@lota-sdk/core 0.4.13 → 0.4.15
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 +4 -4
- package/src/ai/embedding-cache.ts +17 -11
- package/src/ai-gateway/ai-gateway.ts +164 -94
- package/src/ai-gateway/index.ts +4 -1
- package/src/config/agent-defaults.ts +2 -2
- package/src/config/agent-types.ts +1 -1
- package/src/config/constants.ts +1 -1
- package/src/create-runtime.ts +259 -200
- package/src/db/cursor-pagination.ts +2 -9
- package/src/db/memory-store.ts +194 -175
- package/src/db/memory.ts +125 -71
- package/src/db/schema-fingerprint.ts +5 -4
- package/src/db/service-normalization.ts +4 -3
- package/src/db/service.ts +3 -2
- package/src/db/startup.ts +15 -16
- package/src/effect/errors.ts +161 -21
- package/src/effect/index.ts +0 -1
- package/src/embeddings/provider.ts +15 -7
- package/src/queues/autonomous-job.queue.ts +10 -22
- package/src/queues/delayed-node-promotion.queue.ts +8 -14
- package/src/queues/document-processor.queue.ts +13 -4
- package/src/queues/memory-consolidation.queue.ts +26 -14
- package/src/queues/plan-agent-heartbeat.queue.ts +48 -31
- package/src/queues/plan-scheduler.queue.ts +37 -15
- package/src/queues/queue-factory.ts +59 -35
- package/src/queues/standalone-worker.ts +3 -2
- package/src/redis/connection.ts +10 -3
- package/src/redis/org-memory-lock.ts +1 -1
- package/src/redis/redis-lease-lock.ts +5 -5
- package/src/redis/stream-context.ts +1 -1
- package/src/runtime/chat-message.ts +64 -1
- package/src/runtime/chat-run-orchestration.ts +33 -20
- package/src/runtime/context-compaction/context-compaction-runtime.ts +14 -7
- package/src/runtime/context-compaction/context-compaction.ts +78 -66
- package/src/runtime/domain-layer.ts +19 -13
- package/src/runtime/execution-plan.ts +7 -3
- package/src/runtime/memory/memory-block.ts +3 -9
- package/src/runtime/memory/memory-scope.ts +3 -1
- package/src/runtime/plugin-resolution.ts +2 -1
- package/src/runtime/post-turn-side-effects.ts +6 -5
- package/src/runtime/retrieval-adapters.ts +8 -20
- package/src/runtime/runtime-config.ts +3 -9
- package/src/runtime/runtime-extensions.ts +2 -4
- package/src/runtime/runtime-lifecycle.ts +56 -16
- package/src/runtime/runtime-services.ts +180 -102
- package/src/runtime/runtime-worker-registry.ts +3 -1
- package/src/runtime/social-chat/social-chat-agent-runner.ts +1 -1
- package/src/runtime/social-chat/social-chat-history.ts +21 -18
- package/src/runtime/social-chat/social-chat.ts +356 -223
- package/src/runtime/specialist-runner.ts +3 -1
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +3 -2
- package/src/runtime/thread-turn-context.ts +142 -102
- package/src/runtime/turn-lifecycle.ts +15 -46
- package/src/services/agent-activity.service.ts +1 -1
- package/src/services/agent-executor.service.ts +107 -77
- package/src/services/autonomous-job.service.ts +354 -293
- package/src/services/background-work.service.ts +3 -3
- package/src/services/context-compaction.service.ts +7 -2
- package/src/services/document-chunk.service.ts +50 -32
- package/src/services/execution-plan/execution-plan-schedule.ts +5 -3
- package/src/services/execution-plan/execution-plan.service.ts +162 -179
- package/src/services/feedback-loop.service.ts +5 -4
- package/src/services/graph-full-routing.ts +37 -36
- package/src/services/institutional-memory.service.ts +28 -30
- package/src/services/learned-skill.service.ts +107 -72
- package/src/services/memory/memory-errors.ts +4 -23
- package/src/services/memory/memory-org-memory.ts +10 -5
- package/src/services/memory/memory-rerank.ts +18 -6
- package/src/services/memory/memory.service.ts +170 -111
- package/src/services/memory/rerank.service.ts +29 -20
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +69 -75
- package/src/services/ownership-dispatcher.service.ts +40 -39
- package/src/services/plan/plan-agent-heartbeat.service.ts +22 -24
- package/src/services/plan/plan-agent-query.service.ts +39 -31
- package/src/services/plan/plan-completion-side-effects.ts +13 -17
- package/src/services/plan/plan-coordination.service.ts +2 -1
- package/src/services/plan/plan-cycle.service.ts +6 -5
- package/src/services/plan/plan-deadline.service.ts +57 -54
- package/src/services/plan/plan-event-delivery.service.ts +5 -4
- package/src/services/plan/plan-executor-graph.ts +18 -15
- package/src/services/plan/plan-executor.service.ts +235 -262
- package/src/services/plan/plan-run.service.ts +169 -93
- package/src/services/plan/plan-scheduler.service.ts +192 -202
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +23 -14
- package/src/services/plugin-executor.service.ts +5 -9
- package/src/services/queue-job.service.ts +117 -59
- package/src/services/recent-activity-title.service.ts +13 -12
- package/src/services/recent-activity.service.ts +6 -1
- package/src/services/social-chat-history.service.ts +29 -25
- package/src/services/system-executor.service.ts +5 -9
- package/src/services/thread/thread-active-run.ts +2 -2
- package/src/services/thread/thread-listing.ts +61 -57
- package/src/services/thread/thread-memory-block.ts +73 -48
- package/src/services/thread/thread-message.service.ts +76 -65
- package/src/services/thread/thread-record-store.ts +8 -8
- package/src/services/thread/thread-title.service.ts +10 -4
- package/src/services/thread/thread-turn-execution.ts +43 -45
- package/src/services/thread/thread-turn-preparation.service.ts +257 -135
- package/src/services/thread/thread-turn-streaming.ts +83 -92
- package/src/services/thread/thread-turn.ts +18 -16
- package/src/services/thread/thread.service.ts +135 -100
- package/src/services/user.service.ts +45 -48
- package/src/storage/attachment-parser.ts +6 -2
- package/src/storage/attachment-storage.service.ts +5 -6
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +10 -9
- package/src/system-agents/delegated-agent-factory.ts +30 -6
- package/src/system-agents/memory-reranker.agent.ts +10 -9
- package/src/system-agents/memory.agent.ts +10 -9
- package/src/system-agents/recent-activity-title-refiner.agent.ts +13 -15
- package/src/system-agents/regular-chat-memory-digest.agent.ts +13 -12
- package/src/system-agents/skill-extractor.agent.ts +13 -12
- package/src/system-agents/skill-manager.agent.ts +13 -12
- package/src/system-agents/thread-router.agent.ts +11 -7
- package/src/system-agents/title-generator.agent.ts +13 -12
- package/src/tools/fetch-webpage.tool.ts +13 -13
- package/src/tools/memory-block.tool.ts +3 -1
- package/src/tools/plan-approval.tool.ts +4 -2
- package/src/tools/read-file-parts.tool.ts +10 -4
- package/src/tools/remember-memory.tool.ts +3 -1
- package/src/tools/research-topic.tool.ts +9 -5
- package/src/tools/search-web.tool.ts +16 -16
- package/src/tools/search.tool.ts +20 -5
- package/src/tools/team-think.tool.ts +61 -38
- package/src/utils/async.ts +5 -5
- package/src/utils/errors.ts +19 -18
- package/src/utils/sse-keepalive.ts +28 -25
- package/src/workers/bootstrap.ts +75 -11
- package/src/workers/memory-consolidation.worker.ts +82 -91
- package/src/workers/organization-learning.worker.ts +14 -4
- package/src/workers/regular-chat-memory-digest.runner.ts +105 -67
- package/src/workers/skill-extraction.runner.ts +97 -61
- package/src/workers/utils/repo-structure-extractor.ts +13 -8
- package/src/workers/utils/thread-message-query.ts +24 -24
- package/src/workers/worker-utils.ts +23 -4
- package/src/effect/helpers.ts +0 -123
|
@@ -3,18 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The plugin connect/disconnect helpers run inside the supplied
|
|
5
5
|
* `ManagedRuntime` so spans, logging, and layer context stay consistent with
|
|
6
|
-
* the rest of the SDK runtime.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* does not preserve the SDK runtime context — by then the runtime is being
|
|
10
|
-
* torn down.
|
|
6
|
+
* the rest of the SDK runtime. Disconnect runs its teardown sequence as a
|
|
7
|
+
* plain `Effect.runPromise` — the services it yields have no layer
|
|
8
|
+
* requirements because they are closure-captured shutdown thunks.
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
import type { ManagedRuntime } from 'effect'
|
|
14
12
|
import { Effect } from 'effect'
|
|
15
13
|
|
|
16
|
-
import {
|
|
17
|
-
import { effectTryPromise } from '../effect/helpers'
|
|
14
|
+
import { RuntimeLifecycleError } from '../effect/errors'
|
|
18
15
|
import type { LotaPlugin } from './plugin-types'
|
|
19
16
|
|
|
20
17
|
// eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
|
|
@@ -24,6 +21,26 @@ function getPluginLifecycleServices(plugin: LotaPlugin): Record<string, unknown>
|
|
|
24
21
|
return plugin.services
|
|
25
22
|
}
|
|
26
23
|
|
|
24
|
+
function toRuntimeLifecycleError(
|
|
25
|
+
operation: RuntimeLifecycleError['operation'],
|
|
26
|
+
cause: unknown,
|
|
27
|
+
pluginName?: string,
|
|
28
|
+
): RuntimeLifecycleError {
|
|
29
|
+
const detail = pluginName ? ` "${pluginName}"` : ''
|
|
30
|
+
const action =
|
|
31
|
+
operation === 'connect-plugin-database'
|
|
32
|
+
? `connect plugin database${detail}`
|
|
33
|
+
: operation === 'disconnect-plugin-database'
|
|
34
|
+
? `disconnect plugin database${detail}`
|
|
35
|
+
: operation === 'shutdown-social-chat'
|
|
36
|
+
? 'shut down social chat'
|
|
37
|
+
: operation === 'disconnect-plugin-databases'
|
|
38
|
+
? 'disconnect plugin databases'
|
|
39
|
+
: 'dispose managed runtime'
|
|
40
|
+
|
|
41
|
+
return new RuntimeLifecycleError({ operation, message: `Failed to ${action}.`, cause })
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
/**
|
|
28
45
|
* Build a plugin database connector that iterates the configured plugins and
|
|
29
46
|
* calls each `services.connectDatabase()` once, tracking completion in
|
|
@@ -49,7 +66,10 @@ export function createPluginDatabaseConnector(
|
|
|
49
66
|
}
|
|
50
67
|
|
|
51
68
|
const connectDatabaseFn = connectDatabase as (this: typeof services) => Promise<void>
|
|
52
|
-
yield*
|
|
69
|
+
yield* Effect.tryPromise({
|
|
70
|
+
try: () => connectDatabaseFn.call(services),
|
|
71
|
+
catch: (cause) => toRuntimeLifecycleError('connect-plugin-database', cause, pluginName),
|
|
72
|
+
})
|
|
53
73
|
connectedPluginDatabases.add(pluginName)
|
|
54
74
|
}
|
|
55
75
|
}),
|
|
@@ -82,7 +102,10 @@ export function createPluginDatabaseDisconnector(
|
|
|
82
102
|
}
|
|
83
103
|
|
|
84
104
|
const disconnectDatabaseFn = disconnectDatabase as (this: typeof services) => Promise<void>
|
|
85
|
-
yield*
|
|
105
|
+
yield* Effect.tryPromise({
|
|
106
|
+
try: () => disconnectDatabaseFn.call(services),
|
|
107
|
+
catch: (cause) => toRuntimeLifecycleError('disconnect-plugin-database', cause, pluginName),
|
|
108
|
+
})
|
|
86
109
|
connectedPluginDatabases.delete(pluginName)
|
|
87
110
|
}
|
|
88
111
|
}),
|
|
@@ -91,7 +114,6 @@ export function createPluginDatabaseDisconnector(
|
|
|
91
114
|
|
|
92
115
|
interface CreateDisconnectInput {
|
|
93
116
|
managedRuntime: SdkManagedRuntime
|
|
94
|
-
runPromiseWithCurrentContext: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
95
117
|
socialChatShutdown: () => Promise<void>
|
|
96
118
|
disconnectPluginDatabases: () => Promise<void>
|
|
97
119
|
}
|
|
@@ -100,9 +122,15 @@ interface CreateDisconnectInput {
|
|
|
100
122
|
* Compose the runtime `disconnect()` function. The returned function is
|
|
101
123
|
* idempotent: the first call starts the shutdown sequence, subsequent calls
|
|
102
124
|
* return the same in-flight promise.
|
|
125
|
+
*
|
|
126
|
+
* Teardown order:
|
|
127
|
+
* 1. socialChat shutdown (user-facing bots must go quiet first)
|
|
128
|
+
* 2. plugin database disconnect (release external connections)
|
|
129
|
+
* 3. clear AI gateway runtime slot BEFORE dispose (no new fibers)
|
|
130
|
+
* 4. managedRuntime.dispose() (release all scoped layer resources)
|
|
103
131
|
*/
|
|
104
132
|
export function createRuntimeDisconnect(input: CreateDisconnectInput): () => Promise<void> {
|
|
105
|
-
const { managedRuntime,
|
|
133
|
+
const { managedRuntime, socialChatShutdown, disconnectPluginDatabases } = input
|
|
106
134
|
|
|
107
135
|
let disconnectPromise: Promise<void> | null = null
|
|
108
136
|
|
|
@@ -111,12 +139,24 @@ export function createRuntimeDisconnect(input: CreateDisconnectInput): () => Pro
|
|
|
111
139
|
return disconnectPromise
|
|
112
140
|
}
|
|
113
141
|
|
|
114
|
-
disconnectPromise =
|
|
142
|
+
disconnectPromise = Effect.runPromise(
|
|
115
143
|
Effect.gen(function* () {
|
|
116
|
-
yield* Effect.ignore(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
144
|
+
yield* Effect.ignore(
|
|
145
|
+
Effect.tryPromise({
|
|
146
|
+
try: () => socialChatShutdown(),
|
|
147
|
+
catch: (cause) => toRuntimeLifecycleError('shutdown-social-chat', cause),
|
|
148
|
+
}),
|
|
149
|
+
)
|
|
150
|
+
yield* Effect.ignore(
|
|
151
|
+
Effect.tryPromise({
|
|
152
|
+
try: () => disconnectPluginDatabases(),
|
|
153
|
+
catch: (cause) => toRuntimeLifecycleError('disconnect-plugin-databases', cause),
|
|
154
|
+
}),
|
|
155
|
+
)
|
|
156
|
+
yield* Effect.tryPromise({
|
|
157
|
+
try: () => managedRuntime.dispose(),
|
|
158
|
+
catch: (cause) => toRuntimeLifecycleError('dispose-managed-runtime', cause),
|
|
159
|
+
})
|
|
120
160
|
}),
|
|
121
161
|
)
|
|
122
162
|
return disconnectPromise
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Eagerly resolves the
|
|
2
|
+
* Eagerly resolves the host runtime surface against a live ManagedRuntime.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* the
|
|
7
|
-
*
|
|
4
|
+
* Services are resolved once at boot, then adapted into plain Promise-returning
|
|
5
|
+
* host methods. Sync helpers that are intentionally host-visible stay explicit
|
|
6
|
+
* on the returned objects instead of relying on runtime `Effect.isEffect(...)`
|
|
7
|
+
* checks or prototype walking.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ChatMessage } from '@lota-sdk/shared'
|
|
@@ -16,8 +16,7 @@ import type { ResolvedAgentConfig } from '../config/agent-defaults'
|
|
|
16
16
|
import { ensureRecordId } from '../db/record-id'
|
|
17
17
|
import type { SurrealDBService } from '../db/service'
|
|
18
18
|
import { TABLES } from '../db/tables'
|
|
19
|
-
import { BadRequestError, NotFoundError } from '../effect/errors'
|
|
20
|
-
import { effectTryPromise } from '../effect/helpers'
|
|
19
|
+
import { BadRequestError, NotFoundError, ServiceError } from '../effect/errors'
|
|
21
20
|
import { AgentConfigServiceTag } from '../effect/services'
|
|
22
21
|
import type { RedisConnectionManager } from '../redis/connection'
|
|
23
22
|
import type { SharedThreadStreamSubscriberTag } from '../redis/stream-context'
|
|
@@ -83,10 +82,8 @@ type PromisifiedService<T> = {
|
|
|
83
82
|
|
|
84
83
|
type HostSvc<T extends { readonly Service: object }> = PromisifiedService<T['Service']>
|
|
85
84
|
|
|
86
|
-
export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag>
|
|
87
|
-
|
|
88
|
-
export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
|
|
89
|
-
Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
|
|
85
|
+
export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag>
|
|
86
|
+
export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag>
|
|
90
87
|
|
|
91
88
|
export type ArchiveSdkThread = (
|
|
92
89
|
threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
|
|
@@ -113,7 +110,7 @@ export interface LotaRuntimeServices {
|
|
|
113
110
|
generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
|
|
114
111
|
memoryService: HostSvc<typeof MemoryServiceTag>
|
|
115
112
|
rerankService: HostSvc<typeof RerankServiceTag>
|
|
116
|
-
verifyMutatingApproval:
|
|
113
|
+
verifyMutatingApproval: PromisifiedValue<Svc<typeof MutatingApprovalServiceTag>>
|
|
117
114
|
organizationService: HostSvc<typeof OrganizationServiceTag>
|
|
118
115
|
organizationMemberService: HostSvc<typeof OrganizationMemberServiceTag>
|
|
119
116
|
userService: HostSvc<typeof UserServiceTag>
|
|
@@ -133,13 +130,13 @@ export interface LotaRuntimeServices {
|
|
|
133
130
|
threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
|
|
134
131
|
threadService: PromisifiedThreadService
|
|
135
132
|
threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
|
|
136
|
-
createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
|
|
137
|
-
createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
|
|
138
|
-
createThreadTurnStream: typeof createThreadTurnStream
|
|
133
|
+
createThreadApprovalContinuationStream: PromisifiedValue<typeof createThreadApprovalContinuationStream>
|
|
134
|
+
createThreadNativeToolApprovalStream: PromisifiedValue<typeof createThreadNativeToolApprovalStream>
|
|
135
|
+
createThreadTurnStream: PromisifiedValue<typeof createThreadTurnStream>
|
|
139
136
|
isApprovalContinuationRequest: typeof isApprovalContinuationRequestFn
|
|
140
|
-
launchBackgroundThreadWork: typeof launchBackgroundThreadWork
|
|
141
|
-
runThreadTurnInBackground: typeof runThreadTurnInBackground
|
|
142
|
-
triggerPlanNodeTurn: typeof triggerPlanNodeTurn
|
|
137
|
+
launchBackgroundThreadWork: PromisifiedValue<typeof launchBackgroundThreadWork>
|
|
138
|
+
runThreadTurnInBackground: PromisifiedValue<typeof runThreadTurnInBackground>
|
|
139
|
+
triggerPlanNodeTurn: PromisifiedValue<typeof triggerPlanNodeTurn>
|
|
143
140
|
}
|
|
144
141
|
|
|
145
142
|
export interface LotaRuntimeLota {
|
|
@@ -212,51 +209,33 @@ interface RuntimeServiceSurface {
|
|
|
212
209
|
}
|
|
213
210
|
|
|
214
211
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* unchanged. Each Effect-returning method is wrapped so callers receive a
|
|
219
|
-
* Promise resolved by the supplied `managedRuntime`, keeping the host-facing
|
|
220
|
-
* API stable while the SDK internals stay pure Effect.
|
|
212
|
+
* Host-facing runtime services are plain object literals, so we adapt only the
|
|
213
|
+
* explicit method table we pass in here. Sync helpers stay on the raw object
|
|
214
|
+
* and are reattached explicitly at the call site.
|
|
221
215
|
*/
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
type EffectMethod = (...args: Array<never>) => Effect.Effect<unknown, object, object>
|
|
217
|
+
|
|
218
|
+
function bindEffectMethod<TMethod extends EffectMethod>(
|
|
219
|
+
runPromise: <A, E extends object, R extends object>(effect: Effect.Effect<A, E, R>) => Promise<A>,
|
|
220
|
+
method: TMethod,
|
|
221
|
+
): PromisifiedValue<TMethod> {
|
|
222
|
+
return ((...args: Parameters<TMethod>) => runPromise(method(...args))) as PromisifiedValue<TMethod>
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function bindEffectService<T extends { [K in keyof T]: EffectMethod }>(
|
|
226
|
+
runPromise: <A, E extends object, R extends object>(effect: Effect.Effect<A, E, R>) => Promise<A>,
|
|
224
227
|
rawService: T,
|
|
225
|
-
):
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
// only sees own enumerable string keys — silent miss for class methods.
|
|
230
|
-
let proto: object | null = rawService
|
|
231
|
-
while (proto && proto !== Object.prototype) {
|
|
232
|
-
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
233
|
-
if (key === 'constructor' || key in out) continue
|
|
234
|
-
const descriptor = Object.getOwnPropertyDescriptor(proto, key)
|
|
235
|
-
if (!descriptor || typeof descriptor.value !== 'function') continue
|
|
236
|
-
const method = descriptor.value as (...args: unknown[]) => unknown
|
|
237
|
-
out[key] = (...args: unknown[]) => {
|
|
238
|
-
const result = method.apply(rawService, args)
|
|
239
|
-
return Effect.isEffect(result)
|
|
240
|
-
? managedRuntime.runPromise(result as Effect.Effect<unknown, unknown, never>)
|
|
241
|
-
: result
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
proto = Object.getPrototypeOf(proto)
|
|
245
|
-
}
|
|
246
|
-
// Copy non-function own properties not already set.
|
|
247
|
-
for (const [key, value] of Object.entries(rawService)) {
|
|
248
|
-
if (!(key in out)) out[key] = value
|
|
228
|
+
): { [K in keyof T]: PromisifiedValue<T[K]> } {
|
|
229
|
+
const bound = {} as { [K in keyof T]: PromisifiedValue<T[K]> }
|
|
230
|
+
for (const key of Object.keys(rawService) as Array<keyof T>) {
|
|
231
|
+
bound[key] = bindEffectMethod(runPromise, rawService[key]) as { [K in keyof T]: PromisifiedValue<T[K]> }[typeof key]
|
|
249
232
|
}
|
|
250
|
-
return
|
|
233
|
+
return bound
|
|
251
234
|
}
|
|
252
235
|
|
|
253
236
|
/**
|
|
254
|
-
* Eagerly resolve the full service surface exactly once
|
|
255
|
-
*
|
|
256
|
-
* Effect-returning service methods are wrapped into plain Promise-returning
|
|
257
|
-
* functions by `promisifyServiceMethods`, which means callers can `await`
|
|
258
|
-
* them directly. The SDK retains the raw Effect-aware services internally
|
|
259
|
-
* for composition within `Effect.gen` blocks.
|
|
237
|
+
* Eagerly resolve the full service surface exactly once and adapt it into the
|
|
238
|
+
* public Promise-based runtime boundary.
|
|
260
239
|
*/
|
|
261
240
|
export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInput): RuntimeServiceSurface {
|
|
262
241
|
const { managedRuntime, db, redisManager, threadTurnService, socialChatHistoryService } = input
|
|
@@ -265,58 +244,155 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
|
|
|
265
244
|
// The explicit `any` for R lets this helper accept effects with residual
|
|
266
245
|
// service requirements (e.g. `ThreadTurnServiceTag | LotaQueuesServiceTag`)
|
|
267
246
|
// without forcing each call site to provide them.
|
|
268
|
-
const runPromise = <A, E, R>(effect: Effect.Effect<A, E, R>): Promise<A> =>
|
|
247
|
+
const runPromise = <A, E extends object, R extends object>(effect: Effect.Effect<A, E, R>): Promise<A> =>
|
|
269
248
|
managedRuntime.runPromise(effect as unknown as Effect.Effect<A, E, never>)
|
|
270
249
|
|
|
271
250
|
const resolveRaw = <I, T>(tag: Context.Key<I, T>): T => managedRuntime.runSync(Effect.service(tag))
|
|
272
|
-
const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): PromisifiedService<T> =>
|
|
273
|
-
promisifyServiceMethods(managedRuntime, resolveRaw(tag))
|
|
274
251
|
|
|
275
252
|
// ── Resolve every tag eagerly. Each binding is a plain value from here. ──
|
|
276
|
-
const agentActivityService =
|
|
277
|
-
const artifactService =
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
253
|
+
const agentActivityService = bindEffectService(runPromise, resolveRaw(AgentActivityServiceTag))
|
|
254
|
+
const artifactService = bindEffectService(runPromise, resolveRaw(ArtifactServiceTag))
|
|
255
|
+
const attachmentServiceRaw = resolveRaw(AttachmentServiceTag)
|
|
256
|
+
const attachmentService = {
|
|
257
|
+
extractStoredAttachmentText: (...args) => runPromise(attachmentServiceRaw.extractStoredAttachmentText(...args)),
|
|
258
|
+
extractStoredAttachmentPages: (...args) => runPromise(attachmentServiceRaw.extractStoredAttachmentPages(...args)),
|
|
259
|
+
readFilePartsFromUpload: (...args) => runPromise(attachmentServiceRaw.readFilePartsFromUpload(...args)),
|
|
260
|
+
writeOrganizationDocument: (...args) => runPromise(attachmentServiceRaw.writeOrganizationDocument(...args)),
|
|
261
|
+
uploadOrganizationDocument: (...args) => runPromise(attachmentServiceRaw.uploadOrganizationDocument(...args)),
|
|
262
|
+
uploadThreadAttachment: (...args) => runPromise(attachmentServiceRaw.uploadThreadAttachment(...args)),
|
|
263
|
+
hydrateSignedFileUrlsInMessageParts: (...args) => attachmentServiceRaw.hydrateSignedFileUrlsInMessageParts(...args),
|
|
264
|
+
listReadableUploadsFromMessages: (...args) => attachmentServiceRaw.listReadableUploadsFromMessages(...args),
|
|
265
|
+
getAttachmentUrl: (...args) => attachmentServiceRaw.getAttachmentUrl(...args),
|
|
266
|
+
} satisfies HostSvc<typeof AttachmentServiceTag>
|
|
267
|
+
const autonomousJobServiceRaw = resolveRaw(AutonomousJobServiceTag)
|
|
268
|
+
const { computeNextRunAt, ...autonomousJobEffectMethods } = autonomousJobServiceRaw
|
|
269
|
+
const autonomousJobService = {
|
|
270
|
+
...bindEffectService(runPromise, autonomousJobEffectMethods),
|
|
271
|
+
computeNextRunAt,
|
|
272
|
+
} satisfies HostSvc<typeof AutonomousJobServiceTag>
|
|
273
|
+
const contextCompactionServiceRaw = resolveRaw(ContextCompactionServiceTag)
|
|
274
|
+
const contextCompactionService = {
|
|
275
|
+
compactThreadHistory: (...args) => runPromise(contextCompactionServiceRaw.compactThreadHistory(...args)),
|
|
276
|
+
compactMemoryBlock: (...args) => runPromise(contextCompactionServiceRaw.compactMemoryBlock(...args)),
|
|
277
|
+
createSummaryMessage: (...args) => contextCompactionServiceRaw.createSummaryMessage(...args),
|
|
278
|
+
estimateThreshold: (...args) => contextCompactionServiceRaw.estimateThreshold(...args),
|
|
279
|
+
shouldCompactHistory: (...args) => contextCompactionServiceRaw.shouldCompactHistory(...args),
|
|
280
|
+
} satisfies HostSvc<typeof ContextCompactionServiceTag>
|
|
281
|
+
const documentChunkServiceRaw = resolveRaw(DocumentChunkServiceTag)
|
|
282
|
+
const documentChunkService = {
|
|
283
|
+
syncVersionedChunks: (...args) => runPromise(documentChunkServiceRaw.syncVersionedChunks(...args)),
|
|
284
|
+
buildChunks: (...args) => documentChunkServiceRaw.buildChunks(...args),
|
|
285
|
+
hashContent: (...args) => documentChunkServiceRaw.hashContent(...args),
|
|
286
|
+
estimateTokenCount: (...args) => documentChunkServiceRaw.estimateTokenCount(...args),
|
|
287
|
+
embedQuery: (...args) => documentChunkServiceRaw.embedQuery(...args),
|
|
288
|
+
} satisfies PromisifiedDocumentChunkService
|
|
289
|
+
const generatedDocumentStorageService = bindEffectService(runPromise, resolveRaw(GeneratedDocumentStorageServiceTag))
|
|
290
|
+
const memoryService = bindEffectService(runPromise, resolveRaw(MemoryServiceTag))
|
|
291
|
+
const rerankService = bindEffectService(runPromise, resolveRaw(RerankServiceTag))
|
|
292
|
+
const verifyMutatingApproval = bindEffectMethod(runPromise, resolveRaw(MutatingApprovalServiceTag))
|
|
293
|
+
const organizationService = bindEffectService(runPromise, resolveRaw(OrganizationServiceTag))
|
|
294
|
+
const organizationMemberService = bindEffectService(runPromise, resolveRaw(OrganizationMemberServiceTag))
|
|
295
|
+
const userService = bindEffectService(runPromise, resolveRaw(UserServiceTag))
|
|
296
|
+
const recentActivityServiceRaw = resolveRaw(RecentActivityServiceTag)
|
|
297
|
+
const recentActivityService = {
|
|
298
|
+
recordEvent: (...args) => runPromise(recentActivityServiceRaw.recordEvent(...args)),
|
|
299
|
+
recordEvents: (...args) => runPromise(recentActivityServiceRaw.recordEvents(...args)),
|
|
300
|
+
listRecentActivities: (...args) => runPromise(recentActivityServiceRaw.listRecentActivities(...args)),
|
|
301
|
+
listRecentEvents: (...args) => runPromise(recentActivityServiceRaw.listRecentEvents(...args)),
|
|
302
|
+
getRecentActivityById: (...args) => runPromise(recentActivityServiceRaw.getRecentActivityById(...args)),
|
|
303
|
+
refineTitle: (...args) => runPromise(recentActivityServiceRaw.refineTitle(...args)),
|
|
304
|
+
getRefinementCandidate: (...args) => runPromise(recentActivityServiceRaw.getRefinementCandidate(...args)),
|
|
305
|
+
isMeaningfulRefinementCandidate: (...args) => recentActivityServiceRaw.isMeaningfulRefinementCandidate(...args),
|
|
306
|
+
isAgentTitleUseful: (...args) => recentActivityServiceRaw.isAgentTitleUseful(...args),
|
|
307
|
+
} satisfies HostSvc<typeof RecentActivityServiceTag>
|
|
308
|
+
const recentActivityTitleService = bindEffectService(runPromise, resolveRaw(RecentActivityTitleServiceTag))
|
|
309
|
+
const executionPlanService = bindEffectService(runPromise, resolveRaw(ExecutionPlanServiceTag))
|
|
310
|
+
const planDeadlineServiceRaw = resolveRaw(PlanDeadlineServiceTag)
|
|
311
|
+
const planDeadlineService = {
|
|
312
|
+
checkDeadlines: (...args) => runPromise(planDeadlineServiceRaw.checkDeadlines(...args)),
|
|
313
|
+
recoverDeadlineChecks: (...args) => runPromise(planDeadlineServiceRaw.recoverDeadlineChecks(...args)),
|
|
314
|
+
applyDeadlineMissAction: (...args) => runPromise(planDeadlineServiceRaw.applyDeadlineMissAction(...args)),
|
|
315
|
+
maybeEmitEscalationPolicyEvent: (...args) =>
|
|
316
|
+
runPromise(planDeadlineServiceRaw.maybeEmitEscalationPolicyEvent(...args)),
|
|
317
|
+
emitDeadlineEvent: (...args) => runPromise(planDeadlineServiceRaw.emitDeadlineEvent(...args)),
|
|
318
|
+
enqueueDeadlineCheck: (...args) => runPromise(planDeadlineServiceRaw.enqueueDeadlineCheck(...args)),
|
|
319
|
+
evaluateDeadline: (...args) => planDeadlineServiceRaw.evaluateDeadline(...args),
|
|
320
|
+
} satisfies HostSvc<typeof PlanDeadlineServiceTag>
|
|
321
|
+
const planExecutorServiceRaw = resolveRaw(PlanExecutorServiceTag)
|
|
322
|
+
const planExecutorService = {
|
|
323
|
+
submitNodeResult: (...args) => runPromise(planExecutorServiceRaw.submitNodeResult(...args)),
|
|
324
|
+
submitHumanNodeResponse: (...args) => runPromise(planExecutorServiceRaw.submitHumanNodeResponse(...args)),
|
|
325
|
+
resumeRun: (...args) => runPromise(planExecutorServiceRaw.resumeRun(...args)),
|
|
326
|
+
transitionNodeToRunning: (...args) => runPromise(planExecutorServiceRaw.transitionNodeToRunning(...args)),
|
|
327
|
+
blockNodeOnDispatchFailure: (...args) => runPromise(planExecutorServiceRaw.blockNodeOnDispatchFailure(...args)),
|
|
328
|
+
promoteDelayedNode: (...args) => runPromise(planExecutorServiceRaw.promoteDelayedNode(...args)),
|
|
329
|
+
syncRunGraph: (...args) => runPromise(planExecutorServiceRaw.syncRunGraph(...args)),
|
|
330
|
+
resolveFailureAction: (...args) => planExecutorServiceRaw.resolveFailureAction(...args),
|
|
331
|
+
buildResolvedInput: (...args) => runPromise(planExecutorServiceRaw.buildResolvedInput(...args)),
|
|
332
|
+
} satisfies HostSvc<typeof PlanExecutorServiceTag>
|
|
333
|
+
const planRunService = bindEffectService(runPromise, resolveRaw(PlanRunServiceTag))
|
|
334
|
+
const planTemplateService = bindEffectService(runPromise, resolveRaw(PlanTemplateServiceTag))
|
|
335
|
+
const planCoordinationServiceRaw = resolveRaw(PlanCoordinationServiceTag)
|
|
336
|
+
const { isStale, validateNoCycles, ...planCoordinationEffectMethods } = planCoordinationServiceRaw
|
|
337
|
+
const planCoordinationService = {
|
|
338
|
+
...bindEffectService(runPromise, planCoordinationEffectMethods),
|
|
339
|
+
isStale,
|
|
340
|
+
validateNoCycles,
|
|
341
|
+
} satisfies HostSvc<typeof PlanCoordinationServiceTag>
|
|
342
|
+
const planSchedulerServiceRaw = resolveRaw(PlanSchedulerServiceTag)
|
|
343
|
+
const planSchedulerService = {
|
|
344
|
+
createSchedule: (...args) => runPromise(planSchedulerServiceRaw.createSchedule(...args)),
|
|
345
|
+
fireScheduleById: (...args) => runPromise(planSchedulerServiceRaw.fireScheduleById(...args)),
|
|
346
|
+
fireSchedule: (...args) => runPromise(planSchedulerServiceRaw.fireSchedule(...args)),
|
|
347
|
+
recoverActiveSchedules: (...args) => runPromise(planSchedulerServiceRaw.recoverActiveSchedules(...args)),
|
|
348
|
+
cancelSchedule: (...args) => runPromise(planSchedulerServiceRaw.cancelSchedule(...args)),
|
|
349
|
+
pauseSchedule: (...args) => runPromise(planSchedulerServiceRaw.pauseSchedule(...args)),
|
|
350
|
+
resumeSchedule: (...args) => runPromise(planSchedulerServiceRaw.resumeSchedule(...args)),
|
|
351
|
+
listSchedules: (...args) => runPromise(planSchedulerServiceRaw.listSchedules(...args)),
|
|
352
|
+
computeNextFireAt: (...args) => planSchedulerServiceRaw.computeNextFireAt(...args),
|
|
353
|
+
} satisfies HostSvc<typeof PlanSchedulerServiceTag>
|
|
354
|
+
const planAgentHeartbeatService = bindEffectService(runPromise, resolveRaw(PlanAgentHeartbeatServiceTag))
|
|
355
|
+
const planAgentQueryService = bindEffectService(runPromise, resolveRaw(PlanAgentQueryServiceTag))
|
|
356
|
+
const planCycleServiceRaw = resolveRaw(PlanCycleServiceTag)
|
|
357
|
+
const planCycleService = {
|
|
358
|
+
createCycle: (...args) => runPromise(planCycleServiceRaw.createCycle(...args)),
|
|
359
|
+
advanceCycle: (...args) => runPromise(planCycleServiceRaw.advanceCycle(...args)),
|
|
360
|
+
cancelCycle: (...args) => runPromise(planCycleServiceRaw.cancelCycle(...args)),
|
|
361
|
+
pauseCycle: (...args) => runPromise(planCycleServiceRaw.pauseCycle(...args)),
|
|
362
|
+
resumeCycle: (...args) => runPromise(planCycleServiceRaw.resumeCycle(...args)),
|
|
363
|
+
listCycles: (...args) => runPromise(planCycleServiceRaw.listCycles(...args)),
|
|
364
|
+
getCycle: (...args) => runPromise(planCycleServiceRaw.getCycle(...args)),
|
|
365
|
+
cycleScheduleToSpec: (...args) => planCycleServiceRaw.cycleScheduleToSpec(...args),
|
|
366
|
+
buildCarryForwardDraft: (...args) => planCycleServiceRaw.buildCarryForwardDraft(...args),
|
|
367
|
+
} satisfies HostSvc<typeof PlanCycleServiceTag>
|
|
368
|
+
const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
|
|
369
|
+
const threadMessageService = bindEffectService(runPromise, threadMessageServiceRaw)
|
|
370
|
+
const threadServiceRaw = resolveRaw(ThreadServiceTag)
|
|
371
|
+
const { formatMemoryBlockForPrompt, toPublicThread, ...threadServiceEffectMethods } = threadServiceRaw
|
|
372
|
+
const threadService = {
|
|
373
|
+
...bindEffectService(runPromise, threadServiceEffectMethods),
|
|
374
|
+
formatMemoryBlockForPrompt,
|
|
375
|
+
toPublicThread,
|
|
376
|
+
} satisfies PromisifiedThreadService
|
|
377
|
+
const threadTitleService = bindEffectService(runPromise, resolveRaw(ThreadTitleServiceTag))
|
|
304
378
|
const firecrawl = resolveRaw(FirecrawlTag)
|
|
305
379
|
const agentConfig = resolveRaw(AgentConfigServiceTag)
|
|
306
380
|
|
|
307
381
|
// ── Resolve the raw service instances once for inline Effect composition ──
|
|
308
|
-
// `
|
|
309
|
-
//
|
|
310
|
-
// `continueApproval` wrappers below need the raw Effect-returning
|
|
311
|
-
// signatures so they can `yield*` service methods inside `Effect.gen`.
|
|
312
|
-
const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
|
|
313
|
-
const threadServiceRaw = resolveRaw(ThreadServiceTag)
|
|
382
|
+
// `getMessage` / `sendMessage` / `continueApproval` still compose multiple
|
|
383
|
+
// service calls in a single fiber, so they keep the raw Effect methods here.
|
|
314
384
|
|
|
315
385
|
const services: LotaRuntimeServices = {
|
|
316
386
|
agentConfig,
|
|
317
387
|
database: db,
|
|
318
388
|
redis: redisManager,
|
|
319
|
-
closeRedisConnection: () =>
|
|
389
|
+
closeRedisConnection: () =>
|
|
390
|
+
runPromise(
|
|
391
|
+
Effect.tryPromise({
|
|
392
|
+
try: () => redisManager.closeConnection(),
|
|
393
|
+
catch: (cause) => new ServiceError({ message: 'Failed to close Redis connection.', cause }),
|
|
394
|
+
}),
|
|
395
|
+
),
|
|
320
396
|
firecrawl,
|
|
321
397
|
agentActivityService,
|
|
322
398
|
artifactService,
|
|
@@ -347,14 +423,16 @@ export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInpu
|
|
|
347
423
|
threadMessageService,
|
|
348
424
|
threadService,
|
|
349
425
|
threadTitleService,
|
|
350
|
-
createThreadApprovalContinuationStream: (
|
|
351
|
-
threadTurnService.createThreadApprovalContinuationStream(
|
|
352
|
-
createThreadNativeToolApprovalStream: (
|
|
353
|
-
|
|
426
|
+
createThreadApprovalContinuationStream: (params: Parameters<typeof createThreadApprovalContinuationStream>[0]) =>
|
|
427
|
+
runPromise(threadTurnService.createThreadApprovalContinuationStream(params)),
|
|
428
|
+
createThreadNativeToolApprovalStream: (params: Parameters<typeof createThreadNativeToolApprovalStream>[0]) =>
|
|
429
|
+
runPromise(threadTurnService.createThreadNativeToolApprovalStream(params)),
|
|
430
|
+
createThreadTurnStream: (params: Parameters<typeof createThreadTurnStream>[0]) =>
|
|
431
|
+
runPromise(threadTurnService.createThreadTurnStream(params)),
|
|
354
432
|
isApprovalContinuationRequest: isApprovalContinuationRequestFn,
|
|
355
|
-
launchBackgroundThreadWork: (
|
|
356
|
-
runThreadTurnInBackground: (
|
|
357
|
-
triggerPlanNodeTurn: (
|
|
433
|
+
launchBackgroundThreadWork: (params) => runPromise(threadTurnService.launchBackgroundThreadWork(params)),
|
|
434
|
+
runThreadTurnInBackground: (params) => runPromise(threadTurnService.runThreadTurnInBackground(params)),
|
|
435
|
+
triggerPlanNodeTurn: (params) => runPromise(threadTurnService.triggerPlanNodeTurn(params)),
|
|
358
436
|
}
|
|
359
437
|
|
|
360
438
|
const lota: LotaRuntimeLota = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Context } from 'effect'
|
|
1
|
+
import type { Context, Effect } from 'effect'
|
|
2
2
|
|
|
3
3
|
import type { DatabaseServiceTag } from '../effect/services'
|
|
4
4
|
import type { LotaQueuesRuntime } from '../queues/queues.service'
|
|
@@ -19,6 +19,7 @@ type StartWorkerResult = ReturnType<LotaQueuesRuntime['autonomousJob']['startWor
|
|
|
19
19
|
|
|
20
20
|
export interface LotaRuntimeWorkerServices {
|
|
21
21
|
databaseService: Context.Service.Shape<typeof DatabaseServiceTag>
|
|
22
|
+
runPromise: <A, E, R>(effect: Effect.Effect<A, E, R>) => Promise<A>
|
|
22
23
|
threadService: Context.Service.Shape<typeof ThreadServiceTag>
|
|
23
24
|
contextCompactionService: Context.Service.Shape<typeof ContextCompactionServiceTag>
|
|
24
25
|
autonomousJobService: Context.Service.Shape<typeof AutonomousJobServiceTag>
|
|
@@ -102,6 +103,7 @@ export function buildRuntimeWorkerRegistry(
|
|
|
102
103
|
registerSignals: options.registerSignals,
|
|
103
104
|
deps: {
|
|
104
105
|
databaseService: services.databaseService,
|
|
106
|
+
runPromise: services.runPromise,
|
|
105
107
|
planSchedulerService: services.planSchedulerService,
|
|
106
108
|
planDeadlineService: services.planDeadlineService,
|
|
107
109
|
planExecutorService: services.planExecutorService,
|
|
@@ -10,7 +10,7 @@ interface ExecutableToolDefinition {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
class SocialChatAgentRunnerError extends Schema.TaggedErrorClass<SocialChatAgentRunnerError>()(
|
|
13
|
-
'SocialChatAgentRunnerError',
|
|
13
|
+
'@lota-sdk/core/SocialChatAgentRunnerError',
|
|
14
14
|
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
15
15
|
) {}
|
|
16
16
|
|
|
@@ -3,7 +3,7 @@ import type { Message, Thread } from 'chat'
|
|
|
3
3
|
import { Schema, Effect } from 'effect'
|
|
4
4
|
|
|
5
5
|
import type { ResolvedAgentConfig } from '../../config/agent-defaults'
|
|
6
|
-
import {
|
|
6
|
+
import { ERROR_TAGS } from '../../effect/errors'
|
|
7
7
|
import type {
|
|
8
8
|
SocialChatHistoryMessage,
|
|
9
9
|
SocialChatHistoryMetadata,
|
|
@@ -11,10 +11,10 @@ import type {
|
|
|
11
11
|
} from '../../services/social-chat-history.service'
|
|
12
12
|
import { toHistoryMessages, toOptionalTrimmedString } from '../thread-chat-helpers'
|
|
13
13
|
|
|
14
|
-
class SocialChatHistoryError extends Schema.TaggedErrorClass<SocialChatHistoryError>()(
|
|
15
|
-
|
|
16
|
-
cause: Schema.optional(Schema.Defect),
|
|
17
|
-
|
|
14
|
+
class SocialChatHistoryError extends Schema.TaggedErrorClass<SocialChatHistoryError>()(
|
|
15
|
+
ERROR_TAGS.SocialChatHistoryError,
|
|
16
|
+
{ message: Schema.String, cause: Schema.optional(Schema.Defect) },
|
|
17
|
+
) {}
|
|
18
18
|
|
|
19
19
|
export function readSlackAuthorName(message: Message): string | undefined {
|
|
20
20
|
return (
|
|
@@ -112,24 +112,27 @@ export function collectThreadMessages(thread: Thread, incomingMessage: Message):
|
|
|
112
112
|
Effect.gen(function* () {
|
|
113
113
|
const iterator = thread.allMessages[Symbol.asyncIterator]()
|
|
114
114
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
const collectMessages = (state: {
|
|
116
|
+
messages: Message[]
|
|
117
|
+
done: boolean
|
|
118
|
+
}): Effect.Effect<{ messages: Message[]; done: boolean }, SocialChatHistoryError> =>
|
|
119
|
+
state.done
|
|
120
|
+
? Effect.succeed(state)
|
|
121
|
+
: Effect.tryPromise({
|
|
121
122
|
try: () => iterator.next(),
|
|
122
123
|
catch: (error: unknown) =>
|
|
123
124
|
new SocialChatHistoryError({ message: 'Failed to read thread messages', cause: error }),
|
|
124
125
|
}).pipe(
|
|
125
|
-
Effect.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
Effect.flatMap((next) =>
|
|
127
|
+
collectMessages(
|
|
128
|
+
next.done
|
|
129
|
+
? { messages: state.messages, done: true }
|
|
130
|
+
: { messages: [...state.messages, next.value], done: false },
|
|
131
|
+
),
|
|
129
132
|
),
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const collected = yield* collectMessages({ messages: [] as Message[], done: false })
|
|
133
136
|
|
|
134
137
|
return collected.messages.length > 0
|
|
135
138
|
? collected.messages
|