@kuralle-agents/core 0.5.0 → 0.6.1
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 +1 -1
- package/dist/capabilities/adapters/gemini.js +2 -2
- package/dist/flow/choiceMatch.d.ts +1 -1
- package/dist/flow/nodeBuilders.d.ts +1 -1
- package/dist/flow/nodeBuilders.js +5 -3
- package/dist/index.d.ts +12 -4
- package/dist/index.js +7 -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 +8 -8
- 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/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 +18 -0
- package/dist/tools/effect/wrapAiSdkTool.js +18 -0
- package/dist/tools/fs/createFsTool.d.ts +30 -0
- package/dist/tools/fs/createFsTool.js +200 -0
- package/dist/tools/handoff.d.ts +1 -1
- package/dist/tools/http.js +1 -1
- 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/utils/chrono.d.ts +1 -9
- package/guides/AGENTS.md +2 -3
- package/guides/FLOWS.md +2 -2
- package/guides/TOOLS.md +69 -2
- package/package.json +15 -7
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ const agent = defineAgent({
|
|
|
41
41
|
instructions: 'You are a helpful support agent.',
|
|
42
42
|
model: openai('gpt-4o-mini'),
|
|
43
43
|
tools: buildToolSet({ echo }), // model-visible
|
|
44
|
-
|
|
44
|
+
tools: { echo }, // durable executor
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
const runtime = createRuntime({ agents: [agent], defaultAgentId: 'support' });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
/**
|
|
3
3
|
* Convert ToolDeclarations to Gemini FunctionDeclarations.
|
|
4
4
|
*
|
|
@@ -11,7 +11,7 @@ export function toGeminiDeclarations(tools) {
|
|
|
11
11
|
name: tool.name,
|
|
12
12
|
description: tool.description,
|
|
13
13
|
parameters: tool.parameters
|
|
14
|
-
? stripUnsupported(
|
|
14
|
+
? stripUnsupported(z.toJSONSchema(tool.parameters, { target: 'openapi-3.0' }))
|
|
15
15
|
: { type: 'object', properties: {} },
|
|
16
16
|
}));
|
|
17
17
|
}
|
|
@@ -10,7 +10,7 @@ export declare function isChoiceFieldSchema(schema: unknown): schema is z.ZodObj
|
|
|
10
10
|
choice: z.ZodString;
|
|
11
11
|
}>;
|
|
12
12
|
export declare function buildChoiceEnumSchema(choices: ChoiceOption[]): z.ZodObject<{
|
|
13
|
-
choice: z.ZodEnum<
|
|
13
|
+
choice: z.ZodEnum<Record<string, string>>;
|
|
14
14
|
}>;
|
|
15
15
|
export declare function latestUserMessageText(messages: ModelMessage[]): string | undefined;
|
|
16
16
|
export declare function matchChoiceFromInput(input: string, choices: ChoiceOption[]): string | undefined;
|
|
@@ -8,7 +8,7 @@ export declare function buildNodePrompt(node: ReplyNode, state: FlowState): stri
|
|
|
8
8
|
* agent's base instructions (persona / safety / grounding) prefix the node's
|
|
9
9
|
* own instructions. Node instructions layer ON TOP — they never replace the
|
|
10
10
|
* base. Base resolves against the current state so dynamic base prompts work. */
|
|
11
|
-
export declare function composeSystem(base: Instructions | undefined, nodeSystem: string, state: FlowState): string;
|
|
11
|
+
export declare function composeSystem(base: Instructions | undefined, nodeSystem: string, state: FlowState, skillPrompt?: string, workingMemoryPrompt?: string): string;
|
|
12
12
|
export declare function resolveReplyNode(node: ReplyNode, state: FlowState, options?: {
|
|
13
13
|
freeConversation?: boolean;
|
|
14
14
|
}): ResolvedNode;
|
|
@@ -19,9 +19,11 @@ export function buildNodePrompt(node, state) {
|
|
|
19
19
|
* agent's base instructions (persona / safety / grounding) prefix the node's
|
|
20
20
|
* own instructions. Node instructions layer ON TOP — they never replace the
|
|
21
21
|
* base. Base resolves against the current state so dynamic base prompts work. */
|
|
22
|
-
export function composeSystem(base, nodeSystem, state) {
|
|
22
|
+
export function composeSystem(base, nodeSystem, state, skillPrompt, workingMemoryPrompt) {
|
|
23
23
|
const baseText = base ? resolveInstructions(base, state) : '';
|
|
24
|
-
return [baseText, nodeSystem]
|
|
24
|
+
return [baseText, skillPrompt, workingMemoryPrompt, nodeSystem]
|
|
25
|
+
.filter((s) => s && s.trim())
|
|
26
|
+
.join('\n\n');
|
|
25
27
|
}
|
|
26
28
|
function buildNodeTools(node, state) {
|
|
27
29
|
if (!node.tools) {
|
|
@@ -39,7 +41,7 @@ export function resolveReplyNode(node, state, options) {
|
|
|
39
41
|
prompt: buildNodePrompt(node, state),
|
|
40
42
|
tools,
|
|
41
43
|
// Recover the raw executors from the node's `buildToolSet` tools so they run
|
|
42
|
-
// in-flow (with run context) — without also needing `agent.
|
|
44
|
+
// in-flow (with run context) — without also needing `agent.tools`.
|
|
43
45
|
localTools: rawToolsFromSet(tools),
|
|
44
46
|
...(options?.freeConversation && { freeConversation: true }),
|
|
45
47
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -47,8 +47,11 @@ export type { MemoryEntry, SearchMemoryRequest, SearchMemoryResponse, MemoryInge
|
|
|
47
47
|
export { InMemoryMemoryService } from './memory/index.js';
|
|
48
48
|
export { preloadMemoryContext } from './memory/index.js';
|
|
49
49
|
export { extractMemories } from './memory/index.js';
|
|
50
|
-
export type { PersistentMemoryStore, PersistentMemoryBlock, PersistentMemoryConfig, MemoryBlockScope, } from './memory/index.js';
|
|
51
|
-
export { FilePersistentMemoryStore, scanMemoryWrite, buildMemoryBlockTool, DEFAULT_BLOCK_CHAR_LIMIT, DEFAULT_AUTO_LOAD_BLOCKS, } from './memory/index.js';
|
|
50
|
+
export type { PersistentMemoryStore, PersistentMemoryBlock, PersistentMemoryConfig, MemoryBlockScope, WorkingMemoryBlockSpec, WorkingMemoryConfig, } from './memory/index.js';
|
|
51
|
+
export { FilePersistentMemoryStore, InMemoryPersistentMemoryStore, RoutedPersistentMemoryStore, TieredPersistentMemoryStore, scanMemoryWrite, buildMemoryBlockTool, DEFAULT_BLOCK_CHAR_LIMIT, DEFAULT_AUTO_LOAD_BLOCKS, } from './memory/index.js';
|
|
52
|
+
export type { RoutedPersistentMemoryStoreConfig, MemoryRouteFn, } from './memory/index.js';
|
|
53
|
+
export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection, resolveWorkingMemoryStore, } from './runtime/grounding/workingMemory.js';
|
|
54
|
+
export { resolveAgentWorkspace, type ResolvedAgentWorkspace, } from './runtime/resolveAgentWorkspace.js';
|
|
52
55
|
export { DEFAULT_CONTEXT_BUDGET, VOICE_CONTEXT_BUDGET, computeMessageHistoryBudget, truncateToTokenBudget, formatMemoryWithBudget, estimateTokenCount, ContextBudget, } from './runtime/ContextBudget.js';
|
|
53
56
|
export type { ContextBudgetConfig } from './runtime/ContextBudget.js';
|
|
54
57
|
export { TokenAccumulator } from './runtime/TokenAccumulator.js';
|
|
@@ -67,10 +70,15 @@ export type { Hooks } from './types/hooks.js';
|
|
|
67
70
|
export type { HarnessHooks } from './types/runtime.js';
|
|
68
71
|
export { defineAgent, defineFlow, reply, collect, action, decide, confirmGate, } from './authoring/index.js';
|
|
69
72
|
export { defineTool } from './types/effectTool.js';
|
|
70
|
-
export {
|
|
73
|
+
export { fsErrorCode } from './types/filesystem.js';
|
|
74
|
+
export { createFsTool } from './tools/fs/createFsTool.js';
|
|
75
|
+
export type { CreateFsToolOptions, GrepHit } from './tools/fs/createFsTool.js';
|
|
76
|
+
export { SkillsCapability, wireAgentSkills, collectRegisteredNames, validateSkillAllowedTools, prepareSkillStore, isSkillStore, InlineSkillStore, } from './skills/index.js';
|
|
77
|
+
export type { WiredAgentSkills, SkillWireAgent } from './skills/index.js';
|
|
78
|
+
export { buildToolSet, toolToAiSdk, wrapAiSdkTool, ToolApprovalDeniedError, ToolTimeoutError, } from './tools/effect/index.js';
|
|
71
79
|
export type { Tool as EffectTool } from './types/effectTool.js';
|
|
72
80
|
export type { AgentRoute } from './types/processors.js';
|
|
73
|
-
export type { AgentConfig, Instructions } from './types/agentConfig.js';
|
|
81
|
+
export type { AgentConfig, AgentWorkspaceConfig, Instructions } from './types/agentConfig.js';
|
|
74
82
|
export type { Flow, FlowNode, Transition, CollectNode, DecideNode, ConfirmGate, NodeGrounding, } from './types/flow.js';
|
|
75
83
|
export { parseConfirmation } from './flow/confirmParse.js';
|
|
76
84
|
export type { ConfirmVerdict } from './flow/confirmParse.js';
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,9 @@ export { getTemplate, registerTemplate, listTemplates, getAllTemplates } from '.
|
|
|
29
29
|
export { InMemoryMemoryService } from './memory/index.js';
|
|
30
30
|
export { preloadMemoryContext } from './memory/index.js';
|
|
31
31
|
export { extractMemories } from './memory/index.js';
|
|
32
|
-
export { FilePersistentMemoryStore, scanMemoryWrite, buildMemoryBlockTool, DEFAULT_BLOCK_CHAR_LIMIT, DEFAULT_AUTO_LOAD_BLOCKS, } from './memory/index.js';
|
|
32
|
+
export { FilePersistentMemoryStore, InMemoryPersistentMemoryStore, RoutedPersistentMemoryStore, TieredPersistentMemoryStore, scanMemoryWrite, buildMemoryBlockTool, DEFAULT_BLOCK_CHAR_LIMIT, DEFAULT_AUTO_LOAD_BLOCKS, } from './memory/index.js';
|
|
33
|
+
export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection, resolveWorkingMemoryStore, } from './runtime/grounding/workingMemory.js';
|
|
34
|
+
export { resolveAgentWorkspace, } from './runtime/resolveAgentWorkspace.js';
|
|
33
35
|
export { DEFAULT_CONTEXT_BUDGET, VOICE_CONTEXT_BUDGET, computeMessageHistoryBudget, truncateToTokenBudget, formatMemoryWithBudget, estimateTokenCount, ContextBudget, } from './runtime/ContextBudget.js';
|
|
34
36
|
export { TokenAccumulator } from './runtime/TokenAccumulator.js';
|
|
35
37
|
export { handoffFilters, removeToolHistory, keepRecentMessages, removeKeys, composeFilters, } from './runtime/handoffFilters.js';
|
|
@@ -38,7 +40,10 @@ export { CapabilityHost, TriageCapability, ExtractionCapability, HandoffCapabili
|
|
|
38
40
|
export { filterAuditEntries } from './audit/index.js';
|
|
39
41
|
export { defineAgent, defineFlow, reply, collect, action, decide, confirmGate, } from './authoring/index.js';
|
|
40
42
|
export { defineTool } from './types/effectTool.js';
|
|
41
|
-
export {
|
|
43
|
+
export { fsErrorCode } from './types/filesystem.js';
|
|
44
|
+
export { createFsTool } from './tools/fs/createFsTool.js';
|
|
45
|
+
export { SkillsCapability, wireAgentSkills, collectRegisteredNames, validateSkillAllowedTools, prepareSkillStore, isSkillStore, InlineSkillStore, } from './skills/index.js';
|
|
46
|
+
export { buildToolSet, toolToAiSdk, wrapAiSdkTool, ToolApprovalDeniedError, ToolTimeoutError, } from './tools/effect/index.js';
|
|
42
47
|
export { parseConfirmation } from './flow/confirmParse.js';
|
|
43
48
|
export { harnessToUIMessageStream } from './ai-sdk/uiMessageStream.js';
|
|
44
49
|
export { createRuntime, Runtime, } from './runtime/Runtime.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PersistentMemoryStore, PersistentMemoryBlock, MemoryBlockScope } from './types.js';
|
|
2
2
|
export interface FilePersistentMemoryStoreOptions {
|
|
3
3
|
/** Root directory. Defaults to `KURALLE_MEMORY_DIR` or `~/.kuralle/memories`. */
|
|
4
4
|
rootDir?: string;
|
|
@@ -9,6 +9,13 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Defaults to `process.env.KURALLE_MEMORY_DIR ?? <homedir>/.kuralle/memories`.
|
|
11
11
|
*
|
|
12
|
+
* Relationship to `AgentConfig.workspace` (RFC-02): this store persists long-term
|
|
13
|
+
* memory *blocks* on the local Node filesystem via `node:fs`. It is not a
|
|
14
|
+
* portable `FileSystem` backend and is not wired into the agent workspace tool.
|
|
15
|
+
* Use `@kuralle-agents/fs` (`InMemoryFs`, `KnowledgeFs`, …) for model-visible
|
|
16
|
+
* workspace exploration; keep `FilePersistentMemoryStore` for durable USER/AGENT
|
|
17
|
+
* markdown blocks when running on Node.
|
|
18
|
+
*
|
|
12
19
|
* Atomicity: writes go to a sibling `.tmp` file then `rename` over the
|
|
13
20
|
* target. `rename` is atomic on POSIX within a single filesystem;
|
|
14
21
|
* Windows is best-effort.
|
|
@@ -21,6 +28,7 @@
|
|
|
21
28
|
import { promises as fs } from 'node:fs';
|
|
22
29
|
import os from 'node:os';
|
|
23
30
|
import path from 'node:path';
|
|
31
|
+
import { registerNodeDefaultWorkingMemoryStore } from '../../runtime/grounding/defaultStoreRegistry.js';
|
|
24
32
|
export class FilePersistentMemoryStore {
|
|
25
33
|
rootDir;
|
|
26
34
|
constructor(opts = {}) {
|
|
@@ -111,3 +119,4 @@ export class FilePersistentMemoryStore {
|
|
|
111
119
|
function isNodeError(err) {
|
|
112
120
|
return typeof err === 'object' && err !== null && 'code' in err;
|
|
113
121
|
}
|
|
122
|
+
registerNodeDefaultWorkingMemoryStore(() => new FilePersistentMemoryStore());
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MemoryBlockScope, PersistentMemoryBlock, PersistentMemoryStore } from './types.js';
|
|
2
|
+
export declare class InMemoryPersistentMemoryStore implements PersistentMemoryStore {
|
|
3
|
+
private readonly blocks;
|
|
4
|
+
loadBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<PersistentMemoryBlock | null>;
|
|
5
|
+
saveBlock(block: PersistentMemoryBlock, owner: string): Promise<void>;
|
|
6
|
+
deleteBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<void>;
|
|
7
|
+
listBlocks(scope: MemoryBlockScope, owner: string): Promise<string[]>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function blockKey(scope, owner, key) {
|
|
2
|
+
return `${scope}:${owner}:${key}`;
|
|
3
|
+
}
|
|
4
|
+
export class InMemoryPersistentMemoryStore {
|
|
5
|
+
blocks = new Map();
|
|
6
|
+
async loadBlock(scope, owner, key) {
|
|
7
|
+
return this.blocks.get(blockKey(scope, owner, key)) ?? null;
|
|
8
|
+
}
|
|
9
|
+
async saveBlock(block, owner) {
|
|
10
|
+
this.blocks.set(blockKey(block.scope, owner, block.key), {
|
|
11
|
+
...block,
|
|
12
|
+
updatedAt: new Date().toISOString(),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async deleteBlock(scope, owner, key) {
|
|
16
|
+
this.blocks.delete(blockKey(scope, owner, key));
|
|
17
|
+
}
|
|
18
|
+
async listBlocks(scope, owner) {
|
|
19
|
+
const prefix = `${scope}:${owner}:`;
|
|
20
|
+
return [...this.blocks.keys()]
|
|
21
|
+
.filter((k) => k.startsWith(prefix))
|
|
22
|
+
.map((k) => k.slice(prefix.length))
|
|
23
|
+
.sort();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MemoryBlockScope, PersistentMemoryBlock, PersistentMemoryStore } from './types.js';
|
|
2
|
+
export type MemoryRouteFn = (scope: MemoryBlockScope, owner: string) => PersistentMemoryStore;
|
|
3
|
+
export interface RoutedPersistentMemoryStoreConfig {
|
|
4
|
+
routes: Partial<Record<MemoryBlockScope, PersistentMemoryStore>>;
|
|
5
|
+
default?: PersistentMemoryStore;
|
|
6
|
+
route?: MemoryRouteFn;
|
|
7
|
+
}
|
|
8
|
+
export declare class RoutedPersistentMemoryStore implements PersistentMemoryStore {
|
|
9
|
+
private readonly routes;
|
|
10
|
+
private readonly defaultStore?;
|
|
11
|
+
private readonly routeFn?;
|
|
12
|
+
constructor(config: RoutedPersistentMemoryStoreConfig);
|
|
13
|
+
private resolve;
|
|
14
|
+
loadBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<PersistentMemoryBlock | null>;
|
|
15
|
+
saveBlock(block: PersistentMemoryBlock, owner: string): Promise<void>;
|
|
16
|
+
deleteBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<void>;
|
|
17
|
+
listBlocks(scope: MemoryBlockScope, owner: string): Promise<string[]>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export class RoutedPersistentMemoryStore {
|
|
2
|
+
routes;
|
|
3
|
+
defaultStore;
|
|
4
|
+
routeFn;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.routes = config.routes;
|
|
7
|
+
this.defaultStore = config.default;
|
|
8
|
+
this.routeFn = config.route;
|
|
9
|
+
}
|
|
10
|
+
resolve(scope, owner) {
|
|
11
|
+
if (this.routeFn) {
|
|
12
|
+
return this.routeFn(scope, owner);
|
|
13
|
+
}
|
|
14
|
+
const byScope = this.routes[scope];
|
|
15
|
+
if (byScope) {
|
|
16
|
+
return byScope;
|
|
17
|
+
}
|
|
18
|
+
if (this.defaultStore) {
|
|
19
|
+
return this.defaultStore;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`No PersistentMemoryStore route for scope=${scope}`);
|
|
22
|
+
}
|
|
23
|
+
async loadBlock(scope, owner, key) {
|
|
24
|
+
return this.resolve(scope, owner).loadBlock(scope, owner, key);
|
|
25
|
+
}
|
|
26
|
+
async saveBlock(block, owner) {
|
|
27
|
+
await this.resolve(block.scope, owner).saveBlock(block, owner);
|
|
28
|
+
}
|
|
29
|
+
async deleteBlock(scope, owner, key) {
|
|
30
|
+
await this.resolve(scope, owner).deleteBlock(scope, owner, key);
|
|
31
|
+
}
|
|
32
|
+
async listBlocks(scope, owner) {
|
|
33
|
+
return this.resolve(scope, owner).listBlocks(scope, owner);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MemoryBlockScope, PersistentMemoryBlock, PersistentMemoryStore } from './types.js';
|
|
2
|
+
export declare class TieredPersistentMemoryStore implements PersistentMemoryStore {
|
|
3
|
+
private readonly cache;
|
|
4
|
+
private readonly durable;
|
|
5
|
+
constructor(cache: PersistentMemoryStore, durable: PersistentMemoryStore);
|
|
6
|
+
loadBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<PersistentMemoryBlock | null>;
|
|
7
|
+
saveBlock(block: PersistentMemoryBlock, owner: string): Promise<void>;
|
|
8
|
+
deleteBlock(scope: MemoryBlockScope, owner: string, key: string): Promise<void>;
|
|
9
|
+
listBlocks(scope: MemoryBlockScope, owner: string): Promise<string[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class TieredPersistentMemoryStore {
|
|
2
|
+
cache;
|
|
3
|
+
durable;
|
|
4
|
+
constructor(cache, durable) {
|
|
5
|
+
this.cache = cache;
|
|
6
|
+
this.durable = durable;
|
|
7
|
+
}
|
|
8
|
+
async loadBlock(scope, owner, key) {
|
|
9
|
+
const cached = await this.cache.loadBlock(scope, owner, key);
|
|
10
|
+
if (cached) {
|
|
11
|
+
return cached;
|
|
12
|
+
}
|
|
13
|
+
const fromDurable = await this.durable.loadBlock(scope, owner, key);
|
|
14
|
+
if (fromDurable) {
|
|
15
|
+
await this.cache.saveBlock(fromDurable, owner);
|
|
16
|
+
}
|
|
17
|
+
return fromDurable;
|
|
18
|
+
}
|
|
19
|
+
async saveBlock(block, owner) {
|
|
20
|
+
await this.durable.saveBlock(block, owner);
|
|
21
|
+
await this.cache.saveBlock(block, owner);
|
|
22
|
+
}
|
|
23
|
+
async deleteBlock(scope, owner, key) {
|
|
24
|
+
await this.durable.deleteBlock(scope, owner, key);
|
|
25
|
+
await this.cache.deleteBlock(scope, owner, key);
|
|
26
|
+
}
|
|
27
|
+
async listBlocks(scope, owner) {
|
|
28
|
+
return this.durable.listBlocks(scope, owner);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -9,11 +9,11 @@ export interface MemoryBlockToolOptions {
|
|
|
9
9
|
scanForInjection?: boolean;
|
|
10
10
|
}
|
|
11
11
|
export declare function buildMemoryBlockTool(opts: MemoryBlockToolOptions): import("ai").Tool<{
|
|
12
|
-
block: string;
|
|
13
12
|
action: "replace" | "view" | "add" | "remove";
|
|
14
|
-
|
|
15
|
-
content?: string | undefined;
|
|
13
|
+
block: string;
|
|
16
14
|
scope?: "user" | "agent" | "shared" | undefined;
|
|
15
|
+
content?: string | undefined;
|
|
16
|
+
match?: string | undefined;
|
|
17
17
|
}, {
|
|
18
18
|
block: string;
|
|
19
19
|
scope: MemoryBlockScope;
|
|
@@ -21,7 +21,7 @@ export declare function buildMemoryBlockTool(opts: MemoryBlockToolOptions): impo
|
|
|
21
21
|
empty: boolean;
|
|
22
22
|
updatedAt?: undefined;
|
|
23
23
|
chars?: undefined;
|
|
24
|
-
|
|
24
|
+
error?: undefined;
|
|
25
25
|
message?: undefined;
|
|
26
26
|
ok?: undefined;
|
|
27
27
|
removed?: undefined;
|
|
@@ -38,7 +38,7 @@ export declare function buildMemoryBlockTool(opts: MemoryBlockToolOptions): impo
|
|
|
38
38
|
updatedAt: string | undefined;
|
|
39
39
|
chars: number;
|
|
40
40
|
empty?: undefined;
|
|
41
|
-
|
|
41
|
+
error?: undefined;
|
|
42
42
|
message?: undefined;
|
|
43
43
|
ok?: undefined;
|
|
44
44
|
removed?: undefined;
|
|
@@ -75,7 +75,7 @@ export declare function buildMemoryBlockTool(opts: MemoryBlockToolOptions): impo
|
|
|
75
75
|
empty?: undefined;
|
|
76
76
|
updatedAt?: undefined;
|
|
77
77
|
chars?: undefined;
|
|
78
|
-
|
|
78
|
+
error?: undefined;
|
|
79
79
|
message?: undefined;
|
|
80
80
|
remainingChars?: undefined;
|
|
81
81
|
pattern?: undefined;
|
|
@@ -92,7 +92,7 @@ export declare function buildMemoryBlockTool(opts: MemoryBlockToolOptions): impo
|
|
|
92
92
|
empty?: undefined;
|
|
93
93
|
updatedAt?: undefined;
|
|
94
94
|
chars?: undefined;
|
|
95
|
-
|
|
95
|
+
error?: undefined;
|
|
96
96
|
message?: undefined;
|
|
97
97
|
note?: undefined;
|
|
98
98
|
pattern?: undefined;
|
|
@@ -143,7 +143,7 @@ export declare function buildMemoryBlockTool(opts: MemoryBlockToolOptions): impo
|
|
|
143
143
|
content?: undefined;
|
|
144
144
|
empty?: undefined;
|
|
145
145
|
updatedAt?: undefined;
|
|
146
|
-
|
|
146
|
+
error?: undefined;
|
|
147
147
|
message?: undefined;
|
|
148
148
|
removed?: undefined;
|
|
149
149
|
note?: undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PersistentMemoryStore } from './types.js';
|
|
2
|
+
export type PersistentMemoryStoreFactory = () => PersistentMemoryStore | Promise<PersistentMemoryStore>;
|
|
3
|
+
export type PersistentMemoryDurabilityFactory = () => {
|
|
4
|
+
storeA: PersistentMemoryStore;
|
|
5
|
+
storeB: PersistentMemoryStore;
|
|
6
|
+
} | Promise<{
|
|
7
|
+
storeA: PersistentMemoryStore;
|
|
8
|
+
storeB: PersistentMemoryStore;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function runPersistentMemoryStoreContract(factory: PersistentMemoryStoreFactory): void;
|
|
11
|
+
export declare function runPersistentMemoryDurabilityContract(factory: PersistentMemoryDurabilityFactory): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/// <reference types="bun-types" />
|
|
2
|
+
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
3
|
+
const sampleBlock = (overrides = {}) => ({
|
|
4
|
+
key: 'USER',
|
|
5
|
+
scope: 'user',
|
|
6
|
+
content: 'name: Maya\nprefers: vegetarian',
|
|
7
|
+
charLimit: 1000,
|
|
8
|
+
...overrides,
|
|
9
|
+
});
|
|
10
|
+
export function runPersistentMemoryStoreContract(factory) {
|
|
11
|
+
describe('PersistentMemoryStore contract', () => {
|
|
12
|
+
let store;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
store = await factory();
|
|
15
|
+
});
|
|
16
|
+
test('loadBlock returns null for missing block', async () => {
|
|
17
|
+
expect(await store.loadBlock('user', 'alice', 'USER')).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
test('saveBlock + loadBlock round-trips', async () => {
|
|
20
|
+
const block = sampleBlock();
|
|
21
|
+
await store.saveBlock(block, 'maya@example.com');
|
|
22
|
+
const loaded = await store.loadBlock('user', 'maya@example.com', 'USER');
|
|
23
|
+
expect(loaded).not.toBeNull();
|
|
24
|
+
expect(loaded.content).toBe(block.content);
|
|
25
|
+
expect(loaded.scope).toBe('user');
|
|
26
|
+
expect(loaded.key).toBe('USER');
|
|
27
|
+
expect(typeof loaded.updatedAt).toBe('string');
|
|
28
|
+
});
|
|
29
|
+
test('listBlocks returns keys within scope+owner', async () => {
|
|
30
|
+
await store.saveBlock(sampleBlock({ key: 'USER' }), 'bob');
|
|
31
|
+
await store.saveBlock(sampleBlock({ key: 'preferences', content: 'dark mode' }), 'bob');
|
|
32
|
+
await store.saveBlock(sampleBlock({ key: 'MEMORY', scope: 'agent', content: 'notes' }), 'bob');
|
|
33
|
+
expect((await store.listBlocks('user', 'bob')).sort()).toEqual([
|
|
34
|
+
'USER',
|
|
35
|
+
'preferences',
|
|
36
|
+
]);
|
|
37
|
+
expect(await store.listBlocks('agent', 'bob')).toEqual(['MEMORY']);
|
|
38
|
+
});
|
|
39
|
+
test('listBlocks returns empty array when none exist', async () => {
|
|
40
|
+
expect(await store.listBlocks('user', 'never-existed')).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
test('deleteBlock removes block; no-op when missing', async () => {
|
|
43
|
+
await store.saveBlock(sampleBlock({ key: 'ephemeral' }), 'dave');
|
|
44
|
+
await store.deleteBlock('user', 'dave', 'ephemeral');
|
|
45
|
+
expect(await store.loadBlock('user', 'dave', 'ephemeral')).toBeNull();
|
|
46
|
+
await store.deleteBlock('user', 'dave', 'ephemeral');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function runPersistentMemoryDurabilityContract(factory) {
|
|
51
|
+
describe('PersistentMemoryStore durability', () => {
|
|
52
|
+
test('store B reads block written by store A', async () => {
|
|
53
|
+
const { storeA, storeB } = await factory();
|
|
54
|
+
await storeA.saveBlock(sampleBlock({ content: 'durable payload' }), 'owner-1');
|
|
55
|
+
const loaded = await storeB.loadBlock('user', 'owner-1', 'USER');
|
|
56
|
+
expect(loaded?.content).toBe('durable payload');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
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
|