@capekai/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/package.json +105 -0
- package/src/adapters/ai-sdk.ts +84 -0
- package/src/compaction/contracts.ts +82 -0
- package/src/compaction/executor.ts +161 -0
- package/src/compaction/policy.ts +318 -0
- package/src/compaction/recovery.ts +139 -0
- package/src/compaction/task.ts +540 -0
- package/src/configuration/contracts.ts +58 -0
- package/src/configuration/defaults.ts +27 -0
- package/src/configuration/runtime.ts +42 -0
- package/src/configuration/single-model.ts +75 -0
- package/src/context/assembler.ts +112 -0
- package/src/context/index.ts +2 -0
- package/src/context/sources.ts +119 -0
- package/src/context/workspace.ts +63 -0
- package/src/core/agent.ts +401 -0
- package/src/core/build-tools.ts +139 -0
- package/src/core/chat-handler.ts +858 -0
- package/src/core/error-handling.ts +18 -0
- package/src/core/fork.ts +103 -0
- package/src/core/interrupt.ts +192 -0
- package/src/core/message-utils.ts +261 -0
- package/src/core/model-utils.ts +149 -0
- package/src/core/part-utils.ts +88 -0
- package/src/core/provider-utils.ts +67 -0
- package/src/core/revert.ts +46 -0
- package/src/core/step-handlers.ts +157 -0
- package/src/core/stream/finalization.ts +65 -0
- package/src/core/stream/stream-config.ts +82 -0
- package/src/core/stream-handlers.ts +242 -0
- package/src/core/structured-output.ts +68 -0
- package/src/core/tool-builders/agent-tools.ts +71 -0
- package/src/core/tool-builders/external-tools.ts +179 -0
- package/src/core/tool-builders/types.ts +16 -0
- package/src/core/tool-builders/workspace-tools.ts +293 -0
- package/src/core/tool-capabilities.ts +65 -0
- package/src/goals/evaluator.ts +171 -0
- package/src/goals/index.ts +3 -0
- package/src/goals/loop.ts +167 -0
- package/src/goals/service.ts +39 -0
- package/src/index.ts +10 -0
- package/src/internal/ask-authority.ts +29 -0
- package/src/internal/composition.ts +44 -0
- package/src/internal/configuration.ts +22 -0
- package/src/internal/execution.ts +108 -0
- package/src/internal/hosts.ts +64 -0
- package/src/internal/plugins.ts +71 -0
- package/src/internal/providers.ts +32 -0
- package/src/internal/sandbox.ts +19 -0
- package/src/internal/tools.ts +48 -0
- package/src/internal/workspace.ts +25 -0
- package/src/kernel/diagnostics.ts +249 -0
- package/src/kernel/errors.ts +120 -0
- package/src/kernel/events.ts +82 -0
- package/src/kernel/index.ts +72 -0
- package/src/kernel/kernel.ts +62 -0
- package/src/kernel/lifecycle.ts +72 -0
- package/src/kernel/plugin.ts +218 -0
- package/src/kernel/registry.ts +493 -0
- package/src/kernel/scope.ts +776 -0
- package/src/kernel/service-key.ts +19 -0
- package/src/kernel/types.ts +317 -0
- package/src/memory/index.ts +2 -0
- package/src/memory/memory-tool.ts +75 -0
- package/src/memory/registry.ts +172 -0
- package/src/permission/ask-user-api.ts +70 -0
- package/src/permission/contracts.ts +135 -0
- package/src/permission/permission-request-manager.ts +58 -0
- package/src/permission/policy.ts +277 -0
- package/src/permission/runtime.ts +612 -0
- package/src/plugins/compaction-policy.ts +46 -0
- package/src/plugins/compose.ts +171 -0
- package/src/plugins/context-sections.ts +246 -0
- package/src/plugins/default-agent-driver.ts +14 -0
- package/src/plugins/facade-plugins.ts +129 -0
- package/src/plugins/goal-domain.ts +82 -0
- package/src/plugins/legacy-system-message.ts +152 -0
- package/src/plugins/loaded-tools.ts +23 -0
- package/src/plugins/memory-domain.ts +264 -0
- package/src/plugins/orchestrator-session.ts +29 -0
- package/src/plugins/permission-policy.ts +49 -0
- package/src/plugins/retry-policy.ts +28 -0
- package/src/plugins/scheduler-domain.ts +192 -0
- package/src/plugins/service-keys.ts +294 -0
- package/src/plugins/session-search-domain.ts +238 -0
- package/src/plugins/skills-domain.ts +272 -0
- package/src/plugins/subagent-domain.ts +287 -0
- package/src/plugins/tool-catalog.ts +78 -0
- package/src/plugins/tool-output-policy.ts +52 -0
- package/src/plugins/value-plugins.ts +150 -0
- package/src/plugins/workflow-domain.ts +198 -0
- package/src/plugins/workspace-policy.ts +37 -0
- package/src/providers/registry.ts +63 -0
- package/src/providers/types.ts +44 -0
- package/src/retry/policy.ts +282 -0
- package/src/retry/stream-chat.ts +312 -0
- package/src/runtime/agent-runtime.ts +83 -0
- package/src/runtime/default-agent-driver.ts +23 -0
- package/src/runtime/domain-tool-source.ts +156 -0
- package/src/runtime/events.ts +61 -0
- package/src/runtime/host-dependencies.ts +71 -0
- package/src/runtime/host-guidance.ts +22 -0
- package/src/runtime/host-layout.ts +23 -0
- package/src/runtime/host.ts +129 -0
- package/src/runtime/standalone-host.ts +118 -0
- package/src/sandbox/controller.ts +204 -0
- package/src/sandbox/model.ts +305 -0
- package/src/sandbox/provider.ts +53 -0
- package/src/sandbox/types.ts +110 -0
- package/src/scheduler/host.ts +22 -0
- package/src/scheduler/scheduler-tool.ts +172 -0
- package/src/session-search/host.ts +56 -0
- package/src/session-search/index.ts +23 -0
- package/src/session-search/session-search-tool.ts +151 -0
- package/src/skills/index.ts +3 -0
- package/src/skills/registry.ts +63 -0
- package/src/skills/skill-manage-tool.ts +205 -0
- package/src/skills/skill-tool.ts +42 -0
- package/src/storage/contracts.ts +159 -0
- package/src/storage/memory.ts +321 -0
- package/src/storage/options.ts +75 -0
- package/src/storage/runtime.ts +115 -0
- package/src/storage/sqlite-tool-output-artifacts.ts +106 -0
- package/src/storage/sqlite.ts +321 -0
- package/src/storage/tool-output-artifacts.ts +75 -0
- package/src/storage.ts +31 -0
- package/src/subagent/child-session.ts +282 -0
- package/src/subagent/guidance.ts +8 -0
- package/src/subagent/policy.ts +198 -0
- package/src/subagent/task-tool.ts +584 -0
- package/src/tool-output/contracts.ts +111 -0
- package/src/tool-output/policy.ts +410 -0
- package/src/tool.ts +1 -0
- package/src/tools/executor.ts +258 -0
- package/src/tools/install-manifest.ts +40 -0
- package/src/tools/llm-api.ts +77 -0
- package/src/tools/registry.ts +206 -0
- package/src/tools/tool-artifact.ts +182 -0
- package/src/tools/tool-source.ts +53 -0
- package/src/utils/errors.ts +334 -0
- package/src/utils/strip-visualization.ts +50 -0
- package/src/workflow/decomposer.ts +139 -0
- package/src/workflow/execution.ts +523 -0
- package/src/workflow/orchestrator-session.ts +161 -0
- package/src/workflow/synthesizer.ts +130 -0
- package/src/workspace/contracts.ts +135 -0
- package/src/workspace/policy.ts +327 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import type { PermissionRiskLevel } from '@capekai/tool';
|
|
2
|
+
import {
|
|
3
|
+
validateContextAssemblyData,
|
|
4
|
+
type ContextAssemblyData,
|
|
5
|
+
} from '../context/assembler';
|
|
6
|
+
import { serviceKey } from '../kernel/service-key';
|
|
7
|
+
import type {
|
|
8
|
+
CapekPlugin,
|
|
9
|
+
ContextSectionContribution,
|
|
10
|
+
PluginContext,
|
|
11
|
+
ToolDefinition as KernelToolDefinition,
|
|
12
|
+
} from '../kernel/types';
|
|
13
|
+
import {
|
|
14
|
+
DOMAIN_TOOL_PAYLOAD_FIELD,
|
|
15
|
+
registerDomainToolFallback,
|
|
16
|
+
type DomainToolExecuteContext,
|
|
17
|
+
type DomainToolPayload,
|
|
18
|
+
} from '../runtime/domain-tool-source';
|
|
19
|
+
import { getHostGuidance } from '../runtime/host-guidance';
|
|
20
|
+
import type { SessionSearchHost } from '../session-search/host';
|
|
21
|
+
import {
|
|
22
|
+
executeSessionSearchTool,
|
|
23
|
+
executeSessionSearchToolWithHost,
|
|
24
|
+
sessionSearchToolDefinition,
|
|
25
|
+
type SessionSearchResult,
|
|
26
|
+
} from '../session-search/session-search-tool';
|
|
27
|
+
import type { StorageBundle } from '../storage/contracts';
|
|
28
|
+
import { getWorkspace } from '../storage/runtime';
|
|
29
|
+
import { capekSessionSearchHostKey, capekStorageKey } from './service-keys';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* C5 session-search domain plugin. Owns the domain service (agent scope),
|
|
33
|
+
* the `session_search` tool contribution, and the `session-search-guidance`
|
|
34
|
+
* section. The composed payload executes through the process-scoped host
|
|
35
|
+
* service and the scope storage captured at setup; one `isEnabled`
|
|
36
|
+
* predicate gates both the tool and the guidance.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
export const CURRENT_SESSION_SEARCH_DOMAIN_PLUGIN_ID = 'current.session-search-domain';
|
|
40
|
+
export const SESSION_SEARCH_TOOL_CONTRIBUTION_ID = 'session-search.session_search';
|
|
41
|
+
export const SESSION_SEARCH_TOOL_CONTRIBUTION_ORDER = 700;
|
|
42
|
+
export const SESSION_SEARCH_GUIDANCE_SECTION_ID = 'session-search-guidance';
|
|
43
|
+
|
|
44
|
+
export interface SessionSearchDomainService {
|
|
45
|
+
readonly tools: readonly DomainToolPayload[];
|
|
46
|
+
/** Single availability predicate for the workspace settings gate,
|
|
47
|
+
* shared by the tool gate and the guidance section. */
|
|
48
|
+
isEnabled(workspaceId: string): boolean | Promise<boolean>;
|
|
49
|
+
readonly guidance: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const capekSessionSearchDomainKey = serviceKey<SessionSearchDomainService>(
|
|
53
|
+
'capek.session-search-domain',
|
|
54
|
+
'agent',
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
interface SessionSearchPayloadDeps {
|
|
58
|
+
readonly isEnabled: (workspaceId: string) => boolean | Promise<boolean>;
|
|
59
|
+
readonly run: (
|
|
60
|
+
input: Record<string, unknown>,
|
|
61
|
+
context: DomainToolExecuteContext,
|
|
62
|
+
includeToolResults: boolean,
|
|
63
|
+
risk: PermissionRiskLevel,
|
|
64
|
+
agentId: string | null,
|
|
65
|
+
) => Promise<SessionSearchResult>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function shapeSessionSearchResult(result: SessionSearchResult): Record<string, unknown> {
|
|
69
|
+
if (!result.success) {
|
|
70
|
+
return { error: result.error ?? 'Session search failed' };
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
success: result.success,
|
|
74
|
+
mode: result.mode,
|
|
75
|
+
title: result.title,
|
|
76
|
+
...(result.sessions !== undefined && { sessions: result.sessions }),
|
|
77
|
+
...(result.query !== undefined && { query: result.query }),
|
|
78
|
+
...(result.scope !== undefined && { scope: result.scope }),
|
|
79
|
+
...(result.results !== undefined && { results: result.results }),
|
|
80
|
+
...(result.sessionId !== undefined && { sessionId: result.sessionId }),
|
|
81
|
+
...(result.sessionTitle !== undefined && { sessionTitle: result.sessionTitle }),
|
|
82
|
+
...(result.anchorMessageId !== undefined && { anchorMessageId: result.anchorMessageId }),
|
|
83
|
+
...(result.anchorInferred !== undefined && { anchorInferred: result.anchorInferred }),
|
|
84
|
+
...(result.messagesBefore !== undefined && { messagesBefore: result.messagesBefore }),
|
|
85
|
+
...(result.messagesAfter !== undefined && { messagesAfter: result.messagesAfter }),
|
|
86
|
+
...(result.messages !== undefined && { messages: result.messages }),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function sessionSearchPayload(deps: SessionSearchPayloadDeps): DomainToolPayload {
|
|
91
|
+
return {
|
|
92
|
+
name: sessionSearchToolDefinition.name,
|
|
93
|
+
description: sessionSearchToolDefinition.description,
|
|
94
|
+
inputSchema: sessionSearchToolDefinition.inputSchema as Readonly<Record<string, unknown>>,
|
|
95
|
+
display: { summary: '{action} {query}' },
|
|
96
|
+
isEnabled: deps.isEnabled,
|
|
97
|
+
visualize: (_input, result) => {
|
|
98
|
+
const results = Array.isArray(result.results) ? result.results : undefined;
|
|
99
|
+
if (results) {
|
|
100
|
+
return {
|
|
101
|
+
type: 'file-list',
|
|
102
|
+
collapsed: true,
|
|
103
|
+
badge: `${results.length} result${results.length === 1 ? '' : 's'}`,
|
|
104
|
+
title: String(result.query ?? String(result.title ?? 'Search')),
|
|
105
|
+
files: results.slice(0, 20).map((r) => ({
|
|
106
|
+
path: String((r as { sessionTitle?: string }).sessionTitle ?? (r as { sessionId?: string }).sessionId ?? ''),
|
|
107
|
+
})),
|
|
108
|
+
total: results.length,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : undefined;
|
|
112
|
+
if (sessions) {
|
|
113
|
+
return {
|
|
114
|
+
type: 'file-list',
|
|
115
|
+
collapsed: true,
|
|
116
|
+
badge: `${sessions.length} session${sessions.length === 1 ? '' : 's'}`,
|
|
117
|
+
files: sessions.slice(0, 20).map((s) => ({
|
|
118
|
+
path: String((s as { title?: string }).title ?? (s as { id?: string }).id ?? ''),
|
|
119
|
+
})),
|
|
120
|
+
total: sessions.length,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const messages = Array.isArray(result.messages) ? result.messages : undefined;
|
|
124
|
+
if (messages) {
|
|
125
|
+
return {
|
|
126
|
+
type: 'none',
|
|
127
|
+
badge: `${messages.length} message${messages.length === 1 ? '' : 's'}`,
|
|
128
|
+
message: String(result.sessionTitle ?? 'Session context'),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return { type: 'none', message: String(result.title ?? 'Session search completed') };
|
|
132
|
+
},
|
|
133
|
+
execute: async (input, context) => {
|
|
134
|
+
// workspace-tools captures permissionRisk and includeToolResults at
|
|
135
|
+
// build time exactly like pre-C5 and passes them through the execution
|
|
136
|
+
// context; the payload never re-reads workspace settings at execution
|
|
137
|
+
// time.
|
|
138
|
+
const includeToolResults = context.includeToolResults === true;
|
|
139
|
+
const risk = context.permissionRisk as PermissionRiskLevel;
|
|
140
|
+
const agentId = typeof context.agentId === 'string' ? context.agentId : null;
|
|
141
|
+
const result = await deps.run(input, context, includeToolResults, risk, agentId);
|
|
142
|
+
return shapeSessionSearchResult(result);
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Unscoped compatibility payload: keeps the pre-C5 execute-time module host
|
|
148
|
+
* and storage reads. Installed through `installSessionSearchToolFallback`,
|
|
149
|
+
* never at module load. */
|
|
150
|
+
export function createSessionSearchToolFallbackPayload(): DomainToolPayload {
|
|
151
|
+
return sessionSearchPayload({
|
|
152
|
+
isEnabled: async (workspaceId) => Boolean(
|
|
153
|
+
(await getWorkspace(workspaceId))?.settings?.sessionSearch?.enabled,
|
|
154
|
+
),
|
|
155
|
+
run: (input, context, includeToolResults, risk, agentId) => executeSessionSearchTool(
|
|
156
|
+
input,
|
|
157
|
+
context.workspaceId,
|
|
158
|
+
context.sessionId,
|
|
159
|
+
includeToolResults,
|
|
160
|
+
risk,
|
|
161
|
+
context.ask,
|
|
162
|
+
agentId,
|
|
163
|
+
),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Explicitly installs the unscoped legacy fallback. Called by the Jean2
|
|
168
|
+
* compatibility bindings installation (server bootstrap) and by focused
|
|
169
|
+
* tests; no module-load registration exists. */
|
|
170
|
+
export function installSessionSearchToolFallback(): void {
|
|
171
|
+
registerDomainToolFallback(
|
|
172
|
+
sessionSearchToolDefinition.name,
|
|
173
|
+
createSessionSearchToolFallbackPayload(),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
type GuidanceSectionContribution = ContextSectionContribution<ContextAssemblyData>;
|
|
178
|
+
|
|
179
|
+
export function sessionSearchDomainPlugin(id: string): CapekPlugin<unknown> {
|
|
180
|
+
return {
|
|
181
|
+
id,
|
|
182
|
+
scope: 'agent',
|
|
183
|
+
provides: [capekSessionSearchDomainKey],
|
|
184
|
+
requires: [capekStorageKey, capekSessionSearchHostKey],
|
|
185
|
+
setup(context: PluginContext) {
|
|
186
|
+
const storage: StorageBundle = context.require(capekStorageKey);
|
|
187
|
+
const host: SessionSearchHost = context.require(capekSessionSearchHostKey);
|
|
188
|
+
const isEnabled = async (workspaceId: string): Promise<boolean> => Boolean(
|
|
189
|
+
(await storage.workspaces.get(workspaceId))?.settings?.sessionSearch?.enabled,
|
|
190
|
+
);
|
|
191
|
+
const payload = sessionSearchPayload({
|
|
192
|
+
isEnabled,
|
|
193
|
+
run: (input, executionContext, includeToolResults, risk, agentId) =>
|
|
194
|
+
executeSessionSearchToolWithHost(
|
|
195
|
+
host,
|
|
196
|
+
input,
|
|
197
|
+
executionContext.workspaceId,
|
|
198
|
+
executionContext.sessionId,
|
|
199
|
+
includeToolResults,
|
|
200
|
+
risk,
|
|
201
|
+
executionContext.ask,
|
|
202
|
+
agentId,
|
|
203
|
+
),
|
|
204
|
+
});
|
|
205
|
+
const service: SessionSearchDomainService = {
|
|
206
|
+
tools: [payload],
|
|
207
|
+
isEnabled,
|
|
208
|
+
guidance: getHostGuidance().sessionSearch,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const guidance: GuidanceSectionContribution = {
|
|
212
|
+
id: SESSION_SEARCH_GUIDANCE_SECTION_ID,
|
|
213
|
+
phase: 'workspace',
|
|
214
|
+
order: 50,
|
|
215
|
+
provide: async (build) => {
|
|
216
|
+
const data = validateContextAssemblyData(build.data);
|
|
217
|
+
if (!data.workspaceId) return null;
|
|
218
|
+
return await isEnabled(data.workspaceId) ? service.guidance : null;
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
context.provide(capekSessionSearchDomainKey, service);
|
|
223
|
+
context.contributeTool({
|
|
224
|
+
id: SESSION_SEARCH_TOOL_CONTRIBUTION_ID,
|
|
225
|
+
order: SESSION_SEARCH_TOOL_CONTRIBUTION_ORDER,
|
|
226
|
+
definition: {
|
|
227
|
+
name: payload.name,
|
|
228
|
+
description: payload.description,
|
|
229
|
+
inputSchema: payload.inputSchema,
|
|
230
|
+
timeout: sessionSearchToolDefinition.timeout,
|
|
231
|
+
[DOMAIN_TOOL_PAYLOAD_FIELD]: payload,
|
|
232
|
+
} as KernelToolDefinition,
|
|
233
|
+
requiredCapabilities: [capekSessionSearchDomainKey],
|
|
234
|
+
});
|
|
235
|
+
context.contributeContext(guidance);
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { getHostGuidance } from '../runtime/host-guidance';
|
|
2
|
+
import { getHostLayout } from '../runtime/host-layout';
|
|
3
|
+
import type { PermissionRiskLevel } from '@capekai/tool';
|
|
4
|
+
import { serviceKey } from '../kernel/service-key';
|
|
5
|
+
import type {
|
|
6
|
+
CapekPlugin,
|
|
7
|
+
ContextSectionContribution,
|
|
8
|
+
PluginContext,
|
|
9
|
+
ToolDefinition as KernelToolDefinition,
|
|
10
|
+
} from '../kernel/types';
|
|
11
|
+
import {
|
|
12
|
+
DOMAIN_TOOL_PAYLOAD_FIELD,
|
|
13
|
+
registerDomainToolFallback,
|
|
14
|
+
type DomainToolPayload,
|
|
15
|
+
} from '../runtime/domain-tool-source';
|
|
16
|
+
import { validateContextAssemblyData, type ContextAssemblyData } from '../context/assembler';
|
|
17
|
+
import {
|
|
18
|
+
buildSkillManageToolDescription,
|
|
19
|
+
buildSkillToolDefinition,
|
|
20
|
+
executeSkillManageTool,
|
|
21
|
+
executeSkillTool,
|
|
22
|
+
skillManageToolDefinition,
|
|
23
|
+
} from '../skills';
|
|
24
|
+
import type { StorageBundle } from '../storage/contracts';
|
|
25
|
+
import { capekStorageKey } from './service-keys';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* C5 skills domain plugin. Owns the agent-scoped skills service: the
|
|
29
|
+
* workspace `skill` and `skill_manage` tool payloads, the agent
|
|
30
|
+
* `agent_skill_manage` tool payload, and the skill-management-guidance
|
|
31
|
+
* context section. Tool building stays in the core tool builders over the
|
|
32
|
+
* generic contributed-domain-tool seam; the payloads read only the build
|
|
33
|
+
* context the builders capture (workspace path, allowed skills, agent
|
|
34
|
+
* skills directory, permission risk), never module globals. The unscoped
|
|
35
|
+
* fallback installs explicitly, never at module load.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
export const CURRENT_SKILLS_DOMAIN_PLUGIN_ID = 'current.skills-domain';
|
|
39
|
+
export const SKILL_TOOL_CONTRIBUTION_ID = 'skills.skill';
|
|
40
|
+
export const SKILL_TOOL_CONTRIBUTION_ORDER = 660;
|
|
41
|
+
export const SKILL_MANAGE_TOOL_CONTRIBUTION_ID = 'skills.skill_manage';
|
|
42
|
+
export const SKILL_MANAGE_TOOL_CONTRIBUTION_ORDER = 695;
|
|
43
|
+
export const AGENT_SKILL_MANAGE_TOOL_CONTRIBUTION_ID = 'skills.agent_skill_manage';
|
|
44
|
+
export const AGENT_SKILL_MANAGE_TOOL_CONTRIBUTION_ORDER = 801;
|
|
45
|
+
|
|
46
|
+
export interface SkillsDomainService {
|
|
47
|
+
readonly tools: readonly DomainToolPayload[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const capekSkillsDomainKey = serviceKey<SkillsDomainService>(
|
|
51
|
+
'capek.skills-domain',
|
|
52
|
+
'agent',
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export function createSkillToolPayload(): DomainToolPayload {
|
|
56
|
+
return {
|
|
57
|
+
name: 'skill',
|
|
58
|
+
description: 'Load a specialized skill that provides domain-specific instructions and workflows.',
|
|
59
|
+
inputSchema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
|
|
60
|
+
display: { summary: '{name}' },
|
|
61
|
+
visualize: (input, result) => {
|
|
62
|
+
const output = (result as { output?: unknown }).output;
|
|
63
|
+
const content = typeof output === 'string' ? output : undefined;
|
|
64
|
+
const title = (result as { title?: unknown }).title;
|
|
65
|
+
if (content && content.length <= 20_000) {
|
|
66
|
+
return {
|
|
67
|
+
type: 'markdown',
|
|
68
|
+
collapsed: true,
|
|
69
|
+
badge: `${(content.length / 1024).toFixed(1)} KB`,
|
|
70
|
+
content: content.slice(0, 20_000),
|
|
71
|
+
title: typeof title === 'string' ? title : String(input.name ?? 'Skill'),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
type: 'none',
|
|
76
|
+
message: typeof title === 'string' ? title : `Loaded skill: ${String(input.name ?? '')}`,
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
resolveDefinition: async (sessionId, options) => {
|
|
80
|
+
const definition = await buildSkillToolDefinition(
|
|
81
|
+
options?.workspacePath as string,
|
|
82
|
+
options?.allowedSkills as string[] | null | undefined,
|
|
83
|
+
sessionId,
|
|
84
|
+
options?.agentSkillsDir as string | undefined,
|
|
85
|
+
);
|
|
86
|
+
if (!definition) return null;
|
|
87
|
+
return { description: definition.description, inputSchema: definition.inputSchema };
|
|
88
|
+
},
|
|
89
|
+
execute: async (input, context) => {
|
|
90
|
+
return executeSkillTool(
|
|
91
|
+
input.name as string,
|
|
92
|
+
context.workspacePath as string,
|
|
93
|
+
context.allowedSkills as string[] | null | undefined,
|
|
94
|
+
context.sessionId,
|
|
95
|
+
context.agentSkillsDir as string | undefined,
|
|
96
|
+
) as unknown as Record<string, unknown>;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function createSkillManageToolPayload(): DomainToolPayload {
|
|
102
|
+
return {
|
|
103
|
+
name: 'skill_manage',
|
|
104
|
+
description: skillManageToolDefinition.description,
|
|
105
|
+
inputSchema: skillManageToolDefinition.inputSchema,
|
|
106
|
+
display: { summary: '{action} {name}' },
|
|
107
|
+
visualize: (_input, result) => {
|
|
108
|
+
const skills = Array.isArray(result.skills) ? result.skills : undefined;
|
|
109
|
+
if (skills) {
|
|
110
|
+
return {
|
|
111
|
+
type: 'file-list',
|
|
112
|
+
collapsed: true,
|
|
113
|
+
badge: `${skills.length} skill${skills.length === 1 ? '' : 's'}`,
|
|
114
|
+
files: skills.slice(0, 20).map((s) => ({
|
|
115
|
+
path: String((s as { name?: string }).name ?? ''),
|
|
116
|
+
content: (s as { description?: string }).description,
|
|
117
|
+
})),
|
|
118
|
+
total: skills.length,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return { type: 'none', message: String(result.title ?? 'Skill updated') };
|
|
122
|
+
},
|
|
123
|
+
resolveDefinition: async (_sessionId, options) => {
|
|
124
|
+
const description = await buildSkillManageToolDescription(
|
|
125
|
+
getHostLayout().workspaceSkillsDir(options?.workspacePath as string),
|
|
126
|
+
);
|
|
127
|
+
return { description, inputSchema: skillManageToolDefinition.inputSchema };
|
|
128
|
+
},
|
|
129
|
+
execute: async (input, context) => {
|
|
130
|
+
const risk = (context.permissionRisk ?? 'none') as PermissionRiskLevel;
|
|
131
|
+
const result = await executeSkillManageTool(
|
|
132
|
+
input,
|
|
133
|
+
getHostLayout().workspaceSkillsDir(context.workspacePath as string),
|
|
134
|
+
risk,
|
|
135
|
+
context.ask,
|
|
136
|
+
);
|
|
137
|
+
if (!result.success) {
|
|
138
|
+
return { error: result.error ?? 'Skill management operation failed' };
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
title: result.title,
|
|
142
|
+
action: result.action,
|
|
143
|
+
name: result.name,
|
|
144
|
+
description: result.description,
|
|
145
|
+
path: result.path,
|
|
146
|
+
summary: result.summary,
|
|
147
|
+
skills: result.skills,
|
|
148
|
+
};
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function createAgentSkillManageToolPayload(): DomainToolPayload {
|
|
154
|
+
return {
|
|
155
|
+
name: 'agent_skill_manage',
|
|
156
|
+
description: skillManageToolDefinition.description,
|
|
157
|
+
inputSchema: skillManageToolDefinition.inputSchema,
|
|
158
|
+
display: { summary: '{action} {name}' },
|
|
159
|
+
visualize: (_input, result) => {
|
|
160
|
+
const skills = Array.isArray(result.skills) ? result.skills : undefined;
|
|
161
|
+
if (skills) {
|
|
162
|
+
return {
|
|
163
|
+
type: 'file-list',
|
|
164
|
+
collapsed: true,
|
|
165
|
+
badge: `${skills.length} skill${skills.length === 1 ? '' : 's'}`,
|
|
166
|
+
files: skills.slice(0, 20).map((s) => ({
|
|
167
|
+
path: String((s as { name?: string }).name ?? ''),
|
|
168
|
+
content: (s as { description?: string }).description,
|
|
169
|
+
})),
|
|
170
|
+
total: skills.length,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return { type: 'none', message: String(result.title ?? 'Skill updated') };
|
|
174
|
+
},
|
|
175
|
+
resolveDefinition: async (_sessionId, options) => {
|
|
176
|
+
const description = await buildSkillManageToolDescription(
|
|
177
|
+
getHostLayout().agentSkillsDir(options?.agentDir as string),
|
|
178
|
+
);
|
|
179
|
+
return { description, inputSchema: skillManageToolDefinition.inputSchema };
|
|
180
|
+
},
|
|
181
|
+
execute: async (input, context) => {
|
|
182
|
+
const result = await executeSkillManageTool(
|
|
183
|
+
input,
|
|
184
|
+
getHostLayout().agentSkillsDir(context.agentDir as string),
|
|
185
|
+
'none',
|
|
186
|
+
);
|
|
187
|
+
if (!result.success) {
|
|
188
|
+
return { error: result.error ?? 'Agent skill management failed' };
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
title: result.title,
|
|
192
|
+
action: result.action,
|
|
193
|
+
name: result.name,
|
|
194
|
+
description: result.description,
|
|
195
|
+
path: result.path,
|
|
196
|
+
summary: result.summary,
|
|
197
|
+
skills: result.skills,
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Explicitly installs the unscoped legacy fallbacks. Called by the Jean2
|
|
204
|
+
* compatibility bindings installation (server bootstrap) and by focused
|
|
205
|
+
* tests; no module-load registration exists. */
|
|
206
|
+
export function installSkillsToolFallback(): void {
|
|
207
|
+
registerDomainToolFallback('skill', createSkillToolPayload());
|
|
208
|
+
registerDomainToolFallback('skill_manage', createSkillManageToolPayload());
|
|
209
|
+
registerDomainToolFallback('agent_skill_manage', createAgentSkillManageToolPayload());
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
type SkillSectionContribution = ContextSectionContribution<ContextAssemblyData>;
|
|
213
|
+
|
|
214
|
+
function skillManagementGuidanceSection(storage: StorageBundle): SkillSectionContribution {
|
|
215
|
+
return {
|
|
216
|
+
id: 'skill-management-guidance',
|
|
217
|
+
phase: 'workspace',
|
|
218
|
+
order: 40,
|
|
219
|
+
provide: async (build) => {
|
|
220
|
+
const data = validateContextAssemblyData(build.data);
|
|
221
|
+
if (!data.workspaceId) return null;
|
|
222
|
+
return (await storage.workspaces.get(data.workspaceId))?.settings?.skills?.managementEnabled
|
|
223
|
+
? getHostGuidance().skillManage
|
|
224
|
+
: null;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function skillsDomainPlugin(id: string): CapekPlugin<unknown> {
|
|
230
|
+
return {
|
|
231
|
+
id,
|
|
232
|
+
scope: 'agent',
|
|
233
|
+
provides: [capekSkillsDomainKey],
|
|
234
|
+
requires: [capekStorageKey],
|
|
235
|
+
setup(context: PluginContext) {
|
|
236
|
+
const storage: StorageBundle = context.require(capekStorageKey);
|
|
237
|
+
|
|
238
|
+
const service: SkillsDomainService = {
|
|
239
|
+
tools: [
|
|
240
|
+
createSkillToolPayload(),
|
|
241
|
+
createSkillManageToolPayload(),
|
|
242
|
+
createAgentSkillManageToolPayload(),
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
context.provide(capekSkillsDomainKey, service);
|
|
247
|
+
for (const payload of service.tools) {
|
|
248
|
+
context.contributeTool({
|
|
249
|
+
id: payload.name === 'skill'
|
|
250
|
+
? SKILL_TOOL_CONTRIBUTION_ID
|
|
251
|
+
: payload.name === 'skill_manage'
|
|
252
|
+
? SKILL_MANAGE_TOOL_CONTRIBUTION_ID
|
|
253
|
+
: AGENT_SKILL_MANAGE_TOOL_CONTRIBUTION_ID,
|
|
254
|
+
order: payload.name === 'skill'
|
|
255
|
+
? SKILL_TOOL_CONTRIBUTION_ORDER
|
|
256
|
+
: payload.name === 'skill_manage'
|
|
257
|
+
? SKILL_MANAGE_TOOL_CONTRIBUTION_ORDER
|
|
258
|
+
: AGENT_SKILL_MANAGE_TOOL_CONTRIBUTION_ORDER,
|
|
259
|
+
definition: {
|
|
260
|
+
name: payload.name,
|
|
261
|
+
description: payload.description,
|
|
262
|
+
inputSchema: payload.inputSchema,
|
|
263
|
+
timeout: payload.name === 'skill' ? 5000 : 10000,
|
|
264
|
+
[DOMAIN_TOOL_PAYLOAD_FIELD]: payload,
|
|
265
|
+
} as KernelToolDefinition,
|
|
266
|
+
requiredCapabilities: [capekSkillsDomainKey],
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
context.contributeContext(skillManagementGuidanceSection(storage));
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|