@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,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C2 composition helpers. Scope creation is async (kernel activation);
|
|
3
|
+
* entering a composed agent scope is fully synchronous: every service is
|
|
4
|
+
* resolved and every AsyncLocalStorage accessor is seeded before the
|
|
5
|
+
* callback starts, so no async work runs with unseeded accessors.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { withRuntimeConfiguration } from '../configuration/runtime';
|
|
11
|
+
import { withContextAssembler } from '../context/assembler';
|
|
12
|
+
import { withContextSources } from '../context/sources';
|
|
13
|
+
import { withRetryPolicy } from '../retry/policy';
|
|
14
|
+
import { withCompactionService } from '../compaction/policy';
|
|
15
|
+
import { withAskPermissionPolicy } from '../permission/policy';
|
|
16
|
+
import { withPermissionRuntimeService } from '../permission/runtime';
|
|
17
|
+
import { withWorkspaceService } from '../workspace/policy';
|
|
18
|
+
import { withToolOutputService } from '../tool-output/policy';
|
|
19
|
+
import { withGoalDomain } from '../goals/service';
|
|
20
|
+
import { createAgentScope } from '../kernel/kernel';
|
|
21
|
+
export { createAgentScope, createProcessScope } from '../kernel/kernel';
|
|
22
|
+
import type { AgentScopeHandle, ProcessScopeHandle } from '../kernel/types';
|
|
23
|
+
import { withProviderOverrides } from '../providers/registry';
|
|
24
|
+
import {
|
|
25
|
+
DOMAIN_TOOL_PAYLOAD_FIELD,
|
|
26
|
+
isDomainToolPayload,
|
|
27
|
+
withContributedDomainToolPayloads,
|
|
28
|
+
type DomainToolPayload,
|
|
29
|
+
} from '../runtime/domain-tool-source';
|
|
30
|
+
import { withRuntimeHost, getRuntimeHost, type RuntimeHost } from '../runtime/host';
|
|
31
|
+
import { createStandaloneHost } from '../runtime/standalone-host';
|
|
32
|
+
import { withSandboxController } from '../sandbox/controller';
|
|
33
|
+
import { withStorage } from '../storage/runtime';
|
|
34
|
+
import { withToolRegistryResolver } from '../tools/registry';
|
|
35
|
+
import { withWorkspaceToolDiscovery } from '../tools/tool-source';
|
|
36
|
+
import { createFacadeAgentPlugins, type FacadeScopeValues } from './facade-plugins';
|
|
37
|
+
export { facadeProcessPlugins } from './facade-plugins';
|
|
38
|
+
import { capekGoalDomainKey } from './goal-domain';
|
|
39
|
+
import {
|
|
40
|
+
capekContextAssemblerKey,
|
|
41
|
+
capekContextSourcesKey,
|
|
42
|
+
capekProviderOverridesKey,
|
|
43
|
+
capekRuntimeConfigurationKey,
|
|
44
|
+
capekRuntimeHostKey,
|
|
45
|
+
capekRetryPolicyKey,
|
|
46
|
+
capekCompactionServiceKey,
|
|
47
|
+
capekPermissionPolicyKey,
|
|
48
|
+
capekPermissionRuntimeKey,
|
|
49
|
+
capekWorkspacePolicyKey,
|
|
50
|
+
capekToolOutputPolicyKey,
|
|
51
|
+
capekSandboxControllerKey,
|
|
52
|
+
capekStorageKey,
|
|
53
|
+
capekToolResolverKey,
|
|
54
|
+
capekWorkspaceToolDiscoveryKey,
|
|
55
|
+
} from './service-keys';
|
|
56
|
+
|
|
57
|
+
export interface Composition {
|
|
58
|
+
readonly processScope: ProcessScopeHandle;
|
|
59
|
+
readonly agentScope: AgentScopeHandle;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Composes one agent scope above an explicit process scope using the
|
|
63
|
+
* package's curated plugin set. The C6 policy providers read the ambient
|
|
64
|
+
* runtime host (tool-output temp root) at activation, so composition runs
|
|
65
|
+
* inside `withRuntimeHost`; when no host is configured ambiently, the
|
|
66
|
+
* reference standalone host is installed for the composition's duration.
|
|
67
|
+
* The caller owns both scopes' lifetimes:
|
|
68
|
+
* `await composition.agentScope.dispose()` and
|
|
69
|
+
* `await composition.processScope.dispose()` when done. Multiple agent
|
|
70
|
+
* scopes may share one process scope concurrently. */
|
|
71
|
+
export async function createComposition(
|
|
72
|
+
processScope: ProcessScopeHandle,
|
|
73
|
+
values: FacadeScopeValues,
|
|
74
|
+
): Promise<Composition> {
|
|
75
|
+
let ambient: RuntimeHost | undefined;
|
|
76
|
+
try {
|
|
77
|
+
ambient = getRuntimeHost();
|
|
78
|
+
} catch {
|
|
79
|
+
// No ambient host configured; the reference standalone host covers
|
|
80
|
+
// composition-time activation reads (tool-output temp root).
|
|
81
|
+
ambient = undefined;
|
|
82
|
+
}
|
|
83
|
+
return withRuntimeHost(ambient ?? createStandaloneHost({
|
|
84
|
+
workspace: process.cwd(),
|
|
85
|
+
sandboxActive: false,
|
|
86
|
+
tempRoot: join(tmpdir(), 'capek-composition'),
|
|
87
|
+
}), () =>
|
|
88
|
+
createAgentScope(
|
|
89
|
+
processScope,
|
|
90
|
+
[...createFacadeAgentPlugins(values)],
|
|
91
|
+
).then((agentScope): Composition => ({ processScope, agentScope })));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Synchronously seeds every current accessor from the composed agent scope
|
|
96
|
+
* and then runs the callback. Seeding order is fixed: storage, runtime
|
|
97
|
+
* configuration, runtime host, context sources, provider overrides, optional
|
|
98
|
+
* tool resolver, tool source, sandbox controller, context assembler. The
|
|
99
|
+
* optional resolver layer is omitted when no plugin contributed it,
|
|
100
|
+
* exactly like the unseeded installed-tool path today. The scope's
|
|
101
|
+
* assembler is bound to this scope at composition time and seeded here
|
|
102
|
+
* through the context-assembler ALS runtime, so ordered context assembly
|
|
103
|
+
* always resolves this exact scope, even across async suspensions and
|
|
104
|
+
* interleaved scopes.
|
|
105
|
+
*
|
|
106
|
+
* Contributed domain tool payloads are seeded generically from the scope's
|
|
107
|
+
* visible tool contributions carrying `DOMAIN_TOOL_PAYLOAD_FIELD`; an empty
|
|
108
|
+
* map means a composed scope without domain payloads, which disables the
|
|
109
|
+
* unscoped legacy fallbacks for the callback duration.
|
|
110
|
+
*/
|
|
111
|
+
export function enterAgentScope<T>(scope: AgentScopeHandle, callback: () => T): T {
|
|
112
|
+
const storage = scope.require(capekStorageKey);
|
|
113
|
+
const configuration = scope.require(capekRuntimeConfigurationKey);
|
|
114
|
+
const host = scope.require(capekRuntimeHostKey);
|
|
115
|
+
const retryPolicy = scope.require(capekRetryPolicyKey);
|
|
116
|
+
const compactionService = scope.require(capekCompactionServiceKey);
|
|
117
|
+
const permissionPolicy = scope.require(capekPermissionPolicyKey);
|
|
118
|
+
const permissionRuntime = scope.require(capekPermissionRuntimeKey);
|
|
119
|
+
const workspacePolicy = scope.require(capekWorkspacePolicyKey);
|
|
120
|
+
const toolOutputPolicy = scope.require(capekToolOutputPolicyKey);
|
|
121
|
+
const contextSources = scope.require(capekContextSourcesKey);
|
|
122
|
+
const providerOverrides = scope.require(capekProviderOverridesKey);
|
|
123
|
+
const workspaceToolDiscovery = scope.require(capekWorkspaceToolDiscoveryKey);
|
|
124
|
+
const sandboxController = scope.require(capekSandboxControllerKey);
|
|
125
|
+
const toolResolver = scope.optional(capekToolResolverKey);
|
|
126
|
+
const contextAssembler = scope.require(capekContextAssemblerKey);
|
|
127
|
+
const goalDomain = scope.optional(capekGoalDomainKey);
|
|
128
|
+
|
|
129
|
+
const domainToolPayloads = new Map<string, DomainToolPayload>();
|
|
130
|
+
for (const tool of scope.listTools()) {
|
|
131
|
+
if (!tool.visible) continue;
|
|
132
|
+
const candidate = tool.definition[DOMAIN_TOOL_PAYLOAD_FIELD];
|
|
133
|
+
if (isDomainToolPayload(candidate) && candidate.name === tool.definition.name) {
|
|
134
|
+
domainToolPayloads.set(candidate.name, candidate);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const resolveTools = toolResolver === undefined
|
|
139
|
+
? (inner: () => T): T => withWorkspaceToolDiscovery(workspaceToolDiscovery, () =>
|
|
140
|
+
withSandboxController(sandboxController, inner))
|
|
141
|
+
: (inner: () => T): T => withToolRegistryResolver(toolResolver, () =>
|
|
142
|
+
withWorkspaceToolDiscovery(workspaceToolDiscovery, () =>
|
|
143
|
+
withSandboxController(sandboxController, inner)));
|
|
144
|
+
|
|
145
|
+
const resolveGoalDomain = goalDomain === undefined
|
|
146
|
+
? (inner: () => T): T => inner()
|
|
147
|
+
: (inner: () => T): T => withGoalDomain(goalDomain, inner);
|
|
148
|
+
|
|
149
|
+
return withContributedDomainToolPayloads(domainToolPayloads, () =>
|
|
150
|
+
resolveGoalDomain(() =>
|
|
151
|
+
withContextAssembler(contextAssembler, () =>
|
|
152
|
+
withRetryPolicy(retryPolicy, () =>
|
|
153
|
+
withCompactionService(compactionService, () =>
|
|
154
|
+
withAskPermissionPolicy(permissionPolicy, () =>
|
|
155
|
+
withPermissionRuntimeService(permissionRuntime, () =>
|
|
156
|
+
withWorkspaceService(workspacePolicy, () =>
|
|
157
|
+
withToolOutputService(toolOutputPolicy, () =>
|
|
158
|
+
withStorage(storage, () =>
|
|
159
|
+
withRuntimeConfiguration(configuration, () =>
|
|
160
|
+
withRuntimeHost(host, () =>
|
|
161
|
+
withContextSources(contextSources, () =>
|
|
162
|
+
withProviderOverrides(providerOverrides, () =>
|
|
163
|
+
resolveTools(callback)))))))))))))));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export type {
|
|
167
|
+
AgentScopeHandle,
|
|
168
|
+
CapekPlugin,
|
|
169
|
+
ProcessScopeHandle,
|
|
170
|
+
ToolDefinition,
|
|
171
|
+
} from '../kernel/types';
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateContextAssemblyData,
|
|
3
|
+
type ContextAssembler,
|
|
4
|
+
type ContextAssemblyData,
|
|
5
|
+
} from '../context/assembler';
|
|
6
|
+
import {
|
|
7
|
+
formatInstructions,
|
|
8
|
+
getAgentDirectory,
|
|
9
|
+
loadInstructions,
|
|
10
|
+
readAgentMemoryFile,
|
|
11
|
+
} from '../context/sources';
|
|
12
|
+
import { buildWorkspaceSystemPrompt } from '../context/workspace';
|
|
13
|
+
import type {
|
|
14
|
+
CapekPlugin,
|
|
15
|
+
ContextBuildContext,
|
|
16
|
+
ContextSectionContribution,
|
|
17
|
+
PluginContext,
|
|
18
|
+
ProvidedContextSection,
|
|
19
|
+
} from '../kernel/types';
|
|
20
|
+
import { loadMemoryInstructions } from '../memory';
|
|
21
|
+
import { getHostGuidance } from '../runtime/host-guidance';
|
|
22
|
+
import { getHostLayout } from '../runtime/host-layout';
|
|
23
|
+
import { getWorkspace } from '../storage/runtime';
|
|
24
|
+
import {
|
|
25
|
+
legacySelfDelegationGuidanceSection,
|
|
26
|
+
legacySessionSearchGuidanceSection,
|
|
27
|
+
} from './legacy-system-message';
|
|
28
|
+
import { capekContextAssemblerKey } from './service-keys';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* C3 ordered context contributions.
|
|
32
|
+
*
|
|
33
|
+
* Registers the exact current system-message sections, wrappers, omission
|
|
34
|
+
* rules, and order as kernel context contributions. Byte parity with the
|
|
35
|
+
* fixed builder is preserved because the guidance constants and section
|
|
36
|
+
* formats are shared with `legacy-system-message`, and the assembler joins
|
|
37
|
+
* provided sections with '\n\n' exactly like the fixed builder's append
|
|
38
|
+
* chain, including the empty-prompt artifact (the system-prompt section
|
|
39
|
+
* always provides a string, even when it is empty).
|
|
40
|
+
*
|
|
41
|
+
* The ordered assembler is bound to its owning scope at composition time
|
|
42
|
+
* through the narrow `PluginContext.buildContext` closure: it never resolves
|
|
43
|
+
* an ambient active scope at build time. Two simultaneous agents never share
|
|
44
|
+
* an assembler view, and a captured assembler keeps building exactly its own
|
|
45
|
+
* scope's sections even while another scope is entered.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
type SectionContribution = ContextSectionContribution<ContextAssemblyData>;
|
|
49
|
+
|
|
50
|
+
/** Every contribution receives assembly options through the typed narrow
|
|
51
|
+
* data path and validates them, so malformed data fails predictably instead
|
|
52
|
+
* of surfacing unsafe property access. */
|
|
53
|
+
function requiredData(context: ContextBuildContext<ContextAssemblyData>): ContextAssemblyData {
|
|
54
|
+
return validateContextAssemblyData(context.data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const CURRENT_CONTEXT_SECTION_IDS = [
|
|
58
|
+
'agent-memory',
|
|
59
|
+
'agent-user-preferences',
|
|
60
|
+
'system-prompt',
|
|
61
|
+
'memory-skills-guidance',
|
|
62
|
+
'self-delegation',
|
|
63
|
+
'instructions',
|
|
64
|
+
'workspace',
|
|
65
|
+
'workspace-memory',
|
|
66
|
+
'memory-guidance',
|
|
67
|
+
'skill-management-guidance',
|
|
68
|
+
'session-search-guidance',
|
|
69
|
+
] as const;
|
|
70
|
+
|
|
71
|
+
const CONTEXT_SECTIONS: readonly SectionContribution[] = [
|
|
72
|
+
{
|
|
73
|
+
id: 'system-prompt',
|
|
74
|
+
phase: 'identity',
|
|
75
|
+
order: 30,
|
|
76
|
+
provide: (context) => {
|
|
77
|
+
const data = requiredData(context);
|
|
78
|
+
// Never null: an empty prompt is a real artifact of the fixed builder,
|
|
79
|
+
// and the '\n\n' join must reproduce its exact bytes.
|
|
80
|
+
return data.preconfig.systemPrompt || '';
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'instructions',
|
|
85
|
+
phase: 'instructions',
|
|
86
|
+
order: 10,
|
|
87
|
+
provide: async (context) => {
|
|
88
|
+
const data = requiredData(context);
|
|
89
|
+
const instructions = await loadInstructions(data.workspacePath);
|
|
90
|
+
return formatInstructions(instructions);
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'workspace',
|
|
95
|
+
phase: 'workspace',
|
|
96
|
+
order: 10,
|
|
97
|
+
provide: (context) => {
|
|
98
|
+
const data = requiredData(context);
|
|
99
|
+
return data.workspacePath
|
|
100
|
+
? buildWorkspaceSystemPrompt(data.workspacePath, data.additionalPaths)
|
|
101
|
+
: null;
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
/** The legacy memory and skills contributions, kept for facade and legacy
|
|
107
|
+
* compositions that reproduce the fixed builder byte-for-byte. The C5
|
|
108
|
+
* memory and skills domain plugins own these sections in the current Jean2
|
|
109
|
+
* composition; `createContextSectionsPlugin` includes them only when its
|
|
110
|
+
* `includeMemorySkillsSections` option stays at the legacy default. */
|
|
111
|
+
const LEGACY_MEMORY_SKILLS_SECTIONS: readonly SectionContribution[] = [
|
|
112
|
+
{
|
|
113
|
+
id: 'agent-memory',
|
|
114
|
+
phase: 'identity',
|
|
115
|
+
order: 10,
|
|
116
|
+
provide: async (context) => {
|
|
117
|
+
const data = requiredData(context);
|
|
118
|
+
const agentDir = await getAgentDirectory(data.preconfig.id);
|
|
119
|
+
if (!agentDir) return null;
|
|
120
|
+
const memory = await readAgentMemoryFile(data.preconfig.id, 'MEMORY.md');
|
|
121
|
+
return memory ? `<agent_memory>\n${memory}\n</agent_memory>` : null;
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'agent-user-preferences',
|
|
126
|
+
phase: 'identity',
|
|
127
|
+
order: 20,
|
|
128
|
+
provide: async (context) => {
|
|
129
|
+
const data = requiredData(context);
|
|
130
|
+
const agentDir = await getAgentDirectory(data.preconfig.id);
|
|
131
|
+
if (!agentDir) return null;
|
|
132
|
+
const memory = await readAgentMemoryFile(data.preconfig.id, 'USER.md');
|
|
133
|
+
return memory ? `<agent_user_preferences>\n${memory}\n</agent_user_preferences>` : null;
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'memory-skills-guidance',
|
|
138
|
+
phase: 'identity',
|
|
139
|
+
order: 40,
|
|
140
|
+
provide: async (context) => {
|
|
141
|
+
const data = requiredData(context);
|
|
142
|
+
const agentDir = await getAgentDirectory(data.preconfig.id);
|
|
143
|
+
return agentDir ? getHostGuidance().agentMemorySkills : null;
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'workspace-memory',
|
|
148
|
+
phase: 'workspace',
|
|
149
|
+
order: 20,
|
|
150
|
+
provide: async (context) => {
|
|
151
|
+
const data = requiredData(context);
|
|
152
|
+
if (!data.workspaceId) return null;
|
|
153
|
+
const workspace = await getWorkspace(data.workspaceId);
|
|
154
|
+
if (!workspace?.settings?.memory?.enabled || !data.workspacePath) return null;
|
|
155
|
+
return loadMemoryInstructions(getHostLayout().workspaceMemoryDir(data.workspacePath));
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 'memory-guidance',
|
|
160
|
+
phase: 'workspace',
|
|
161
|
+
order: 30,
|
|
162
|
+
provide: async (context) => {
|
|
163
|
+
const data = requiredData(context);
|
|
164
|
+
if (!data.workspaceId) return null;
|
|
165
|
+
const workspace = await getWorkspace(data.workspaceId);
|
|
166
|
+
return workspace?.settings?.memory?.enabled && data.workspacePath ? getHostGuidance().memory : null;
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: 'skill-management-guidance',
|
|
171
|
+
phase: 'workspace',
|
|
172
|
+
order: 40,
|
|
173
|
+
provide: async (context) => {
|
|
174
|
+
const data = requiredData(context);
|
|
175
|
+
if (!data.workspaceId) return null;
|
|
176
|
+
return (await getWorkspace(data.workspaceId))?.settings?.skills?.managementEnabled
|
|
177
|
+
? getHostGuidance().skillManage
|
|
178
|
+
: null;
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
/** Builds the ordered section list for one scope. Captured through
|
|
184
|
+
* `PluginContext.buildContext` at composition time so the assembler stays
|
|
185
|
+
* bound to the scope that owns it. */
|
|
186
|
+
export type ContextSectionBuilder = (
|
|
187
|
+
data: ContextAssemblyData,
|
|
188
|
+
) => Promise<readonly ProvidedContextSection[]>;
|
|
189
|
+
|
|
190
|
+
/** The ordered assembler: validates the typed assembly options, asks its
|
|
191
|
+
* bound scope for the deterministic kernel-ordered sections, and joins them
|
|
192
|
+
* with the fixed builder's exact '\n\n' separator. */
|
|
193
|
+
export function createOrderedContextAssembler(
|
|
194
|
+
id: string,
|
|
195
|
+
buildSections: ContextSectionBuilder,
|
|
196
|
+
): ContextAssembler {
|
|
197
|
+
return {
|
|
198
|
+
id,
|
|
199
|
+
async build(data: ContextAssemblyData): Promise<string> {
|
|
200
|
+
const validated = validateContextAssemblyData(data);
|
|
201
|
+
const sections = await buildSections(validated);
|
|
202
|
+
return sections.map((section) => section.content).join('\n\n');
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** One plugin provides the required context-assembler service and registers
|
|
208
|
+
* every current section. Facade and current compositions install it under
|
|
209
|
+
* their own deterministic plugin id, so diagnostics stay unambiguous. */
|
|
210
|
+
export function createContextSectionsPlugin(
|
|
211
|
+
id: string,
|
|
212
|
+
options: ContextSectionsPluginOptions = {},
|
|
213
|
+
): CapekPlugin<unknown> {
|
|
214
|
+
const sections: readonly SectionContribution[] = [
|
|
215
|
+
...CONTEXT_SECTIONS,
|
|
216
|
+
...(options.includeMemorySkillsSections === false ? [] : LEGACY_MEMORY_SKILLS_SECTIONS),
|
|
217
|
+
...(options.includeSelfDelegationGuidance === false ? [] : [legacySelfDelegationGuidanceSection]),
|
|
218
|
+
...(options.includeSessionSearchGuidance === false ? [] : [legacySessionSearchGuidanceSection]),
|
|
219
|
+
];
|
|
220
|
+
return {
|
|
221
|
+
id,
|
|
222
|
+
scope: 'agent',
|
|
223
|
+
provides: [capekContextAssemblerKey],
|
|
224
|
+
setup(context: PluginContext) {
|
|
225
|
+
context.provide(
|
|
226
|
+
capekContextAssemblerKey,
|
|
227
|
+
createOrderedContextAssembler(id, (data) => context.buildContext(data)),
|
|
228
|
+
);
|
|
229
|
+
for (const section of sections) {
|
|
230
|
+
context.contributeContext(section);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** C5 ownership options. Defaults (omitted) keep the legacy full behavior
|
|
237
|
+
* including the memory, skills, self-delegation, and session-search
|
|
238
|
+
* guidance sections, so facade and legacy compositions stay byte-identical
|
|
239
|
+
* to the fixed builder. The current Jean2 composition passes false for all
|
|
240
|
+
* of them because the memory, skills, subagent, and session-search domain
|
|
241
|
+
* plugins own those sections there. */
|
|
242
|
+
export interface ContextSectionsPluginOptions {
|
|
243
|
+
includeMemorySkillsSections?: boolean;
|
|
244
|
+
includeSelfDelegationGuidance?: boolean;
|
|
245
|
+
includeSessionSearchGuidance?: boolean;
|
|
246
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CapekPlugin } from '../kernel/types';
|
|
2
|
+
import { DefaultAgentDriver } from '../runtime/default-agent-driver';
|
|
3
|
+
import { capekAgentDriverKey } from './service-keys';
|
|
4
|
+
|
|
5
|
+
export function defaultAgentDriverPlugin(id: string): CapekPlugin<unknown> {
|
|
6
|
+
return {
|
|
7
|
+
id,
|
|
8
|
+
scope: 'agent',
|
|
9
|
+
provides: [capekAgentDriverKey],
|
|
10
|
+
setup(context) {
|
|
11
|
+
context.provide(capekAgentDriverKey, new DefaultAgentDriver());
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facade agent plugins. One facade agent gets its own agent scope whose
|
|
3
|
+
* plugins bind the per-agent values the facade used to seed directly. Every
|
|
4
|
+
* value stays owned by the agent instance, so two simultaneous facade agents
|
|
5
|
+
* never share storage, configuration, host, tool source, resolver, sandbox
|
|
6
|
+
* controller, or provider overrides.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { RuntimeConfiguration } from '../configuration/contracts';
|
|
10
|
+
import type { ContextSources } from '../context/sources';
|
|
11
|
+
import type { LoadedTool } from '@capekai/tool';
|
|
12
|
+
import type { CapekPlugin } from '../kernel/types';
|
|
13
|
+
import type { ConnectableProvider } from '../providers/types';
|
|
14
|
+
import type { RuntimeHost } from '../runtime/host';
|
|
15
|
+
import type { SandboxController } from '../sandbox/controller';
|
|
16
|
+
import type { StorageBundle } from '../storage/contracts';
|
|
17
|
+
import type { ToolRegistryResolver } from '../tools/registry';
|
|
18
|
+
import type { WorkspaceToolDiscovery } from '../tools/tool-source';
|
|
19
|
+
import { getSchedulerHost } from '../scheduler/host';
|
|
20
|
+
import { getSessionSearchHost } from '../session-search/host';
|
|
21
|
+
import { createContextSectionsPlugin } from './context-sections';
|
|
22
|
+
import { loadedToolsPlugin } from './loaded-tools';
|
|
23
|
+
import { retryPolicyPlugin } from './retry-policy';
|
|
24
|
+
import { compactionPolicyPlugin } from './compaction-policy';
|
|
25
|
+
import { permissionPolicyPlugin } from './permission-policy';
|
|
26
|
+
import { workspacePolicyPlugin } from './workspace-policy';
|
|
27
|
+
import { toolOutputPolicyPlugin } from './tool-output-policy';
|
|
28
|
+
import { defaultAgentDriverPlugin } from './default-agent-driver';
|
|
29
|
+
import { contributedToolResolverPlugin } from './tool-catalog';
|
|
30
|
+
import {
|
|
31
|
+
contextSourcesValuePlugin,
|
|
32
|
+
providerOverridesValuePlugin,
|
|
33
|
+
runtimeConfigurationValuePlugin,
|
|
34
|
+
runtimeHostValuePlugin,
|
|
35
|
+
sandboxControllerValuePlugin,
|
|
36
|
+
storageValuePlugin,
|
|
37
|
+
toolResolverValuePlugin,
|
|
38
|
+
workspaceToolDiscoveryValuePlugin,
|
|
39
|
+
installedToolRegistryValuePlugin,
|
|
40
|
+
providerRegistryValuePlugin,
|
|
41
|
+
schedulerHostValuePlugin,
|
|
42
|
+
sessionSearchHostValuePlugin,
|
|
43
|
+
} from './value-plugins';
|
|
44
|
+
|
|
45
|
+
export const FACADE_PROCESS_PLUGIN_IDS = [
|
|
46
|
+
'facade.provider-registry',
|
|
47
|
+
'facade.installed-tool-registry',
|
|
48
|
+
'facade.session-search-host',
|
|
49
|
+
'facade.scheduler-host',
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
export function facadeProcessPlugins(): readonly CapekPlugin<unknown>[] {
|
|
53
|
+
return [
|
|
54
|
+
providerRegistryValuePlugin('facade.provider-registry'),
|
|
55
|
+
installedToolRegistryValuePlugin('facade.installed-tool-registry'),
|
|
56
|
+
sessionSearchHostValuePlugin('facade.session-search-host', getSessionSearchHost()),
|
|
57
|
+
schedulerHostValuePlugin('facade.scheduler-host', getSchedulerHost()),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface FacadeScopeValues {
|
|
62
|
+
storage: StorageBundle;
|
|
63
|
+
configuration: RuntimeConfiguration;
|
|
64
|
+
host: RuntimeHost;
|
|
65
|
+
contextSources: Partial<ContextSources>;
|
|
66
|
+
workspaceToolDiscovery: WorkspaceToolDiscovery;
|
|
67
|
+
/** Optional compatibility resolver. When omitted, the facade
|
|
68
|
+
* composition derives the resolver from the composed scope's effective
|
|
69
|
+
* contributed tool payloads. The explicit value is the rollback
|
|
70
|
+
* path and the C2 test seam. */
|
|
71
|
+
toolResolver?: ToolRegistryResolver;
|
|
72
|
+
/** Host-supplied plugins appended after the facade's own (external tool
|
|
73
|
+
* contributions land here). */
|
|
74
|
+
profilePlugins?: readonly CapekPlugin<unknown>[];
|
|
75
|
+
/** Convenience: loaded tools contributed by one generated plugin, as with
|
|
76
|
+
* the former `createAgent({ tools })` option. Equivalent to passing
|
|
77
|
+
* `loadedToolsPlugin('facade.loaded-tools', tools)` in profilePlugins. */
|
|
78
|
+
loadedTools?: readonly LoadedTool[];
|
|
79
|
+
sandboxController: SandboxController;
|
|
80
|
+
providerOverrides: ReadonlyMap<string, ConnectableProvider>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const FACADE_AGENT_PLUGIN_IDS = [
|
|
84
|
+
'facade.storage',
|
|
85
|
+
'facade.runtime-configuration',
|
|
86
|
+
'facade.runtime-host',
|
|
87
|
+
'facade.agent-driver',
|
|
88
|
+
'facade.retry-policy',
|
|
89
|
+
'facade.compaction-policy',
|
|
90
|
+
'facade.permission-policy',
|
|
91
|
+
'facade.workspace-policy',
|
|
92
|
+
'facade.tool-output-policy',
|
|
93
|
+
'facade.context-sources',
|
|
94
|
+
'facade.context-sections',
|
|
95
|
+
'facade.workspace-tool-discovery',
|
|
96
|
+
'facade.tool-resolver',
|
|
97
|
+
'facade.sandbox-controller',
|
|
98
|
+
'facade.provider-overrides',
|
|
99
|
+
] as const;
|
|
100
|
+
|
|
101
|
+
export function createFacadeAgentPlugins(values: FacadeScopeValues): readonly CapekPlugin<unknown>[] {
|
|
102
|
+
return [
|
|
103
|
+
storageValuePlugin('facade.storage', values.storage),
|
|
104
|
+
runtimeConfigurationValuePlugin('facade.runtime-configuration', values.configuration),
|
|
105
|
+
runtimeHostValuePlugin('facade.runtime-host', values.host),
|
|
106
|
+
defaultAgentDriverPlugin('facade.agent-driver'),
|
|
107
|
+
// C6: the agent scope owns the retry policy (and its circuit state)
|
|
108
|
+
// instead of the facade's pre-C6 per-agent withRetryCircuitState wrap.
|
|
109
|
+
retryPolicyPlugin('facade.retry-policy'),
|
|
110
|
+
compactionPolicyPlugin('facade.compaction-policy'),
|
|
111
|
+
permissionPolicyPlugin('facade.permission-policy'),
|
|
112
|
+
workspacePolicyPlugin('facade.workspace-policy'),
|
|
113
|
+
toolOutputPolicyPlugin('facade.tool-output-policy'),
|
|
114
|
+
contextSourcesValuePlugin('facade.context-sources', values.contextSources),
|
|
115
|
+
// Facade context parity: the facade keeps the legacy self-delegation and
|
|
116
|
+
// session-search guidance sections (the C5 domain plugins own them only
|
|
117
|
+
// in the current Jean2 composition), so context-sections stays at its
|
|
118
|
+
// pre-C5 defaults here.
|
|
119
|
+
createContextSectionsPlugin('facade.context-sections'),
|
|
120
|
+
workspaceToolDiscoveryValuePlugin('facade.workspace-tool-discovery', values.workspaceToolDiscovery),
|
|
121
|
+
values.toolResolver === undefined
|
|
122
|
+
? contributedToolResolverPlugin('facade.tool-resolver')
|
|
123
|
+
: toolResolverValuePlugin('facade.tool-resolver', values.toolResolver),
|
|
124
|
+
sandboxControllerValuePlugin('facade.sandbox-controller', values.sandboxController),
|
|
125
|
+
providerOverridesValuePlugin('facade.provider-overrides', values.providerOverrides),
|
|
126
|
+
...(values.loadedTools?.length ? [loadedToolsPlugin('facade.loaded-tools', values.loadedTools)] : []),
|
|
127
|
+
...(values.profilePlugins ?? []),
|
|
128
|
+
];
|
|
129
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { serviceKey } from '../kernel/service-key';
|
|
2
|
+
import type { CapekPlugin, PluginContext } from '../kernel/types';
|
|
3
|
+
import type { Session } from '@capekai/types';
|
|
4
|
+
import type { RuntimeHost } from '../runtime/host';
|
|
5
|
+
import type { StorageBundle } from '../storage/contracts';
|
|
6
|
+
import type { GoalDomainService } from '../goals/service';
|
|
7
|
+
import {
|
|
8
|
+
evaluateGoalWithDeps,
|
|
9
|
+
runGoalLoopWithDeps,
|
|
10
|
+
type GoalEvaluatorDeps,
|
|
11
|
+
type GoalLoopDeps,
|
|
12
|
+
} from '../goals';
|
|
13
|
+
import {
|
|
14
|
+
capekOrchestratorSessionKey,
|
|
15
|
+
capekRuntimeHostKey,
|
|
16
|
+
capekStorageKey,
|
|
17
|
+
type OrchestratorSessionContract,
|
|
18
|
+
} from './service-keys';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* C5 goal domain plugin. Owns the agent-scoped `capek.goal-domain` service:
|
|
22
|
+
* goal evaluation and the persistent goal loop run directive over the
|
|
23
|
+
* scope-captured storage bundle and the shared `capek.orchestrator-session`
|
|
24
|
+
* contract. No model-facing goal tool exists in the product (goal mode is a
|
|
25
|
+
* client session directive through `handleChat`), so the domain contributes
|
|
26
|
+
* no tool and no context section. Live adoption: `core/chat-handler.ts`
|
|
27
|
+
* resolves this service through `getGoalDomain()`; the unscoped fallback in
|
|
28
|
+
* `goals/service.ts` keeps the module path for uncomposed consumers.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export const CURRENT_GOAL_DOMAIN_PLUGIN_ID = 'current.goal-domain';
|
|
32
|
+
|
|
33
|
+
export type { GoalDomainService };
|
|
34
|
+
|
|
35
|
+
export const capekGoalDomainKey = serviceKey<GoalDomainService>(
|
|
36
|
+
'capek.goal-domain',
|
|
37
|
+
'agent',
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
function sessionUpdatedBroadcast(host: RuntimeHost): (session: Session) => void {
|
|
41
|
+
return (session) => {
|
|
42
|
+
const delivery = {
|
|
43
|
+
event: { kind: 'session', action: 'updated', session } as const,
|
|
44
|
+
audience: { scope: 'global' } as const,
|
|
45
|
+
};
|
|
46
|
+
host.delivery.observe?.(delivery);
|
|
47
|
+
host.delivery.emit(delivery);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function goalDomainPlugin(id: string): CapekPlugin<unknown> {
|
|
52
|
+
return {
|
|
53
|
+
id,
|
|
54
|
+
scope: 'agent',
|
|
55
|
+
provides: [capekGoalDomainKey],
|
|
56
|
+
requires: [capekStorageKey, capekOrchestratorSessionKey, capekRuntimeHostKey],
|
|
57
|
+
setup(context: PluginContext) {
|
|
58
|
+
const storage: StorageBundle = context.require(capekStorageKey);
|
|
59
|
+
const orchestrator: OrchestratorSessionContract = context.require(capekOrchestratorSessionKey);
|
|
60
|
+
const host: RuntimeHost = context.require(capekRuntimeHostKey);
|
|
61
|
+
|
|
62
|
+
const evaluatorDeps: GoalEvaluatorDeps = {
|
|
63
|
+
listTranscript: (sessionId) => storage.conversation.listMessagesWithParts(sessionId),
|
|
64
|
+
orchestrator,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const loopDeps: GoalLoopDeps = {
|
|
68
|
+
getSession: (sessionId) => storage.conversation.getSession(sessionId),
|
|
69
|
+
updateSession: (sessionId, updates) => storage.conversation.updateSession(sessionId, updates),
|
|
70
|
+
evaluate: (evaluateOptions) => evaluateGoalWithDeps(evaluateOptions, evaluatorDeps),
|
|
71
|
+
broadcastSessionUpdatedDefault: sessionUpdatedBroadcast(host),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const service: GoalDomainService = {
|
|
75
|
+
evaluateGoal: (options) => evaluateGoalWithDeps(options, evaluatorDeps),
|
|
76
|
+
runGoalLoop: (options) => runGoalLoopWithDeps(options, loopDeps),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
context.provide(capekGoalDomainKey, service);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|