@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.
Files changed (148) hide show
  1. package/README.md +12 -0
  2. package/package.json +105 -0
  3. package/src/adapters/ai-sdk.ts +84 -0
  4. package/src/compaction/contracts.ts +82 -0
  5. package/src/compaction/executor.ts +161 -0
  6. package/src/compaction/policy.ts +318 -0
  7. package/src/compaction/recovery.ts +139 -0
  8. package/src/compaction/task.ts +540 -0
  9. package/src/configuration/contracts.ts +58 -0
  10. package/src/configuration/defaults.ts +27 -0
  11. package/src/configuration/runtime.ts +42 -0
  12. package/src/configuration/single-model.ts +75 -0
  13. package/src/context/assembler.ts +112 -0
  14. package/src/context/index.ts +2 -0
  15. package/src/context/sources.ts +119 -0
  16. package/src/context/workspace.ts +63 -0
  17. package/src/core/agent.ts +401 -0
  18. package/src/core/build-tools.ts +139 -0
  19. package/src/core/chat-handler.ts +858 -0
  20. package/src/core/error-handling.ts +18 -0
  21. package/src/core/fork.ts +103 -0
  22. package/src/core/interrupt.ts +192 -0
  23. package/src/core/message-utils.ts +261 -0
  24. package/src/core/model-utils.ts +149 -0
  25. package/src/core/part-utils.ts +88 -0
  26. package/src/core/provider-utils.ts +67 -0
  27. package/src/core/revert.ts +46 -0
  28. package/src/core/step-handlers.ts +157 -0
  29. package/src/core/stream/finalization.ts +65 -0
  30. package/src/core/stream/stream-config.ts +82 -0
  31. package/src/core/stream-handlers.ts +242 -0
  32. package/src/core/structured-output.ts +68 -0
  33. package/src/core/tool-builders/agent-tools.ts +71 -0
  34. package/src/core/tool-builders/external-tools.ts +179 -0
  35. package/src/core/tool-builders/types.ts +16 -0
  36. package/src/core/tool-builders/workspace-tools.ts +293 -0
  37. package/src/core/tool-capabilities.ts +65 -0
  38. package/src/goals/evaluator.ts +171 -0
  39. package/src/goals/index.ts +3 -0
  40. package/src/goals/loop.ts +167 -0
  41. package/src/goals/service.ts +39 -0
  42. package/src/index.ts +10 -0
  43. package/src/internal/ask-authority.ts +29 -0
  44. package/src/internal/composition.ts +44 -0
  45. package/src/internal/configuration.ts +22 -0
  46. package/src/internal/execution.ts +108 -0
  47. package/src/internal/hosts.ts +64 -0
  48. package/src/internal/plugins.ts +71 -0
  49. package/src/internal/providers.ts +32 -0
  50. package/src/internal/sandbox.ts +19 -0
  51. package/src/internal/tools.ts +48 -0
  52. package/src/internal/workspace.ts +25 -0
  53. package/src/kernel/diagnostics.ts +249 -0
  54. package/src/kernel/errors.ts +120 -0
  55. package/src/kernel/events.ts +82 -0
  56. package/src/kernel/index.ts +72 -0
  57. package/src/kernel/kernel.ts +62 -0
  58. package/src/kernel/lifecycle.ts +72 -0
  59. package/src/kernel/plugin.ts +218 -0
  60. package/src/kernel/registry.ts +493 -0
  61. package/src/kernel/scope.ts +776 -0
  62. package/src/kernel/service-key.ts +19 -0
  63. package/src/kernel/types.ts +317 -0
  64. package/src/memory/index.ts +2 -0
  65. package/src/memory/memory-tool.ts +75 -0
  66. package/src/memory/registry.ts +172 -0
  67. package/src/permission/ask-user-api.ts +70 -0
  68. package/src/permission/contracts.ts +135 -0
  69. package/src/permission/permission-request-manager.ts +58 -0
  70. package/src/permission/policy.ts +277 -0
  71. package/src/permission/runtime.ts +612 -0
  72. package/src/plugins/compaction-policy.ts +46 -0
  73. package/src/plugins/compose.ts +171 -0
  74. package/src/plugins/context-sections.ts +246 -0
  75. package/src/plugins/default-agent-driver.ts +14 -0
  76. package/src/plugins/facade-plugins.ts +129 -0
  77. package/src/plugins/goal-domain.ts +82 -0
  78. package/src/plugins/legacy-system-message.ts +152 -0
  79. package/src/plugins/loaded-tools.ts +23 -0
  80. package/src/plugins/memory-domain.ts +264 -0
  81. package/src/plugins/orchestrator-session.ts +29 -0
  82. package/src/plugins/permission-policy.ts +49 -0
  83. package/src/plugins/retry-policy.ts +28 -0
  84. package/src/plugins/scheduler-domain.ts +192 -0
  85. package/src/plugins/service-keys.ts +294 -0
  86. package/src/plugins/session-search-domain.ts +238 -0
  87. package/src/plugins/skills-domain.ts +272 -0
  88. package/src/plugins/subagent-domain.ts +287 -0
  89. package/src/plugins/tool-catalog.ts +78 -0
  90. package/src/plugins/tool-output-policy.ts +52 -0
  91. package/src/plugins/value-plugins.ts +150 -0
  92. package/src/plugins/workflow-domain.ts +198 -0
  93. package/src/plugins/workspace-policy.ts +37 -0
  94. package/src/providers/registry.ts +63 -0
  95. package/src/providers/types.ts +44 -0
  96. package/src/retry/policy.ts +282 -0
  97. package/src/retry/stream-chat.ts +312 -0
  98. package/src/runtime/agent-runtime.ts +83 -0
  99. package/src/runtime/default-agent-driver.ts +23 -0
  100. package/src/runtime/domain-tool-source.ts +156 -0
  101. package/src/runtime/events.ts +61 -0
  102. package/src/runtime/host-dependencies.ts +71 -0
  103. package/src/runtime/host-guidance.ts +22 -0
  104. package/src/runtime/host-layout.ts +23 -0
  105. package/src/runtime/host.ts +129 -0
  106. package/src/runtime/standalone-host.ts +118 -0
  107. package/src/sandbox/controller.ts +204 -0
  108. package/src/sandbox/model.ts +305 -0
  109. package/src/sandbox/provider.ts +53 -0
  110. package/src/sandbox/types.ts +110 -0
  111. package/src/scheduler/host.ts +22 -0
  112. package/src/scheduler/scheduler-tool.ts +172 -0
  113. package/src/session-search/host.ts +56 -0
  114. package/src/session-search/index.ts +23 -0
  115. package/src/session-search/session-search-tool.ts +151 -0
  116. package/src/skills/index.ts +3 -0
  117. package/src/skills/registry.ts +63 -0
  118. package/src/skills/skill-manage-tool.ts +205 -0
  119. package/src/skills/skill-tool.ts +42 -0
  120. package/src/storage/contracts.ts +159 -0
  121. package/src/storage/memory.ts +321 -0
  122. package/src/storage/options.ts +75 -0
  123. package/src/storage/runtime.ts +115 -0
  124. package/src/storage/sqlite-tool-output-artifacts.ts +106 -0
  125. package/src/storage/sqlite.ts +321 -0
  126. package/src/storage/tool-output-artifacts.ts +75 -0
  127. package/src/storage.ts +31 -0
  128. package/src/subagent/child-session.ts +282 -0
  129. package/src/subagent/guidance.ts +8 -0
  130. package/src/subagent/policy.ts +198 -0
  131. package/src/subagent/task-tool.ts +584 -0
  132. package/src/tool-output/contracts.ts +111 -0
  133. package/src/tool-output/policy.ts +410 -0
  134. package/src/tool.ts +1 -0
  135. package/src/tools/executor.ts +258 -0
  136. package/src/tools/install-manifest.ts +40 -0
  137. package/src/tools/llm-api.ts +77 -0
  138. package/src/tools/registry.ts +206 -0
  139. package/src/tools/tool-artifact.ts +182 -0
  140. package/src/tools/tool-source.ts +53 -0
  141. package/src/utils/errors.ts +334 -0
  142. package/src/utils/strip-visualization.ts +50 -0
  143. package/src/workflow/decomposer.ts +139 -0
  144. package/src/workflow/execution.ts +523 -0
  145. package/src/workflow/orchestrator-session.ts +161 -0
  146. package/src/workflow/synthesizer.ts +130 -0
  147. package/src/workspace/contracts.ts +135 -0
  148. package/src/workspace/policy.ts +327 -0
@@ -0,0 +1,287 @@
1
+ import type { Preconfig } from '@capekai/types'
2
+ import type { ToolDefinition } from '@capekai/tool';
3
+ import { validateContextAssemblyData, type ContextAssemblyData } from '../context/assembler';
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 type { RuntimeDelivery, RuntimeEvent } from '../runtime/events';
17
+ import type { BroadcastFn, RuntimeHost } from '../runtime/host';
18
+ import type { StorageBundle } from '../storage/contracts';
19
+ import { executeChildSession } from '../subagent/child-session';
20
+ import { selfDelegationGuidance } from '../subagent/guidance';
21
+ import {
22
+ resolveEffectiveSubagentTargets,
23
+ type ResolveSubagentTargetsOptions,
24
+ } from '../subagent/policy';
25
+ import {
26
+ buildTaskToolDefinition,
27
+ canSpawnSubagent,
28
+ canSpawnSubagentWithDeps,
29
+ executeSubagent,
30
+ executeSubagentWithDeps,
31
+ getSubagentToolDefinition,
32
+ type GetSubagentToolDefinitionOptions,
33
+ type SubagentInput,
34
+ type SubagentOutput,
35
+ type SubagentServiceBroadcasts,
36
+ type SubagentServiceDeps,
37
+ type SubagentServiceSessionAccess,
38
+ } from '../subagent/task-tool';
39
+ import { capekContextSourcesKey, capekRuntimeHostKey, capekStorageKey } from './service-keys';
40
+
41
+ /**
42
+ * C5 subagent domain plugin. Owns the agent-scoped subagent service (depth
43
+ * and ancestry policy over the captured storage and preconfig sources), the
44
+ * `task` tool contribution through the generic contributed-domain-tool seam,
45
+ * and the `self-delegation` context section. Composed payloads never read
46
+ * module-level globals; the unscoped fallback keeps the pre-C5
47
+ * execute-time module accessors and is installed explicitly, never at
48
+ * module load.
49
+ */
50
+
51
+ export const CURRENT_SUBAGENT_DOMAIN_PLUGIN_ID = 'current.subagent-domain';
52
+ export const SUBAGENT_TOOL_CONTRIBUTION_ID = 'subagent.task';
53
+ /** Before session-search (700) and scheduler (750) so the contributed tool
54
+ * order keeps `task` ahead of the workspace-gated domain tools, matching
55
+ * the pre-C5 buildAiSdkTools phase-1 placement. */
56
+ export const SUBAGENT_TOOL_CONTRIBUTION_ORDER = 650;
57
+ export const SELF_DELEGATION_SECTION_ID = 'self-delegation';
58
+
59
+ export interface SubagentDomainService {
60
+ readonly tools: readonly DomainToolPayload[];
61
+ /** Depth gate shared by the task tool payload. */
62
+ canSpawnSubagent(sessionId: string): Promise<boolean>;
63
+ resolveTargets(options: ResolveSubagentTargetsOptions): Promise<Preconfig[]>;
64
+ /** Composed leaf execution for other C5 domains (workflow): runs the task
65
+ * execution path over this domain's scope-captured deps, never module
66
+ * globals. */
67
+ execute(input: SubagentInput): Promise<SubagentOutput>;
68
+ /** Scope-captured subagent preconfig listing for other C5 domains
69
+ * (workflow decomposition). */
70
+ listSubagents(): Promise<Preconfig[]>;
71
+ /** Whether the current session may delegate to a fresh instance of its own
72
+ * preconfig: task tool visible + allowSelfAsSubagent + the resolved target
73
+ * list contains the current preconfig. Mirrors the pre-C5 agent.ts
74
+ * computation over the same domain policy. */
75
+ selfDelegationAvailable(
76
+ sessionId: string,
77
+ preconfigId: string,
78
+ allowSelfAsSubagent: boolean,
79
+ ): Promise<boolean>;
80
+ guidance(preconfigId: string): string;
81
+ }
82
+
83
+ export const capekSubagentDomainKey = serviceKey<SubagentDomainService>(
84
+ 'capek.subagent-domain',
85
+ 'agent',
86
+ );
87
+
88
+ function deliver(host: RuntimeHost, delivery: RuntimeDelivery): void {
89
+ host.delivery.observe?.(delivery);
90
+ host.delivery.emit(delivery);
91
+ }
92
+
93
+ /** Runtime-host delivery projection shared by the C5 domain plugins
94
+ * (subagent, workflow) that route leaf events through the captured host. */
95
+ export function broadcastsFromHost(host: RuntimeHost): SubagentServiceBroadcasts {
96
+ return {
97
+ event: (event) => deliver(host, { event, audience: { scope: 'global' } }),
98
+ sessionCreated: (session) =>
99
+ deliver(host, { event: { kind: 'session', action: 'created', session }, audience: { scope: 'global' } }),
100
+ sessionUpdated: (session) =>
101
+ deliver(host, { event: { kind: 'session', action: 'updated', session }, audience: { scope: 'global' } }),
102
+ toSession: (sessionId: string, event: RuntimeEvent) =>
103
+ deliver(host, { event, audience: { scope: 'session', sessionId } }),
104
+ };
105
+ }
106
+
107
+ interface TaskPayloadDeps {
108
+ canSpawn: (sessionId: string) => boolean | Promise<boolean>;
109
+ resolveDefinition: (
110
+ options: GetSubagentToolDefinitionOptions,
111
+ ) => Promise<ToolDefinition | null>;
112
+ execute: (input: SubagentInput) => Promise<Record<string, unknown>>;
113
+ }
114
+
115
+ function taskPayload(deps: TaskPayloadDeps): DomainToolPayload {
116
+ const placeholder = buildTaskToolDefinition([]);
117
+ return {
118
+ name: placeholder.name,
119
+ description: placeholder.description,
120
+ inputSchema: placeholder.inputSchema,
121
+ display: { summary: '{description}' },
122
+ visualize: (_input, result) => {
123
+ const taskId = typeof result.task_id === 'string' ? result.task_id : '';
124
+ const text = typeof result.result === 'string' ? result.result : '';
125
+ return {
126
+ type: 'none',
127
+ badge: taskId ? 'session ready' : undefined,
128
+ message: text.split('\n').filter((line) => line && !line.startsWith('task_id:'))
129
+ .join('\n').replace(/<\/?task_result>/g, '').replace(/<\/?structured_result>/g, '').trim().slice(0, 200) || 'Subagent completed',
130
+ };
131
+ },
132
+ isEnabled: async (workspaceId, sessionId) =>
133
+ typeof sessionId === 'string' && await deps.canSpawn(sessionId),
134
+ resolveDefinition: async (sessionId, options) => {
135
+ const definition = await deps.resolveDefinition({
136
+ sessionId,
137
+ canSpawnSubagents: options?.canSpawnSubagents as boolean | string[] | null | undefined,
138
+ allowSelfAsSubagent: options?.allowSelfAsSubagent as boolean | undefined,
139
+ });
140
+ if (!definition) return null;
141
+ return {
142
+ description: definition.description,
143
+ inputSchema: definition.inputSchema,
144
+ };
145
+ },
146
+ execute: async (input, context) => {
147
+ const subagentInput: SubagentInput = {
148
+ description: input.description as string,
149
+ prompt: input.prompt as string,
150
+ subagent_type: input.subagent_type as string,
151
+ task_id: input.task_id as string | undefined,
152
+ sessionId: context.sessionId,
153
+ workspaceId: typeof context.workspaceId === 'string' ? context.workspaceId : undefined,
154
+ workspacePath: typeof context.workspacePath === 'string' ? context.workspacePath : undefined,
155
+ abortSignal: context.abortSignal as AbortSignal | undefined,
156
+ onSessionCreated: context.onSessionCreated as ((childSessionId: string) => void | Promise<void>) | undefined,
157
+ allowedSubagentIds: context.allowedSubagentIds as string[] | undefined,
158
+ broadcast: context.broadcast as BroadcastFn | undefined,
159
+ ...(input.outputSchema ? { outputSchema: input.outputSchema as Record<string, unknown> } : {}),
160
+ };
161
+ return deps.execute(subagentInput);
162
+ },
163
+ };
164
+ }
165
+
166
+ /** Unscoped compatibility payload: keeps the pre-C5 execute-time module
167
+ * accessors. Installed through `installTaskToolFallback`, never at module
168
+ * load. */
169
+ export function createTaskToolFallbackPayload(): DomainToolPayload {
170
+ return taskPayload({
171
+ canSpawn: (sessionId) => canSpawnSubagent(sessionId),
172
+ resolveDefinition: (options) => getSubagentToolDefinition(options),
173
+ execute: async (input) => executeSubagent(input) as unknown as Record<string, unknown>,
174
+ });
175
+ }
176
+
177
+ /** Explicitly installs the unscoped legacy fallback. Called by the Jean2
178
+ * compatibility bindings installation (server bootstrap) and by focused
179
+ * tests; no module-load registration exists. */
180
+ export function installTaskToolFallback(): void {
181
+ registerDomainToolFallback('task', createTaskToolFallbackPayload());
182
+ }
183
+
184
+ type GuidanceSectionContribution = ContextSectionContribution<ContextAssemblyData>;
185
+
186
+ export function subagentDomainPlugin(id: string): CapekPlugin<unknown> {
187
+ return {
188
+ id,
189
+ scope: 'agent',
190
+ provides: [capekSubagentDomainKey],
191
+ requires: [capekStorageKey, capekContextSourcesKey, capekRuntimeHostKey],
192
+ setup(context: PluginContext) {
193
+ const storage: StorageBundle = context.require(capekStorageKey);
194
+ const contextSources = context.require(capekContextSourcesKey);
195
+ const host: RuntimeHost = context.require(capekRuntimeHostKey);
196
+ const preconfigSource = contextSources.preconfigs;
197
+ const getPreconfigOrAgentScoped = (preconfigId: string): Promise<Preconfig | null> =>
198
+ preconfigSource ? preconfigSource.getForAgent(preconfigId) : Promise.resolve(null);
199
+ const listSubagentPreconfigsScoped = (): Promise<Preconfig[]> =>
200
+ preconfigSource ? preconfigSource.listSubagents() : Promise.resolve([]);
201
+
202
+ const sessionAccess: SubagentServiceSessionAccess = {
203
+ getSession: async (sessionId) => storage.conversation.getSession(sessionId),
204
+ createSession: async (session) => storage.conversation.createSession(session),
205
+ updateSession: async (sessionId, updates) => storage.conversation.updateSession(sessionId, updates),
206
+ getWorkspaceAutoApproveSeverity: async (workspaceId) => storage.workspaces.getAutoApproveSeverity(workspaceId),
207
+ };
208
+
209
+ const serviceDeps: SubagentServiceDeps = {
210
+ sessionAccess,
211
+ preconfigs: {
212
+ getPreconfigOrAgent: getPreconfigOrAgentScoped,
213
+ listSubagentPreconfigs: listSubagentPreconfigsScoped,
214
+ },
215
+ broadcasts: broadcastsFromHost(host),
216
+ executeChild: executeChildSession,
217
+ };
218
+
219
+ const service: SubagentDomainService = {
220
+ tools: [
221
+ taskPayload({
222
+ canSpawn: async (sessionId) => canSpawnSubagentWithDeps(sessionId, sessionAccess.getSession),
223
+ resolveDefinition: async (options) => {
224
+ // The composed path resolves targets through the scope-captured
225
+ // storage and preconfig sources; it never reads module globals.
226
+ const deps = {
227
+ getSession: sessionAccess.getSession,
228
+ listPreconfigs: listSubagentPreconfigsScoped,
229
+ };
230
+ const maximumDepthReached = !(await canSpawnSubagentWithDeps(options.sessionId, deps.getSession));
231
+ return resolveEffectiveSubagentTargets({
232
+ ...options,
233
+ maximumDepthReached,
234
+ }, deps).then((targets) =>
235
+ targets.length === 0 ? null : buildTaskToolDefinition(targets));
236
+ },
237
+ execute: (input) => executeSubagentWithDeps(input, serviceDeps) as unknown as Promise<Record<string, unknown>>,
238
+ }),
239
+ ],
240
+ canSpawnSubagent: async (sessionId) => canSpawnSubagentWithDeps(sessionId, sessionAccess.getSession),
241
+ execute: (input) => executeSubagentWithDeps(input, serviceDeps),
242
+ listSubagents: listSubagentPreconfigsScoped,
243
+ resolveTargets: (options) => resolveEffectiveSubagentTargets(options, {
244
+ getSession: sessionAccess.getSession,
245
+ listPreconfigs: listSubagentPreconfigsScoped,
246
+ }),
247
+ selfDelegationAvailable: async (sessionId, preconfigId, allowSelfAsSubagent) =>
248
+ resolveEffectiveSubagentTargets({
249
+ sessionId,
250
+ canSpawnSubagents: true,
251
+ allowSelfAsSubagent,
252
+ maximumDepthReached: !(await canSpawnSubagentWithDeps(sessionId, sessionAccess.getSession)),
253
+ }, {
254
+ getSession: sessionAccess.getSession,
255
+ listPreconfigs: listSubagentPreconfigsScoped,
256
+ }).then((targets) =>
257
+ allowSelfAsSubagent === true && targets.some((candidate) => candidate.id === preconfigId)),
258
+ guidance: selfDelegationGuidance,
259
+ };
260
+
261
+ const guidance: GuidanceSectionContribution = {
262
+ id: SELF_DELEGATION_SECTION_ID,
263
+ phase: 'identity',
264
+ order: 50,
265
+ provide: (build) => {
266
+ const data = validateContextAssemblyData(build.data);
267
+ return data.selfDelegationAvailable ? service.guidance(data.preconfig.id) : null;
268
+ },
269
+ };
270
+
271
+ context.provide(capekSubagentDomainKey, service);
272
+ context.contributeTool({
273
+ id: SUBAGENT_TOOL_CONTRIBUTION_ID,
274
+ order: SUBAGENT_TOOL_CONTRIBUTION_ORDER,
275
+ definition: {
276
+ name: service.tools[0].name,
277
+ description: service.tools[0].description,
278
+ inputSchema: service.tools[0].inputSchema,
279
+ timeout: 300000,
280
+ [DOMAIN_TOOL_PAYLOAD_FIELD]: service.tools[0],
281
+ } as KernelToolDefinition,
282
+ requiredCapabilities: [capekSubagentDomainKey],
283
+ });
284
+ context.contributeContext(guidance);
285
+ },
286
+ };
287
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Contributed tool catalog.
3
+ *
4
+ * Joins the effective tool contributions of a scope with the payloads
5
+ * carried on those contributions (`ToolContribution.payload`). The resolver
6
+ * re-attaches each contributed definition to its executor and install path
7
+ * by identity, in the deterministic kernel tool order.
8
+ */
9
+
10
+ import type { LoadedTool } from '@capekai/tool';
11
+ import type { CapekPlugin, EffectiveTool, PluginContext, ServiceKey } from '../kernel/types';
12
+ import type { ToolRegistryResolver } from '../tools/registry';
13
+ import { capekToolResolverKey } from './service-keys';
14
+
15
+ /** The narrow surface a contributed resolver reads: effective tools plus
16
+ * optional service resolution. `ScopeHandle` and `PluginContext` both
17
+ * satisfy it. */
18
+ export interface ContributedToolScope {
19
+ listTools(): readonly EffectiveTool[];
20
+ optional<T>(key: ServiceKey<T>): T | undefined;
21
+ }
22
+
23
+ function isLoadedToolPayload(value: unknown): value is LoadedTool {
24
+ if (typeof value !== 'object' || value === null) return false;
25
+ const candidate = value as { definition?: unknown; execute?: unknown };
26
+ return typeof candidate.definition === 'object' && candidate.definition !== null
27
+ && typeof candidate.execute === 'function';
28
+ }
29
+
30
+ /** Builds a `ToolRegistryResolver` from the scope's effective visible tool
31
+ * contributions carrying payloads. Hidden tools are omitted, exactly like
32
+ * the kernel's effective visibility decision. Order follows the
33
+ * deterministic kernel tool order. The payload snapshot is taken lazily on
34
+ * first use, so plugin activation order (the resolver plugin id may sort
35
+ * before payload-contributing plugins) cannot drop contributions. */
36
+ export function createContributedToolResolver(
37
+ scope: ContributedToolScope,
38
+ ): ToolRegistryResolver {
39
+ let loaded: LoadedTool[] | null = null;
40
+ const byName = new Map<string, LoadedTool>();
41
+ const ensureSnapshot = (): void => {
42
+ if (loaded !== null) return;
43
+ const collected: LoadedTool[] = [];
44
+ for (const tool of scope.listTools()) {
45
+ if (!tool.visible) continue;
46
+ const payload = tool.payload;
47
+ if (isLoadedToolPayload(payload) && payload.definition.name === tool.definition.name) {
48
+ collected.push(payload);
49
+ byName.set(payload.definition.name, payload);
50
+ }
51
+ }
52
+ loaded = collected;
53
+ };
54
+ return {
55
+ get(name: string): LoadedTool | null {
56
+ ensureSnapshot();
57
+ return byName.get(name) ?? null;
58
+ },
59
+ list(): LoadedTool[] {
60
+ ensureSnapshot();
61
+ return [...loaded!];
62
+ },
63
+ };
64
+ }
65
+
66
+ /** Agent plugin that provides `capek.tool-resolver` with a resolver built
67
+ * from this scope's effective contributed tool payloads. The resolver stays
68
+ * bound to the owning scope. */
69
+ export function contributedToolResolverPlugin(id: string): CapekPlugin<unknown> {
70
+ return {
71
+ id,
72
+ scope: 'agent',
73
+ provides: [capekToolResolverKey],
74
+ setup(context: PluginContext) {
75
+ context.provide(capekToolResolverKey, createContributedToolResolver(context));
76
+ },
77
+ };
78
+ }
@@ -0,0 +1,52 @@
1
+ import { getHostLayout } from '../runtime/host-layout';
2
+ import type { CapekPlugin, PluginContext, ToolDefinition as KernelToolDefinition } from '../kernel/types';
3
+ import {
4
+ createToolOutputService,
5
+ retrieveToolOutputStandardTool,
6
+ type ToolOutputPolicyOptions,
7
+ } from '../tool-output/policy';
8
+ import { capekToolOutputPolicyKey } from './service-keys';
9
+
10
+ /**
11
+ * C6 provider for the agent-scoped tool-output policy service
12
+ * (`capek.tool-output-policy`). The bounding thresholds and legacy
13
+ * truncation constants translate into provider options here, at
14
+ * composition: there is no current environment source for them, so the
15
+ * exact pre-C6 constants freeze into the service options (the same
16
+ * documented pattern as the generic ask timeout in C6 step 3). The page
17
+ * limits (10k default, 20k max) are mandatory storage invariants and are
18
+ * NOT options. The default provider reproduces the exact envelope,
19
+ * fallback, retrieval, wrap, and truncation behavior; the strict ID
20
+ * validation and session-scoped retrieval invariants stay in the storage
21
+ * layer.
22
+ */
23
+ export function toolOutputPolicyPlugin(id: string, tempRoot?: string): CapekPlugin<unknown> {
24
+ return {
25
+ id,
26
+ scope: 'agent',
27
+ provides: [capekToolOutputPolicyKey],
28
+ setup(context: PluginContext) {
29
+ const options: ToolOutputPolicyOptions = {
30
+ thresholdChars: 50_000,
31
+ previewChars: 10_000,
32
+ retrievalToolName: 'retrieve-tool-output',
33
+ truncationMaxChars: 50_000,
34
+ truncationPreviewChars: 10_000,
35
+ truncationTempDir: tempRoot ?? getHostLayout().toolOutputTempRoot(),
36
+ };
37
+ context.provide(
38
+ capekToolOutputPolicyKey,
39
+ createToolOutputService({ id, options }),
40
+ );
41
+ // The retrieval tool is the tool-output capability's own contribution:
42
+ // it enters the effective catalog through the service it depends on.
43
+ context.contributeTool({
44
+ id: 'tool-output.retrieve-tool-output',
45
+ order: 600,
46
+ definition: retrieveToolOutputStandardTool.definition as KernelToolDefinition,
47
+ payload: retrieveToolOutputStandardTool,
48
+ requiredCapabilities: [capekToolOutputPolicyKey],
49
+ });
50
+ },
51
+ };
52
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Value-bound provider plugin factories. Each factory produces one plugin
3
+ * that provides one C2 service key with the exact supplied value; the plugin
4
+ * declares the key in `provides` so kernel validation and diagnostics see the
5
+ * real ownership. Plugins carry no disposable resources: disposal never
6
+ * closes storage, controllers, or hosts.
7
+ */
8
+
9
+ import type { CapekPlugin, ServiceKey } from '../kernel/types';
10
+ import type { RuntimeConfiguration } from '../configuration/contracts';
11
+ import type { ContextSources } from '../context/sources';
12
+ import {
13
+ connectProvider,
14
+ createModelForProvider,
15
+ disconnectProvider,
16
+ getConnectableProviders,
17
+ getProvider,
18
+ getProviderStatus,
19
+ registerProvider,
20
+ } from '../providers/registry';
21
+ import type { ConnectableProvider } from '../providers/types';
22
+ import type { RuntimeHost } from '../runtime/host';
23
+ import type { SandboxController } from '../sandbox/controller';
24
+ import type { SchedulerHost } from '../scheduler/host';
25
+ import type { SessionSearchHost } from '../session-search/host';
26
+ import type { StorageBundle } from '../storage/contracts';
27
+ import {
28
+ clearCache,
29
+ configureToolsPath,
30
+ getTool,
31
+ listTools,
32
+ scanTools,
33
+ stopWatching,
34
+ watchTools,
35
+ type ToolRegistryResolver,
36
+ } from '../tools/registry';
37
+ import type { WorkspaceToolDiscovery } from '../tools/tool-source';
38
+ import {
39
+ capekContextSourcesKey,
40
+ capekInstalledToolRegistryKey,
41
+ capekProviderOverridesKey,
42
+ capekProviderRegistryKey,
43
+ capekRuntimeConfigurationKey,
44
+ capekRuntimeHostKey,
45
+ capekSandboxControllerKey,
46
+ capekSchedulerHostKey,
47
+ capekSessionSearchHostKey,
48
+ capekStorageKey,
49
+ capekToolResolverKey,
50
+ capekWorkspaceToolDiscoveryKey,
51
+ type InstalledToolRegistryContract,
52
+ type ProviderRegistryContract,
53
+ } from './service-keys';
54
+
55
+ function valuePlugin<T>(id: string, key: ServiceKey<T>, value: T): CapekPlugin<unknown> {
56
+ return {
57
+ id,
58
+ scope: key.scope,
59
+ provides: [key],
60
+ setup(context) {
61
+ context.provide(key, value);
62
+ },
63
+ };
64
+ }
65
+
66
+ export function storageValuePlugin(id: string, storage: StorageBundle): CapekPlugin<unknown> {
67
+ return valuePlugin(id, capekStorageKey, storage);
68
+ }
69
+
70
+ export function runtimeConfigurationValuePlugin(
71
+ id: string,
72
+ configuration: RuntimeConfiguration,
73
+ ): CapekPlugin<unknown> {
74
+ return valuePlugin(id, capekRuntimeConfigurationKey, configuration);
75
+ }
76
+
77
+ export function runtimeHostValuePlugin(id: string, host: RuntimeHost): CapekPlugin<unknown> {
78
+ return valuePlugin(id, capekRuntimeHostKey, host);
79
+ }
80
+
81
+ export function contextSourcesValuePlugin(
82
+ id: string,
83
+ sources: Partial<ContextSources>,
84
+ ): CapekPlugin<unknown> {
85
+ return valuePlugin(id, capekContextSourcesKey, sources);
86
+ }
87
+
88
+ export function workspaceToolDiscoveryValuePlugin(
89
+ id: string,
90
+ discovery: WorkspaceToolDiscovery,
91
+ ): CapekPlugin<unknown> {
92
+ return valuePlugin(id, capekWorkspaceToolDiscoveryKey, discovery);
93
+ }
94
+
95
+ export function toolResolverValuePlugin(id: string, resolver: ToolRegistryResolver): CapekPlugin<unknown> {
96
+ return valuePlugin(id, capekToolResolverKey, resolver);
97
+ }
98
+
99
+ export function sandboxControllerValuePlugin(
100
+ id: string,
101
+ controller: SandboxController,
102
+ ): CapekPlugin<unknown> {
103
+ return valuePlugin(id, capekSandboxControllerKey, controller);
104
+ }
105
+
106
+ export function providerOverridesValuePlugin(
107
+ id: string,
108
+ overrides: ReadonlyMap<string, ConnectableProvider>,
109
+ ): CapekPlugin<unknown> {
110
+ return valuePlugin(id, capekProviderOverridesKey, overrides);
111
+ }
112
+
113
+ /** Process-scope registry provider. Delegates to the current module
114
+ * functions, which read the seeded per-agent overrides exactly like the
115
+ * runtime does today. */
116
+ export function providerRegistryValuePlugin(id: string): CapekPlugin<unknown> {
117
+ const registry: ProviderRegistryContract = {
118
+ registerProvider,
119
+ getProvider,
120
+ getConnectableProviders,
121
+ getProviderStatus,
122
+ connectProvider,
123
+ disconnectProvider,
124
+ createModelForProvider,
125
+ };
126
+ return valuePlugin(id, capekProviderRegistryKey, registry);
127
+ }
128
+
129
+ /** Process-scope installed tool registry provider. Delegates to the current
130
+ * module functions, which read the seeded resolver first. */
131
+ export function installedToolRegistryValuePlugin(id: string): CapekPlugin<unknown> {
132
+ const registry: InstalledToolRegistryContract = {
133
+ getTool,
134
+ listTools,
135
+ scanTools,
136
+ watchTools,
137
+ stopWatching,
138
+ clearCache,
139
+ configureToolsPath,
140
+ };
141
+ return valuePlugin(id, capekInstalledToolRegistryKey, registry);
142
+ }
143
+
144
+ export function sessionSearchHostValuePlugin(id: string, host: SessionSearchHost): CapekPlugin<unknown> {
145
+ return valuePlugin(id, capekSessionSearchHostKey, host);
146
+ }
147
+
148
+ export function schedulerHostValuePlugin(id: string, host: SchedulerHost): CapekPlugin<unknown> {
149
+ return valuePlugin(id, capekSchedulerHostKey, host);
150
+ }