@pikku/core 0.12.19 → 0.12.21
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/CHANGELOG.md +77 -0
- package/dist/dev/hot-reload.js +20 -6
- package/dist/errors/error-handler.d.ts +1 -1
- package/dist/errors/error-handler.js +2 -2
- package/dist/function/function-runner.js +53 -3
- package/dist/function/functions.types.d.ts +3 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +2 -2
- package/dist/middleware/telemetry.d.ts +2 -2
- package/dist/middleware/telemetry.js +2 -2
- package/dist/middleware-runner.d.ts +15 -27
- package/dist/middleware-runner.js +25 -30
- package/dist/permissions.d.ts +15 -22
- package/dist/permissions.js +30 -25
- package/dist/pikku-request.js +1 -1
- package/dist/pikku-state.js +2 -3
- package/dist/services/ai-agent-runner-service.d.ts +1 -0
- package/dist/services/content-service.d.ts +66 -37
- package/dist/services/in-memory-queue-service.js +1 -1
- package/dist/services/in-memory-workflow-service.d.ts +15 -13
- package/dist/services/in-memory-workflow-service.js +31 -13
- package/dist/services/index.d.ts +1 -1
- package/dist/services/local-content.d.ts +10 -12
- package/dist/services/local-content.js +54 -38
- package/dist/services/user-session-service.d.ts +1 -1
- package/dist/testing/service-tests.js +24 -0
- package/dist/types/core.types.d.ts +4 -0
- package/dist/types/state.types.d.ts +2 -18
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +24 -5
- package/dist/wirings/ai-agent/ai-agent-memory.js +128 -23
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +10 -1
- package/dist/wirings/ai-agent/ai-agent-model-config.js +15 -35
- package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +45 -31
- package/dist/wirings/ai-agent/ai-agent-stream.js +63 -34
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +20 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-store.d.ts +13 -0
- package/dist/wirings/channel/channel.types.d.ts +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +23 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +8 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +9 -0
- package/dist/wirings/cli/cli-runner.js +24 -5
- package/dist/wirings/cli/command-parser.js +19 -4
- package/dist/wirings/http/http-runner.js +72 -36
- package/dist/wirings/http/http.types.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -1
- package/dist/wirings/http/web-request.js +32 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +3 -2
- package/dist/wirings/rpc/rpc-runner.js +45 -11
- package/dist/wirings/workflow/graph/graph-node.d.ts +8 -0
- package/dist/wirings/workflow/graph/graph-node.js +4 -0
- package/dist/wirings/workflow/graph/graph-runner.js +12 -10
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +4 -0
- package/dist/wirings/workflow/index.d.ts +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +81 -16
- package/dist/wirings/workflow/pikku-workflow-service.js +266 -45
- package/dist/wirings/workflow/workflow.types.d.ts +34 -0
- package/package.json +1 -1
- package/run-tests.sh +4 -1
- package/src/dev/hot-reload.test.ts +62 -11
- package/src/dev/hot-reload.ts +28 -7
- package/src/errors/error-handler.ts +8 -2
- package/src/errors/error.test.ts +2 -0
- package/src/function/function-runner.test.ts +500 -10
- package/src/function/function-runner.ts +68 -3
- package/src/function/functions.types.ts +3 -2
- package/src/index.ts +22 -3
- package/src/middleware/index.ts +11 -2
- package/src/middleware/telemetry.ts +2 -2
- package/src/middleware-runner.test.ts +16 -16
- package/src/middleware-runner.ts +42 -30
- package/src/permissions.test.ts +27 -24
- package/src/permissions.ts +41 -25
- package/src/pikku-request.test.ts +35 -0
- package/src/pikku-request.ts +1 -1
- package/src/pikku-state.ts +2 -3
- package/src/run-tests-script.test.ts +18 -0
- package/src/services/ai-agent-runner-service.ts +1 -0
- package/src/services/content-service.ts +79 -51
- package/src/services/in-memory-queue-service.ts +1 -1
- package/src/services/in-memory-session-store.ts +1 -2
- package/src/services/in-memory-workflow-service.test.ts +33 -11
- package/src/services/in-memory-workflow-service.ts +49 -13
- package/src/services/index.ts +10 -1
- package/src/services/local-content.test.ts +54 -0
- package/src/services/local-content.ts +80 -53
- package/src/services/typed-credential-service.ts +3 -3
- package/src/services/typed-secret-service.ts +3 -3
- package/src/services/typed-variables-service.ts +3 -3
- package/src/services/user-session-service.ts +4 -4
- package/src/testing/service-tests.ts +30 -0
- package/src/types/core.types.ts +6 -2
- package/src/types/state.types.ts +2 -13
- package/src/wirings/ai-agent/ai-agent-memory.test.ts +324 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +187 -36
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +12 -90
- package/src/wirings/ai-agent/ai-agent-model-config.ts +14 -38
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +292 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -1
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +230 -3
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +625 -6
- package/src/wirings/ai-agent/ai-agent-runner.ts +65 -50
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +544 -5
- package/src/wirings/ai-agent/ai-agent-stream.ts +71 -69
- package/src/wirings/ai-agent/ai-agent.types.ts +24 -0
- package/src/wirings/channel/channel-handler.test.ts +272 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-middleware-runner.test.ts +163 -0
- package/src/wirings/channel/channel-store.ts +19 -0
- package/src/wirings/channel/channel.types.ts +4 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +63 -0
- package/src/wirings/channel/local/local-channel-runner.ts +41 -5
- package/src/wirings/channel/local/local-eventhub-service.ts +3 -3
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +9 -2
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +23 -5
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +7 -2
- package/src/wirings/cli/cli-runner.test.ts +255 -2
- package/src/wirings/cli/cli-runner.ts +31 -10
- package/src/wirings/cli/cli.types.ts +4 -8
- package/src/wirings/cli/command-parser.test.ts +83 -0
- package/src/wirings/cli/command-parser.ts +23 -4
- package/src/wirings/http/http-runner.test.ts +296 -1
- package/src/wirings/http/http-runner.ts +87 -57
- package/src/wirings/http/http.types.ts +11 -26
- package/src/wirings/http/pikku-fetch-http-request.ts +8 -4
- package/src/wirings/http/pikku-fetch-http-response.test.ts +41 -0
- package/src/wirings/http/web-request.test.ts +115 -0
- package/src/wirings/http/web-request.ts +43 -5
- package/src/wirings/mcp/mcp-runner.test.ts +367 -0
- package/src/wirings/queue/queue.types.ts +2 -5
- package/src/wirings/rpc/rpc-runner.test.ts +511 -0
- package/src/wirings/rpc/rpc-runner.ts +60 -21
- package/src/wirings/rpc/wire-addon.test.ts +57 -0
- package/src/wirings/workflow/graph/graph-node.ts +12 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +98 -0
- package/src/wirings/workflow/graph/graph-runner.ts +28 -10
- package/src/wirings/workflow/graph/workflow-graph.types.ts +4 -0
- package/src/wirings/workflow/index.ts +1 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +19 -2
- package/src/wirings/workflow/pikku-workflow-service.ts +370 -71
- package/src/wirings/workflow/workflow-queue-workers.test.ts +131 -0
- package/src/wirings/workflow/workflow.types.ts +68 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,14 +3,17 @@ import type { CoreAIAgent, AIAgentMemoryConfig, AIAgentInput, AIMessage } from '
|
|
|
3
3
|
import type { AIStorageService } from '../../services/ai-storage-service.js';
|
|
4
4
|
import type { Logger } from '../../services/logger.js';
|
|
5
5
|
import type { SchemaService } from '../../services/schema-service.js';
|
|
6
|
+
import type { PikkuAIMiddlewareHooks } from './ai-agent.types.js';
|
|
6
7
|
export declare function resolveMemoryServices(agent: CoreAIAgent, singletonServices: CoreSingletonServices): {
|
|
7
8
|
storage: AIStorageService | undefined;
|
|
8
9
|
};
|
|
10
|
+
export declare function isWorkingMemoryEnabled(memoryConfig: AIAgentMemoryConfig | undefined, storage: AIStorageService | undefined): boolean;
|
|
9
11
|
export declare function deepMergeWorkingMemory(existing: Record<string, unknown>, updates: Record<string, unknown>): Record<string, unknown>;
|
|
10
12
|
export declare function buildWorkingMemoryPrompt(currentState: Record<string, unknown> | null, jsonSchema?: Record<string, unknown>): string;
|
|
11
13
|
export declare function loadContextMessages(memoryConfig: AIAgentMemoryConfig | undefined, storage: AIStorageService | undefined, input: AIAgentInput, workingMemoryJsonSchema?: Record<string, unknown>): Promise<AIMessage[]>;
|
|
12
14
|
export declare function saveMessages(storage: AIStorageService | undefined, threadId: string, resourceId: string, memoryConfig: AIAgentMemoryConfig | undefined, userMessage: AIMessage | null | undefined, result: {
|
|
13
15
|
text: string;
|
|
16
|
+
uiSpec?: unknown;
|
|
14
17
|
steps: {
|
|
15
18
|
toolCalls?: {
|
|
16
19
|
name: string;
|
|
@@ -18,12 +21,28 @@ export declare function saveMessages(storage: AIStorageService | undefined, thre
|
|
|
18
21
|
result: string;
|
|
19
22
|
}[];
|
|
20
23
|
}[];
|
|
21
|
-
}, options?: {
|
|
22
|
-
workingMemoryJsonSchema?: Record<string, unknown>;
|
|
23
|
-
workingMemorySchemaName?: string | null;
|
|
24
|
-
logger?: Logger;
|
|
25
|
-
schemaService?: SchemaService;
|
|
26
24
|
}): Promise<string>;
|
|
27
25
|
export declare function trimMessages(messages: AIMessage[], maxTokenBudget?: number): AIMessage[];
|
|
28
26
|
export declare function parseWorkingMemory(text: string): Record<string, unknown> | null;
|
|
29
27
|
export declare function stripWorkingMemoryTags(text: string): string;
|
|
28
|
+
export declare function extractWorkingMemory(text: string): {
|
|
29
|
+
workingMemory: Record<string, unknown> | null;
|
|
30
|
+
cleanedText: string;
|
|
31
|
+
};
|
|
32
|
+
export declare function stripWorkingMemoryForStreaming(text: string): string;
|
|
33
|
+
export declare function createWorkingMemoryMiddleware(options: {
|
|
34
|
+
storage?: AIStorageService;
|
|
35
|
+
threadId: string;
|
|
36
|
+
workingMemorySchemaName?: string | null;
|
|
37
|
+
logger?: Logger;
|
|
38
|
+
schemaService?: SchemaService;
|
|
39
|
+
}): PikkuAIMiddlewareHooks<{
|
|
40
|
+
rawText?: string;
|
|
41
|
+
emittedVisibleText?: string;
|
|
42
|
+
}>;
|
|
43
|
+
export declare function getWorkingMemoryMiddleware(memoryConfig: AIAgentMemoryConfig | undefined, storage: AIStorageService | undefined, options: {
|
|
44
|
+
threadId: string;
|
|
45
|
+
workingMemorySchemaName?: string | null;
|
|
46
|
+
logger?: Logger;
|
|
47
|
+
schemaService?: SchemaService;
|
|
48
|
+
}): PikkuAIMiddlewareHooks[];
|
|
@@ -6,9 +6,15 @@ export function resolveMemoryServices(agent, singletonServices) {
|
|
|
6
6
|
: singletonServices.aiStorage;
|
|
7
7
|
return { storage };
|
|
8
8
|
}
|
|
9
|
+
export function isWorkingMemoryEnabled(memoryConfig, storage) {
|
|
10
|
+
return !!memoryConfig?.workingMemory && !!storage;
|
|
11
|
+
}
|
|
9
12
|
export function deepMergeWorkingMemory(existing, updates) {
|
|
10
13
|
const result = { ...existing };
|
|
11
14
|
for (const key of Object.keys(updates)) {
|
|
15
|
+
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
12
18
|
const value = updates[key];
|
|
13
19
|
if (value === null) {
|
|
14
20
|
delete result[key];
|
|
@@ -46,13 +52,18 @@ export function buildWorkingMemoryPrompt(currentState, jsonSchema) {
|
|
|
46
52
|
parts.push('Current working memory: (empty)');
|
|
47
53
|
}
|
|
48
54
|
parts.push('When you learn new information, output a partial JSON update in <working_memory> tags. ' +
|
|
49
|
-
'Only include
|
|
55
|
+
'Only include durable facts you have actually derived or the user has confirmed. ' +
|
|
56
|
+
'Do not output templates, placeholders, or narration. ' +
|
|
57
|
+
'Only include changed fields. Leave unknown fields untouched. Set a field to null to delete it.');
|
|
50
58
|
return parts.join('\n\n');
|
|
51
59
|
}
|
|
52
60
|
export async function loadContextMessages(memoryConfig, storage, input, workingMemoryJsonSchema) {
|
|
53
61
|
const contextMessages = [];
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
const workingMemoryStorage = isWorkingMemoryEnabled(memoryConfig, storage)
|
|
63
|
+
? storage
|
|
64
|
+
: undefined;
|
|
65
|
+
if (workingMemoryStorage) {
|
|
66
|
+
const workingMem = await workingMemoryStorage.getWorkingMemory(input.threadId, 'thread');
|
|
56
67
|
const prompt = buildWorkingMemoryPrompt(workingMem, workingMemoryJsonSchema);
|
|
57
68
|
contextMessages.push({
|
|
58
69
|
id: `wm-${randomUUID()}`,
|
|
@@ -63,8 +74,10 @@ export async function loadContextMessages(memoryConfig, storage, input, workingM
|
|
|
63
74
|
}
|
|
64
75
|
return contextMessages;
|
|
65
76
|
}
|
|
66
|
-
export async function saveMessages(storage, threadId, resourceId, memoryConfig, userMessage, result
|
|
67
|
-
|
|
77
|
+
export async function saveMessages(storage, threadId, resourceId, memoryConfig, userMessage, result) {
|
|
78
|
+
const responseText = memoryConfig?.workingMemory
|
|
79
|
+
? extractWorkingMemory(result.text).cleanedText
|
|
80
|
+
: result.text;
|
|
68
81
|
if (storage) {
|
|
69
82
|
const newMessages = userMessage ? [userMessage] : [];
|
|
70
83
|
for (const step of result.steps) {
|
|
@@ -92,30 +105,21 @@ export async function saveMessages(storage, threadId, resourceId, memoryConfig,
|
|
|
92
105
|
});
|
|
93
106
|
}
|
|
94
107
|
}
|
|
108
|
+
const assistantContent = result.uiSpec != null
|
|
109
|
+
? [
|
|
110
|
+
...(responseText
|
|
111
|
+
? [{ type: 'text', text: responseText }]
|
|
112
|
+
: []),
|
|
113
|
+
{ type: 'generative-ui', spec: result.uiSpec },
|
|
114
|
+
]
|
|
115
|
+
: responseText;
|
|
95
116
|
newMessages.push({
|
|
96
117
|
id: randomUUID(),
|
|
97
118
|
role: 'assistant',
|
|
98
|
-
content:
|
|
119
|
+
content: assistantContent || undefined,
|
|
99
120
|
createdAt: new Date(),
|
|
100
121
|
});
|
|
101
122
|
await storage.saveMessages(threadId, newMessages);
|
|
102
|
-
if (memoryConfig?.workingMemory) {
|
|
103
|
-
const parsed = parseWorkingMemory(responseText);
|
|
104
|
-
if (parsed) {
|
|
105
|
-
const existing = (await storage.getWorkingMemory(threadId, 'thread')) ?? {};
|
|
106
|
-
const merged = deepMergeWorkingMemory(existing, parsed);
|
|
107
|
-
if (options?.schemaService && options?.workingMemorySchemaName) {
|
|
108
|
-
try {
|
|
109
|
-
await options.schemaService.validateSchema(options.workingMemorySchemaName, merged);
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
options.logger?.warn(`Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
await storage.saveWorkingMemory(threadId, 'thread', merged);
|
|
116
|
-
responseText = stripWorkingMemoryTags(responseText);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
123
|
}
|
|
120
124
|
return responseText;
|
|
121
125
|
}
|
|
@@ -209,3 +213,104 @@ export function parseWorkingMemory(text) {
|
|
|
209
213
|
export function stripWorkingMemoryTags(text) {
|
|
210
214
|
return text.replace(/<working_memory>[\s\S]*?<\/working_memory>/g, '').trim();
|
|
211
215
|
}
|
|
216
|
+
export function extractWorkingMemory(text) {
|
|
217
|
+
const workingMemory = parseWorkingMemory(text);
|
|
218
|
+
return {
|
|
219
|
+
workingMemory,
|
|
220
|
+
cleanedText: workingMemory ? stripWorkingMemoryTags(text) : text,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function getPendingWorkingMemoryPrefixLength(text) {
|
|
224
|
+
const prefixes = ['<working_memory>', '</working_memory>'];
|
|
225
|
+
const lastLt = text.lastIndexOf('<');
|
|
226
|
+
if (lastLt === -1)
|
|
227
|
+
return 0;
|
|
228
|
+
const suffix = text.slice(lastLt);
|
|
229
|
+
for (const prefix of prefixes) {
|
|
230
|
+
if (prefix.startsWith(suffix)) {
|
|
231
|
+
return suffix.length;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return 0;
|
|
235
|
+
}
|
|
236
|
+
export function stripWorkingMemoryForStreaming(text) {
|
|
237
|
+
let output = '';
|
|
238
|
+
let cursor = 0;
|
|
239
|
+
while (cursor < text.length) {
|
|
240
|
+
const openIndex = text.indexOf('<working_memory>', cursor);
|
|
241
|
+
if (openIndex === -1) {
|
|
242
|
+
const tail = text.slice(cursor);
|
|
243
|
+
const pendingPrefixLength = getPendingWorkingMemoryPrefixLength(tail);
|
|
244
|
+
output +=
|
|
245
|
+
pendingPrefixLength > 0 ? tail.slice(0, -pendingPrefixLength) : tail;
|
|
246
|
+
return output;
|
|
247
|
+
}
|
|
248
|
+
output += text.slice(cursor, openIndex);
|
|
249
|
+
const closeIndex = text.indexOf('</working_memory>', openIndex);
|
|
250
|
+
if (closeIndex === -1) {
|
|
251
|
+
return output;
|
|
252
|
+
}
|
|
253
|
+
cursor = closeIndex + '</working_memory>'.length;
|
|
254
|
+
}
|
|
255
|
+
return output;
|
|
256
|
+
}
|
|
257
|
+
export function createWorkingMemoryMiddleware(options) {
|
|
258
|
+
return {
|
|
259
|
+
modifyOutputStream: async (_services, { event, state }) => {
|
|
260
|
+
if (event.type !== 'text-delta')
|
|
261
|
+
return event;
|
|
262
|
+
const rawText = `${state.rawText ?? ''}${event.text}`;
|
|
263
|
+
state.rawText = rawText;
|
|
264
|
+
const visibleText = stripWorkingMemoryForStreaming(rawText);
|
|
265
|
+
const emittedVisibleText = state.emittedVisibleText ?? '';
|
|
266
|
+
if (!visibleText.startsWith(emittedVisibleText)) {
|
|
267
|
+
state.emittedVisibleText = visibleText;
|
|
268
|
+
return { ...event, text: visibleText };
|
|
269
|
+
}
|
|
270
|
+
const delta = visibleText.slice(emittedVisibleText.length);
|
|
271
|
+
state.emittedVisibleText = visibleText;
|
|
272
|
+
if (!delta)
|
|
273
|
+
return null;
|
|
274
|
+
return { ...event, text: delta };
|
|
275
|
+
},
|
|
276
|
+
modifyOutput: async (_services, { text, messages, usage }) => {
|
|
277
|
+
const { workingMemory, cleanedText } = extractWorkingMemory(text);
|
|
278
|
+
if (workingMemory && options.storage) {
|
|
279
|
+
const existing = (await options.storage.getWorkingMemory(options.threadId, 'thread')) ?? {};
|
|
280
|
+
const merged = deepMergeWorkingMemory(existing, workingMemory);
|
|
281
|
+
let valid = true;
|
|
282
|
+
if (options.schemaService && options.workingMemorySchemaName) {
|
|
283
|
+
try {
|
|
284
|
+
await options.schemaService.validateSchema(options.workingMemorySchemaName, merged);
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
valid = false;
|
|
288
|
+
options.logger?.warn(`Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Only persist when the merged value passes schema validation —
|
|
292
|
+
// saving invalid data would poison subsequent getWorkingMemory reads.
|
|
293
|
+
if (valid) {
|
|
294
|
+
await options.storage.saveWorkingMemory(options.threadId, 'thread', merged);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
text: cleanedText,
|
|
299
|
+
messages,
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
export function getWorkingMemoryMiddleware(memoryConfig, storage, options) {
|
|
305
|
+
if (!isWorkingMemoryEnabled(memoryConfig, storage))
|
|
306
|
+
return [];
|
|
307
|
+
return [
|
|
308
|
+
createWorkingMemoryMiddleware({
|
|
309
|
+
storage,
|
|
310
|
+
threadId: options.threadId,
|
|
311
|
+
workingMemorySchemaName: options.workingMemorySchemaName,
|
|
312
|
+
logger: options.logger,
|
|
313
|
+
schemaService: options.schemaService,
|
|
314
|
+
}),
|
|
315
|
+
];
|
|
316
|
+
}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the effective model/temperature/maxSteps for an agent at runtime.
|
|
3
|
+
*
|
|
4
|
+
* Models are declared per-agent using the provider-qualified `provider/model`
|
|
5
|
+
* form (e.g. `openai/gpt-5-mini`); there is no config-level alias map. This
|
|
6
|
+
* function remains the single merge point for request-time overrides (see
|
|
7
|
+
* ai-agent-prepare's `input.model`), so callers stay decoupled from how the
|
|
8
|
+
* effective config is assembled.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveModelConfig(_agentName: string, agent: {
|
|
2
11
|
model: string;
|
|
3
12
|
temperature?: number;
|
|
4
13
|
maxSteps?: number;
|
|
@@ -1,36 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!entry)
|
|
17
|
-
throw new Error(`Unknown model alias '${rawModel}'.`);
|
|
18
|
-
if (typeof entry === 'string') {
|
|
19
|
-
rawModel = entry;
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
rawModel = entry.model;
|
|
23
|
-
aliasTemperature = entry.temperature;
|
|
24
|
-
aliasMaxSteps = entry.maxSteps;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const temperature = agentOverride?.temperature ??
|
|
28
|
-
aliasTemperature ??
|
|
29
|
-
defaults?.temperature ??
|
|
30
|
-
agent.temperature;
|
|
31
|
-
const maxSteps = agentOverride?.maxSteps ??
|
|
32
|
-
aliasMaxSteps ??
|
|
33
|
-
defaults?.maxSteps ??
|
|
34
|
-
agent.maxSteps;
|
|
35
|
-
return { model: rawModel, temperature, maxSteps };
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the effective model/temperature/maxSteps for an agent at runtime.
|
|
3
|
+
*
|
|
4
|
+
* Models are declared per-agent using the provider-qualified `provider/model`
|
|
5
|
+
* form (e.g. `openai/gpt-5-mini`); there is no config-level alias map. This
|
|
6
|
+
* function remains the single merge point for request-time overrides (see
|
|
7
|
+
* ai-agent-prepare's `input.model`), so callers stay decoupled from how the
|
|
8
|
+
* effective config is assembled.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveModelConfig(_agentName, agent) {
|
|
11
|
+
return {
|
|
12
|
+
model: agent.model,
|
|
13
|
+
temperature: agent.temperature,
|
|
14
|
+
maxSteps: agent.maxSteps,
|
|
15
|
+
};
|
|
36
16
|
}
|
|
@@ -169,6 +169,9 @@ export function createScopedChannel(parent, agentName, session) {
|
|
|
169
169
|
parent.send(event);
|
|
170
170
|
}
|
|
171
171
|
},
|
|
172
|
+
setState: (s) => parent.setState(s),
|
|
173
|
+
getState: () => parent.getState(),
|
|
174
|
+
clearState: () => parent.clearState(),
|
|
172
175
|
};
|
|
173
176
|
}
|
|
174
177
|
export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares, agentMode) {
|
|
@@ -254,7 +257,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
254
257
|
}
|
|
255
258
|
}
|
|
256
259
|
tools.push({
|
|
257
|
-
name: toolName.replaceAll(':', '__'),
|
|
260
|
+
name: toolName.replaceAll('@', '_').replaceAll(':', '__'),
|
|
258
261
|
description: fnMeta?.description || fnMeta?.title || toolName,
|
|
259
262
|
inputSchema,
|
|
260
263
|
needsApproval: needsApproval || undefined,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { saveMessages, resolveMemoryServices, loadContextMessages, trimMessages, } from './ai-agent-memory.js';
|
|
1
|
+
import { saveMessages, resolveMemoryServices, loadContextMessages, trimMessages, getWorkingMemoryMiddleware, } from './ai-agent-memory.js';
|
|
2
2
|
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, } from './ai-agent-prepare.js';
|
|
3
3
|
import { checkForApprovals, appendStepMessages } from './ai-agent-stream.js';
|
|
4
4
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
@@ -20,9 +20,19 @@ function stripNulls(obj) {
|
|
|
20
20
|
return result;
|
|
21
21
|
}
|
|
22
22
|
import { randomUUID } from 'crypto';
|
|
23
|
+
function extractStructuredAssistantOutput(object) {
|
|
24
|
+
if (!object || typeof object !== 'object') {
|
|
25
|
+
return { text: null, uiSpec: null };
|
|
26
|
+
}
|
|
27
|
+
const record = object;
|
|
28
|
+
return {
|
|
29
|
+
text: typeof record.text === 'string' ? record.text : null,
|
|
30
|
+
uiSpec: record.ui ?? null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
23
33
|
export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
24
34
|
const sessionMap = agentSessionMap ?? new Map();
|
|
25
|
-
const { agent, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, maxSteps, missingRpcs,
|
|
35
|
+
const { agent, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, maxSteps, missingRpcs, workingMemorySchemaName, } = await prepareAgentRun(agentName, input, params, sessionMap);
|
|
26
36
|
const singletonServices = getSingletonServices();
|
|
27
37
|
const { aiRunState } = singletonServices;
|
|
28
38
|
if (!aiRunState) {
|
|
@@ -48,7 +58,15 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
48
58
|
usage: { inputTokens: 0, outputTokens: 0 },
|
|
49
59
|
};
|
|
50
60
|
}
|
|
51
|
-
const aiMiddlewares =
|
|
61
|
+
const aiMiddlewares = [
|
|
62
|
+
...getWorkingMemoryMiddleware(memoryConfig, storage, {
|
|
63
|
+
threadId,
|
|
64
|
+
workingMemorySchemaName,
|
|
65
|
+
logger: singletonServices.logger,
|
|
66
|
+
schemaService: singletonServices.schema,
|
|
67
|
+
}),
|
|
68
|
+
...(agent.aiMiddleware ?? []),
|
|
69
|
+
];
|
|
52
70
|
let modifiedMessages = runnerParams.messages;
|
|
53
71
|
let modifiedInstructions = runnerParams.instructions;
|
|
54
72
|
for (const mw of aiMiddlewares) {
|
|
@@ -152,12 +170,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
152
170
|
args: a.args,
|
|
153
171
|
});
|
|
154
172
|
const completedStepsForSave = accumulatedSteps.slice(0, -1);
|
|
155
|
-
await saveMessages(storage, threadId, input.resourceId, memoryConfig, userMessage, { text: '', steps: completedStepsForSave }
|
|
156
|
-
workingMemoryJsonSchema,
|
|
157
|
-
workingMemorySchemaName,
|
|
158
|
-
logger: singletonServices.logger,
|
|
159
|
-
schemaService: singletonServices.schema,
|
|
160
|
-
});
|
|
173
|
+
await saveMessages(storage, threadId, input.resourceId, memoryConfig, userMessage, { text: '', steps: completedStepsForSave });
|
|
161
174
|
if (storage) {
|
|
162
175
|
await storage.saveMessages(threadId, [
|
|
163
176
|
{
|
|
@@ -197,19 +210,14 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
197
210
|
}
|
|
198
211
|
appendStepMessages(runnerParams, stepResult);
|
|
199
212
|
}
|
|
200
|
-
const finalText = lastStepResult?.text ?? '';
|
|
201
213
|
const finalObject = lastStepResult?.object;
|
|
214
|
+
const structuredOutput = extractStructuredAssistantOutput(finalObject);
|
|
215
|
+
const finalText = structuredOutput.text ?? lastStepResult?.text ?? '';
|
|
202
216
|
const result = {
|
|
203
217
|
text: finalText,
|
|
204
218
|
steps: accumulatedSteps,
|
|
205
219
|
};
|
|
206
|
-
|
|
207
|
-
workingMemoryJsonSchema,
|
|
208
|
-
workingMemorySchemaName,
|
|
209
|
-
logger: singletonServices.logger,
|
|
210
|
-
schemaService: singletonServices.schema,
|
|
211
|
-
});
|
|
212
|
-
let outputText = responseText;
|
|
220
|
+
let outputText = finalText;
|
|
213
221
|
let outputMessages = runnerParams.messages;
|
|
214
222
|
for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
|
|
215
223
|
const mw = aiMiddlewares[i];
|
|
@@ -223,6 +231,11 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
223
231
|
outputMessages = modResult.messages;
|
|
224
232
|
}
|
|
225
233
|
}
|
|
234
|
+
await saveMessages(storage, threadId, input.resourceId, memoryConfig, userMessage, {
|
|
235
|
+
...result,
|
|
236
|
+
text: outputText,
|
|
237
|
+
uiSpec: structuredOutput.uiSpec,
|
|
238
|
+
});
|
|
226
239
|
await aiRunState.updateRun(runId, {
|
|
227
240
|
status: 'completed',
|
|
228
241
|
usage: { ...totalUsage, model: agent.model },
|
|
@@ -369,7 +382,15 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
369
382
|
const allMessages = [...contextMessages, ...messages];
|
|
370
383
|
const trimmedMessages = trimMessages(allMessages);
|
|
371
384
|
const instructions = await buildInstructions(resolvedName, packageName);
|
|
372
|
-
const aiMiddlewares =
|
|
385
|
+
const aiMiddlewares = [
|
|
386
|
+
...getWorkingMemoryMiddleware(memoryConfig, storage, {
|
|
387
|
+
threadId: run.threadId,
|
|
388
|
+
workingMemorySchemaName,
|
|
389
|
+
logger: singletonServices.logger,
|
|
390
|
+
schemaService: singletonServices.schema,
|
|
391
|
+
}),
|
|
392
|
+
...(agent.aiMiddleware ?? []),
|
|
393
|
+
];
|
|
373
394
|
let modifiedMessages = trimmedMessages;
|
|
374
395
|
let modifiedInstructions = instructions;
|
|
375
396
|
for (const mw of aiMiddlewares) {
|
|
@@ -463,12 +484,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
463
484
|
});
|
|
464
485
|
const completedSteps = accumulatedSteps.slice(0, -1);
|
|
465
486
|
if (completedSteps.length > 0) {
|
|
466
|
-
await saveMessages(storage, run.threadId, run.resourceId, memoryConfig, null, { text: '', steps: completedSteps }
|
|
467
|
-
workingMemoryJsonSchema,
|
|
468
|
-
workingMemorySchemaName,
|
|
469
|
-
logger: singletonServices.logger,
|
|
470
|
-
schemaService: singletonServices.schema,
|
|
471
|
-
});
|
|
487
|
+
await saveMessages(storage, run.threadId, run.resourceId, memoryConfig, null, { text: '', steps: completedSteps });
|
|
472
488
|
}
|
|
473
489
|
if (storage) {
|
|
474
490
|
await storage.saveMessages(run.threadId, [
|
|
@@ -515,13 +531,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
515
531
|
text: finalText,
|
|
516
532
|
steps: accumulatedSteps,
|
|
517
533
|
};
|
|
518
|
-
|
|
519
|
-
workingMemoryJsonSchema,
|
|
520
|
-
workingMemorySchemaName,
|
|
521
|
-
logger: singletonServices.logger,
|
|
522
|
-
schemaService: singletonServices.schema,
|
|
523
|
-
});
|
|
524
|
-
let outputText = responseText;
|
|
534
|
+
let outputText = finalText;
|
|
525
535
|
let outputMessages = runnerParams.messages;
|
|
526
536
|
for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
|
|
527
537
|
const mw = aiMiddlewares[i];
|
|
@@ -535,6 +545,10 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
535
545
|
outputMessages = modResult.messages;
|
|
536
546
|
}
|
|
537
547
|
}
|
|
548
|
+
await saveMessages(storage, run.threadId, run.resourceId, memoryConfig, null, {
|
|
549
|
+
...result,
|
|
550
|
+
text: outputText,
|
|
551
|
+
});
|
|
538
552
|
await aiRunState.updateRun(run.runId, {
|
|
539
553
|
status: 'completed',
|
|
540
554
|
usage: { ...totalUsage, model: agent.model },
|