@lota-sdk/core 0.3.1 → 0.3.3
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-gateway/ai-gateway.ts +6 -9
- package/src/redis/stream-context.ts +4 -1
- package/src/services/thread.service.ts +13 -0
- package/src/system-agents/context-compaction.agent.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/thread-router.agent.ts +1 -1
- package/src/system-agents/title-generator.agent.ts +1 -1
- package/src/tools/execution-plan.tool.ts +28 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lota-sdk/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@chat-adapter/slack": "^4.23.0",
|
|
33
33
|
"@chat-adapter/state-ioredis": "^4.23.0",
|
|
34
34
|
"@logtape/logtape": "^2.0.5",
|
|
35
|
-
"@lota-sdk/shared": "0.3.
|
|
35
|
+
"@lota-sdk/shared": "0.3.3",
|
|
36
36
|
"@mendable/firecrawl-js": "^4.18.1",
|
|
37
37
|
"@surrealdb/node": "^3.0.3",
|
|
38
38
|
"ai": "^6.0.145",
|
|
@@ -5,7 +5,7 @@ import type { LanguageModelMiddleware } from 'ai'
|
|
|
5
5
|
|
|
6
6
|
import { getRuntimeConfig } from '../runtime/runtime-config'
|
|
7
7
|
import { isRecord, readString } from '../utils/string'
|
|
8
|
-
import { buildAiGatewayCacheHeaders
|
|
8
|
+
import { buildAiGatewayCacheHeaders } from './cache-headers'
|
|
9
9
|
|
|
10
10
|
type AiGatewayLanguageModel = Parameters<typeof wrapLanguageModel>[0]['model']
|
|
11
11
|
type AiGatewayExtraParams = Record<string, unknown>
|
|
@@ -55,13 +55,10 @@ function parseAiGatewayJsonRequestBody(body: BodyInit | null | undefined): Recor
|
|
|
55
55
|
return isRecord(parsed) ? parsed : null
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
function withDefaultAiGatewayCacheHeaders(params: AiGatewayCallOptions
|
|
58
|
+
function withDefaultAiGatewayCacheHeaders(params: AiGatewayCallOptions): AiGatewayCallOptions {
|
|
59
59
|
return {
|
|
60
60
|
...params,
|
|
61
|
-
headers: mergeAiGatewayHeaders(
|
|
62
|
-
params.headers,
|
|
63
|
-
buildAiGatewayCacheHeaders(`model:${toAiGatewayCacheKeyPart(modelId)}`),
|
|
64
|
-
),
|
|
61
|
+
headers: mergeAiGatewayHeaders(params.headers, buildAiGatewayCacheHeaders('lota-sdk')),
|
|
65
62
|
}
|
|
66
63
|
}
|
|
67
64
|
|
|
@@ -417,7 +414,7 @@ export function aiGatewayModel(modelId: string) {
|
|
|
417
414
|
middleware: {
|
|
418
415
|
specificationVersion: 'v3',
|
|
419
416
|
transformParams: async ({ params, type }) =>
|
|
420
|
-
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)
|
|
417
|
+
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)),
|
|
421
418
|
wrapStream: async ({ doStream, params }) => {
|
|
422
419
|
const result = await doStream()
|
|
423
420
|
if (!isReasoningEnabled(params)) return result
|
|
@@ -435,7 +432,7 @@ export function aiGatewayOpenRouterResponseHealingModel(modelId: string) {
|
|
|
435
432
|
model: getAiGatewayOpenRouterResponseHealingProvider()(modelId),
|
|
436
433
|
middleware: {
|
|
437
434
|
specificationVersion: 'v3',
|
|
438
|
-
transformParams: async ({ params }) => withDefaultAiGatewayCacheHeaders(params
|
|
435
|
+
transformParams: async ({ params }) => withDefaultAiGatewayCacheHeaders(params),
|
|
439
436
|
},
|
|
440
437
|
}),
|
|
441
438
|
)
|
|
@@ -449,7 +446,7 @@ export function aiGatewayChatModel(modelId: string) {
|
|
|
449
446
|
specificationVersion: 'v3',
|
|
450
447
|
transformParams: async ({ params, type }) =>
|
|
451
448
|
normalizeAiGatewayChatProviderOptions(
|
|
452
|
-
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)
|
|
449
|
+
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)),
|
|
453
450
|
),
|
|
454
451
|
wrapGenerate: async ({ doGenerate }) => {
|
|
455
452
|
const result = await doGenerate()
|
|
@@ -38,7 +38,10 @@ let sharedSubscriber: { client: Redis; subscriber: Subscriber } | undefined
|
|
|
38
38
|
|
|
39
39
|
function getSharedSubscriber(): Subscriber {
|
|
40
40
|
if (!sharedSubscriber) {
|
|
41
|
-
|
|
41
|
+
// Disable enableReadyCheck — the ready check sends INFO which is rejected
|
|
42
|
+
// on connections in subscribe mode, causing unhandled ioredis error events.
|
|
43
|
+
const client = getRedisConnection().duplicate({ enableReadyCheck: false })
|
|
44
|
+
client.on('error', () => {}) // prevent [ioredis] Unhandled error event logs
|
|
42
45
|
sharedSubscriber = { client, subscriber: toSubscriber(client) }
|
|
43
46
|
}
|
|
44
47
|
return sharedSubscriber.subscriber
|
|
@@ -712,6 +712,19 @@ class ThreadService extends BaseService<typeof ThreadSchema> {
|
|
|
712
712
|
return true
|
|
713
713
|
}
|
|
714
714
|
|
|
715
|
+
async clearThread(threadId: RecordIdRef): Promise<void> {
|
|
716
|
+
const threadRef = ensureRecordId(threadId, TABLES.THREAD)
|
|
717
|
+
await databaseService.deleteWhere(TABLES.THREAD_MESSAGE, { threadId: threadRef })
|
|
718
|
+
await databaseService.query<unknown>(surql`
|
|
719
|
+
UPDATE ONLY ${threadRef}
|
|
720
|
+
SET turnCount = 0,
|
|
721
|
+
compactionSummary = NONE,
|
|
722
|
+
lastCompactedMessageId = NONE,
|
|
723
|
+
activeRunId = NONE,
|
|
724
|
+
activeStreamId = NONE
|
|
725
|
+
`)
|
|
726
|
+
}
|
|
727
|
+
|
|
715
728
|
async deleteThread(threadId: RecordIdRef): Promise<void> {
|
|
716
729
|
const existing = await this.getById(threadId)
|
|
717
730
|
assertMutableThread(existing)
|
|
@@ -35,7 +35,7 @@ export function createContextCompactionAgent(options: CreateHelperToolLoopAgentO
|
|
|
35
35
|
return new ToolLoopAgent({
|
|
36
36
|
id: 'context-compaction',
|
|
37
37
|
model: aiGatewayOpenRouterResponseHealingModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
38
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
38
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
39
39
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
40
40
|
...resolveHelperAgentOptions(options, { instructions: CONTEXT_COMPACTION_PROMPT }),
|
|
41
41
|
})
|
|
@@ -33,7 +33,7 @@ export function createMemoryRerankerAgent(options: CreateHelperToolLoopAgentOpti
|
|
|
33
33
|
return new ToolLoopAgent({
|
|
34
34
|
id: 'memory-reranker',
|
|
35
35
|
model: aiGatewayOpenRouterResponseHealingModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
36
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
36
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
37
37
|
providerOptions: OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS,
|
|
38
38
|
...resolveHelperAgentOptions(options),
|
|
39
39
|
})
|
|
@@ -53,7 +53,7 @@ export function createOrgMemoryAgent(options: CreateHelperToolLoopAgentOptions)
|
|
|
53
53
|
return new ToolLoopAgent({
|
|
54
54
|
id: 'org-memory',
|
|
55
55
|
model: aiGatewayOpenRouterResponseHealingModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
56
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
56
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
57
57
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
58
58
|
...resolveHelperAgentOptions(options),
|
|
59
59
|
})
|
|
@@ -80,7 +80,7 @@ export function createRecentActivityTitleRefinerAgent(options: CreateHelperToolL
|
|
|
80
80
|
return new ToolLoopAgent({
|
|
81
81
|
id: 'recent-activity-title-refiner',
|
|
82
82
|
model: aiGatewayModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
83
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
83
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
84
84
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
85
85
|
...resolveHelperAgentOptions(options, {
|
|
86
86
|
instructions: buildRecentActivityTitleRefinerPrompt(),
|
|
@@ -28,7 +28,7 @@ export function createRegularChatMemoryDigestAgent(options: CreateHelperToolLoop
|
|
|
28
28
|
return new ToolLoopAgent({
|
|
29
29
|
id: 'regular-chat-memory-digest',
|
|
30
30
|
model: aiGatewayOpenRouterResponseHealingModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
31
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
31
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
32
32
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
33
33
|
...resolveHelperAgentOptions(options, {
|
|
34
34
|
instructions: regularChatMemoryDigestPrompt,
|
|
@@ -46,7 +46,7 @@ export function createSkillExtractorAgent(options: CreateHelperToolLoopAgentOpti
|
|
|
46
46
|
return new ToolLoopAgent({
|
|
47
47
|
id: 'skill-extractor',
|
|
48
48
|
model: aiGatewayOpenRouterResponseHealingModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
49
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
49
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
50
50
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
51
51
|
...resolveHelperAgentOptions(options, {
|
|
52
52
|
instructions: skillExtractorPrompt,
|
|
@@ -70,7 +70,7 @@ export function createSkillManagerAgent(options: CreateHelperToolLoopAgentOption
|
|
|
70
70
|
return new ToolLoopAgent({
|
|
71
71
|
id: 'skill-manager',
|
|
72
72
|
model: aiGatewayOpenRouterResponseHealingModel(OPENROUTER_STRUCTURED_HELPER_MODEL_ID),
|
|
73
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
73
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
74
74
|
providerOptions: OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS,
|
|
75
75
|
...resolveHelperAgentOptions(options, {
|
|
76
76
|
instructions: skillManagerPrompt,
|
|
@@ -165,7 +165,7 @@ async function generateRouterObject<TSchema extends z.ZodTypeAny>(params: {
|
|
|
165
165
|
const { object } = await withTimeout(
|
|
166
166
|
generateObject({
|
|
167
167
|
model: aiGatewayChatModel(modelId),
|
|
168
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
168
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
169
169
|
providerOptions: { openai: { reasoningEffort: 'low' } },
|
|
170
170
|
schema: params.schema,
|
|
171
171
|
system: params.system,
|
|
@@ -34,7 +34,7 @@ export function createThreadTitleGeneratorAgent(options: CreateHelperToolLoopAge
|
|
|
34
34
|
return new ToolLoopAgent({
|
|
35
35
|
id: 'thread-title-generator',
|
|
36
36
|
model: aiGatewayModel(OPENROUTER_FAST_REASONING_MODEL_ID),
|
|
37
|
-
headers: buildAiGatewayDirectCacheHeaders('
|
|
37
|
+
headers: buildAiGatewayDirectCacheHeaders('lota-sdk'),
|
|
38
38
|
providerOptions: OPENROUTER_MINIMAL_REASONING_PROVIDER_OPTIONS,
|
|
39
39
|
...resolveHelperAgentOptions(options, {
|
|
40
40
|
instructions: THREAD_TITLE_GENERATOR_PROMPT,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
expandAgentPlanDraft,
|
|
6
6
|
getLatestExecutionPlanResult,
|
|
7
7
|
} from '@lota-sdk/shared'
|
|
8
|
-
import type { CreateProjectWithPlanResultData
|
|
8
|
+
import type { CreateProjectWithPlanResultData } from '@lota-sdk/shared'
|
|
9
9
|
import { tool } from 'ai'
|
|
10
10
|
|
|
11
11
|
import type { RecordIdRef } from '../db/record-id'
|
|
@@ -26,11 +26,6 @@ type ExecutionPlanExecutionPlanService = Pick<
|
|
|
26
26
|
| 'getActivePlansForThread'
|
|
27
27
|
>
|
|
28
28
|
|
|
29
|
-
function extractDraft(input: ExecutionPlanArgs) {
|
|
30
|
-
const { action, projectTitle, targetThreadId, runId, reason, ...draftInput } = input
|
|
31
|
-
return { action, projectTitle, targetThreadId, runId, reason, draft: expandAgentPlanDraft(draftInput) }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
29
|
export function createExecutionPlanTool(params: {
|
|
35
30
|
orgId: RecordIdRef
|
|
36
31
|
userId: RecordIdRef
|
|
@@ -49,20 +44,26 @@ export function createExecutionPlanTool(params: {
|
|
|
49
44
|
'Manage execution plans. Actions: create (inline, 1-2 nodes), create-project (dedicated project thread, 3+ nodes), replace (swap active plan), resume (resume interrupted plan).',
|
|
50
45
|
inputSchema: ExecutionPlanArgsSchema,
|
|
51
46
|
execute: async (input) => {
|
|
52
|
-
const
|
|
47
|
+
const parsed = ExecutionPlanArgsSchema.parse(input)
|
|
48
|
+
let result: unknown
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
create:
|
|
50
|
+
switch (parsed.action) {
|
|
51
|
+
case 'create': {
|
|
52
|
+
const { action: _action, targetThreadId, ...draftInput } = parsed
|
|
53
|
+
const draft = expandAgentPlanDraft(draftInput)
|
|
56
54
|
params.validateInlinePlan?.(draft)
|
|
57
|
-
|
|
55
|
+
result = await resolvedEpService.createPlan({
|
|
58
56
|
organizationId: params.orgId,
|
|
59
57
|
threadId: targetThreadId ?? params.threadId,
|
|
60
58
|
leadAgentId: params.agentId,
|
|
61
59
|
input: draft,
|
|
62
60
|
})
|
|
63
|
-
|
|
61
|
+
break
|
|
62
|
+
}
|
|
64
63
|
|
|
65
|
-
'create-project':
|
|
64
|
+
case 'create-project': {
|
|
65
|
+
const { action: _action, projectTitle, targetThreadId, ...draftInput } = parsed
|
|
66
|
+
const draft = expandAgentPlanDraft(draftInput)
|
|
66
67
|
const targetThread = targetThreadId
|
|
67
68
|
? await resolvedWsService.getThread(targetThreadId)
|
|
68
69
|
: await (() => {
|
|
@@ -94,14 +95,14 @@ export function createExecutionPlanTool(params: {
|
|
|
94
95
|
|
|
95
96
|
const createdThread = !targetThreadId
|
|
96
97
|
try {
|
|
97
|
-
const
|
|
98
|
+
const created = await resolvedEpService.createPlan({
|
|
98
99
|
organizationId: params.orgId,
|
|
99
100
|
threadId: targetThread.id,
|
|
100
101
|
leadAgentId: params.agentId,
|
|
101
102
|
input: draft,
|
|
102
103
|
})
|
|
103
|
-
|
|
104
|
-
...
|
|
104
|
+
result = {
|
|
105
|
+
...created,
|
|
105
106
|
threadId: targetThread.id,
|
|
106
107
|
threadTitle: targetThread.title,
|
|
107
108
|
createdThread,
|
|
@@ -112,35 +113,30 @@ export function createExecutionPlanTool(params: {
|
|
|
112
113
|
}
|
|
113
114
|
throw error
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
replace: async () => {
|
|
118
|
-
if (!runId || !reason) {
|
|
119
|
-
throw new Error('runId and reason are required when action is "replace".')
|
|
120
|
-
}
|
|
116
|
+
break
|
|
117
|
+
}
|
|
121
118
|
|
|
122
|
-
|
|
119
|
+
case 'replace': {
|
|
120
|
+
const { action: _action, runId, reason, ...draftInput } = parsed
|
|
121
|
+
const draft = expandAgentPlanDraft(draftInput)
|
|
122
|
+
result = await resolvedEpService.replacePlan({
|
|
123
123
|
organizationId: params.orgId,
|
|
124
124
|
threadId: params.threadId,
|
|
125
125
|
leadAgentId: params.agentId,
|
|
126
126
|
input: { runId, reason, ...draft },
|
|
127
127
|
})
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
resume: async () => {
|
|
131
|
-
if (!runId) {
|
|
132
|
-
throw new Error('runId is required when action is "resume".')
|
|
133
|
-
}
|
|
128
|
+
break
|
|
129
|
+
}
|
|
134
130
|
|
|
135
|
-
|
|
131
|
+
case 'resume':
|
|
132
|
+
result = await resolvedEpService.resumeRun({
|
|
136
133
|
threadId: params.threadId,
|
|
137
134
|
emittedBy: params.agentId,
|
|
138
|
-
input: { runId },
|
|
135
|
+
input: { runId: parsed.runId },
|
|
139
136
|
})
|
|
140
|
-
|
|
137
|
+
break
|
|
141
138
|
}
|
|
142
139
|
|
|
143
|
-
const result = await handler[action]()
|
|
144
140
|
params.onPlanChanged?.()
|
|
145
141
|
return result
|
|
146
142
|
},
|