@lota-sdk/core 0.4.8 → 0.4.9

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.
Files changed (259) hide show
  1. package/package.json +11 -12
  2. package/src/ai/embedding-cache.ts +94 -22
  3. package/src/ai-gateway/ai-gateway.ts +738 -223
  4. package/src/config/agent-defaults.ts +176 -75
  5. package/src/config/agent-types.ts +54 -4
  6. package/src/config/constants.ts +8 -2
  7. package/src/config/logger.ts +286 -19
  8. package/src/config/thread-defaults.ts +33 -21
  9. package/src/create-runtime.ts +725 -387
  10. package/src/db/base.service.ts +52 -28
  11. package/src/db/cursor-pagination.ts +71 -30
  12. package/src/db/memory-store.helpers.ts +4 -7
  13. package/src/db/memory-store.ts +856 -598
  14. package/src/db/memory.ts +398 -275
  15. package/src/db/record-id.ts +32 -10
  16. package/src/db/schema-fingerprint.ts +30 -12
  17. package/src/db/service-normalization.ts +255 -0
  18. package/src/db/service.ts +726 -761
  19. package/src/db/startup.ts +140 -66
  20. package/src/db/transaction-conflict.ts +15 -0
  21. package/src/effect/awaitable-effect.ts +87 -0
  22. package/src/effect/errors.ts +121 -0
  23. package/src/effect/helpers.ts +98 -0
  24. package/src/effect/index.ts +22 -0
  25. package/src/effect/layers.ts +228 -0
  26. package/src/effect/runtime-ref.ts +25 -0
  27. package/src/effect/runtime.ts +31 -0
  28. package/src/effect/services.ts +57 -0
  29. package/src/effect/zod.ts +43 -0
  30. package/src/embeddings/provider.ts +122 -76
  31. package/src/index.ts +46 -1
  32. package/src/openrouter/direct-provider.ts +11 -35
  33. package/src/queues/autonomous-job.queue.ts +130 -74
  34. package/src/queues/context-compaction.queue.ts +60 -15
  35. package/src/queues/delayed-node-promotion.queue.ts +52 -15
  36. package/src/queues/document-processor.queue.ts +52 -77
  37. package/src/queues/memory-consolidation.queue.ts +47 -32
  38. package/src/queues/organization-learning.queue.ts +13 -4
  39. package/src/queues/plan-agent-heartbeat.queue.ts +65 -21
  40. package/src/queues/plan-scheduler.queue.ts +107 -31
  41. package/src/queues/post-chat-memory.queue.ts +66 -24
  42. package/src/queues/queue-factory.ts +142 -52
  43. package/src/queues/standalone-worker.ts +39 -0
  44. package/src/queues/title-generation.queue.ts +54 -9
  45. package/src/redis/connection.ts +84 -32
  46. package/src/redis/index.ts +6 -8
  47. package/src/redis/org-memory-lock.ts +60 -27
  48. package/src/redis/redis-lease-lock.ts +200 -121
  49. package/src/redis/runtime-connection.ts +10 -0
  50. package/src/redis/stream-context.ts +84 -46
  51. package/src/runtime/agent-identity-overrides.ts +2 -2
  52. package/src/runtime/agent-runtime-policy.ts +4 -1
  53. package/src/runtime/agent-stream-helpers.ts +20 -9
  54. package/src/runtime/chat-run-orchestration.ts +102 -19
  55. package/src/runtime/chat-run-registry.ts +36 -2
  56. package/src/runtime/context-compaction/context-compaction-runtime.ts +107 -0
  57. package/src/runtime/{context-compaction.ts → context-compaction/context-compaction.ts} +114 -91
  58. package/src/runtime/execution-plan-visibility.ts +2 -2
  59. package/src/runtime/execution-plan.ts +42 -15
  60. package/src/runtime/graph-designer.ts +11 -7
  61. package/src/runtime/helper-model.ts +135 -48
  62. package/src/runtime/index.ts +7 -7
  63. package/src/runtime/indexed-repositories-policy.ts +3 -3
  64. package/src/runtime/{memory-block.ts → memory/memory-block.ts} +40 -36
  65. package/src/runtime/{memory-digest-policy.ts → memory/memory-digest-policy.ts} +1 -1
  66. package/src/runtime/{memory-pipeline.ts → memory/memory-pipeline.ts} +1 -1
  67. package/src/runtime/{memory-prompts-fact.ts → memory/memory-prompts-fact.ts} +2 -2
  68. package/src/runtime/{memory-scope.ts → memory/memory-scope.ts} +12 -6
  69. package/src/runtime/plugin-resolution.ts +144 -24
  70. package/src/runtime/plugin-types.ts +9 -1
  71. package/src/runtime/post-turn-side-effects.ts +197 -130
  72. package/src/runtime/retrieval-adapters.ts +38 -4
  73. package/src/runtime/runtime-config.ts +150 -61
  74. package/src/runtime/runtime-extensions.ts +21 -34
  75. package/src/runtime/social-chat/social-chat-agent-runner.ts +157 -0
  76. package/src/runtime/{social-chat-history.ts → social-chat/social-chat-history.ts} +42 -20
  77. package/src/runtime/social-chat/social-chat.ts +594 -0
  78. package/src/runtime/specialist-runner.ts +36 -10
  79. package/src/runtime/team-consultation/team-consultation-orchestrator.ts +427 -0
  80. package/src/runtime/{team-consultation-prompts.ts → team-consultation/team-consultation-prompts.ts} +6 -2
  81. package/src/runtime/thread-chat-helpers.ts +2 -2
  82. package/src/runtime/thread-plan-turn.ts +2 -1
  83. package/src/runtime/thread-turn-context.ts +172 -94
  84. package/src/runtime/turn-lifecycle.ts +93 -27
  85. package/src/services/agent-activity.service.ts +287 -203
  86. package/src/services/agent-executor.service.ts +329 -217
  87. package/src/services/artifact.service.ts +225 -148
  88. package/src/services/attachment.service.ts +137 -115
  89. package/src/services/autonomous-job.service.ts +888 -491
  90. package/src/services/chat-run-registry.service.ts +11 -1
  91. package/src/services/context-compaction.service.ts +136 -86
  92. package/src/services/document-chunk.service.ts +162 -90
  93. package/src/services/execution-plan/execution-plan-approval.ts +26 -0
  94. package/src/services/execution-plan/execution-plan-context.ts +29 -0
  95. package/src/services/execution-plan/execution-plan-graph.ts +256 -0
  96. package/src/services/execution-plan/execution-plan-schedule.ts +84 -0
  97. package/src/services/execution-plan/execution-plan-spec.ts +75 -0
  98. package/src/services/execution-plan/execution-plan.service.ts +1041 -0
  99. package/src/services/feedback-loop.service.ts +132 -76
  100. package/src/services/global-orchestrator.service.ts +80 -170
  101. package/src/services/graph-full-routing.ts +182 -0
  102. package/src/services/index.ts +18 -21
  103. package/src/services/institutional-memory.service.ts +220 -123
  104. package/src/services/learned-skill.service.ts +364 -259
  105. package/src/services/memory/memory-conversation.ts +95 -0
  106. package/src/services/memory/memory-org-memory.ts +39 -0
  107. package/src/services/memory/memory-preseeded.ts +80 -0
  108. package/src/services/memory/memory-rerank.ts +297 -0
  109. package/src/services/{memory-utils.ts → memory/memory-utils.ts} +5 -5
  110. package/src/services/memory/memory.service.ts +692 -0
  111. package/src/services/memory/rerank.service.ts +209 -0
  112. package/src/services/monitoring-window.service.ts +92 -70
  113. package/src/services/mutating-approval.service.ts +62 -53
  114. package/src/services/node-workspace.service.ts +141 -98
  115. package/src/services/notification.service.ts +17 -16
  116. package/src/services/organization-member.service.ts +120 -66
  117. package/src/services/organization.service.ts +144 -51
  118. package/src/services/ownership-dispatcher.service.ts +415 -264
  119. package/src/services/plan/plan-agent-heartbeat.service.ts +234 -0
  120. package/src/services/plan/plan-agent-query.service.ts +322 -0
  121. package/src/services/plan/plan-approval.service.ts +102 -0
  122. package/src/services/plan/plan-artifact.service.ts +60 -0
  123. package/src/services/plan/plan-builder.service.ts +76 -0
  124. package/src/services/plan/plan-checkpoint.service.ts +103 -0
  125. package/src/services/{plan-compiler.service.ts → plan/plan-compiler.service.ts} +26 -9
  126. package/src/services/plan/plan-completion-side-effects.ts +175 -0
  127. package/src/services/plan/plan-coordination.service.ts +181 -0
  128. package/src/services/plan/plan-cycle.service.ts +398 -0
  129. package/src/services/plan/plan-deadline.service.ts +547 -0
  130. package/src/services/plan/plan-event-delivery.service.ts +261 -0
  131. package/src/services/plan/plan-executor-context.ts +35 -0
  132. package/src/services/plan/plan-executor-graph.ts +475 -0
  133. package/src/services/plan/plan-executor-helpers.ts +322 -0
  134. package/src/services/plan/plan-executor-persistence.ts +209 -0
  135. package/src/services/plan/plan-executor.service.ts +1654 -0
  136. package/src/services/{plan-helpers.ts → plan/plan-helpers.ts} +1 -1
  137. package/src/services/{plan-run-data.ts → plan/plan-run-data.ts} +4 -4
  138. package/src/services/plan/plan-run-serialization.ts +15 -0
  139. package/src/services/plan/plan-run.service.ts +644 -0
  140. package/src/services/plan/plan-scheduler.service.ts +385 -0
  141. package/src/services/plan/plan-template.service.ts +224 -0
  142. package/src/services/plan/plan-transaction-events.ts +33 -0
  143. package/src/services/plan/plan-validator.service.ts +907 -0
  144. package/src/services/plan/plan-workspace.service.ts +125 -0
  145. package/src/services/plugin-executor.service.ts +97 -68
  146. package/src/services/quality-metrics.service.ts +112 -94
  147. package/src/services/queue-job.service.ts +296 -230
  148. package/src/services/recent-activity-title.service.ts +65 -36
  149. package/src/services/recent-activity.service.ts +274 -259
  150. package/src/services/skill-resolver.service.ts +38 -12
  151. package/src/services/social-chat-history.service.ts +176 -125
  152. package/src/services/system-executor.service.ts +91 -61
  153. package/src/services/thread/thread-active-run.ts +203 -0
  154. package/src/services/thread/thread-bootstrap.ts +369 -0
  155. package/src/services/thread/thread-listing.ts +198 -0
  156. package/src/services/thread/thread-memory-block.ts +117 -0
  157. package/src/services/thread/thread-message.service.ts +363 -0
  158. package/src/services/thread/thread-record-store.ts +155 -0
  159. package/src/services/thread/thread-title.service.ts +74 -0
  160. package/src/services/thread/thread-turn-execution.ts +280 -0
  161. package/src/services/thread/thread-turn-message-context.ts +73 -0
  162. package/src/services/thread/thread-turn-preparation.service.ts +1146 -0
  163. package/src/services/thread/thread-turn-streaming.ts +402 -0
  164. package/src/services/thread/thread-turn-tracing.ts +35 -0
  165. package/src/services/thread/thread-turn.ts +343 -0
  166. package/src/services/thread/thread.service.ts +335 -0
  167. package/src/services/user.service.ts +82 -32
  168. package/src/services/write-intent-validator.service.ts +63 -51
  169. package/src/storage/attachment-parser.ts +69 -27
  170. package/src/storage/attachment-storage.service.ts +331 -275
  171. package/src/storage/generated-document-storage.service.ts +66 -34
  172. package/src/system-agents/agent-result.ts +3 -1
  173. package/src/system-agents/context-compaction.agent.ts +2 -2
  174. package/src/system-agents/delegated-agent-factory.ts +159 -90
  175. package/src/system-agents/memory-reranker.agent.ts +2 -2
  176. package/src/system-agents/memory.agent.ts +2 -2
  177. package/src/system-agents/recent-activity-title-refiner.agent.ts +2 -2
  178. package/src/system-agents/regular-chat-memory-digest.agent.ts +2 -2
  179. package/src/system-agents/skill-extractor.agent.ts +2 -2
  180. package/src/system-agents/skill-manager.agent.ts +2 -2
  181. package/src/system-agents/thread-router.agent.ts +157 -113
  182. package/src/system-agents/title-generator.agent.ts +2 -2
  183. package/src/tools/execution-plan.tool.ts +220 -161
  184. package/src/tools/fetch-webpage.tool.ts +21 -17
  185. package/src/tools/firecrawl-client.ts +16 -6
  186. package/src/tools/index.ts +1 -0
  187. package/src/tools/memory-block.tool.ts +14 -6
  188. package/src/tools/plan-approval.tool.ts +49 -47
  189. package/src/tools/read-file-parts.tool.ts +44 -33
  190. package/src/tools/remember-memory.tool.ts +65 -45
  191. package/src/tools/search-web.tool.ts +26 -22
  192. package/src/tools/search.tool.ts +41 -29
  193. package/src/tools/team-think.tool.ts +124 -83
  194. package/src/tools/user-questions.tool.ts +4 -3
  195. package/src/tools/web-tool-shared.ts +6 -0
  196. package/src/utils/async.ts +17 -23
  197. package/src/utils/crypto.ts +21 -0
  198. package/src/utils/date-time.ts +40 -1
  199. package/src/utils/errors.ts +95 -16
  200. package/src/utils/hono-error-handler.ts +24 -39
  201. package/src/utils/index.ts +2 -1
  202. package/src/utils/null-proto-record.ts +41 -0
  203. package/src/utils/sse-keepalive.ts +124 -21
  204. package/src/workers/bootstrap.ts +186 -51
  205. package/src/workers/memory-consolidation.worker.ts +325 -237
  206. package/src/workers/organization-learning.worker.ts +50 -16
  207. package/src/workers/regular-chat-memory-digest.helpers.ts +28 -27
  208. package/src/workers/regular-chat-memory-digest.runner.ts +175 -114
  209. package/src/workers/skill-extraction.runner.ts +176 -93
  210. package/src/workers/utils/file-section-chunker.ts +8 -10
  211. package/src/workers/utils/repo-structure-extractor.ts +349 -260
  212. package/src/workers/utils/repomix-file-sections.ts +2 -2
  213. package/src/workers/utils/thread-message-query.ts +97 -38
  214. package/src/workers/worker-utils.ts +56 -31
  215. package/src/config/debug-logger.ts +0 -47
  216. package/src/redis/connection-accessor.ts +0 -26
  217. package/src/runtime/context-compaction-runtime.ts +0 -87
  218. package/src/runtime/social-chat-agent-runner.ts +0 -118
  219. package/src/runtime/social-chat.ts +0 -516
  220. package/src/runtime/team-consultation-orchestrator.ts +0 -272
  221. package/src/services/adaptive-playbook.service.ts +0 -152
  222. package/src/services/artifact-provenance.service.ts +0 -172
  223. package/src/services/chat-attachments.service.ts +0 -17
  224. package/src/services/context-compaction-runtime.singleton.ts +0 -13
  225. package/src/services/execution-plan.service.ts +0 -1118
  226. package/src/services/memory.service.ts +0 -914
  227. package/src/services/plan-agent-heartbeat.service.ts +0 -136
  228. package/src/services/plan-agent-query.service.ts +0 -267
  229. package/src/services/plan-approval.service.ts +0 -83
  230. package/src/services/plan-artifact.service.ts +0 -50
  231. package/src/services/plan-builder.service.ts +0 -67
  232. package/src/services/plan-checkpoint.service.ts +0 -81
  233. package/src/services/plan-completion-side-effects.ts +0 -80
  234. package/src/services/plan-coordination.service.ts +0 -157
  235. package/src/services/plan-cycle.service.ts +0 -284
  236. package/src/services/plan-deadline.service.ts +0 -430
  237. package/src/services/plan-event-delivery.service.ts +0 -166
  238. package/src/services/plan-executor.service.ts +0 -1950
  239. package/src/services/plan-run.service.ts +0 -515
  240. package/src/services/plan-scheduler.service.ts +0 -240
  241. package/src/services/plan-template.service.ts +0 -177
  242. package/src/services/plan-validator.service.ts +0 -818
  243. package/src/services/plan-workspace.service.ts +0 -83
  244. package/src/services/rerank.service.ts +0 -156
  245. package/src/services/thread-message.service.ts +0 -275
  246. package/src/services/thread-plan-registry.service.ts +0 -22
  247. package/src/services/thread-title.service.ts +0 -39
  248. package/src/services/thread-turn-preparation.service.ts +0 -1147
  249. package/src/services/thread-turn.ts +0 -172
  250. package/src/services/thread.service.ts +0 -869
  251. package/src/utils/env.ts +0 -8
  252. /package/src/runtime/{context-compaction-constants.ts → context-compaction/context-compaction-constants.ts} +0 -0
  253. /package/src/runtime/{memory-format.ts → memory/memory-format.ts} +0 -0
  254. /package/src/runtime/{memory-prompts-parse.ts → memory/memory-prompts-parse.ts} +0 -0
  255. /package/src/runtime/{memory-prompts-update.ts → memory/memory-prompts-update.ts} +0 -0
  256. /package/src/runtime/{social-chat-prompts.ts → social-chat/social-chat-prompts.ts} +0 -0
  257. /package/src/services/{plan-node-spec.ts → plan/plan-node-spec.ts} +0 -0
  258. /package/src/services/{thread-constants.ts → thread/thread-constants.ts} +0 -0
  259. /package/src/services/{thread.types.ts → thread/thread.types.ts} +0 -0
@@ -1,27 +1,294 @@
1
- import type { LogLevel } from '@logtape/logtape'
2
- import { configure, getAnsiColorFormatter, getConsoleSink, getLogger as getLogTapeLogger } from '@logtape/logtape'
1
+ import { Effect, Logger, References } from 'effect'
3
2
 
4
3
  const LOG_CATEGORY = 'lota-sdk'
5
4
 
6
- export async function configureLotaLogger(logLevel: LogLevel = 'info'): Promise<void> {
7
- const formatter = getAnsiColorFormatter({ level: 'FULL' })
5
+ export type LotaLogLevel = 'trace' | 'debug' | 'info' | 'warning' | 'error' | 'fatal'
8
6
 
9
- await configure({
10
- reset: true,
11
- sinks: { console: getConsoleSink({ formatter }) },
12
- loggers: [
13
- { category: ['logtape', 'meta'], lowestLevel: 'warning', sinks: ['console'] },
14
- { category: ['server'], lowestLevel: logLevel, sinks: ['console'] },
15
- { category: [LOG_CATEGORY], lowestLevel: logLevel, sinks: ['console'] },
16
- { category: ['hono'], lowestLevel: logLevel, sinks: ['console'] },
17
- ],
18
- })
7
+ type LogFields = Record<string, unknown>
8
+ type LotaLogEffect = Effect.Effect<void, never, never>
9
+ type EffectLogLevel = 'Trace' | 'Debug' | 'Info' | 'Warn' | 'Error' | 'Fatal'
10
+
11
+ export interface LotaLoggerMethod {
12
+ (message: string, fields?: LogFields): void
13
+ (strings: TemplateStringsArray, ...values: Array<unknown>): void
14
+ }
15
+
16
+ export interface LotaLogger {
17
+ trace: LotaLoggerMethod
18
+ debug: LotaLoggerMethod
19
+ info: LotaLoggerMethod
20
+ warn: LotaLoggerMethod
21
+ error: LotaLoggerMethod
22
+ fatal: LotaLoggerMethod
23
+ }
24
+
25
+ const LOG_LEVEL_PRIORITY: Record<LotaLogLevel, number> = { trace: 0, debug: 1, info: 2, warning: 3, error: 4, fatal: 5 }
26
+
27
+ export function resolveLotaLogLevel(value: string | null | undefined): LotaLogLevel | null {
28
+ const normalized = value?.trim().toLowerCase()
29
+ switch (normalized) {
30
+ case 'trace':
31
+ case 'debug':
32
+ case 'info':
33
+ case 'warning':
34
+ case 'error':
35
+ case 'fatal':
36
+ return normalized
37
+ default:
38
+ return null
39
+ }
40
+ }
41
+
42
+ function readEnvLogLevel(): LotaLogLevel | null {
43
+ const value = Bun.env.LOG_LEVEL?.trim().toLowerCase()
44
+ return resolveLotaLogLevel(value)
45
+ }
46
+
47
+ let configuredLogLevel: LotaLogLevel = readEnvLogLevel() ?? 'info'
48
+
49
+ export function configureLotaLogger(logLevel: LotaLogLevel = 'info'): void {
50
+ configuredLogLevel = logLevel
51
+ }
52
+
53
+ export function getConfiguredLogLevel(): LotaLogLevel {
54
+ return configuredLogLevel
55
+ }
56
+
57
+ export function toEffectLogLevel(logLevel: LotaLogLevel): EffectLogLevel {
58
+ switch (logLevel) {
59
+ case 'trace':
60
+ return 'Trace'
61
+ case 'debug':
62
+ return 'Debug'
63
+ case 'info':
64
+ return 'Info'
65
+ case 'warning':
66
+ return 'Warn'
67
+ case 'error':
68
+ return 'Error'
69
+ case 'fatal':
70
+ return 'Fatal'
71
+ }
72
+ }
73
+
74
+ function shouldLog(level: LotaLogLevel): boolean {
75
+ return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[configuredLogLevel]
19
76
  }
20
77
 
21
- export function getLogger(category: readonly string[]) {
22
- return getLogTapeLogger([...category])
78
+ function isTemplateStringsArray(value: unknown): value is TemplateStringsArray {
79
+ return Array.isArray(value) && Object.prototype.hasOwnProperty.call(value, 'raw')
23
80
  }
24
81
 
25
- export const serverLogger = getLogger([LOG_CATEGORY])
26
- export const chatLogger = getLogger([LOG_CATEGORY, 'chat'])
27
- export const aiLogger = getLogger([LOG_CATEGORY, 'ai'])
82
+ function describeObject(value: object): string {
83
+ return Object.prototype.toString.call(value)
84
+ }
85
+
86
+ function describeScalar(value: unknown): string {
87
+ if (value === null) return 'null'
88
+ if (value === undefined) return 'undefined'
89
+ if (typeof value === 'symbol') {
90
+ return value.description ? `Symbol(${value.description})` : 'Symbol'
91
+ }
92
+ if (typeof value === 'function') {
93
+ return `[Function ${value.name || 'anonymous'}]`
94
+ }
95
+
96
+ return JSON.stringify(value)
97
+ }
98
+
99
+ function normalizeJsonValue(value: unknown): unknown {
100
+ if (typeof value === 'bigint') return value.toString()
101
+ if (value instanceof Date) return value.toISOString()
102
+ if (value instanceof Error) {
103
+ return { name: value.name, message: value.message, stack: value.stack }
104
+ }
105
+ return value
106
+ }
107
+
108
+ function normalizeAnnotationValue(value: unknown): unknown {
109
+ if (value === null || value === undefined) return value
110
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return value
111
+ if (typeof value === 'bigint') return value.toString()
112
+ if (value instanceof Date) return value.toISOString()
113
+ if (value instanceof Error) {
114
+ return { name: value.name, message: value.message, stack: value.stack }
115
+ }
116
+
117
+ try {
118
+ return JSON.parse(JSON.stringify(value, (_key, nestedValue) => normalizeJsonValue(nestedValue)))
119
+ } catch {
120
+ return typeof value === 'object' ? describeObject(value) : describeScalar(value)
121
+ }
122
+ }
123
+
124
+ function formatLogValue(value: unknown): string {
125
+ if (value instanceof Error) {
126
+ return `${value.name}: ${value.message}`
127
+ }
128
+ if (typeof value === 'string') return value
129
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') return String(value)
130
+ if (value === null) return 'null'
131
+ if (value === undefined) return 'undefined'
132
+ if (value instanceof Date) return value.toISOString()
133
+
134
+ try {
135
+ return JSON.stringify(normalizeAnnotationValue(value))
136
+ } catch {
137
+ return typeof value === 'object' ? describeObject(value) : describeScalar(value)
138
+ }
139
+ }
140
+
141
+ function formatTemplate(strings: TemplateStringsArray, values: Array<unknown>): string {
142
+ let output = ''
143
+
144
+ for (let index = 0; index < strings.length; index++) {
145
+ output += strings[index]
146
+ if (index < values.length) {
147
+ output += formatLogValue(values[index])
148
+ }
149
+ }
150
+
151
+ return output
152
+ }
153
+
154
+ function applyFieldPlaceholders(message: string, fields?: LogFields): string {
155
+ if (!fields) return message
156
+
157
+ let output = message
158
+ for (const [key, value] of Object.entries(fields)) {
159
+ output = output.replaceAll(`{${key}}`, formatLogValue(value))
160
+ }
161
+ return output
162
+ }
163
+
164
+ function buildLogContext(fields?: LogFields): Record<string, unknown> {
165
+ const context: Record<string, unknown> = {}
166
+ if (!fields) {
167
+ return context
168
+ }
169
+
170
+ for (const [key, value] of Object.entries(fields)) {
171
+ if (value === undefined) continue
172
+ context[key] = normalizeAnnotationValue(value)
173
+ }
174
+
175
+ return context
176
+ }
177
+
178
+ function getConsoleMethod(level: LotaLogLevel): (...args: Array<unknown>) => void {
179
+ switch (level) {
180
+ case 'trace':
181
+ return console.trace
182
+ case 'debug':
183
+ return console.debug
184
+ case 'info':
185
+ return console.info
186
+ case 'warning':
187
+ return console.warn
188
+ case 'error':
189
+ return console.error
190
+ case 'fatal':
191
+ return console.error
192
+ }
193
+ }
194
+
195
+ function getLogEffect(level: LotaLogLevel, message: string): LotaLogEffect {
196
+ switch (level) {
197
+ case 'trace':
198
+ return Effect.logTrace(message)
199
+ case 'debug':
200
+ return Effect.logDebug(message)
201
+ case 'info':
202
+ return Effect.logInfo(message)
203
+ case 'warning':
204
+ return Effect.logWarning(message)
205
+ case 'error':
206
+ return Effect.logError(message)
207
+ case 'fatal':
208
+ return Effect.logFatal(message)
209
+ }
210
+ }
211
+
212
+ function runStandaloneLogEffect(effect: LotaLogEffect): void {
213
+ Effect.runSync(
214
+ effect.pipe(
215
+ Effect.provide(Logger.layer([Logger.consolePretty()])),
216
+ Effect.provideService(References.MinimumLogLevel, toEffectLogLevel(configuredLogLevel)),
217
+ ),
218
+ )
219
+ }
220
+
221
+ function emitConsoleFallback(
222
+ level: LotaLogLevel,
223
+ category: readonly string[],
224
+ message: string,
225
+ fields?: LogFields,
226
+ ): void {
227
+ if (!shouldLog(level)) return
228
+
229
+ const formattedMessage = `[${category.join(':')}] ${message}`
230
+ const context = buildLogContext(fields)
231
+ const sink = getConsoleMethod(level)
232
+ if (Object.keys(context).length === 0) {
233
+ sink(formattedMessage)
234
+ return
235
+ }
236
+
237
+ sink(formattedMessage, context)
238
+ }
239
+
240
+ function emit(level: LotaLogLevel, category: readonly string[], message: string, fields?: LogFields): void {
241
+ if (!shouldLog(level)) return
242
+
243
+ const formattedMessage = applyFieldPlaceholders(message, fields)
244
+ const annotations = { lotaLogger: category.join(':'), ...buildLogContext(fields) }
245
+ const effect = getLogEffect(level, formattedMessage).pipe(Effect.annotateLogs(annotations))
246
+
247
+ try {
248
+ runStandaloneLogEffect(effect)
249
+ } catch {
250
+ emitConsoleFallback(level, category, formattedMessage, annotations)
251
+ }
252
+ }
253
+
254
+ function createLoggerMethod(level: LotaLogLevel, category: readonly string[]): LotaLoggerMethod {
255
+ return (messageOrStrings: string | TemplateStringsArray, ...values: Array<unknown>) => {
256
+ if (isTemplateStringsArray(messageOrStrings)) {
257
+ emit(level, category, formatTemplate(messageOrStrings, values))
258
+ return
259
+ }
260
+
261
+ const [candidateFields] = values
262
+ const fields =
263
+ candidateFields && typeof candidateFields === 'object' && !Array.isArray(candidateFields)
264
+ ? (candidateFields as LogFields)
265
+ : undefined
266
+
267
+ emit(level, category, messageOrStrings, fields)
268
+ }
269
+ }
270
+
271
+ export function getLogger(category: readonly string[]): LotaLogger {
272
+ return {
273
+ trace: createLoggerMethod('trace', category),
274
+ debug: createLoggerMethod('debug', category),
275
+ info: createLoggerMethod('info', category),
276
+ warn: createLoggerMethod('warning', category),
277
+ error: createLoggerMethod('error', category),
278
+ fatal: createLoggerMethod('fatal', category),
279
+ }
280
+ }
281
+
282
+ export const serverLogger: LotaLogger = getLogger([LOG_CATEGORY])
283
+ export const chatLogger: LotaLogger = getLogger([LOG_CATEGORY, 'chat'])
284
+ export const aiLogger: LotaLogger = getLogger([LOG_CATEGORY, 'ai'])
285
+
286
+ export interface LotaLoggerSet {
287
+ server: LotaLogger
288
+ chat: LotaLogger
289
+ ai: LotaLogger
290
+ }
291
+
292
+ export function getLotaLoggers(): LotaLoggerSet {
293
+ return { server: serverLogger, chat: chatLogger, ai: aiLogger }
294
+ }
@@ -1,3 +1,8 @@
1
+ import { Effect } from 'effect'
2
+
3
+ import { getCurrentRuntime } from '../effect/runtime-ref'
4
+ import { ThreadConfigServiceTag } from '../effect/services'
5
+
1
6
  export interface ThreadBootstrapWelcomeConfig {
2
7
  defaultAgentId: string
3
8
  buildMessageText: (params: { userName?: string | null }) => string
@@ -23,16 +28,9 @@ interface ResolvedThreadBootstrapConfig {
23
28
  onboardingWelcome?: ThreadBootstrapWelcomeConfig
24
29
  }
25
30
 
26
- const DEFAULT_THREAD_BOOTSTRAP_CONFIG: ResolvedThreadBootstrapConfig = {
27
- onboardingDefaultAgents: [],
28
- completedDefaultAgents: [],
29
- threadTypesAfterOnboarding: [],
30
- ensureDefaultGroupOnCompleted: true,
31
- }
32
-
33
- let resolvedThreadBootstrapConfig: ResolvedThreadBootstrapConfig = DEFAULT_THREAD_BOOTSTRAP_CONFIG
31
+ export type { ResolvedThreadBootstrapConfig }
34
32
 
35
- function withDedupedStrings(values: readonly string[]): string[] {
33
+ function normalizeThreadAgentIds(values: readonly string[]): readonly string[] {
36
34
  const seen = new Set<string>()
37
35
  const deduped: string[] = []
38
36
 
@@ -46,27 +44,41 @@ function withDedupedStrings(values: readonly string[]): string[] {
46
44
  return deduped
47
45
  }
48
46
 
49
- export function configureThreads(params: { agentRoster: readonly string[]; config?: LotaThreadConfig }): void {
47
+ function resolveBootstrapAgentIds(
48
+ agentRoster: readonly string[],
49
+ onboardingAgents: readonly string[] | undefined,
50
+ welcomeAgentId: string | undefined,
51
+ ): readonly string[] {
52
+ return normalizeThreadAgentIds([...(onboardingAgents ?? agentRoster), ...(welcomeAgentId ? [welcomeAgentId] : [])])
53
+ }
54
+
55
+ export function resolveThreadConfig(params: {
56
+ agentRoster: readonly string[]
57
+ config?: LotaThreadConfig
58
+ }): ResolvedThreadBootstrapConfig {
50
59
  const bootstrap = params.config?.bootstrap
51
60
  const onboardingWelcome = bootstrap?.onboardingWelcome
52
- const onboardingDefaultAgents = withDedupedStrings([
53
- ...(bootstrap?.onboardingDefaultAgents ?? params.agentRoster),
54
- ...(onboardingWelcome ? [onboardingWelcome.defaultAgentId] : []),
55
- ])
56
61
 
57
- resolvedThreadBootstrapConfig = {
58
- onboardingDefaultAgents,
59
- completedDefaultAgents: withDedupedStrings(bootstrap?.completedDefaultAgents ?? params.agentRoster),
60
- threadTypesAfterOnboarding: withDedupedStrings(bootstrap?.threadTypesAfterOnboarding ?? []),
62
+ return {
63
+ onboardingDefaultAgents: resolveBootstrapAgentIds(
64
+ params.agentRoster,
65
+ bootstrap?.onboardingDefaultAgents,
66
+ onboardingWelcome?.defaultAgentId,
67
+ ),
68
+ completedDefaultAgents: normalizeThreadAgentIds(bootstrap?.completedDefaultAgents ?? params.agentRoster),
69
+ threadTypesAfterOnboarding: normalizeThreadAgentIds(bootstrap?.threadTypesAfterOnboarding ?? []),
61
70
  ensureDefaultGroupOnCompleted: bootstrap?.ensureDefaultGroupOnCompleted ?? true,
62
71
  ...(onboardingWelcome ? { onboardingWelcome } : {}),
63
72
  }
64
73
  }
65
74
 
66
75
  export function getThreadBootstrapConfig(): ResolvedThreadBootstrapConfig {
67
- return resolvedThreadBootstrapConfig
76
+ return getCurrentRuntime().runSync(Effect.service(ThreadConfigServiceTag))
68
77
  }
69
78
 
70
- export function resolveOnboardingOwnerAgentId(defaultLeadAgentId: string): string {
71
- return resolvedThreadBootstrapConfig.onboardingWelcome?.defaultAgentId ?? defaultLeadAgentId
79
+ export function resolveOnboardingOwnerAgentId(
80
+ defaultLeadAgentId: string,
81
+ config: ResolvedThreadBootstrapConfig = getThreadBootstrapConfig(),
82
+ ): string {
83
+ return config.onboardingWelcome?.defaultAgentId ?? defaultLeadAgentId
72
84
  }