@kuralle-agents/core 0.4.1 → 0.6.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/README.md +12 -3
- package/dist/ai-sdk/uiMessageStream.d.ts +51 -0
- package/dist/ai-sdk/uiMessageStream.js +164 -0
- package/dist/events/TurnHandle.js +7 -0
- package/dist/flow/nodeBuilders.d.ts +1 -1
- package/dist/flow/nodeBuilders.js +5 -3
- package/dist/index.d.ts +14 -4
- package/dist/index.js +8 -2
- package/dist/memory/blocks/FilePersistentMemoryStore.d.ts +1 -1
- package/dist/memory/blocks/FilePersistentMemoryStore.js +9 -0
- package/dist/memory/blocks/InMemoryPersistentMemoryStore.d.ts +8 -0
- package/dist/memory/blocks/InMemoryPersistentMemoryStore.js +25 -0
- package/dist/memory/blocks/RoutedPersistentMemoryStore.d.ts +18 -0
- package/dist/memory/blocks/RoutedPersistentMemoryStore.js +35 -0
- package/dist/memory/blocks/TieredPersistentMemoryStore.d.ts +10 -0
- package/dist/memory/blocks/TieredPersistentMemoryStore.js +30 -0
- package/dist/memory/blocks/memoryBlockTool.d.ts +5 -5
- package/dist/memory/blocks/testing.d.ts +11 -0
- package/dist/memory/blocks/testing.js +59 -0
- package/dist/memory/index.d.ts +4 -0
- package/dist/memory/index.js +3 -0
- package/dist/runtime/Runtime.d.ts +3 -0
- package/dist/runtime/Runtime.js +47 -5
- package/dist/runtime/agentReply.js +2 -1
- package/dist/runtime/channels/TextDriver.js +3 -2
- package/dist/runtime/channels/VoiceDriver.js +3 -3
- package/dist/runtime/channels/extractionTurn.js +1 -1
- package/dist/runtime/ctx.d.ts +2 -0
- package/dist/runtime/ctx.js +1 -0
- package/dist/runtime/grounding/defaultStoreRegistry.d.ts +3 -0
- package/dist/runtime/grounding/defaultStoreRegistry.js +10 -0
- package/dist/runtime/grounding/index.d.ts +1 -0
- package/dist/runtime/grounding/index.js +1 -0
- package/dist/runtime/grounding/workingMemory.d.ts +19 -0
- package/dist/runtime/grounding/workingMemory.js +80 -0
- package/dist/runtime/resolveAgentWorkspace.d.ts +10 -0
- package/dist/runtime/resolveAgentWorkspace.js +9 -0
- package/dist/skills/SkillsCapability.d.ts +10 -0
- package/dist/skills/SkillsCapability.js +52 -0
- package/dist/skills/collectSkills.d.ts +17 -0
- package/dist/skills/collectSkills.js +56 -0
- package/dist/skills/index.d.ts +5 -0
- package/dist/skills/index.js +4 -0
- package/dist/skills/inlineSkillStore.d.ts +9 -0
- package/dist/skills/inlineSkillStore.js +37 -0
- package/dist/skills/wireAgentSkills.d.ts +10 -0
- package/dist/skills/wireAgentSkills.js +25 -0
- package/dist/testing/mocks.js +7 -0
- package/dist/tools/effect/defineTool.js +1 -1
- package/dist/tools/effect/index.d.ts +1 -0
- package/dist/tools/effect/index.js +1 -0
- package/dist/tools/effect/wrapAiSdkTool.d.ts +3 -0
- package/dist/tools/effect/wrapAiSdkTool.js +12 -0
- package/dist/tools/fs/createFsTool.d.ts +30 -0
- package/dist/tools/fs/createFsTool.js +200 -0
- package/dist/types/agentConfig.d.ts +16 -3
- package/dist/types/filesystem.d.ts +85 -0
- package/dist/types/filesystem.js +6 -0
- package/dist/types/grounding.d.ts +12 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/run-context.d.ts +11 -2
- package/dist/types/skills.d.ts +19 -0
- package/dist/types/skills.js +1 -0
- package/dist/types/stream.d.ts +3 -0
- package/guides/AGENTS.md +2 -3
- package/guides/FLOWS.md +2 -2
- package/guides/RUNTIME.md +18 -1
- package/guides/TOOLS.md +69 -2
- package/package.json +12 -3
package/dist/memory/index.d.ts
CHANGED
|
@@ -4,7 +4,11 @@ export { InMemoryMemoryService } from './stores/InMemoryMemoryService.js';
|
|
|
4
4
|
export { preloadMemoryContext } from './preloadMemory.js';
|
|
5
5
|
export { extractMemories } from './utils.js';
|
|
6
6
|
export type { PersistentMemoryStore, PersistentMemoryBlock, PersistentMemoryConfig, MemoryBlockScope, } from './blocks/types.js';
|
|
7
|
+
export type { WorkingMemoryBlockSpec, WorkingMemoryConfig } from '../types/grounding.js';
|
|
7
8
|
export { DEFAULT_BLOCK_CHAR_LIMIT, DEFAULT_AUTO_LOAD_BLOCKS, } from './blocks/types.js';
|
|
9
|
+
export { InMemoryPersistentMemoryStore } from './blocks/InMemoryPersistentMemoryStore.js';
|
|
8
10
|
export { FilePersistentMemoryStore, type FilePersistentMemoryStoreOptions, } from './blocks/FilePersistentMemoryStore.js';
|
|
11
|
+
export { RoutedPersistentMemoryStore, type RoutedPersistentMemoryStoreConfig, type MemoryRouteFn, } from './blocks/RoutedPersistentMemoryStore.js';
|
|
12
|
+
export { TieredPersistentMemoryStore } from './blocks/TieredPersistentMemoryStore.js';
|
|
9
13
|
export { scanMemoryWrite, type SafetyScanResult } from './blocks/safetyScanner.js';
|
|
10
14
|
export { buildMemoryBlockTool, type MemoryBlockToolOptions } from './blocks/memoryBlockTool.js';
|
package/dist/memory/index.js
CHANGED
|
@@ -2,6 +2,9 @@ export { InMemoryMemoryService } from './stores/InMemoryMemoryService.js';
|
|
|
2
2
|
export { preloadMemoryContext } from './preloadMemory.js';
|
|
3
3
|
export { extractMemories } from './utils.js';
|
|
4
4
|
export { DEFAULT_BLOCK_CHAR_LIMIT, DEFAULT_AUTO_LOAD_BLOCKS, } from './blocks/types.js';
|
|
5
|
+
export { InMemoryPersistentMemoryStore } from './blocks/InMemoryPersistentMemoryStore.js';
|
|
5
6
|
export { FilePersistentMemoryStore, } from './blocks/FilePersistentMemoryStore.js';
|
|
7
|
+
export { RoutedPersistentMemoryStore, } from './blocks/RoutedPersistentMemoryStore.js';
|
|
8
|
+
export { TieredPersistentMemoryStore } from './blocks/TieredPersistentMemoryStore.js';
|
|
6
9
|
export { scanMemoryWrite } from './blocks/safetyScanner.js';
|
|
7
10
|
export { buildMemoryBlockTool } from './blocks/memoryBlockTool.js';
|
|
@@ -13,6 +13,7 @@ import type { ConversationOutcome, ConversationOutcomeMarkedBy } from '../outcom
|
|
|
13
13
|
import type { selectHostTarget } from './select.js';
|
|
14
14
|
import type { KnowledgeProviderConfig } from '../types/voice.js';
|
|
15
15
|
import type { MemoryService as V1MemoryService } from '../memory/MemoryService.js';
|
|
16
|
+
import type { PersistentMemoryStore } from '../memory/blocks/types.js';
|
|
16
17
|
export interface HarnessConfig {
|
|
17
18
|
agents: AgentConfig[];
|
|
18
19
|
defaultAgentId: string;
|
|
@@ -26,6 +27,8 @@ export interface HarnessConfig {
|
|
|
26
27
|
tools?: Record<string, AnyTool>;
|
|
27
28
|
knowledge?: KnowledgeProviderConfig;
|
|
28
29
|
memoryService?: V1MemoryService;
|
|
30
|
+
/** Default store for `agent.memory.workingMemory` when `workingMemory.store` is omitted. */
|
|
31
|
+
defaultWorkingMemoryStore?: PersistentMemoryStore;
|
|
29
32
|
}
|
|
30
33
|
export interface RunOptions {
|
|
31
34
|
sessionId?: string;
|
package/dist/runtime/Runtime.js
CHANGED
|
@@ -5,6 +5,8 @@ import { TextDriver } from './channels/TextDriver.js';
|
|
|
5
5
|
import { createRunContext } from './ctx.js';
|
|
6
6
|
import { createEventBus, createTurnHandle } from '../events/TurnHandle.js';
|
|
7
7
|
import { CoreToolExecutor } from '../tools/effect/index.js';
|
|
8
|
+
import { createFsTool } from '../tools/fs/createFsTool.js';
|
|
9
|
+
import { wireAgentSkills } from '../skills/wireAgentSkills.js';
|
|
8
10
|
import { hostLoop } from './hostLoop.js';
|
|
9
11
|
import { isDegradableRuntimeError } from '../flow/degradableErrors.js';
|
|
10
12
|
import { SAFE_DEGRADED_MESSAGE } from '../flow/degrade.js';
|
|
@@ -14,7 +16,8 @@ import { SessionRunStore } from './durable/SessionRunStore.js';
|
|
|
14
16
|
import { loadRecordedSteps } from './durable/replay.js';
|
|
15
17
|
import { markSessionOutcome } from './outcomeMarking.js';
|
|
16
18
|
import { resolveAgentPolicies } from './policies/resolvePolicies.js';
|
|
17
|
-
import { buildAutoRetrieveProvider, buildKnowledgeProvider, buildMemoryService, runMemoryIngest, } from './grounding/index.js';
|
|
19
|
+
import { buildAutoRetrieveProvider, buildKnowledgeProvider, buildMemoryService, runMemoryIngest, wireWorkingMemory, } from './grounding/index.js';
|
|
20
|
+
import { resolveAgentWorkspace } from './resolveAgentWorkspace.js';
|
|
18
21
|
import { SessionMutex } from './SessionMutex.js';
|
|
19
22
|
export class Runtime {
|
|
20
23
|
config;
|
|
@@ -62,16 +65,38 @@ export class Runtime {
|
|
|
62
65
|
sessionStore: this.sessionStore,
|
|
63
66
|
});
|
|
64
67
|
const policies = resolveAgentPolicies(opened.agent);
|
|
65
|
-
const
|
|
68
|
+
const agentTools = {
|
|
66
69
|
...(this.config.tools ?? {}),
|
|
67
|
-
...(opened.agent.
|
|
70
|
+
...(opened.agent.tools ?? {}),
|
|
68
71
|
// Global tools (ADR 0001) are model-visible in speaking turns via the
|
|
69
72
|
// drivers; register their executors here too so a model call can actually
|
|
70
73
|
// run them. Visibility stays gated (not exposed during collect extraction).
|
|
71
74
|
...(opened.agent.globalTools ?? {}),
|
|
72
75
|
};
|
|
76
|
+
const resolvedWorkspace = resolveAgentWorkspace(opened.agent.workspace);
|
|
77
|
+
if (resolvedWorkspace) {
|
|
78
|
+
agentTools.workspace = createFsTool({
|
|
79
|
+
fs: resolvedWorkspace.fs,
|
|
80
|
+
readOnly: resolvedWorkspace.readOnly,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const wiredWorkingMemory = await wireWorkingMemory(opened.agent, opened.session, this.config.defaultWorkingMemoryStore);
|
|
84
|
+
if (wiredWorkingMemory) {
|
|
85
|
+
agentTools.memory_block = wiredWorkingMemory.memoryBlockTool;
|
|
86
|
+
}
|
|
87
|
+
let skillPrompt;
|
|
88
|
+
let skillTools = {};
|
|
89
|
+
if (opened.agent.skills) {
|
|
90
|
+
const wired = await wireAgentSkills(opened.agent);
|
|
91
|
+
if (wired) {
|
|
92
|
+
skillTools = wired.tools;
|
|
93
|
+
Object.assign(agentTools, wired.tools);
|
|
94
|
+
skillPrompt = wired.promptSections.map((s) => s.content).join('\n\n');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const workspaceTool = agentTools.workspace;
|
|
73
98
|
const toolExecutor = new CoreToolExecutor({
|
|
74
|
-
tools:
|
|
99
|
+
tools: agentTools,
|
|
75
100
|
enforcer: policies.enforcer,
|
|
76
101
|
agentId: opened.agent.id,
|
|
77
102
|
onInterim: (message) => {
|
|
@@ -111,11 +136,23 @@ export class Runtime {
|
|
|
111
136
|
memoryService: this.config.memoryService
|
|
112
137
|
? buildMemoryService(this.config.memoryService, opened.agent)
|
|
113
138
|
: undefined,
|
|
139
|
+
fs: resolvedWorkspace?.fs,
|
|
114
140
|
});
|
|
115
141
|
// Agent base layer (ADR 0001): composed into every node turn by the drivers.
|
|
116
142
|
runCtx.baseInstructions = opened.agent.instructions;
|
|
117
|
-
runCtx.globalTools =
|
|
143
|
+
runCtx.globalTools = {
|
|
144
|
+
...(opened.agent.globalTools ?? {}),
|
|
145
|
+
...(workspaceTool && resolvedWorkspace?.readOnly !== false
|
|
146
|
+
? { workspace: workspaceTool }
|
|
147
|
+
: {}),
|
|
148
|
+
...skillTools,
|
|
149
|
+
};
|
|
118
150
|
runCtx.outOfBandControl = opened.agent.experimental?.outOfBandControl ?? false;
|
|
151
|
+
runCtx.skillPrompt = skillPrompt;
|
|
152
|
+
runCtx.workingMemoryPrompt = wiredWorkingMemory?.promptSection;
|
|
153
|
+
runCtx.workingMemoryTools = wiredWorkingMemory
|
|
154
|
+
? { memory_block: wiredWorkingMemory.memoryBlockTool }
|
|
155
|
+
: undefined;
|
|
119
156
|
await this.hooks?.onStart?.(runCtx);
|
|
120
157
|
const driver = opts.driver ?? new TextDriver();
|
|
121
158
|
let activeAgent = opened.agent;
|
|
@@ -160,6 +197,11 @@ export class Runtime {
|
|
|
160
197
|
runCtx.memoryService = this.config.memoryService
|
|
161
198
|
? buildMemoryService(this.config.memoryService, target)
|
|
162
199
|
: undefined;
|
|
200
|
+
const targetWorkingMemory = await wireWorkingMemory(target, opened.session, this.config.defaultWorkingMemoryStore);
|
|
201
|
+
runCtx.workingMemoryPrompt = targetWorkingMemory?.promptSection;
|
|
202
|
+
runCtx.workingMemoryTools = targetWorkingMemory
|
|
203
|
+
? { memory_block: targetWorkingMemory.memoryBlockTool }
|
|
204
|
+
: undefined;
|
|
163
205
|
await runCtx.runStore.putRunState(runCtx.runState);
|
|
164
206
|
continue;
|
|
165
207
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildToolSet } from '../tools/effect/defineTool.js';
|
|
1
2
|
export function buildAgentReplyNode(agent) {
|
|
2
3
|
const label = agent.name ?? agent.id;
|
|
3
4
|
const instructions = agent.instructions ??
|
|
@@ -6,7 +7,7 @@ export function buildAgentReplyNode(agent) {
|
|
|
6
7
|
kind: 'reply',
|
|
7
8
|
id: `${agent.id}__host`,
|
|
8
9
|
instructions,
|
|
9
|
-
tools: agent.tools,
|
|
10
|
+
tools: agent.tools ? buildToolSet(agent.tools) : undefined,
|
|
10
11
|
model: agent.model,
|
|
11
12
|
};
|
|
12
13
|
}
|
|
@@ -38,7 +38,7 @@ export class TextDriver {
|
|
|
38
38
|
const out = { text: '', toolResults: [] };
|
|
39
39
|
const model = replyNode.model ?? ctx.model;
|
|
40
40
|
const nodeSystem = node.prompt || buildNodePrompt(replyNode, ctx.runState.state);
|
|
41
|
-
const baseSystem = composeSystem(ctx.baseInstructions, nodeSystem, ctx.runState.state);
|
|
41
|
+
const baseSystem = composeSystem(ctx.baseInstructions, nodeSystem, ctx.runState.state, ctx.skillPrompt, ctx.workingMemoryPrompt);
|
|
42
42
|
const system = appendGatherBlocks(baseSystem, [gather.retrievalBlock, gather.memoryBlock]);
|
|
43
43
|
const messages = [...ctx.runState.messages];
|
|
44
44
|
const aiTools = this.resolveTools(node, ctx);
|
|
@@ -137,7 +137,7 @@ export class TextDriver {
|
|
|
137
137
|
return runSilentExtraction(node, ctx, ctx.controlModel, resolveMaxSteps(ctx.limits, this.maxSteps));
|
|
138
138
|
}
|
|
139
139
|
async runStructured(node, ctx) {
|
|
140
|
-
const system = composeSystem(ctx.baseInstructions, resolveInstructions(node.instructions, ctx.runState.state), ctx.runState.state);
|
|
140
|
+
const system = composeSystem(ctx.baseInstructions, resolveInstructions(node.instructions, ctx.runState.state), ctx.runState.state, ctx.skillPrompt, ctx.workingMemoryPrompt);
|
|
141
141
|
return resolveStructuredDecide(node, ctx, system);
|
|
142
142
|
}
|
|
143
143
|
async awaitUser(ctx) {
|
|
@@ -149,6 +149,7 @@ export class TextDriver {
|
|
|
149
149
|
const merged = {
|
|
150
150
|
...this.toolDefs,
|
|
151
151
|
...(ctx.globalTools ?? {}),
|
|
152
|
+
...(ctx.workingMemoryTools ?? {}),
|
|
152
153
|
...(resolved.localTools ?? {}),
|
|
153
154
|
};
|
|
154
155
|
const aiTools = { ...resolved.tools };
|
|
@@ -63,9 +63,9 @@ export class VoiceDriver {
|
|
|
63
63
|
const gather = await runGatherPhase(ctx, scope);
|
|
64
64
|
const out = { text: '', toolResults: [] };
|
|
65
65
|
const nodeSystem = node.prompt || buildNodePrompt(replyNode, ctx.runState.state);
|
|
66
|
-
const baseSystem = composeSystem(ctx.baseInstructions, nodeSystem, ctx.runState.state);
|
|
66
|
+
const baseSystem = composeSystem(ctx.baseInstructions, nodeSystem, ctx.runState.state, ctx.skillPrompt, ctx.workingMemoryPrompt);
|
|
67
67
|
const system = appendGatherBlocks(baseSystem, [gather.retrievalBlock, gather.memoryBlock]);
|
|
68
|
-
const geminiTools = resolveVoiceGeminiTools(node, { ...this.toolDefs, ...(ctx.globalTools ?? {}) }, { siloFlowControl: ctx.outOfBandControl && !node.freeConversation });
|
|
68
|
+
const geminiTools = resolveVoiceGeminiTools(node, { ...this.toolDefs, ...(ctx.globalTools ?? {}), ...(ctx.workingMemoryTools ?? {}) }, { siloFlowControl: ctx.outOfBandControl && !node.freeConversation });
|
|
69
69
|
const toolCallsMade = [];
|
|
70
70
|
const maxSteps = resolveMaxSteps(ctx.limits, this.maxSteps);
|
|
71
71
|
const mode = resolveStreamMode(ctx, node);
|
|
@@ -139,7 +139,7 @@ export class VoiceDriver {
|
|
|
139
139
|
return out;
|
|
140
140
|
}
|
|
141
141
|
async runStructured(node, ctx) {
|
|
142
|
-
const system = composeSystem(ctx.baseInstructions, resolveInstructions(node.instructions, ctx.runState.state), ctx.runState.state);
|
|
142
|
+
const system = composeSystem(ctx.baseInstructions, resolveInstructions(node.instructions, ctx.runState.state), ctx.runState.state, ctx.skillPrompt, ctx.workingMemoryPrompt);
|
|
143
143
|
return resolveStructuredDecide(node, ctx, system);
|
|
144
144
|
}
|
|
145
145
|
// Non-speaking collect extraction: uses the shared text-model extraction path
|
|
@@ -15,7 +15,7 @@ import { buildNodePrompt, composeSystem } from '../../flow/nodeBuilders.js';
|
|
|
15
15
|
export async function runSilentExtraction(node, ctx, model, maxSteps) {
|
|
16
16
|
const replyNode = node.node;
|
|
17
17
|
const nodeSystem = node.prompt || buildNodePrompt(replyNode, ctx.runState.state);
|
|
18
|
-
const system = composeSystem(ctx.baseInstructions, nodeSystem, ctx.runState.state);
|
|
18
|
+
const system = composeSystem(ctx.baseInstructions, nodeSystem, ctx.runState.state, ctx.skillPrompt, ctx.workingMemoryPrompt);
|
|
19
19
|
const messages = [...ctx.runState.messages];
|
|
20
20
|
const aiTools = resolveExtractionTools(node);
|
|
21
21
|
const out = { text: '', toolResults: [] };
|
package/dist/runtime/ctx.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { RefinementCapability } from '../capabilities/RefinementCapability.
|
|
|
6
6
|
import type { ValidationCapability } from '../capabilities/ValidationCapability.js';
|
|
7
7
|
import type { InputProcessor, OutputProcessor } from '../types/processors.js';
|
|
8
8
|
import type { Limits } from '../types/guardrails.js';
|
|
9
|
+
import type { FileSystem } from '../types/filesystem.js';
|
|
9
10
|
import type { RunState, StepRecord } from './durable/types.js';
|
|
10
11
|
import type { RunStore } from './durable/RunStore.js';
|
|
11
12
|
interface EffectClock {
|
|
@@ -29,6 +30,7 @@ export interface CtxDeps {
|
|
|
29
30
|
limits?: Limits;
|
|
30
31
|
autoRetrieve?: AutoRetrieveProvider;
|
|
31
32
|
memoryService?: MemoryService;
|
|
33
|
+
fs?: FileSystem;
|
|
32
34
|
bargeIn?: AbortSignal;
|
|
33
35
|
abortSignal?: AbortSignal;
|
|
34
36
|
clock?: EffectClock;
|
package/dist/runtime/ctx.js
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PersistentMemoryStore } from '../../memory/blocks/types.js';
|
|
2
|
+
export declare function registerNodeDefaultWorkingMemoryStore(factory: () => PersistentMemoryStore): void;
|
|
3
|
+
export declare function getNodeDefaultWorkingMemoryStore(): (() => PersistentMemoryStore) | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
let nodeDefaultStoreFactory;
|
|
2
|
+
export function registerNodeDefaultWorkingMemoryStore(factory) {
|
|
3
|
+
nodeDefaultStoreFactory = factory;
|
|
4
|
+
}
|
|
5
|
+
export function getNodeDefaultWorkingMemoryStore() {
|
|
6
|
+
if (typeof process === 'undefined' || !process.versions?.node) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
return nodeDefaultStoreFactory;
|
|
10
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { appendGatherBlocks, buildAutoRetrieveProvider, buildKnowledgeProvider, } from './knowledge.js';
|
|
2
2
|
export { buildMemoryService, resetMissingUserIdWarningsForTests, runMemoryIngest, warnMissingUserId, } from './memory.js';
|
|
3
|
+
export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection, resolveWorkingMemoryStore, resolveWorkingMemoryOwner, type LoadedWorkingMemoryBlock, type WiredWorkingMemory, } from './workingMemory.js';
|
|
3
4
|
export { runGatherPhase, type GatherResult, type GatherScope } from './gather.js';
|
|
4
5
|
export { resolveNodeGatherScope } from './nodeScope.js';
|
|
5
6
|
export { createInMemoryKnowledgeConfig, createInMemoryKnowledgeRetriever, type InMemoryKnowledgeDocument, } from './inMemoryKnowledge.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { appendGatherBlocks, buildAutoRetrieveProvider, buildKnowledgeProvider, } from './knowledge.js';
|
|
2
2
|
export { buildMemoryService, resetMissingUserIdWarningsForTests, runMemoryIngest, warnMissingUserId, } from './memory.js';
|
|
3
|
+
export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection, resolveWorkingMemoryStore, resolveWorkingMemoryOwner, } from './workingMemory.js';
|
|
3
4
|
export { runGatherPhase } from './gather.js';
|
|
4
5
|
export { resolveNodeGatherScope } from './nodeScope.js';
|
|
5
6
|
export { createInMemoryKnowledgeConfig, createInMemoryKnowledgeRetriever, } from './inMemoryKnowledge.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AgentConfig } from '../../types/agentConfig.js';
|
|
2
|
+
import type { WorkingMemoryBlockSpec, WorkingMemoryConfig } from '../../types/grounding.js';
|
|
3
|
+
import type { Session } from '../../types/session.js';
|
|
4
|
+
import type { AnyTool } from '../../types/effectTool.js';
|
|
5
|
+
import { type MemoryBlockScope, type PersistentMemoryStore } from '../../memory/blocks/types.js';
|
|
6
|
+
export interface LoadedWorkingMemoryBlock {
|
|
7
|
+
scope: MemoryBlockScope;
|
|
8
|
+
key: string;
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
11
|
+
export interface WiredWorkingMemory {
|
|
12
|
+
promptSection: string | undefined;
|
|
13
|
+
memoryBlockTool: AnyTool;
|
|
14
|
+
}
|
|
15
|
+
export declare function resolveWorkingMemoryStore(config: WorkingMemoryConfig, harnessDefault?: PersistentMemoryStore): PersistentMemoryStore;
|
|
16
|
+
export declare function resolveWorkingMemoryOwner(scope: MemoryBlockScope, agentId: string, userId: string | undefined): string;
|
|
17
|
+
export declare function loadWorkingMemoryBlocks(store: PersistentMemoryStore, autoLoad: WorkingMemoryBlockSpec[], resolveOwner: (scope: MemoryBlockScope) => string): Promise<LoadedWorkingMemoryBlock[]>;
|
|
18
|
+
export declare function formatWorkingMemorySection(blocks: LoadedWorkingMemoryBlock[], autoLoad: WorkingMemoryBlockSpec[]): string | undefined;
|
|
19
|
+
export declare function wireWorkingMemory(agent: AgentConfig, session: Session, harnessDefaultStore?: PersistentMemoryStore): Promise<WiredWorkingMemory | undefined>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { buildMemoryBlockTool } from '../../memory/blocks/memoryBlockTool.js';
|
|
2
|
+
import { DEFAULT_AUTO_LOAD_BLOCKS, DEFAULT_BLOCK_CHAR_LIMIT, } from '../../memory/blocks/types.js';
|
|
3
|
+
import { wrapAiSdkTool } from '../../tools/effect/wrapAiSdkTool.js';
|
|
4
|
+
import { getNodeDefaultWorkingMemoryStore } from './defaultStoreRegistry.js';
|
|
5
|
+
export function resolveWorkingMemoryStore(config, harnessDefault) {
|
|
6
|
+
if (config.store) {
|
|
7
|
+
return config.store;
|
|
8
|
+
}
|
|
9
|
+
if (harnessDefault) {
|
|
10
|
+
return harnessDefault;
|
|
11
|
+
}
|
|
12
|
+
const factory = getNodeDefaultWorkingMemoryStore();
|
|
13
|
+
if (factory) {
|
|
14
|
+
return factory();
|
|
15
|
+
}
|
|
16
|
+
throw new Error('[Kuralle] agent.memory.workingMemory requires a store. Pass workingMemory.store, ' +
|
|
17
|
+
'HarnessConfig.defaultWorkingMemoryStore, or import FilePersistentMemoryStore on Node.');
|
|
18
|
+
}
|
|
19
|
+
export function resolveWorkingMemoryOwner(scope, agentId, userId) {
|
|
20
|
+
return scope === 'agent' ? agentId : (userId ?? 'anonymous');
|
|
21
|
+
}
|
|
22
|
+
export async function loadWorkingMemoryBlocks(store, autoLoad, resolveOwner) {
|
|
23
|
+
const loaded = [];
|
|
24
|
+
for (const spec of autoLoad) {
|
|
25
|
+
const owner = resolveOwner(spec.scope);
|
|
26
|
+
const block = await store.loadBlock(spec.scope, owner, spec.key);
|
|
27
|
+
let content = block?.content?.trim() ?? '';
|
|
28
|
+
if (!content && spec.template) {
|
|
29
|
+
content = spec.template.trim();
|
|
30
|
+
}
|
|
31
|
+
if (content) {
|
|
32
|
+
loaded.push({ scope: spec.scope, key: spec.key, content });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return loaded;
|
|
36
|
+
}
|
|
37
|
+
export function formatWorkingMemorySection(blocks, autoLoad) {
|
|
38
|
+
if (autoLoad.length === 0) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const byKey = new Map(blocks.map((b) => [`${b.scope}/${b.key}`, b]));
|
|
42
|
+
// Directive (Mastra-informed): the model must proactively maintain these blocks
|
|
43
|
+
// via the `memory_block` tool, not just read them. Rendered even when blocks are
|
|
44
|
+
// empty so a first-time conversation knows the capability exists.
|
|
45
|
+
const lines = [
|
|
46
|
+
'## Working memory',
|
|
47
|
+
'',
|
|
48
|
+
'You keep durable notes about the user and conversation in the blocks below, persisted across sessions. Use the `memory_block` tool to keep them current:',
|
|
49
|
+
'- When the user shares a durable fact or preference (name, account details, preferences, anything that may be referenced again), call `memory_block` with action `add`, the relevant block, and a short factual entry. Store proactively — if unsure whether it will matter later, store it.',
|
|
50
|
+
'- Answer questions about stored information from these blocks first; you do NOT need to call the tool to read them.',
|
|
51
|
+
'- Do not announce that you are saving, and do not call the tool when nothing relevant changed.',
|
|
52
|
+
'',
|
|
53
|
+
];
|
|
54
|
+
for (const spec of autoLoad) {
|
|
55
|
+
const block = byKey.get(`${spec.scope}/${spec.key}`);
|
|
56
|
+
lines.push(`### ${spec.key} (${spec.scope})`);
|
|
57
|
+
lines.push(block?.content?.trim() || '(empty — add entries here as you learn them)');
|
|
58
|
+
lines.push('');
|
|
59
|
+
}
|
|
60
|
+
return lines.join('\n').trim();
|
|
61
|
+
}
|
|
62
|
+
export async function wireWorkingMemory(agent, session, harnessDefaultStore) {
|
|
63
|
+
const config = agent.memory?.workingMemory;
|
|
64
|
+
if (!config) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const store = resolveWorkingMemoryStore(config, harnessDefaultStore);
|
|
68
|
+
const autoLoad = config.autoLoad ?? DEFAULT_AUTO_LOAD_BLOCKS;
|
|
69
|
+
const charLimit = config.defaultCharLimit ?? DEFAULT_BLOCK_CHAR_LIMIT;
|
|
70
|
+
const resolveOwner = (scope) => resolveWorkingMemoryOwner(scope, agent.id, session.userId);
|
|
71
|
+
const loaded = await loadWorkingMemoryBlocks(store, autoLoad, resolveOwner);
|
|
72
|
+
const promptSection = formatWorkingMemorySection(loaded, autoLoad);
|
|
73
|
+
const memoryBlockTool = wrapAiSdkTool('memory_block', buildMemoryBlockTool({
|
|
74
|
+
store,
|
|
75
|
+
resolveOwner,
|
|
76
|
+
charLimit,
|
|
77
|
+
scanForInjection: config.scanForInjection,
|
|
78
|
+
}));
|
|
79
|
+
return { promptSection, memoryBlockTool };
|
|
80
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FileSystem } from '../types/filesystem.js';
|
|
2
|
+
export type AgentWorkspaceConfig = FileSystem | {
|
|
3
|
+
fs: FileSystem;
|
|
4
|
+
readOnly?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export interface ResolvedAgentWorkspace {
|
|
7
|
+
fs: FileSystem;
|
|
8
|
+
readOnly: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function resolveAgentWorkspace(workspace: AgentWorkspaceConfig | undefined): ResolvedAgentWorkspace | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function resolveAgentWorkspace(workspace) {
|
|
2
|
+
if (!workspace) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
if (typeof workspace === 'object' && workspace !== null && 'fs' in workspace) {
|
|
6
|
+
return { fs: workspace.fs, readOnly: workspace.readOnly !== false };
|
|
7
|
+
}
|
|
8
|
+
return { fs: workspace, readOnly: true };
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Capability, CapabilityAction, PromptSection, ToolDeclaration } from '../capabilities/index.js';
|
|
2
|
+
import type { SkillMeta, SkillStoreLike } from '../types/skills.js';
|
|
3
|
+
export declare class SkillsCapability implements Capability {
|
|
4
|
+
private readonly store;
|
|
5
|
+
private readonly metas;
|
|
6
|
+
constructor(store: SkillStoreLike, metas: SkillMeta[]);
|
|
7
|
+
getTools(): ToolDeclaration[];
|
|
8
|
+
getPromptSections(): PromptSection[];
|
|
9
|
+
processToolResult(_toolName: string, _args: unknown, _result: unknown): CapabilityAction | null;
|
|
10
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export class SkillsCapability {
|
|
3
|
+
store;
|
|
4
|
+
metas;
|
|
5
|
+
constructor(store, metas) {
|
|
6
|
+
this.store = store;
|
|
7
|
+
this.metas = metas;
|
|
8
|
+
}
|
|
9
|
+
getTools() {
|
|
10
|
+
return [
|
|
11
|
+
{
|
|
12
|
+
name: 'load_skill',
|
|
13
|
+
description: "Load a skill's full instructions by name when the task matches its description.",
|
|
14
|
+
parameters: z.object({
|
|
15
|
+
name: z.string().describe('Skill name from the available skills list'),
|
|
16
|
+
}),
|
|
17
|
+
execute: async (args) => ({
|
|
18
|
+
body: await this.store.loadBody(args.name),
|
|
19
|
+
}),
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'read_skill_resource',
|
|
23
|
+
description: 'Read a bundled resource file from a skill (reference docs, checklists, etc.).',
|
|
24
|
+
parameters: z.object({
|
|
25
|
+
name: z.string().describe('Skill name'),
|
|
26
|
+
path: z.string().describe('Relative resource path within the skill folder'),
|
|
27
|
+
}),
|
|
28
|
+
execute: async (args) => ({
|
|
29
|
+
content: await this.store.loadResource(args.name, args.path),
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
getPromptSections() {
|
|
35
|
+
if (!this.metas.length)
|
|
36
|
+
return [];
|
|
37
|
+
const lines = this.metas.map((m) => `- ${m.name}: ${m.description}`).join('\n');
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
role: 'context',
|
|
41
|
+
content: [
|
|
42
|
+
'## Available skills',
|
|
43
|
+
'Load a skill with load_skill when its description matches the task:',
|
|
44
|
+
lines,
|
|
45
|
+
].join('\n'),
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
processToolResult(_toolName, _args, _result) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AnyTool } from '../types/effectTool.js';
|
|
2
|
+
import type { SkillLike, SkillSource, SkillStoreLike } from '../types/skills.js';
|
|
3
|
+
export interface SkillWireAgent {
|
|
4
|
+
skills?: SkillSource;
|
|
5
|
+
tools?: Record<string, AnyTool>;
|
|
6
|
+
globalTools?: Record<string, AnyTool>;
|
|
7
|
+
flows?: Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export declare function isSkillStore(value: SkillSource): value is SkillStoreLike;
|
|
12
|
+
export declare function collectRegisteredNames(agent: SkillWireAgent): Set<string>;
|
|
13
|
+
export declare function validateSkillAllowedTools(skills: SkillLike[], registered: Set<string>): void;
|
|
14
|
+
export declare function prepareSkillStore(source: SkillSource): Promise<{
|
|
15
|
+
store: SkillStoreLike;
|
|
16
|
+
skills: SkillLike[];
|
|
17
|
+
}>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { InlineSkillStore } from './inlineSkillStore.js';
|
|
2
|
+
export function isSkillStore(value) {
|
|
3
|
+
return (typeof value === 'object' &&
|
|
4
|
+
value !== null &&
|
|
5
|
+
!Array.isArray(value) &&
|
|
6
|
+
'list' in value &&
|
|
7
|
+
typeof value.list === 'function');
|
|
8
|
+
}
|
|
9
|
+
async function collectSkillsFromSource(source) {
|
|
10
|
+
if (!isSkillStore(source)) {
|
|
11
|
+
return Array.isArray(source) ? source : [source];
|
|
12
|
+
}
|
|
13
|
+
if (typeof source.getAllSkills === 'function') {
|
|
14
|
+
const all = source.getAllSkills();
|
|
15
|
+
return Array.isArray(all) ? all : await all;
|
|
16
|
+
}
|
|
17
|
+
if (typeof source.loadAllSkills === 'function') {
|
|
18
|
+
return source.loadAllSkills();
|
|
19
|
+
}
|
|
20
|
+
const metas = await source.list();
|
|
21
|
+
const skills = [];
|
|
22
|
+
for (const meta of metas) {
|
|
23
|
+
const body = await source.loadBody(meta.name);
|
|
24
|
+
skills.push({ name: meta.name, description: meta.description, body });
|
|
25
|
+
}
|
|
26
|
+
return skills;
|
|
27
|
+
}
|
|
28
|
+
export function collectRegisteredNames(agent) {
|
|
29
|
+
const names = new Set();
|
|
30
|
+
for (const [key, tool] of Object.entries(agent.tools ?? {})) {
|
|
31
|
+
names.add(tool.name ?? key);
|
|
32
|
+
}
|
|
33
|
+
for (const [key, tool] of Object.entries(agent.globalTools ?? {})) {
|
|
34
|
+
names.add(tool.name ?? key);
|
|
35
|
+
}
|
|
36
|
+
for (const flow of agent.flows ?? []) {
|
|
37
|
+
names.add(flow.name);
|
|
38
|
+
}
|
|
39
|
+
return names;
|
|
40
|
+
}
|
|
41
|
+
export function validateSkillAllowedTools(skills, registered) {
|
|
42
|
+
for (const skill of skills) {
|
|
43
|
+
for (const toolName of skill.allowedTools ?? []) {
|
|
44
|
+
if (!registered.has(toolName)) {
|
|
45
|
+
throw new Error(`skill ${skill.name}: unknown tool ${toolName}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function prepareSkillStore(source) {
|
|
51
|
+
if (isSkillStore(source)) {
|
|
52
|
+
return { store: source, skills: await collectSkillsFromSource(source) };
|
|
53
|
+
}
|
|
54
|
+
const skills = Array.isArray(source) ? source : [source];
|
|
55
|
+
return { store: new InlineSkillStore(skills), skills };
|
|
56
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SkillsCapability } from './SkillsCapability.js';
|
|
2
|
+
export { wireAgentSkills } from './wireAgentSkills.js';
|
|
3
|
+
export type { WiredAgentSkills } from './wireAgentSkills.js';
|
|
4
|
+
export { collectRegisteredNames, validateSkillAllowedTools, prepareSkillStore, isSkillStore, type SkillWireAgent, } from './collectSkills.js';
|
|
5
|
+
export { InlineSkillStore } from './inlineSkillStore.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SkillsCapability } from './SkillsCapability.js';
|
|
2
|
+
export { wireAgentSkills } from './wireAgentSkills.js';
|
|
3
|
+
export { collectRegisteredNames, validateSkillAllowedTools, prepareSkillStore, isSkillStore, } from './collectSkills.js';
|
|
4
|
+
export { InlineSkillStore } from './inlineSkillStore.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SkillLike, SkillMeta, SkillStoreLike } from '../types/skills.js';
|
|
2
|
+
export declare class InlineSkillStore implements SkillStoreLike {
|
|
3
|
+
private readonly byName;
|
|
4
|
+
constructor(skills: SkillLike[]);
|
|
5
|
+
list(): Promise<SkillMeta[]>;
|
|
6
|
+
loadBody(name: string): Promise<string>;
|
|
7
|
+
loadResource(name: string, path: string): Promise<string | Uint8Array>;
|
|
8
|
+
getAllSkills(): SkillLike[];
|
|
9
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export class InlineSkillStore {
|
|
2
|
+
byName;
|
|
3
|
+
constructor(skills) {
|
|
4
|
+
this.byName = new Map(skills.map((s) => [s.name, s]));
|
|
5
|
+
}
|
|
6
|
+
async list() {
|
|
7
|
+
return [...this.byName.values()].map((s) => ({
|
|
8
|
+
name: s.name,
|
|
9
|
+
description: s.description,
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
async loadBody(name) {
|
|
13
|
+
const skill = this.byName.get(name);
|
|
14
|
+
if (!skill) {
|
|
15
|
+
throw new Error(`[skills] Skill "${name}" not found.`);
|
|
16
|
+
}
|
|
17
|
+
return skill.body;
|
|
18
|
+
}
|
|
19
|
+
async loadResource(name, path) {
|
|
20
|
+
const skill = this.byName.get(name);
|
|
21
|
+
if (!skill) {
|
|
22
|
+
throw new Error(`[skills] Skill "${name}" not found.`);
|
|
23
|
+
}
|
|
24
|
+
const normalized = path.trim().replace(/^\.?\//, '');
|
|
25
|
+
if (normalized.includes('..') || normalized.startsWith('/')) {
|
|
26
|
+
throw new Error(`[skills] Invalid resource path "${path}".`);
|
|
27
|
+
}
|
|
28
|
+
const content = skill.resources?.[normalized];
|
|
29
|
+
if (content === undefined) {
|
|
30
|
+
throw new Error(`[skills] Resource "${normalized}" not found for skill "${name}".`);
|
|
31
|
+
}
|
|
32
|
+
return content;
|
|
33
|
+
}
|
|
34
|
+
getAllSkills() {
|
|
35
|
+
return [...this.byName.values()];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type AnyTool } from '../types/effectTool.js';
|
|
2
|
+
import type { PromptSection } from '../capabilities/index.js';
|
|
3
|
+
import { type SkillWireAgent } from './collectSkills.js';
|
|
4
|
+
import { SkillsCapability } from './SkillsCapability.js';
|
|
5
|
+
export interface WiredAgentSkills {
|
|
6
|
+
capability: SkillsCapability;
|
|
7
|
+
tools: Record<string, AnyTool>;
|
|
8
|
+
promptSections: PromptSection[];
|
|
9
|
+
}
|
|
10
|
+
export declare function wireAgentSkills(agent: SkillWireAgent): Promise<WiredAgentSkills | undefined>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineTool } from '../types/effectTool.js';
|
|
2
|
+
import { collectRegisteredNames, prepareSkillStore, validateSkillAllowedTools, } from './collectSkills.js';
|
|
3
|
+
import { SkillsCapability } from './SkillsCapability.js';
|
|
4
|
+
export async function wireAgentSkills(agent) {
|
|
5
|
+
if (!agent.skills)
|
|
6
|
+
return undefined;
|
|
7
|
+
const { store, skills } = await prepareSkillStore(agent.skills);
|
|
8
|
+
validateSkillAllowedTools(skills, collectRegisteredNames(agent));
|
|
9
|
+
const metas = await store.list();
|
|
10
|
+
const capability = new SkillsCapability(store, metas);
|
|
11
|
+
const tools = {};
|
|
12
|
+
for (const decl of capability.getTools()) {
|
|
13
|
+
tools[decl.name] = defineTool({
|
|
14
|
+
name: decl.name,
|
|
15
|
+
description: decl.description,
|
|
16
|
+
input: decl.parameters,
|
|
17
|
+
execute: async (args) => decl.execute(args),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
capability,
|
|
22
|
+
tools,
|
|
23
|
+
promptSections: capability.getPromptSections(),
|
|
24
|
+
};
|
|
25
|
+
}
|