@lota-sdk/core 0.3.2 → 0.4.0
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 -12
- package/src/db/sdk-database.ts +1 -1
- package/src/redis/stream-context.ts +4 -1
- package/src/services/plan-run.service.ts +1 -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
|
+
"version": "0.4.0",
|
|
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.
|
|
35
|
+
"@lota-sdk/shared": "0.4.0",
|
|
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,14 +55,8 @@ function parseAiGatewayJsonRequestBody(body: BodyInit | null | undefined): Recor
|
|
|
55
55
|
return isRecord(parsed) ? parsed : null
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
function withDefaultAiGatewayCacheHeaders(params: AiGatewayCallOptions
|
|
59
|
-
return {
|
|
60
|
-
...params,
|
|
61
|
-
headers: mergeAiGatewayHeaders(
|
|
62
|
-
params.headers,
|
|
63
|
-
buildAiGatewayCacheHeaders(`model:${toAiGatewayCacheKeyPart(modelId)}`),
|
|
64
|
-
),
|
|
65
|
-
}
|
|
58
|
+
function withDefaultAiGatewayCacheHeaders(params: AiGatewayCallOptions): AiGatewayCallOptions {
|
|
59
|
+
return { ...params, headers: mergeAiGatewayHeaders(params.headers, buildAiGatewayCacheHeaders('lota-sdk')) }
|
|
66
60
|
}
|
|
67
61
|
|
|
68
62
|
function normalizeAiGatewayUrl(value: string): string {
|
|
@@ -417,7 +411,7 @@ export function aiGatewayModel(modelId: string) {
|
|
|
417
411
|
middleware: {
|
|
418
412
|
specificationVersion: 'v3',
|
|
419
413
|
transformParams: async ({ params, type }) =>
|
|
420
|
-
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)
|
|
414
|
+
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)),
|
|
421
415
|
wrapStream: async ({ doStream, params }) => {
|
|
422
416
|
const result = await doStream()
|
|
423
417
|
if (!isReasoningEnabled(params)) return result
|
|
@@ -435,7 +429,7 @@ export function aiGatewayOpenRouterResponseHealingModel(modelId: string) {
|
|
|
435
429
|
model: getAiGatewayOpenRouterResponseHealingProvider()(modelId),
|
|
436
430
|
middleware: {
|
|
437
431
|
specificationVersion: 'v3',
|
|
438
|
-
transformParams: async ({ params }) => withDefaultAiGatewayCacheHeaders(params
|
|
432
|
+
transformParams: async ({ params }) => withDefaultAiGatewayCacheHeaders(params),
|
|
439
433
|
},
|
|
440
434
|
}),
|
|
441
435
|
)
|
|
@@ -449,7 +443,7 @@ export function aiGatewayChatModel(modelId: string) {
|
|
|
449
443
|
specificationVersion: 'v3',
|
|
450
444
|
transformParams: async ({ params, type }) =>
|
|
451
445
|
normalizeAiGatewayChatProviderOptions(
|
|
452
|
-
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)
|
|
446
|
+
withDefaultAiGatewayCacheHeaders(addAiGatewayReasoningRawChunks(params, type)),
|
|
453
447
|
),
|
|
454
448
|
wrapGenerate: async ({ doGenerate }) => {
|
|
455
449
|
const result = await doGenerate()
|
package/src/db/sdk-database.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LOTA_SDK_DATABASE_NAME = '
|
|
1
|
+
export const LOTA_SDK_DATABASE_NAME = 'lotasdk_thread'
|
|
@@ -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
|
|
@@ -368,7 +368,7 @@ class PlanRunService {
|
|
|
368
368
|
|
|
369
369
|
// Slim mode: non-active/ready nodes get summary only (used for prompt injection via JSON.stringify).
|
|
370
370
|
// The cast is safe — this data is only consumed by formatExecutionPlansForPrompt, not by Zod validation.
|
|
371
|
-
//
|
|
371
|
+
// executionPlanQuery calls toSerializablePlan without slim=true for full inspection payloads.
|
|
372
372
|
if (slim && !isActiveOrReady) {
|
|
373
373
|
return {
|
|
374
374
|
id: nodeSpec.nodeId,
|
|
@@ -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
|
},
|