@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.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/dist/capabilities/adapters/gemini.js +2 -2
  3. package/dist/flow/choiceMatch.d.ts +1 -1
  4. package/dist/flow/nodeBuilders.d.ts +1 -1
  5. package/dist/flow/nodeBuilders.js +5 -3
  6. package/dist/index.d.ts +12 -4
  7. package/dist/index.js +7 -2
  8. package/dist/memory/blocks/FilePersistentMemoryStore.d.ts +1 -1
  9. package/dist/memory/blocks/FilePersistentMemoryStore.js +9 -0
  10. package/dist/memory/blocks/InMemoryPersistentMemoryStore.d.ts +8 -0
  11. package/dist/memory/blocks/InMemoryPersistentMemoryStore.js +25 -0
  12. package/dist/memory/blocks/RoutedPersistentMemoryStore.d.ts +18 -0
  13. package/dist/memory/blocks/RoutedPersistentMemoryStore.js +35 -0
  14. package/dist/memory/blocks/TieredPersistentMemoryStore.d.ts +10 -0
  15. package/dist/memory/blocks/TieredPersistentMemoryStore.js +30 -0
  16. package/dist/memory/blocks/memoryBlockTool.d.ts +8 -8
  17. package/dist/memory/blocks/testing.d.ts +11 -0
  18. package/dist/memory/blocks/testing.js +59 -0
  19. package/dist/memory/index.d.ts +4 -0
  20. package/dist/memory/index.js +3 -0
  21. package/dist/runtime/Runtime.d.ts +3 -0
  22. package/dist/runtime/Runtime.js +47 -5
  23. package/dist/runtime/agentReply.js +2 -1
  24. package/dist/runtime/channels/TextDriver.js +3 -2
  25. package/dist/runtime/channels/VoiceDriver.js +3 -3
  26. package/dist/runtime/channels/extractionTurn.js +1 -1
  27. package/dist/runtime/ctx.d.ts +2 -0
  28. package/dist/runtime/ctx.js +1 -0
  29. package/dist/runtime/grounding/defaultStoreRegistry.d.ts +3 -0
  30. package/dist/runtime/grounding/defaultStoreRegistry.js +10 -0
  31. package/dist/runtime/grounding/index.d.ts +1 -0
  32. package/dist/runtime/grounding/index.js +1 -0
  33. package/dist/runtime/grounding/workingMemory.d.ts +19 -0
  34. package/dist/runtime/grounding/workingMemory.js +80 -0
  35. package/dist/runtime/resolveAgentWorkspace.d.ts +10 -0
  36. package/dist/runtime/resolveAgentWorkspace.js +9 -0
  37. package/dist/skills/SkillsCapability.d.ts +10 -0
  38. package/dist/skills/SkillsCapability.js +52 -0
  39. package/dist/skills/collectSkills.d.ts +17 -0
  40. package/dist/skills/collectSkills.js +56 -0
  41. package/dist/skills/index.d.ts +5 -0
  42. package/dist/skills/index.js +4 -0
  43. package/dist/skills/inlineSkillStore.d.ts +9 -0
  44. package/dist/skills/inlineSkillStore.js +37 -0
  45. package/dist/skills/wireAgentSkills.d.ts +10 -0
  46. package/dist/skills/wireAgentSkills.js +25 -0
  47. package/dist/tools/effect/defineTool.js +1 -1
  48. package/dist/tools/effect/index.d.ts +1 -0
  49. package/dist/tools/effect/index.js +1 -0
  50. package/dist/tools/effect/wrapAiSdkTool.d.ts +18 -0
  51. package/dist/tools/effect/wrapAiSdkTool.js +18 -0
  52. package/dist/tools/fs/createFsTool.d.ts +30 -0
  53. package/dist/tools/fs/createFsTool.js +200 -0
  54. package/dist/tools/handoff.d.ts +1 -1
  55. package/dist/tools/http.js +1 -1
  56. package/dist/types/agentConfig.d.ts +16 -3
  57. package/dist/types/filesystem.d.ts +85 -0
  58. package/dist/types/filesystem.js +6 -0
  59. package/dist/types/grounding.d.ts +12 -0
  60. package/dist/types/index.d.ts +2 -0
  61. package/dist/types/index.js +2 -0
  62. package/dist/types/run-context.d.ts +11 -2
  63. package/dist/types/skills.d.ts +19 -0
  64. package/dist/types/skills.js +1 -0
  65. package/dist/utils/chrono.d.ts +1 -9
  66. package/guides/AGENTS.md +2 -3
  67. package/guides/FLOWS.md +2 -2
  68. package/guides/TOOLS.md +69 -2
  69. package/package.json +15 -7
@@ -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: [] };
@@ -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;
@@ -108,6 +108,7 @@ function makeCtx(deps) {
108
108
  limits: deps.limits,
109
109
  autoRetrieve: deps.autoRetrieve,
110
110
  memoryService: deps.memoryService,
111
+ fs: deps.fs,
111
112
  bargeIn: deps.bargeIn,
112
113
  abortSignal: deps.abortSignal,
113
114
  turnInputConsumed: false,
@@ -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
+ }
@@ -25,7 +25,7 @@ export function toolToAiSdk(def) {
25
25
  // `buildToolSet` produces a model-facing ToolSet whose entries are schema-only
26
26
  // (`toolToAiSdk` strips `execute`). Stash the raw effect tools (with executors),
27
27
  // keyed by the returned ToolSet, so a flow node can recover its executors for
28
- // in-flow execution without separately registering them on `agent.effectTools`
28
+ // in-flow execution without separately registering them on `agent.tools`.
29
29
  // (see `resolveReplyNode`). The WeakMap is GC-friendly and invisible to callers.
30
30
  const rawToolsBySet = new WeakMap();
31
31
  export function buildToolSet(tools) {
@@ -1,4 +1,5 @@
1
1
  export { defineTool, toolToAiSdk, buildToolSet } from './defineTool.js';
2
+ export { wrapAiSdkTool } from './wrapAiSdkTool.js';
2
3
  export { CoreToolExecutor } from './ToolExecutor.js';
3
4
  export type { CoreToolExecutorConfig, CoreExecuteArgs } from './ToolExecutor.js';
4
5
  export { PairingTracker, cancelledPlaceholder, inProgressPlaceholder, } from './pairing.js';
@@ -1,4 +1,5 @@
1
1
  export { defineTool, toolToAiSdk, buildToolSet } from './defineTool.js';
2
+ export { wrapAiSdkTool } from './wrapAiSdkTool.js';
2
3
  export { CoreToolExecutor } from './ToolExecutor.js';
3
4
  export { PairingTracker, cancelledPlaceholder, inProgressPlaceholder, } from './pairing.js';
4
5
  export { validateAndSanitize, validateOutput, ToolValidationError } from './schema.js';
@@ -0,0 +1,18 @@
1
+ import type { AnyTool } from '../../types/effectTool.js';
2
+ /**
3
+ * Structural shape of an AI SDK `tool()` result. Intentionally decoupled from the
4
+ * nominal `import('ai').Tool` type so a tool produced by *any* `ai` instance/version
5
+ * in the consumer's tree is accepted (avoids cross-instance nominal mismatches).
6
+ */
7
+ interface AiSdkToolLike {
8
+ description?: string;
9
+ inputSchema?: unknown;
10
+ execute?: unknown;
11
+ }
12
+ /**
13
+ * Adapt a third-party AI SDK tool into a durable Kuralle effect tool so its `execute`
14
+ * runs through the journal (exactly-once on replay). Throws on a schema-only tool
15
+ * (no `execute`) — use `defineTool` for those.
16
+ */
17
+ export declare function wrapAiSdkTool(name: string, aiTool: AiSdkToolLike): AnyTool;
18
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Adapt a third-party AI SDK tool into a durable Kuralle effect tool so its `execute`
3
+ * runs through the journal (exactly-once on replay). Throws on a schema-only tool
4
+ * (no `execute`) — use `defineTool` for those.
5
+ */
6
+ export function wrapAiSdkTool(name, aiTool) {
7
+ const exec = aiTool.execute;
8
+ if (typeof exec !== 'function') {
9
+ throw new Error(`wrapAiSdkTool("${name}"): AI SDK tool has no execute; use defineTool for schema-only tools.`);
10
+ }
11
+ const run = exec;
12
+ return {
13
+ name,
14
+ description: typeof aiTool.description === 'string' ? aiTool.description : name,
15
+ input: aiTool.inputSchema,
16
+ execute: (args, ctx) => run(args, ctx),
17
+ };
18
+ }
@@ -0,0 +1,30 @@
1
+ import type { AnyTool } from '../../types/effectTool.js';
2
+ import { type FileSystem } from '../../types/filesystem.js';
3
+ export interface CreateFsToolOptions {
4
+ fs: FileSystem;
5
+ readOnly?: boolean;
6
+ timeoutMs?: number;
7
+ }
8
+ export interface GrepHit {
9
+ path: string;
10
+ line: number;
11
+ text: string;
12
+ }
13
+ export interface FsSearchHit {
14
+ slug: string;
15
+ chunkIndex: number;
16
+ text: string;
17
+ }
18
+ export interface FsWithSearch extends FileSystem {
19
+ search?(pattern: string, opts?: {
20
+ limit?: number;
21
+ path?: string;
22
+ }): Promise<FsSearchHit[]>;
23
+ }
24
+ /**
25
+ * One durable `workspace` tool over a {@link FileSystem} (ls/cat/grep/find/read/write/edit).
26
+ * Lives in core (not `@kuralle-agents/fs`) because it needs only `defineTool` + the
27
+ * `FileSystem` interface — both core-owned — so the runtime can auto-register it with a
28
+ * static import and no core->fs dependency (RFC-02 §5.2). `@kuralle-agents/fs` re-exports it.
29
+ */
30
+ export declare function createFsTool(opts: CreateFsToolOptions): AnyTool;