@lota-sdk/core 0.4.9 → 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 +2 -2
- package/src/ai/embedding-cache.ts +3 -1
- package/src/ai-gateway/ai-gateway.ts +38 -10
- package/src/config/agent-defaults.ts +22 -9
- package/src/config/agent-types.ts +1 -1
- package/src/config/background-processing.ts +1 -1
- package/src/config/index.ts +0 -1
- package/src/config/logger.ts +20 -7
- package/src/config/thread-defaults.ts +12 -4
- package/src/create-runtime.ts +69 -656
- package/src/db/memory-query-builder.ts +2 -1
- package/src/db/memory-store.ts +29 -20
- package/src/db/memory.ts +188 -195
- package/src/db/service-normalization.ts +97 -64
- package/src/db/service.ts +706 -538
- package/src/db/startup.ts +30 -19
- package/src/effect/awaitable-effect.ts +46 -37
- package/src/effect/helpers.ts +30 -5
- package/src/effect/index.ts +7 -5
- package/src/effect/layers.ts +82 -72
- package/src/effect/runtime.ts +18 -3
- package/src/effect/services.ts +15 -11
- package/src/embeddings/provider.ts +65 -66
- package/src/index.ts +13 -11
- package/src/queues/autonomous-job.queue.ts +59 -71
- package/src/queues/context-compaction.queue.ts +6 -18
- package/src/queues/delayed-node-promotion.queue.ts +9 -17
- package/src/queues/organization-learning.queue.ts +17 -4
- package/src/queues/plan-agent-heartbeat.queue.ts +23 -20
- package/src/queues/plan-scheduler.queue.ts +6 -18
- package/src/queues/post-chat-memory.queue.ts +6 -18
- package/src/queues/queue-factory.ts +128 -50
- package/src/queues/title-generation.queue.ts +6 -17
- package/src/redis/connection.ts +181 -164
- package/src/redis/runtime-connection.ts +13 -3
- package/src/redis/stream-context.ts +17 -9
- package/src/runtime/agent-runtime-policy.ts +1 -1
- package/src/runtime/agent-stream-helpers.ts +15 -11
- package/src/runtime/chat-run-orchestration.ts +1 -1
- package/src/runtime/context-compaction/context-compaction-runtime.ts +1 -1
- package/src/runtime/context-compaction/context-compaction.ts +126 -82
- package/src/runtime/domain-layer.ts +192 -0
- package/src/runtime/graph-designer.ts +15 -7
- package/src/runtime/helper-model.ts +8 -4
- package/src/runtime/index.ts +0 -1
- package/src/runtime/memory/memory-block.ts +19 -9
- package/src/runtime/memory/memory-pipeline.ts +53 -66
- package/src/runtime/memory/memory-scope.ts +33 -29
- package/src/runtime/plugin-resolution.ts +33 -54
- package/src/runtime/post-turn-side-effects.ts +6 -26
- package/src/runtime/retrieval-adapters.ts +4 -4
- package/src/runtime/runtime-accessors.ts +92 -0
- package/src/runtime/runtime-config.ts +3 -3
- package/src/runtime/runtime-extensions.ts +20 -9
- 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 +7 -5
- package/src/runtime/social-chat/social-chat-history.ts +21 -12
- package/src/runtime/social-chat/social-chat.ts +401 -365
- package/src/runtime/team-consultation/team-consultation-orchestrator.ts +58 -52
- package/src/runtime/thread-turn-context.ts +21 -27
- package/src/services/agent-activity.service.ts +1 -1
- package/src/services/agent-executor.service.ts +179 -187
- package/src/services/artifact.service.ts +10 -5
- package/src/services/attachment.service.ts +35 -1
- package/src/services/autonomous-job.service.ts +58 -56
- package/src/services/background-work.service.ts +54 -0
- package/src/services/chat-run-registry.service.ts +3 -1
- package/src/services/context-compaction.service.ts +1 -1
- package/src/services/document-chunk.service.ts +8 -17
- package/src/services/execution-plan/execution-plan-graph.ts +74 -52
- package/src/services/execution-plan/execution-plan.service.ts +1 -1
- package/src/services/feedback-loop.service.ts +1 -1
- package/src/services/global-orchestrator.service.ts +33 -10
- package/src/services/graph-full-routing.ts +44 -33
- package/src/services/index.ts +1 -0
- package/src/services/institutional-memory.service.ts +8 -17
- package/src/services/learned-skill.service.ts +38 -35
- package/src/services/memory/memory-errors.ts +27 -0
- package/src/services/memory/memory-org-memory.ts +14 -3
- package/src/services/memory/memory-preseeded.ts +10 -4
- package/src/services/memory/memory-utils.ts +2 -1
- package/src/services/memory/memory.service.ts +26 -44
- package/src/services/memory/rerank.service.ts +3 -11
- package/src/services/monitoring-window.service.ts +1 -1
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +2 -2
- package/src/services/notification.service.ts +16 -4
- package/src/services/organization-member.service.ts +1 -1
- package/src/services/organization.service.ts +34 -51
- package/src/services/ownership-dispatcher.service.ts +132 -90
- package/src/services/plan/plan-agent-heartbeat.service.ts +1 -1
- package/src/services/plan/plan-agent-query.service.ts +1 -1
- package/src/services/plan/plan-approval.service.ts +52 -48
- package/src/services/plan/plan-artifact.service.ts +2 -2
- package/src/services/plan/plan-builder.service.ts +2 -2
- package/src/services/plan/plan-checkpoint.service.ts +1 -1
- package/src/services/plan/plan-compiler.service.ts +1 -1
- package/src/services/plan/plan-completion-side-effects.ts +18 -24
- package/src/services/plan/plan-coordination.service.ts +1 -1
- package/src/services/plan/plan-cycle.service.ts +171 -164
- package/src/services/plan/plan-deadline.service.ts +290 -304
- package/src/services/plan/plan-event-delivery.service.ts +44 -39
- package/src/services/plan/plan-executor-graph.ts +114 -67
- package/src/services/plan/plan-executor-helpers.ts +60 -75
- package/src/services/plan/plan-executor.service.ts +550 -467
- package/src/services/plan/plan-run.service.ts +12 -19
- package/src/services/plan/plan-scheduler.service.ts +27 -33
- package/src/services/plan/plan-template.service.ts +1 -1
- package/src/services/plan/plan-transaction-events.ts +8 -5
- package/src/services/plan/plan-validator.service.ts +1 -1
- package/src/services/plan/plan-workspace.service.ts +17 -11
- package/src/services/plugin-executor.service.ts +26 -21
- package/src/services/quality-metrics.service.ts +1 -1
- package/src/services/queue-job.service.ts +8 -17
- package/src/services/recent-activity-title.service.ts +17 -9
- package/src/services/recent-activity.service.ts +1 -1
- package/src/services/skill-resolver.service.ts +1 -1
- package/src/services/social-chat-history.service.ts +37 -20
- package/src/services/system-executor.service.ts +25 -20
- package/src/services/thread/thread-bootstrap.ts +26 -10
- package/src/services/thread/thread-listing.ts +2 -1
- package/src/services/thread/thread-memory-block.ts +18 -5
- package/src/services/thread/thread-message.service.ts +24 -8
- package/src/services/thread/thread-title.service.ts +1 -1
- package/src/services/thread/thread-turn-execution.ts +1 -1
- package/src/services/thread/thread-turn-preparation.service.ts +18 -16
- package/src/services/thread/thread-turn-streaming.ts +12 -11
- package/src/services/thread/thread-turn.ts +43 -10
- package/src/services/thread/thread.service.ts +11 -2
- package/src/services/user.service.ts +1 -1
- package/src/services/write-intent-validator.service.ts +1 -1
- package/src/storage/attachment-storage.service.ts +7 -4
- package/src/storage/generated-document-storage.service.ts +1 -1
- package/src/system-agents/context-compaction.agent.ts +1 -1
- package/src/system-agents/helper-agent-options.ts +1 -1
- 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/system-agents/regular-chat-memory-digest.agent.ts +1 -1
- package/src/system-agents/skill-extractor.agent.ts +1 -1
- package/src/system-agents/skill-manager.agent.ts +1 -1
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +28 -17
- package/src/tools/fetch-webpage.tool.ts +20 -13
- package/src/tools/firecrawl-client.ts +13 -3
- package/src/tools/plan-approval.tool.ts +9 -1
- package/src/tools/search-web.tool.ts +16 -9
- package/src/tools/team-think.tool.ts +2 -2
- package/src/utils/async.ts +15 -6
- package/src/utils/errors.ts +27 -15
- package/src/workers/bootstrap.ts +25 -48
- package/src/workers/organization-learning.worker.ts +1 -1
- package/src/workers/regular-chat-memory-digest.runner.ts +25 -15
- package/src/workers/worker-utils.ts +20 -2
- package/src/config/search.ts +0 -3
- package/src/runtime/agent-types.ts +0 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin database connect/disconnect helpers and runtime disconnect assembly.
|
|
3
|
+
*
|
|
4
|
+
* The plugin connect/disconnect helpers run inside the supplied
|
|
5
|
+
* `ManagedRuntime` so spans, logging, and layer context stay consistent with
|
|
6
|
+
* the rest of the SDK runtime. `createRuntimeDisconnect` instead drives the
|
|
7
|
+
* shutdown sequence through the caller-supplied `runPromiseWithCurrentContext`
|
|
8
|
+
* (currently `Effect.runPromiseWith(Context.empty())`), which intentionally
|
|
9
|
+
* does not preserve the SDK runtime context — by then the runtime is being
|
|
10
|
+
* torn down.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ManagedRuntime } from 'effect'
|
|
14
|
+
import { Effect } from 'effect'
|
|
15
|
+
|
|
16
|
+
import { effectTryPromise } from '../effect/helpers'
|
|
17
|
+
import type { LotaPlugin } from './plugin-types'
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
|
|
20
|
+
type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
|
|
21
|
+
|
|
22
|
+
function getPluginLifecycleServices(plugin: LotaPlugin): Record<string, unknown> {
|
|
23
|
+
return plugin.services
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Build a plugin database connector that iterates the configured plugins and
|
|
28
|
+
* calls each `services.connectDatabase()` once, tracking completion in
|
|
29
|
+
* `connectedPluginDatabases` so repeated calls are idempotent.
|
|
30
|
+
*/
|
|
31
|
+
export function createPluginDatabaseConnector(
|
|
32
|
+
managedRuntime: SdkManagedRuntime,
|
|
33
|
+
pluginRuntime: Record<string, LotaPlugin>,
|
|
34
|
+
connectedPluginDatabases: Set<string>,
|
|
35
|
+
): () => Promise<void> {
|
|
36
|
+
return () =>
|
|
37
|
+
managedRuntime.runPromise(
|
|
38
|
+
Effect.gen(function* () {
|
|
39
|
+
for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
|
|
40
|
+
if (connectedPluginDatabases.has(pluginName)) {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const services = getPluginLifecycleServices(plugin)
|
|
45
|
+
const connectDatabase = Reflect.get(services, 'connectDatabase')
|
|
46
|
+
if (typeof connectDatabase !== 'function') {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const connectDatabaseFn = connectDatabase as (this: typeof services) => Promise<void>
|
|
51
|
+
yield* effectTryPromise(() => connectDatabaseFn.call(services))
|
|
52
|
+
connectedPluginDatabases.add(pluginName)
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Build a plugin database disconnector. Clears `connectedPluginDatabases`
|
|
60
|
+
* entries regardless of whether the plugin provides a `disconnectDatabase`
|
|
61
|
+
* hook, so the set stays in sync with actual connection state.
|
|
62
|
+
*/
|
|
63
|
+
export function createPluginDatabaseDisconnector(
|
|
64
|
+
managedRuntime: SdkManagedRuntime,
|
|
65
|
+
pluginRuntime: Record<string, LotaPlugin>,
|
|
66
|
+
connectedPluginDatabases: Set<string>,
|
|
67
|
+
): () => Promise<void> {
|
|
68
|
+
return () =>
|
|
69
|
+
managedRuntime.runPromise(
|
|
70
|
+
Effect.gen(function* () {
|
|
71
|
+
for (const [pluginName, plugin] of Object.entries(pluginRuntime)) {
|
|
72
|
+
if (!connectedPluginDatabases.has(pluginName)) {
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const services = getPluginLifecycleServices(plugin)
|
|
77
|
+
const disconnectDatabase = Reflect.get(services, 'disconnectDatabase')
|
|
78
|
+
if (typeof disconnectDatabase !== 'function') {
|
|
79
|
+
connectedPluginDatabases.delete(pluginName)
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const disconnectDatabaseFn = disconnectDatabase as (this: typeof services) => Promise<void>
|
|
84
|
+
yield* effectTryPromise(() => disconnectDatabaseFn.call(services))
|
|
85
|
+
connectedPluginDatabases.delete(pluginName)
|
|
86
|
+
}
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface CreateDisconnectInput {
|
|
92
|
+
managedRuntime: SdkManagedRuntime
|
|
93
|
+
runPromiseWithCurrentContext: <A, E>(effect: Effect.Effect<A, E, never>) => Promise<A>
|
|
94
|
+
socialChatShutdown: () => Promise<void>
|
|
95
|
+
disconnectPluginDatabases: () => Promise<void>
|
|
96
|
+
onFinalize: () => void
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Compose the runtime `disconnect()` function. The returned function is
|
|
101
|
+
* idempotent: the first call starts the shutdown sequence, subsequent calls
|
|
102
|
+
* return the same in-flight promise.
|
|
103
|
+
*/
|
|
104
|
+
export function createRuntimeDisconnect(input: CreateDisconnectInput): () => Promise<void> {
|
|
105
|
+
const { managedRuntime, runPromiseWithCurrentContext, socialChatShutdown, disconnectPluginDatabases, onFinalize } =
|
|
106
|
+
input
|
|
107
|
+
|
|
108
|
+
let disconnectPromise: Promise<void> | null = null
|
|
109
|
+
|
|
110
|
+
return () => {
|
|
111
|
+
if (disconnectPromise) {
|
|
112
|
+
return disconnectPromise
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
disconnectPromise = runPromiseWithCurrentContext(
|
|
116
|
+
Effect.gen(function* () {
|
|
117
|
+
yield* Effect.ignore(effectTryPromise(() => socialChatShutdown()))
|
|
118
|
+
yield* Effect.ignore(effectTryPromise(() => disconnectPluginDatabases()))
|
|
119
|
+
yield* effectTryPromise(() => managedRuntime.dispose())
|
|
120
|
+
}).pipe(Effect.ensuring(Effect.sync(onFinalize))),
|
|
121
|
+
)
|
|
122
|
+
return disconnectPromise
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eagerly resolves the full SDK service surface against a live ManagedRuntime.
|
|
3
|
+
*
|
|
4
|
+
* The previous implementation used per-property `get` Proxies that re-resolved
|
|
5
|
+
* each tag on every access. This module resolves every tag exactly once when
|
|
6
|
+
* the runtime starts and returns a plain object whose shape matches the
|
|
7
|
+
* `LotaRuntime['services']` + `LotaRuntime['lota']` contracts byte-for-byte.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ChatMessage } from '@lota-sdk/shared'
|
|
11
|
+
import type { Context, ManagedRuntime } from 'effect'
|
|
12
|
+
import { Effect } from 'effect'
|
|
13
|
+
|
|
14
|
+
import { ensureRecordId } from '../db/record-id'
|
|
15
|
+
import type { SurrealDBService } from '../db/service'
|
|
16
|
+
import { TABLES } from '../db/tables'
|
|
17
|
+
import type { AwaitableService, AwaitableValue } from '../effect/awaitable-effect'
|
|
18
|
+
import { toAwaitableService } from '../effect/awaitable-effect'
|
|
19
|
+
import { BadRequestError, NotFoundError } from '../effect/errors'
|
|
20
|
+
import { effectTryPromise } from '../effect/helpers'
|
|
21
|
+
import type { RedisConnectionManager } from '../redis/connection'
|
|
22
|
+
import type { SharedThreadStreamSubscriberTag } from '../redis/stream-context'
|
|
23
|
+
import { AgentActivityServiceTag } from '../services/agent-activity.service'
|
|
24
|
+
import { ArtifactServiceTag } from '../services/artifact.service'
|
|
25
|
+
import { AttachmentServiceTag } from '../services/attachment.service'
|
|
26
|
+
import { AutonomousJobServiceTag } from '../services/autonomous-job.service'
|
|
27
|
+
import { ContextCompactionServiceTag } from '../services/context-compaction.service'
|
|
28
|
+
import { DocumentChunkServiceTag } from '../services/document-chunk.service'
|
|
29
|
+
import { ExecutionPlanServiceTag } from '../services/execution-plan/execution-plan.service'
|
|
30
|
+
import { MemoryServiceTag } from '../services/memory/memory.service'
|
|
31
|
+
import { RerankServiceTag } from '../services/memory/rerank.service'
|
|
32
|
+
import { MutatingApprovalServiceTag } from '../services/mutating-approval.service'
|
|
33
|
+
import { OrganizationMemberServiceTag } from '../services/organization-member.service'
|
|
34
|
+
import { OrganizationServiceTag } from '../services/organization.service'
|
|
35
|
+
import { PlanAgentHeartbeatServiceTag } from '../services/plan/plan-agent-heartbeat.service'
|
|
36
|
+
import { PlanAgentQueryServiceTag } from '../services/plan/plan-agent-query.service'
|
|
37
|
+
import { PlanCoordinationServiceTag } from '../services/plan/plan-coordination.service'
|
|
38
|
+
import { PlanCycleServiceTag } from '../services/plan/plan-cycle.service'
|
|
39
|
+
import { PlanDeadlineServiceTag } from '../services/plan/plan-deadline.service'
|
|
40
|
+
import { PlanExecutorServiceTag } from '../services/plan/plan-executor.service'
|
|
41
|
+
import { PlanRunServiceTag } from '../services/plan/plan-run.service'
|
|
42
|
+
import { PlanSchedulerServiceTag } from '../services/plan/plan-scheduler.service'
|
|
43
|
+
import { PlanTemplateServiceTag } from '../services/plan/plan-template.service'
|
|
44
|
+
import { RecentActivityTitleServiceTag } from '../services/recent-activity-title.service'
|
|
45
|
+
import { RecentActivityServiceTag } from '../services/recent-activity.service'
|
|
46
|
+
import type { makeSocialChatHistoryService } from '../services/social-chat-history.service'
|
|
47
|
+
import { ThreadMessageServiceTag } from '../services/thread/thread-message.service'
|
|
48
|
+
import { ThreadTitleServiceTag } from '../services/thread/thread-title.service'
|
|
49
|
+
import { isApprovalContinuationRequest as isApprovalContinuationRequestFn } from '../services/thread/thread-turn'
|
|
50
|
+
import type {
|
|
51
|
+
createThreadApprovalContinuationStream,
|
|
52
|
+
createThreadNativeToolApprovalStream,
|
|
53
|
+
createThreadTurnStream,
|
|
54
|
+
runThreadTurnInBackground,
|
|
55
|
+
ThreadTurnServiceTag,
|
|
56
|
+
triggerPlanNodeTurn,
|
|
57
|
+
} from '../services/thread/thread-turn'
|
|
58
|
+
import { ThreadServiceTag } from '../services/thread/thread.service'
|
|
59
|
+
import { UserServiceTag } from '../services/user.service'
|
|
60
|
+
import { GeneratedDocumentStorageServiceTag } from '../storage/generated-document-storage.service'
|
|
61
|
+
import { routeThreadChatMessages } from './chat-request-routing'
|
|
62
|
+
|
|
63
|
+
// eslint-disable-next-line typescript-eslint/no-explicit-any -- ManagedRuntime is contravariant in R; `any` is the only valid wildcard
|
|
64
|
+
type SdkManagedRuntime = ManagedRuntime.ManagedRuntime<any, any>
|
|
65
|
+
|
|
66
|
+
// ── Type helpers (shared with create-runtime.ts's public interface) ──
|
|
67
|
+
type Svc<T extends { readonly Service: unknown }> = T['Service']
|
|
68
|
+
type HostSvc<T extends { readonly Service: object }> = AwaitableService<T['Service']>
|
|
69
|
+
|
|
70
|
+
export type AwaitableThreadService = HostSvc<typeof ThreadServiceTag> &
|
|
71
|
+
Pick<Svc<typeof ThreadServiceTag>, 'withActiveRunLease'>
|
|
72
|
+
export type AwaitableDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag> &
|
|
73
|
+
Pick<Svc<typeof DocumentChunkServiceTag>, 'syncVersionedChunks'>
|
|
74
|
+
|
|
75
|
+
export type ArchiveSdkThread = (
|
|
76
|
+
threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
|
|
77
|
+
status?: 'archived',
|
|
78
|
+
) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
|
|
79
|
+
|
|
80
|
+
export type UnarchiveSdkThread = (
|
|
81
|
+
threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
|
|
82
|
+
status?: 'active',
|
|
83
|
+
) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
|
|
84
|
+
|
|
85
|
+
export interface LotaRuntimeServices {
|
|
86
|
+
database: SurrealDBService
|
|
87
|
+
redis: RedisConnectionManager
|
|
88
|
+
closeRedisConnection: () => Promise<void>
|
|
89
|
+
agentActivityService: HostSvc<typeof AgentActivityServiceTag>
|
|
90
|
+
artifactService: HostSvc<typeof ArtifactServiceTag>
|
|
91
|
+
attachmentService: HostSvc<typeof AttachmentServiceTag>
|
|
92
|
+
autonomousJobService: HostSvc<typeof AutonomousJobServiceTag>
|
|
93
|
+
contextCompactionService: HostSvc<typeof ContextCompactionServiceTag>
|
|
94
|
+
documentChunkService: AwaitableDocumentChunkService
|
|
95
|
+
generatedDocumentStorageService: HostSvc<typeof GeneratedDocumentStorageServiceTag>
|
|
96
|
+
memoryService: HostSvc<typeof MemoryServiceTag>
|
|
97
|
+
rerankService: HostSvc<typeof RerankServiceTag>
|
|
98
|
+
verifyMutatingApproval: HostSvc<typeof MutatingApprovalServiceTag>
|
|
99
|
+
organizationService: HostSvc<typeof OrganizationServiceTag>
|
|
100
|
+
organizationMemberService: HostSvc<typeof OrganizationMemberServiceTag>
|
|
101
|
+
userService: HostSvc<typeof UserServiceTag>
|
|
102
|
+
recentActivityService: HostSvc<typeof RecentActivityServiceTag>
|
|
103
|
+
recentActivityTitleService: HostSvc<typeof RecentActivityTitleServiceTag>
|
|
104
|
+
socialChatHistoryService: ReturnType<typeof makeSocialChatHistoryService>
|
|
105
|
+
executionPlanService: HostSvc<typeof ExecutionPlanServiceTag>
|
|
106
|
+
planDeadlineService: HostSvc<typeof PlanDeadlineServiceTag>
|
|
107
|
+
planExecutorService: HostSvc<typeof PlanExecutorServiceTag>
|
|
108
|
+
planRunService: HostSvc<typeof PlanRunServiceTag>
|
|
109
|
+
planTemplateService: HostSvc<typeof PlanTemplateServiceTag>
|
|
110
|
+
planCoordinationService: HostSvc<typeof PlanCoordinationServiceTag>
|
|
111
|
+
planSchedulerService: HostSvc<typeof PlanSchedulerServiceTag>
|
|
112
|
+
planAgentHeartbeatService: HostSvc<typeof PlanAgentHeartbeatServiceTag>
|
|
113
|
+
planAgentQueryService: HostSvc<typeof PlanAgentQueryServiceTag>
|
|
114
|
+
planCycleService: HostSvc<typeof PlanCycleServiceTag>
|
|
115
|
+
threadMessageService: HostSvc<typeof ThreadMessageServiceTag>
|
|
116
|
+
threadService: AwaitableThreadService
|
|
117
|
+
threadTitleService: HostSvc<typeof ThreadTitleServiceTag>
|
|
118
|
+
createThreadApprovalContinuationStream: typeof createThreadApprovalContinuationStream
|
|
119
|
+
createThreadNativeToolApprovalStream: typeof createThreadNativeToolApprovalStream
|
|
120
|
+
createThreadTurnStream: typeof createThreadTurnStream
|
|
121
|
+
isApprovalContinuationRequest: typeof isApprovalContinuationRequestFn
|
|
122
|
+
runThreadTurnInBackground: typeof runThreadTurnInBackground
|
|
123
|
+
triggerPlanNodeTurn: typeof triggerPlanNodeTurn
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface LotaRuntimeLota {
|
|
127
|
+
organizations: {
|
|
128
|
+
create: AwaitableValue<Svc<typeof OrganizationServiceTag>['createOrganization']>
|
|
129
|
+
upsert: AwaitableValue<Svc<typeof OrganizationServiceTag>['upsertOrganization']>
|
|
130
|
+
get: AwaitableValue<Svc<typeof OrganizationServiceTag>['getOrganization']>
|
|
131
|
+
list: AwaitableValue<Svc<typeof OrganizationServiceTag>['listOrganizations']>
|
|
132
|
+
update: AwaitableValue<Svc<typeof OrganizationServiceTag>['updateOrganization']>
|
|
133
|
+
delete: AwaitableValue<Svc<typeof OrganizationServiceTag>['deleteOrganization']>
|
|
134
|
+
}
|
|
135
|
+
users: {
|
|
136
|
+
upsert: AwaitableValue<Svc<typeof UserServiceTag>['upsertUser']>
|
|
137
|
+
get: AwaitableValue<Svc<typeof UserServiceTag>['getUser']>
|
|
138
|
+
list: AwaitableValue<Svc<typeof UserServiceTag>['listUsers']>
|
|
139
|
+
update: AwaitableValue<Svc<typeof UserServiceTag>['updateUser']>
|
|
140
|
+
delete: AwaitableValue<Svc<typeof UserServiceTag>['deleteUser']>
|
|
141
|
+
}
|
|
142
|
+
memberships: {
|
|
143
|
+
add: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['addMembership']>
|
|
144
|
+
listForOrganization: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForOrganization']>
|
|
145
|
+
listForUser: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['listMembershipsForUser']>
|
|
146
|
+
remove: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['removeMembership']>
|
|
147
|
+
isMember: AwaitableValue<Svc<typeof OrganizationMemberServiceTag>['isMember']>
|
|
148
|
+
}
|
|
149
|
+
threads: {
|
|
150
|
+
create: AwaitableValue<Svc<typeof ThreadServiceTag>['createThread']>
|
|
151
|
+
list: AwaitableValue<Svc<typeof ThreadServiceTag>['listThreads']>
|
|
152
|
+
get: AwaitableValue<Svc<typeof ThreadServiceTag>['getThread']>
|
|
153
|
+
update: AwaitableValue<Svc<typeof ThreadServiceTag>['updateTitle']>
|
|
154
|
+
archive: AwaitableValue<ArchiveSdkThread>
|
|
155
|
+
unarchive: AwaitableValue<UnarchiveSdkThread>
|
|
156
|
+
delete: AwaitableValue<Svc<typeof ThreadServiceTag>['deleteThread']>
|
|
157
|
+
stop: AwaitableValue<Svc<typeof ThreadServiceTag>['stopActiveRun']>
|
|
158
|
+
listMessages: AwaitableValue<Svc<typeof ThreadMessageServiceTag>['listMessageHistoryPage']>
|
|
159
|
+
getMessage: (params: { threadId: string; messageId: string }) => Promise<ChatMessage>
|
|
160
|
+
sendMessage: (params: {
|
|
161
|
+
threadId: string
|
|
162
|
+
organizationId: string
|
|
163
|
+
userId: string
|
|
164
|
+
userName: string
|
|
165
|
+
messages: Parameters<typeof routeThreadChatMessages>[0]
|
|
166
|
+
}) => Promise<Awaited<ReturnType<typeof createThreadTurnStream>>>
|
|
167
|
+
continueApproval: (params: {
|
|
168
|
+
threadId: string
|
|
169
|
+
organizationId: string
|
|
170
|
+
userId: string
|
|
171
|
+
userName: string
|
|
172
|
+
messages: Parameters<typeof routeThreadChatMessages>[0]
|
|
173
|
+
}) => Promise<Awaited<ReturnType<typeof createThreadApprovalContinuationStream>>>
|
|
174
|
+
uploadAttachment: AwaitableValue<Svc<typeof AttachmentServiceTag>['uploadThreadAttachment']>
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface BuildRuntimeServiceSurfaceInput {
|
|
179
|
+
managedRuntime: SdkManagedRuntime
|
|
180
|
+
db: SurrealDBService
|
|
181
|
+
redisManager: RedisConnectionManager
|
|
182
|
+
sharedSubscriber: Svc<typeof SharedThreadStreamSubscriberTag>
|
|
183
|
+
threadTurnService: Svc<typeof ThreadTurnServiceTag>
|
|
184
|
+
socialChatHistoryService: ReturnType<typeof makeSocialChatHistoryService>
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface RuntimeServiceSurface {
|
|
188
|
+
services: LotaRuntimeServices
|
|
189
|
+
lota: LotaRuntimeLota
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Eagerly resolve the full service surface exactly once.
|
|
194
|
+
*
|
|
195
|
+
* All Effect-returning service methods are wrapped with `toAwaitableService`,
|
|
196
|
+
* which means callers can `await` them directly while they stay discoverable
|
|
197
|
+
* as Effects for composition.
|
|
198
|
+
*/
|
|
199
|
+
export function buildRuntimeServiceSurface(input: BuildRuntimeServiceSurfaceInput): RuntimeServiceSurface {
|
|
200
|
+
const { managedRuntime, db, redisManager, threadTurnService, socialChatHistoryService } = input
|
|
201
|
+
const runPromise = <A, E>(effect: Effect.Effect<A, E>): Promise<A> => managedRuntime.runPromise(effect)
|
|
202
|
+
|
|
203
|
+
const resolveRaw = <I, T>(tag: Context.Key<I, T>): T => managedRuntime.runSync(Effect.service(tag))
|
|
204
|
+
const resolveOnce = <I, T extends object>(tag: Context.Key<I, T>): AwaitableService<T> =>
|
|
205
|
+
toAwaitableService(resolveRaw(tag), { runPromise: (effect) => managedRuntime.runPromise(effect) })
|
|
206
|
+
|
|
207
|
+
// ── Resolve every tag eagerly. Each binding is a plain value from here. ──
|
|
208
|
+
const agentActivityService = resolveOnce(AgentActivityServiceTag)
|
|
209
|
+
const artifactService = resolveOnce(ArtifactServiceTag)
|
|
210
|
+
const attachmentService = resolveOnce(AttachmentServiceTag)
|
|
211
|
+
const autonomousJobService = resolveOnce(AutonomousJobServiceTag)
|
|
212
|
+
const contextCompactionService = resolveOnce(ContextCompactionServiceTag)
|
|
213
|
+
const documentChunkService = resolveOnce(DocumentChunkServiceTag) as AwaitableDocumentChunkService
|
|
214
|
+
const generatedDocumentStorageService = resolveOnce(GeneratedDocumentStorageServiceTag)
|
|
215
|
+
const memoryService = resolveOnce(MemoryServiceTag)
|
|
216
|
+
const rerankService = resolveOnce(RerankServiceTag)
|
|
217
|
+
const verifyMutatingApproval = resolveOnce(MutatingApprovalServiceTag)
|
|
218
|
+
const organizationService = resolveOnce(OrganizationServiceTag)
|
|
219
|
+
const organizationMemberService = resolveOnce(OrganizationMemberServiceTag)
|
|
220
|
+
const userService = resolveOnce(UserServiceTag)
|
|
221
|
+
const recentActivityService = resolveOnce(RecentActivityServiceTag)
|
|
222
|
+
const recentActivityTitleService = resolveOnce(RecentActivityTitleServiceTag)
|
|
223
|
+
const executionPlanService = resolveOnce(ExecutionPlanServiceTag)
|
|
224
|
+
const planDeadlineService = resolveOnce(PlanDeadlineServiceTag)
|
|
225
|
+
const planExecutorService = resolveOnce(PlanExecutorServiceTag)
|
|
226
|
+
const planRunService = resolveOnce(PlanRunServiceTag)
|
|
227
|
+
const planTemplateService = resolveOnce(PlanTemplateServiceTag)
|
|
228
|
+
const planCoordinationService = resolveOnce(PlanCoordinationServiceTag)
|
|
229
|
+
const planSchedulerService = resolveOnce(PlanSchedulerServiceTag)
|
|
230
|
+
const planAgentHeartbeatService = resolveOnce(PlanAgentHeartbeatServiceTag)
|
|
231
|
+
const planAgentQueryService = resolveOnce(PlanAgentQueryServiceTag)
|
|
232
|
+
const planCycleService = resolveOnce(PlanCycleServiceTag)
|
|
233
|
+
const threadMessageService = resolveOnce(ThreadMessageServiceTag)
|
|
234
|
+
const threadService = resolveOnce(ThreadServiceTag) as AwaitableThreadService
|
|
235
|
+
const threadTitleService = resolveOnce(ThreadTitleServiceTag)
|
|
236
|
+
|
|
237
|
+
// ── Resolve the raw service instances once for inline Effect composition ──
|
|
238
|
+
// `toAwaitableService` (used above) erases Effect return types so callers
|
|
239
|
+
// can `await` directly. The `getMessage`/`sendMessage`/`continueApproval`
|
|
240
|
+
// wrappers below need the raw Effect-returning signatures so they can
|
|
241
|
+
// `yield*` service methods inside their `Effect.gen` blocks.
|
|
242
|
+
const threadMessageServiceRaw = resolveRaw(ThreadMessageServiceTag)
|
|
243
|
+
const threadServiceRaw = resolveRaw(ThreadServiceTag)
|
|
244
|
+
|
|
245
|
+
const services: LotaRuntimeServices = {
|
|
246
|
+
database: db,
|
|
247
|
+
redis: redisManager,
|
|
248
|
+
closeRedisConnection: () => runPromise(effectTryPromise(() => redisManager.closeConnection())),
|
|
249
|
+
agentActivityService,
|
|
250
|
+
artifactService,
|
|
251
|
+
attachmentService,
|
|
252
|
+
autonomousJobService,
|
|
253
|
+
contextCompactionService,
|
|
254
|
+
documentChunkService,
|
|
255
|
+
generatedDocumentStorageService,
|
|
256
|
+
memoryService,
|
|
257
|
+
rerankService,
|
|
258
|
+
verifyMutatingApproval,
|
|
259
|
+
organizationService,
|
|
260
|
+
organizationMemberService,
|
|
261
|
+
userService,
|
|
262
|
+
recentActivityService,
|
|
263
|
+
recentActivityTitleService,
|
|
264
|
+
socialChatHistoryService,
|
|
265
|
+
executionPlanService,
|
|
266
|
+
planDeadlineService,
|
|
267
|
+
planExecutorService,
|
|
268
|
+
planRunService,
|
|
269
|
+
planTemplateService,
|
|
270
|
+
planCoordinationService,
|
|
271
|
+
planSchedulerService,
|
|
272
|
+
planAgentHeartbeatService,
|
|
273
|
+
planAgentQueryService,
|
|
274
|
+
planCycleService,
|
|
275
|
+
threadMessageService,
|
|
276
|
+
threadService,
|
|
277
|
+
threadTitleService,
|
|
278
|
+
createThreadApprovalContinuationStream: (...args) =>
|
|
279
|
+
runPromise(threadTurnService.createThreadApprovalContinuationStream(...args)),
|
|
280
|
+
createThreadNativeToolApprovalStream: (...args) =>
|
|
281
|
+
runPromise(threadTurnService.createThreadNativeToolApprovalStream(...args)),
|
|
282
|
+
createThreadTurnStream: (...args) => runPromise(threadTurnService.createThreadTurnStream(...args)),
|
|
283
|
+
isApprovalContinuationRequest: isApprovalContinuationRequestFn,
|
|
284
|
+
runThreadTurnInBackground: (...args) => runPromise(threadTurnService.runThreadTurnInBackground(...args)),
|
|
285
|
+
triggerPlanNodeTurn: (...args) => runPromise(threadTurnService.triggerPlanNodeTurn(...args)),
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const lota: LotaRuntimeLota = {
|
|
289
|
+
organizations: {
|
|
290
|
+
create: (...args) => organizationService.createOrganization(...args),
|
|
291
|
+
upsert: (...args) => organizationService.upsertOrganization(...args),
|
|
292
|
+
get: (...args) => organizationService.getOrganization(...args),
|
|
293
|
+
list: (...args) => organizationService.listOrganizations(...args),
|
|
294
|
+
update: (...args) => organizationService.updateOrganization(...args),
|
|
295
|
+
delete: (...args) => organizationService.deleteOrganization(...args),
|
|
296
|
+
},
|
|
297
|
+
users: {
|
|
298
|
+
upsert: (...args) => userService.upsertUser(...args),
|
|
299
|
+
get: (...args) => userService.getUser(...args),
|
|
300
|
+
list: (...args) => userService.listUsers(...args),
|
|
301
|
+
update: (...args) => userService.updateUser(...args),
|
|
302
|
+
delete: (...args) => userService.deleteUser(...args),
|
|
303
|
+
},
|
|
304
|
+
memberships: {
|
|
305
|
+
add: (...args) => organizationMemberService.addMembership(...args),
|
|
306
|
+
listForOrganization: (...args) => organizationMemberService.listMembershipsForOrganization(...args),
|
|
307
|
+
listForUser: (...args) => organizationMemberService.listMembershipsForUser(...args),
|
|
308
|
+
remove: (...args) => organizationMemberService.removeMembership(...args),
|
|
309
|
+
isMember: (...args) => organizationMemberService.isMember(...args),
|
|
310
|
+
},
|
|
311
|
+
threads: {
|
|
312
|
+
create: (...args) => threadService.createThread(...args),
|
|
313
|
+
list: (...args) => threadService.listThreads(...args),
|
|
314
|
+
get: (...args) => threadService.getThread(...args),
|
|
315
|
+
update: (...args) => threadService.updateTitle(...args),
|
|
316
|
+
archive: (threadId, status = 'archived') => threadService.updateStatus(threadId, status),
|
|
317
|
+
unarchive: (threadId, status = 'active') => threadService.updateStatus(threadId, status),
|
|
318
|
+
delete: (...args) => threadService.deleteThread(...args),
|
|
319
|
+
stop: (...args) => threadService.stopActiveRun(...args),
|
|
320
|
+
listMessages: (...args) => threadMessageService.listMessageHistoryPage(...args),
|
|
321
|
+
getMessage: ({ threadId, messageId }) =>
|
|
322
|
+
runPromise(
|
|
323
|
+
Effect.gen(function* () {
|
|
324
|
+
const messages = yield* threadMessageServiceRaw.listMessages(ensureRecordId(threadId, TABLES.THREAD))
|
|
325
|
+
const message = messages.find((candidate: ChatMessage) => candidate.id === messageId)
|
|
326
|
+
if (!message) {
|
|
327
|
+
return yield* new NotFoundError({
|
|
328
|
+
resource: 'Thread message',
|
|
329
|
+
id: messageId,
|
|
330
|
+
message: `Thread message not found: ${messageId}`,
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
return message
|
|
334
|
+
}),
|
|
335
|
+
),
|
|
336
|
+
sendMessage: ({ threadId, organizationId, userId, userName, messages }) =>
|
|
337
|
+
runPromise(
|
|
338
|
+
Effect.gen(function* () {
|
|
339
|
+
const threadRef = ensureRecordId(threadId, TABLES.THREAD)
|
|
340
|
+
const thread = yield* threadServiceRaw.getThread(threadRef)
|
|
341
|
+
const routed = routeThreadChatMessages(messages)
|
|
342
|
+
if (routed.kind !== 'turn') {
|
|
343
|
+
return yield* new BadRequestError({
|
|
344
|
+
message: routed.kind === 'invalid' ? routed.message : 'Expected a user turn payload.',
|
|
345
|
+
})
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return yield* threadTurnService.createThreadTurnStream({
|
|
349
|
+
thread,
|
|
350
|
+
threadRef,
|
|
351
|
+
orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
|
|
352
|
+
userRef: ensureRecordId(userId, TABLES.USER),
|
|
353
|
+
userName,
|
|
354
|
+
inputMessage: routed.inputMessage,
|
|
355
|
+
})
|
|
356
|
+
}),
|
|
357
|
+
),
|
|
358
|
+
continueApproval: ({ threadId, organizationId, userId, userName, messages }) =>
|
|
359
|
+
runPromise(
|
|
360
|
+
Effect.gen(function* () {
|
|
361
|
+
const threadRef = ensureRecordId(threadId, TABLES.THREAD)
|
|
362
|
+
const thread = yield* threadServiceRaw.getThread(threadRef)
|
|
363
|
+
const routed = routeThreadChatMessages(messages)
|
|
364
|
+
if (routed.kind !== 'approval-continuation') {
|
|
365
|
+
return yield* new BadRequestError({
|
|
366
|
+
message:
|
|
367
|
+
routed.kind === 'invalid' ? routed.message : 'Expected approval continuation messages payload.',
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return yield* threadTurnService.createThreadApprovalContinuationStream({
|
|
372
|
+
thread,
|
|
373
|
+
threadRef,
|
|
374
|
+
orgRef: ensureRecordId(organizationId, TABLES.ORGANIZATION),
|
|
375
|
+
userRef: ensureRecordId(userId, TABLES.USER),
|
|
376
|
+
userName,
|
|
377
|
+
approvalMessages: routed.approvalMessages,
|
|
378
|
+
})
|
|
379
|
+
}),
|
|
380
|
+
),
|
|
381
|
+
uploadAttachment: (...args) => attachmentService.uploadThreadAttachment(...args),
|
|
382
|
+
},
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return { services, lota }
|
|
386
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-slot runtime token. `createLotaRuntime()` claims the slot on success
|
|
3
|
+
* and releases it on disconnect, enforcing the "one runtime per process"
|
|
4
|
+
* invariant. Kept as a small, typed module so the guard is trivially testable
|
|
5
|
+
* and stays out of the main entrypoint.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Effect } from 'effect'
|
|
9
|
+
|
|
10
|
+
import { ConfigurationError } from '../effect/errors'
|
|
11
|
+
|
|
12
|
+
let activeToken: symbol | null = null
|
|
13
|
+
|
|
14
|
+
function buildConflictError(): ConfigurationError {
|
|
15
|
+
return new ConfigurationError({
|
|
16
|
+
message: 'createLotaRuntime() is process-scoped. Disconnect the active runtime before creating another one.',
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Claim the process-wide runtime slot. Fails with `ConfigurationError` if it
|
|
22
|
+
* is already held. Preferred inside `Effect.gen` so the failure is expressed
|
|
23
|
+
* through the typed error channel instead of a thrown value.
|
|
24
|
+
*/
|
|
25
|
+
export function acquireRuntimeTokenEffect(): Effect.Effect<symbol, ConfigurationError> {
|
|
26
|
+
return Effect.suspend(() => {
|
|
27
|
+
if (activeToken) {
|
|
28
|
+
return Effect.fail(buildConflictError())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const token = Symbol('lota-runtime')
|
|
32
|
+
activeToken = token
|
|
33
|
+
return Effect.succeed(token)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Release the slot only if the caller holds the current token. */
|
|
38
|
+
export function releaseRuntimeToken(token: symbol): void {
|
|
39
|
+
if (activeToken === token) {
|
|
40
|
+
activeToken = null
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Diagnostic: whether a runtime is currently active in this process. */
|
|
45
|
+
export function isRuntimeTokenActive(): boolean {
|
|
46
|
+
return activeToken !== null
|
|
47
|
+
}
|
|
@@ -46,13 +46,13 @@ export function withLoggedSocialToolSet(
|
|
|
46
46
|
execute: (...args: unknown[]): Promise<unknown> =>
|
|
47
47
|
Effect.runPromise(
|
|
48
48
|
Effect.gen(function* () {
|
|
49
|
-
aiLogger.
|
|
49
|
+
aiLogger.debug`Slack social-chat tool start: agentId=${params.agentId}, tool=${toolName}, channelId=${params.channelId}, threadId=${params.threadId}`
|
|
50
50
|
const result: unknown = yield* Effect.tryPromise({
|
|
51
51
|
try: () => executableTool.execute(...args),
|
|
52
52
|
catch: (error: unknown) => new SocialChatAgentRunnerError({ message: String(error), cause: error }),
|
|
53
53
|
})
|
|
54
54
|
params.executedToolNames.push(toolName)
|
|
55
|
-
aiLogger.
|
|
55
|
+
aiLogger.debug`Slack social-chat tool finish: agentId=${params.agentId}, tool=${toolName}, channelId=${params.channelId}, threadId=${params.threadId}`
|
|
56
56
|
return result
|
|
57
57
|
}).pipe(
|
|
58
58
|
Effect.tapError((error) =>
|
|
@@ -117,9 +117,11 @@ function runSocialAgentTurnEffect(params: {
|
|
|
117
117
|
extraInstructions: runtimeConfig.extraInstructions,
|
|
118
118
|
stopWhen: [stepCountIs(runtimeConfig.maxSteps)],
|
|
119
119
|
})
|
|
120
|
-
const response = yield* Effect.
|
|
121
|
-
agent.generate({ prompt: params.prompt, abortSignal: params.abortSignal }),
|
|
122
|
-
|
|
120
|
+
const response = yield* Effect.tryPromise({
|
|
121
|
+
try: () => agent.generate({ prompt: params.prompt, abortSignal: params.abortSignal }),
|
|
122
|
+
catch: (cause) =>
|
|
123
|
+
new SocialChatAgentRunnerError({ message: `Social chat agent ${params.agentId} generate() failed.`, cause }),
|
|
124
|
+
})
|
|
123
125
|
const text = response.text.trim()
|
|
124
126
|
if (!text) {
|
|
125
127
|
return yield* new SocialChatAgentRunnerError({
|
|
@@ -2,6 +2,7 @@ import { stripSlackToolExecutionNoticeMarkdown } from '@lota-sdk/shared'
|
|
|
2
2
|
import type { Message, Thread } from 'chat'
|
|
3
3
|
import { Schema, Effect } from 'effect'
|
|
4
4
|
|
|
5
|
+
import { iterateEffect } from '../../effect/helpers'
|
|
5
6
|
import type {
|
|
6
7
|
SocialChatHistoryMessage,
|
|
7
8
|
SocialChatHistoryMetadata,
|
|
@@ -107,21 +108,29 @@ export function collectThreadMessages(thread: Thread, incomingMessage: Message):
|
|
|
107
108
|
return Effect.runPromise(
|
|
108
109
|
Effect.catch(
|
|
109
110
|
Effect.gen(function* () {
|
|
110
|
-
const collected: Message[] = []
|
|
111
111
|
const iterator = thread.allMessages[Symbol.asyncIterator]()
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
const collected = yield* iterateEffect<{ messages: Message[]; done: boolean }, SocialChatHistoryError, never>(
|
|
114
|
+
{ messages: [], done: false },
|
|
115
|
+
{
|
|
116
|
+
while: (state) => !state.done,
|
|
117
|
+
body: (state) =>
|
|
118
|
+
Effect.tryPromise({
|
|
119
|
+
try: () => iterator.next(),
|
|
120
|
+
catch: (error: unknown) =>
|
|
121
|
+
new SocialChatHistoryError({ message: 'Failed to read thread messages', cause: error }),
|
|
122
|
+
}).pipe(
|
|
123
|
+
Effect.map((next) =>
|
|
124
|
+
next.done
|
|
125
|
+
? { messages: state.messages, done: true }
|
|
126
|
+
: { messages: [...state.messages, next.value], done: false },
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
},
|
|
130
|
+
)
|
|
122
131
|
|
|
123
|
-
return collected.length > 0
|
|
124
|
-
? collected
|
|
132
|
+
return collected.messages.length > 0
|
|
133
|
+
? collected.messages
|
|
125
134
|
: thread.recentMessages.length > 0
|
|
126
135
|
? [...thread.recentMessages]
|
|
127
136
|
: [incomingMessage]
|