@kuralle-agents/core 0.7.0 → 0.7.2
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/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/runtime/Runtime.js +26 -56
- package/dist/runtime/buildAgentToolSurface.d.ts +20 -0
- package/dist/runtime/buildAgentToolSurface.js +56 -0
- package/dist/runtime/channels/TextDriver.js +9 -2
- package/dist/runtime/channels/VoiceDriver.js +5 -1
- package/dist/runtime/channels/extractionTurn.js +4 -1
- package/dist/runtime/grounding/index.d.ts +1 -1
- package/dist/runtime/grounding/index.js +1 -1
- package/dist/runtime/grounding/knowledge.d.ts +2 -0
- package/dist/runtime/grounding/knowledge.js +37 -0
- package/dist/runtime/promptCache.d.ts +17 -1
- package/dist/runtime/promptCache.js +24 -0
- package/dist/types/grounding.d.ts +9 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,8 @@ export { resolveAgentWorkspace, type ResolvedAgentWorkspace, } from './runtime/r
|
|
|
55
55
|
export { DEFAULT_CONTEXT_BUDGET, VOICE_CONTEXT_BUDGET, computeMessageHistoryBudget, truncateToTokenBudget, formatMemoryWithBudget, estimateTokenCount, ContextBudget, } from './runtime/ContextBudget.js';
|
|
56
56
|
export type { ContextBudgetConfig } from './runtime/ContextBudget.js';
|
|
57
57
|
export { TokenAccumulator } from './runtime/TokenAccumulator.js';
|
|
58
|
+
export { applyPromptCache, applyAnthropicCacheControl, buildOpenAIResponsesProviderOptions, isAnthropicLanguageModel, isOpenAIResponsesModel, } from './runtime/promptCache.js';
|
|
59
|
+
export type { AnthropicCacheTtl, OpenAIResponsesCompactOptions } from './runtime/promptCache.js';
|
|
58
60
|
export { handoffFilters, removeToolHistory, keepRecentMessages, removeKeys, composeFilters, } from './runtime/handoffFilters.js';
|
|
59
61
|
export type { HandoffInputFilter, HandoffInputData, HandoffInputResult, } from './runtime/handoffFilters.js';
|
|
60
62
|
export { DefaultToolExecutor, DefaultConversationState, DefaultConversationEventLog, DefaultAgentStateController, createFoundation, } from './foundation/index.js';
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection,
|
|
|
34
34
|
export { resolveAgentWorkspace, } from './runtime/resolveAgentWorkspace.js';
|
|
35
35
|
export { DEFAULT_CONTEXT_BUDGET, VOICE_CONTEXT_BUDGET, computeMessageHistoryBudget, truncateToTokenBudget, formatMemoryWithBudget, estimateTokenCount, ContextBudget, } from './runtime/ContextBudget.js';
|
|
36
36
|
export { TokenAccumulator } from './runtime/TokenAccumulator.js';
|
|
37
|
+
export { applyPromptCache, applyAnthropicCacheControl, buildOpenAIResponsesProviderOptions, isAnthropicLanguageModel, isOpenAIResponsesModel, } from './runtime/promptCache.js';
|
|
37
38
|
export { handoffFilters, removeToolHistory, keepRecentMessages, removeKeys, composeFilters, } from './runtime/handoffFilters.js';
|
|
38
39
|
export { DefaultToolExecutor, DefaultConversationState, DefaultConversationEventLog, DefaultAgentStateController, createFoundation, } from './foundation/index.js';
|
|
39
40
|
export { CapabilityHost, ExtractionCapability, GuardrailCapability, AutoRetrieveCapability, PassThroughRefinement, PassThroughValidation, toGeminiDeclarations, toAISDKTools, } from './capabilities/index.js';
|
package/dist/runtime/Runtime.js
CHANGED
|
@@ -5,8 +5,7 @@ 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 {
|
|
9
|
-
import { wireAgentSkills } from '../skills/wireAgentSkills.js';
|
|
8
|
+
import { buildAgentToolSurface } from './buildAgentToolSurface.js';
|
|
10
9
|
import { hostLoop } from './hostLoop.js';
|
|
11
10
|
import { isDegradableRuntimeError } from '../flow/degradableErrors.js';
|
|
12
11
|
import { SAFE_DEGRADED_MESSAGE } from '../flow/degrade.js';
|
|
@@ -17,8 +16,7 @@ import { SessionRunStore } from './durable/SessionRunStore.js';
|
|
|
17
16
|
import { loadRecordedSteps } from './durable/replay.js';
|
|
18
17
|
import { markSessionOutcome } from './outcomeMarking.js';
|
|
19
18
|
import { resolveAgentPolicies } from './policies/resolvePolicies.js';
|
|
20
|
-
import { buildAutoRetrieveProvider, buildKnowledgeProvider, buildMemoryService, runMemoryIngest,
|
|
21
|
-
import { resolveAgentWorkspace } from './resolveAgentWorkspace.js';
|
|
19
|
+
import { buildAutoRetrieveProvider, buildKnowledgeProvider, buildMemoryService, runMemoryIngest, } from './grounding/index.js';
|
|
22
20
|
import { SessionMutex } from './SessionMutex.js';
|
|
23
21
|
export class Runtime {
|
|
24
22
|
config;
|
|
@@ -66,38 +64,16 @@ export class Runtime {
|
|
|
66
64
|
sessionStore: this.sessionStore,
|
|
67
65
|
});
|
|
68
66
|
const policies = resolveAgentPolicies(opened.agent);
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
};
|
|
77
|
-
const resolvedWorkspace = resolveAgentWorkspace(opened.agent.workspace);
|
|
78
|
-
if (resolvedWorkspace) {
|
|
79
|
-
agentTools.workspace = createFsTool({
|
|
80
|
-
fs: resolvedWorkspace.fs,
|
|
81
|
-
readOnly: resolvedWorkspace.readOnly,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
const wiredWorkingMemory = await wireWorkingMemory(opened.agent, opened.session, this.config.defaultWorkingMemoryStore);
|
|
85
|
-
if (wiredWorkingMemory) {
|
|
86
|
-
agentTools.memory_block = wiredWorkingMemory.memoryBlockTool;
|
|
87
|
-
}
|
|
88
|
-
let skillPrompt;
|
|
89
|
-
let skillTools = {};
|
|
90
|
-
if (opened.agent.skills) {
|
|
91
|
-
const wired = await wireAgentSkills(opened.agent);
|
|
92
|
-
if (wired) {
|
|
93
|
-
skillTools = wired.tools;
|
|
94
|
-
Object.assign(agentTools, wired.tools);
|
|
95
|
-
skillPrompt = wired.promptSections.map((s) => s.content).join('\n\n');
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
const workspaceTool = agentTools.workspace;
|
|
67
|
+
const knowledgeProvider = this.config.knowledge
|
|
68
|
+
? buildKnowledgeProvider(this.config.knowledge)
|
|
69
|
+
: undefined;
|
|
70
|
+
const openingSurface = await buildAgentToolSurface(opened.agent, opened.session, {
|
|
71
|
+
configTools: this.config.tools,
|
|
72
|
+
knowledgeProvider,
|
|
73
|
+
defaultWorkingMemoryStore: this.config.defaultWorkingMemoryStore,
|
|
74
|
+
});
|
|
99
75
|
const toolExecutor = new CoreToolExecutor({
|
|
100
|
-
tools:
|
|
76
|
+
tools: openingSurface.executorTools,
|
|
101
77
|
enforcer: policies.enforcer,
|
|
102
78
|
agentId: opened.agent.id,
|
|
103
79
|
onInterim: (message) => {
|
|
@@ -113,9 +89,6 @@ export class Runtime {
|
|
|
113
89
|
if (!model) {
|
|
114
90
|
throw new Error('Runtime requires agent.model or config.defaultModel');
|
|
115
91
|
}
|
|
116
|
-
const knowledgeProvider = this.config.knowledge
|
|
117
|
-
? buildKnowledgeProvider(this.config.knowledge)
|
|
118
|
-
: undefined;
|
|
119
92
|
runCtx = await createRunContext({
|
|
120
93
|
session: opened.session,
|
|
121
94
|
runState: freshRunState,
|
|
@@ -137,23 +110,15 @@ export class Runtime {
|
|
|
137
110
|
memoryService: this.config.memoryService
|
|
138
111
|
? buildMemoryService(this.config.memoryService, opened.agent)
|
|
139
112
|
: undefined,
|
|
140
|
-
fs: resolvedWorkspace?.fs,
|
|
113
|
+
fs: openingSurface.resolvedWorkspace?.fs,
|
|
141
114
|
});
|
|
142
115
|
// Agent base layer (ADR 0001): composed into every node turn by the drivers.
|
|
143
116
|
runCtx.baseInstructions = opened.agent.instructions;
|
|
144
|
-
runCtx.globalTools =
|
|
145
|
-
...(opened.agent.globalTools ?? {}),
|
|
146
|
-
...(workspaceTool && resolvedWorkspace?.readOnly !== false
|
|
147
|
-
? { workspace: workspaceTool }
|
|
148
|
-
: {}),
|
|
149
|
-
...skillTools,
|
|
150
|
-
};
|
|
117
|
+
runCtx.globalTools = openingSurface.globalTools;
|
|
151
118
|
runCtx.outOfBandControl = opened.agent.experimental?.outOfBandControl ?? false;
|
|
152
|
-
runCtx.skillPrompt = skillPrompt;
|
|
153
|
-
runCtx.workingMemoryPrompt =
|
|
154
|
-
runCtx.workingMemoryTools =
|
|
155
|
-
? { memory_block: wiredWorkingMemory.memoryBlockTool }
|
|
156
|
-
: undefined;
|
|
119
|
+
runCtx.skillPrompt = openingSurface.skillPrompt;
|
|
120
|
+
runCtx.workingMemoryPrompt = openingSurface.workingMemoryPrompt;
|
|
121
|
+
runCtx.workingMemoryTools = openingSurface.workingMemoryTools;
|
|
157
122
|
await this.hooks?.onStart?.(runCtx);
|
|
158
123
|
const driver = opts.driver ?? new TextDriver();
|
|
159
124
|
let activeAgent = opened.agent;
|
|
@@ -193,17 +158,22 @@ export class Runtime {
|
|
|
193
158
|
});
|
|
194
159
|
runCtx.runState.activeAgentId = loopResult.to;
|
|
195
160
|
activeAgent = target;
|
|
161
|
+
const targetSurface = await buildAgentToolSurface(target, opened.session, {
|
|
162
|
+
configTools: this.config.tools,
|
|
163
|
+
knowledgeProvider,
|
|
164
|
+
defaultWorkingMemoryStore: this.config.defaultWorkingMemoryStore,
|
|
165
|
+
});
|
|
196
166
|
runCtx.autoRetrieve = knowledgeProvider
|
|
197
167
|
? buildAutoRetrieveProvider(knowledgeProvider, target)
|
|
198
168
|
: undefined;
|
|
169
|
+
runCtx.globalTools = targetSurface.globalTools;
|
|
170
|
+
runCtx.skillPrompt = targetSurface.skillPrompt;
|
|
171
|
+
runCtx.workingMemoryPrompt = targetSurface.workingMemoryPrompt;
|
|
172
|
+
runCtx.workingMemoryTools = targetSurface.workingMemoryTools;
|
|
173
|
+
runCtx.fs = targetSurface.resolvedWorkspace?.fs;
|
|
199
174
|
runCtx.memoryService = this.config.memoryService
|
|
200
175
|
? buildMemoryService(this.config.memoryService, target)
|
|
201
176
|
: undefined;
|
|
202
|
-
const targetWorkingMemory = await wireWorkingMemory(target, opened.session, this.config.defaultWorkingMemoryStore);
|
|
203
|
-
runCtx.workingMemoryPrompt = targetWorkingMemory?.promptSection;
|
|
204
|
-
runCtx.workingMemoryTools = targetWorkingMemory
|
|
205
|
-
? { memory_block: targetWorkingMemory.memoryBlockTool }
|
|
206
|
-
: undefined;
|
|
207
177
|
await runCtx.runStore.putRunState(runCtx.runState);
|
|
208
178
|
continue;
|
|
209
179
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentConfig } from '../types/agentConfig.js';
|
|
2
|
+
import type { Session } from '../types/session.js';
|
|
3
|
+
import type { AnyTool } from '../types/effectTool.js';
|
|
4
|
+
import type { PersistentMemoryStore } from '../memory/blocks/types.js';
|
|
5
|
+
import type { KnowledgeProvider } from './KnowledgeProvider.js';
|
|
6
|
+
import { type ResolvedAgentWorkspace } from './resolveAgentWorkspace.js';
|
|
7
|
+
export interface AgentToolSurface {
|
|
8
|
+
executorTools: Record<string, AnyTool>;
|
|
9
|
+
globalTools: Record<string, AnyTool>;
|
|
10
|
+
workingMemoryTools?: Record<string, AnyTool>;
|
|
11
|
+
workingMemoryPrompt?: string;
|
|
12
|
+
skillPrompt?: string;
|
|
13
|
+
resolvedWorkspace?: ResolvedAgentWorkspace;
|
|
14
|
+
}
|
|
15
|
+
export interface BuildAgentToolSurfaceDeps {
|
|
16
|
+
configTools?: Record<string, AnyTool>;
|
|
17
|
+
knowledgeProvider?: KnowledgeProvider;
|
|
18
|
+
defaultWorkingMemoryStore?: PersistentMemoryStore;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildAgentToolSurface(agent: AgentConfig, session: Session, deps: BuildAgentToolSurfaceDeps): Promise<AgentToolSurface>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createFsTool } from '../tools/fs/createFsTool.js';
|
|
2
|
+
import { wireAgentSkills } from '../skills/wireAgentSkills.js';
|
|
3
|
+
import { buildKnowledgeTool, wireWorkingMemory } from './grounding/index.js';
|
|
4
|
+
import { resolveAgentWorkspace, } from './resolveAgentWorkspace.js';
|
|
5
|
+
export async function buildAgentToolSurface(agent, session, deps) {
|
|
6
|
+
const executorTools = {
|
|
7
|
+
...(deps.configTools ?? {}),
|
|
8
|
+
...(agent.tools ?? {}),
|
|
9
|
+
...(agent.globalTools ?? {}),
|
|
10
|
+
};
|
|
11
|
+
const resolvedWorkspace = resolveAgentWorkspace(agent.workspace);
|
|
12
|
+
let workspaceTool;
|
|
13
|
+
if (resolvedWorkspace) {
|
|
14
|
+
workspaceTool = createFsTool({
|
|
15
|
+
fs: resolvedWorkspace.fs,
|
|
16
|
+
readOnly: resolvedWorkspace.readOnly,
|
|
17
|
+
});
|
|
18
|
+
executorTools.workspace = workspaceTool;
|
|
19
|
+
}
|
|
20
|
+
const wiredWorkingMemory = await wireWorkingMemory(agent, session, deps.defaultWorkingMemoryStore);
|
|
21
|
+
if (wiredWorkingMemory) {
|
|
22
|
+
executorTools.memory_block = wiredWorkingMemory.memoryBlockTool;
|
|
23
|
+
}
|
|
24
|
+
let skillPrompt;
|
|
25
|
+
let skillTools = {};
|
|
26
|
+
if (agent.skills) {
|
|
27
|
+
const wired = await wireAgentSkills(agent);
|
|
28
|
+
if (wired) {
|
|
29
|
+
skillTools = wired.tools;
|
|
30
|
+
Object.assign(executorTools, wired.tools);
|
|
31
|
+
skillPrompt = wired.promptSections.map((s) => s.content).join('\n\n');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const knowledgeTool = deps.knowledgeProvider
|
|
35
|
+
? buildKnowledgeTool(deps.knowledgeProvider, agent)
|
|
36
|
+
: undefined;
|
|
37
|
+
if (knowledgeTool) {
|
|
38
|
+
executorTools.knowledge_search = knowledgeTool;
|
|
39
|
+
}
|
|
40
|
+
const globalTools = {
|
|
41
|
+
...(agent.globalTools ?? {}),
|
|
42
|
+
...(workspaceTool && resolvedWorkspace?.readOnly !== false ? { workspace: workspaceTool } : {}),
|
|
43
|
+
...skillTools,
|
|
44
|
+
...(knowledgeTool ? { knowledge_search: knowledgeTool } : {}),
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
executorTools,
|
|
48
|
+
globalTools,
|
|
49
|
+
workingMemoryPrompt: wiredWorkingMemory?.promptSection,
|
|
50
|
+
workingMemoryTools: wiredWorkingMemory
|
|
51
|
+
? { memory_block: wiredWorkingMemory.memoryBlockTool }
|
|
52
|
+
: undefined,
|
|
53
|
+
skillPrompt,
|
|
54
|
+
resolvedWorkspace,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -9,6 +9,7 @@ import { resolveMaxSteps } from '../policies/limits.js';
|
|
|
9
9
|
import { speakWithHostControl } from './streaming/hostControlSpeak.js';
|
|
10
10
|
import { resolveStreamMode } from './streaming/mode.js';
|
|
11
11
|
import { appendGatherBlocks, resolveNodeGatherScope, runGatherPhase } from '../grounding/index.js';
|
|
12
|
+
import { applyPromptCache } from '../promptCache.js';
|
|
12
13
|
import { isFlowTransitionControlTool } from '../../flow/flowControlTools.js';
|
|
13
14
|
import { resolveStructuredDecide } from '../../flow/choiceMatch.js';
|
|
14
15
|
export class TextDriver {
|
|
@@ -50,12 +51,14 @@ export class TextDriver {
|
|
|
50
51
|
const source = {
|
|
51
52
|
async *[Symbol.asyncIterator]() {
|
|
52
53
|
for (let step = 0; step < maxSteps; step += 1) {
|
|
54
|
+
const cached = applyPromptCache(model, ctx.session.id, messages);
|
|
53
55
|
const result = streamText({
|
|
54
56
|
model,
|
|
55
57
|
system,
|
|
56
|
-
messages,
|
|
58
|
+
messages: cached.messages,
|
|
57
59
|
tools: aiTools,
|
|
58
60
|
abortSignal: ctx.abortSignal,
|
|
61
|
+
...(cached.providerOptions ? { providerOptions: cached.providerOptions } : {}),
|
|
59
62
|
});
|
|
60
63
|
for await (const part of result.fullStream) {
|
|
61
64
|
if (part.type === 'text-delta') {
|
|
@@ -82,7 +85,11 @@ export class TextDriver {
|
|
|
82
85
|
args: call.input,
|
|
83
86
|
toolCallId: call.toolCallId,
|
|
84
87
|
});
|
|
85
|
-
const { result: toolResult, control, failed } = await executeModelToolCall(ctx, { toolName: call.toolName, input: call.input, toolCallId: call.toolCallId },
|
|
88
|
+
const { result: toolResult, control, failed } = await executeModelToolCall(ctx, { toolName: call.toolName, input: call.input, toolCallId: call.toolCallId }, {
|
|
89
|
+
...ctx.globalTools,
|
|
90
|
+
...(ctx.workingMemoryTools ?? {}),
|
|
91
|
+
...node.localTools,
|
|
92
|
+
});
|
|
86
93
|
out.toolResults.push({
|
|
87
94
|
name: call.toolName,
|
|
88
95
|
args: call.input,
|
|
@@ -202,7 +202,11 @@ export class VoiceDriver {
|
|
|
202
202
|
const onToolCall = (id, name, args) => {
|
|
203
203
|
void (async () => {
|
|
204
204
|
ctx.emit({ type: 'tool-call', toolName: name, args, toolCallId: id });
|
|
205
|
-
const { result: toolResult, control, failed } = await executeModelToolCall(ctx, { toolName: name, input: args, toolCallId: id },
|
|
205
|
+
const { result: toolResult, control, failed } = await executeModelToolCall(ctx, { toolName: name, input: args, toolCallId: id }, {
|
|
206
|
+
...ctx.globalTools,
|
|
207
|
+
...(ctx.workingMemoryTools ?? {}),
|
|
208
|
+
...localTools,
|
|
209
|
+
});
|
|
206
210
|
out.toolResults.push({ name, args, result: toolResult, toolCallId: id });
|
|
207
211
|
toolCallsMade.push({
|
|
208
212
|
toolCallId: id,
|
|
@@ -2,6 +2,7 @@ import { streamText } from 'ai';
|
|
|
2
2
|
import { executeModelToolCall, toolResultMessage } from './executeModelTool.js';
|
|
3
3
|
import { buildToolSet } from '../../tools/effect/index.js';
|
|
4
4
|
import { buildNodePrompt, composeSystem } from '../../flow/nodeBuilders.js';
|
|
5
|
+
import { applyPromptCache } from '../promptCache.js';
|
|
5
6
|
/**
|
|
6
7
|
* Shared, NON-SPEAKING field extraction for `collect` nodes, used by every
|
|
7
8
|
* ChannelDriver so text and voice behave identically. It runs the model with the
|
|
@@ -20,13 +21,15 @@ export async function runSilentExtraction(node, ctx, model, maxSteps) {
|
|
|
20
21
|
const aiTools = resolveExtractionTools(node);
|
|
21
22
|
const out = { text: '', toolResults: [] };
|
|
22
23
|
for (let step = 0; step < maxSteps; step += 1) {
|
|
24
|
+
const cached = applyPromptCache(model, ctx.session.id, messages);
|
|
23
25
|
const result = streamText({
|
|
24
26
|
model,
|
|
25
27
|
system,
|
|
26
|
-
messages,
|
|
28
|
+
messages: cached.messages,
|
|
27
29
|
tools: aiTools,
|
|
28
30
|
temperature: 0,
|
|
29
31
|
abortSignal: ctx.abortSignal,
|
|
32
|
+
...(cached.providerOptions ? { providerOptions: cached.providerOptions } : {}),
|
|
30
33
|
});
|
|
31
34
|
for await (const part of result.fullStream) {
|
|
32
35
|
// Intentionally NOT handling 'text-delta' — extraction never speaks.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { appendGatherBlocks, buildAutoRetrieveProvider, buildKnowledgeProvider, } from './knowledge.js';
|
|
1
|
+
export { appendGatherBlocks, buildAutoRetrieveProvider, buildKnowledgeProvider, buildKnowledgeTool, } from './knowledge.js';
|
|
2
2
|
export { buildMemoryService, resetMissingUserIdWarningsForTests, runMemoryIngest, warnMissingUserId, } from './memory.js';
|
|
3
3
|
export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection, resolveWorkingMemoryStore, resolveWorkingMemoryOwner, type LoadedWorkingMemoryBlock, type WiredWorkingMemory, } from './workingMemory.js';
|
|
4
4
|
export { runGatherPhase, type GatherResult, type GatherScope } from './gather.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { appendGatherBlocks, buildAutoRetrieveProvider, buildKnowledgeProvider, } from './knowledge.js';
|
|
1
|
+
export { appendGatherBlocks, buildAutoRetrieveProvider, buildKnowledgeProvider, buildKnowledgeTool, } from './knowledge.js';
|
|
2
2
|
export { buildMemoryService, resetMissingUserIdWarningsForTests, runMemoryIngest, warnMissingUserId, } from './memory.js';
|
|
3
3
|
export { wireWorkingMemory, loadWorkingMemoryBlocks, formatWorkingMemorySection, resolveWorkingMemoryStore, resolveWorkingMemoryOwner, } from './workingMemory.js';
|
|
4
4
|
export { runGatherPhase } from './gather.js';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { AgentConfig } from '../../types/agentConfig.js';
|
|
2
2
|
import type { AutoRetrieveProvider } from '../../types/run-context.js';
|
|
3
|
+
import type { AnyTool } from '../../types/effectTool.js';
|
|
3
4
|
import type { KnowledgeProviderConfig } from '../../types/voice.js';
|
|
4
5
|
import { KnowledgeProvider } from '../KnowledgeProvider.js';
|
|
5
6
|
export declare function buildKnowledgeProvider(config: KnowledgeProviderConfig): KnowledgeProvider;
|
|
6
7
|
export declare function buildAutoRetrieveProvider(provider: KnowledgeProvider, agent: AgentConfig): AutoRetrieveProvider | undefined;
|
|
8
|
+
export declare function buildKnowledgeTool(provider: KnowledgeProvider, agent: AgentConfig): AnyTool | undefined;
|
|
7
9
|
export declare function appendGatherBlocks(system: string, blocks: Array<string | undefined>): string;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineTool } from '../../tools/effect/defineTool.js';
|
|
1
3
|
import { normalizeCitations } from '../citations/index.js';
|
|
2
4
|
import { KnowledgeProvider } from '../KnowledgeProvider.js';
|
|
3
5
|
function latestUserMessage(ctx) {
|
|
@@ -61,6 +63,41 @@ export function buildAutoRetrieveProvider(provider, agent) {
|
|
|
61
63
|
},
|
|
62
64
|
};
|
|
63
65
|
}
|
|
66
|
+
export function buildKnowledgeTool(provider, agent) {
|
|
67
|
+
if (!agent.knowledge || agent.knowledge.autoRetrieve !== false) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
if (!provider.hasRetriever && !provider.hasCompiled) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const overrides = agent.knowledge;
|
|
74
|
+
return defineTool({
|
|
75
|
+
name: 'knowledge_search',
|
|
76
|
+
description: 'Search the knowledge base for facts needed to answer the user. Call this whenever you need grounded information before answering. Returns relevant document snippets.',
|
|
77
|
+
input: z.object({
|
|
78
|
+
query: z
|
|
79
|
+
.string()
|
|
80
|
+
.trim()
|
|
81
|
+
.min(1, 'Query must not be empty.')
|
|
82
|
+
.describe("What to look up, in the user's language."),
|
|
83
|
+
}),
|
|
84
|
+
execute: async ({ query }, ctx) => {
|
|
85
|
+
const { results, events } = await provider.retrieve(query, undefined, overrides, false);
|
|
86
|
+
if (ctx?.emit) {
|
|
87
|
+
for (const event of events) {
|
|
88
|
+
ctx.emit(event);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const compiled = provider.getCompiledKnowledge(overrides);
|
|
92
|
+
return {
|
|
93
|
+
documents: [
|
|
94
|
+
...(compiled ? [compiled] : []),
|
|
95
|
+
...results.map((result) => result.text),
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
64
101
|
export function appendGatherBlocks(system, blocks) {
|
|
65
102
|
const extras = blocks.filter((block) => Boolean(block?.trim()));
|
|
66
103
|
if (extras.length === 0) {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* but extends caching across short user idle periods + cross-session
|
|
24
24
|
* within an hour.
|
|
25
25
|
*/
|
|
26
|
-
import type { ModelMessage } from 'ai';
|
|
26
|
+
import type { JSONValue, ModelMessage } from 'ai';
|
|
27
27
|
export type AnthropicCacheTtl = '5m' | '1h';
|
|
28
28
|
/**
|
|
29
29
|
* Returns a SHALLOW-COPIED message list with cache_control markers
|
|
@@ -90,3 +90,19 @@ export interface OpenAIResponsesCompactOptions {
|
|
|
90
90
|
* branch but ignored otherwise.
|
|
91
91
|
*/
|
|
92
92
|
export declare function buildOpenAIResponsesProviderOptions(opts: OpenAIResponsesCompactOptions, sessionId: string): Record<string, unknown> | null;
|
|
93
|
+
/**
|
|
94
|
+
* Single wiring point for provider prompt caching, called by the driver
|
|
95
|
+
* `streamText` sites. Gated by the conservative detectors so non-matching
|
|
96
|
+
* providers are untouched:
|
|
97
|
+
* - Anthropic → applies `cache_control` breakpoints (caches the system+tools
|
|
98
|
+
* prefix + recent history; ~75% input-cost + TTFT off multi-turn turns).
|
|
99
|
+
* - OpenAI Responses → sets `promptCacheKey` (= sessionId, pins same-session
|
|
100
|
+
* turns to one cache slot) + `truncation: 'auto'` overflow safety net.
|
|
101
|
+
* Returns the (possibly transformed) messages + an optional `providerOptions`
|
|
102
|
+
* bag ready to spread into `streamText`. Default-on: both are no-ops on
|
|
103
|
+
* providers that ignore the fields.
|
|
104
|
+
*/
|
|
105
|
+
export declare function applyPromptCache(model: unknown, sessionId: string, messages: ModelMessage[]): {
|
|
106
|
+
messages: ModelMessage[];
|
|
107
|
+
providerOptions?: Record<string, Record<string, JSONValue>>;
|
|
108
|
+
};
|
|
@@ -110,6 +110,30 @@ export function buildOpenAIResponsesProviderOptions(opts, sessionId) {
|
|
|
110
110
|
}
|
|
111
111
|
return Object.keys(out).length > 0 ? out : null;
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Single wiring point for provider prompt caching, called by the driver
|
|
115
|
+
* `streamText` sites. Gated by the conservative detectors so non-matching
|
|
116
|
+
* providers are untouched:
|
|
117
|
+
* - Anthropic → applies `cache_control` breakpoints (caches the system+tools
|
|
118
|
+
* prefix + recent history; ~75% input-cost + TTFT off multi-turn turns).
|
|
119
|
+
* - OpenAI Responses → sets `promptCacheKey` (= sessionId, pins same-session
|
|
120
|
+
* turns to one cache slot) + `truncation: 'auto'` overflow safety net.
|
|
121
|
+
* Returns the (possibly transformed) messages + an optional `providerOptions`
|
|
122
|
+
* bag ready to spread into `streamText`. Default-on: both are no-ops on
|
|
123
|
+
* providers that ignore the fields.
|
|
124
|
+
*/
|
|
125
|
+
export function applyPromptCache(model, sessionId, messages) {
|
|
126
|
+
const outMessages = isAnthropicLanguageModel(model)
|
|
127
|
+
? applyAnthropicCacheControl(messages)
|
|
128
|
+
: messages;
|
|
129
|
+
if (isOpenAIResponsesModel(model)) {
|
|
130
|
+
const openai = buildOpenAIResponsesProviderOptions({ useSessionAsPromptCacheKey: true, truncationFallback: 'auto' }, sessionId);
|
|
131
|
+
if (openai) {
|
|
132
|
+
return { messages: outMessages, providerOptions: { openai: openai } };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { messages: outMessages };
|
|
136
|
+
}
|
|
113
137
|
function withProviderOptions(msg, cacheControl) {
|
|
114
138
|
const existing = msg.providerOptions ?? {};
|
|
115
139
|
const existingAnthropic = existing.anthropic ?? {};
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { MemoryBlockScope, PersistentMemoryConfig } from '../memory/blocks/types.js';
|
|
2
2
|
export interface AgentKnowledge {
|
|
3
|
+
/** Whether the runtime retrieves automatically. Default: `true`.
|
|
4
|
+
* - `true` (guaranteed): pre-inject retrieved knowledge before every
|
|
5
|
+
* answering turn — always grounded; a fused routing turn pays the
|
|
6
|
+
* retrieval cost (the price of a kept grounding promise).
|
|
7
|
+
* - `false` (on-demand): the runtime does not auto-inject; instead the model
|
|
8
|
+
* is given a `knowledge_search` tool and retrieves only when it answers, so
|
|
9
|
+
* routing/dispatch turns pay zero retrieval tax (grounding becomes
|
|
10
|
+
* model-discretion). `autoRetrieve` and the tool are mutually exclusive —
|
|
11
|
+
* the boolean picks the invoker (runtime vs model), not a separate mode. */
|
|
3
12
|
autoRetrieve?: boolean;
|
|
4
13
|
sources?: string[];
|
|
5
14
|
}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"url": "git+https://github.com/kuralle/kuralle-agents.git",
|
|
7
7
|
"directory": "packages/kuralle-core"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.2",
|
|
10
10
|
"description": "A framework for structured conversational AI agents",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"typescript": "^5.3.0",
|
|
104
104
|
"vitest": "^3.2.4",
|
|
105
105
|
"zod": "^4.0.0",
|
|
106
|
-
"@kuralle-agents/realtime-audio": "0.7.
|
|
106
|
+
"@kuralle-agents/realtime-audio": "0.7.2"
|
|
107
107
|
},
|
|
108
108
|
"dependencies": {
|
|
109
109
|
"chrono-node": "^2.6.0"
|