@cjhyy/code-shell-core 0.8.11 → 0.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities/index.d.ts +5 -54
- package/dist/capabilities/index.js +1 -80
- package/dist/cli/agent-server-stdio.js +21 -21
- package/dist/composition/compiler.d.ts +7 -0
- package/dist/composition/compiler.js +247 -0
- package/dist/composition/core-module.d.ts +10 -0
- package/dist/composition/core-module.js +19 -0
- package/dist/composition/index.d.ts +5 -0
- package/dist/composition/index.js +5 -0
- package/dist/composition/protocol-attach.d.ts +15 -0
- package/dist/composition/protocol-attach.js +21 -0
- package/dist/composition/resolve-preset.d.ts +35 -0
- package/dist/composition/resolve-preset.js +58 -0
- package/dist/composition/snapshot.d.ts +9 -0
- package/dist/composition/snapshot.js +48 -0
- package/dist/composition/types.d.ts +169 -0
- package/dist/composition/types.js +1 -0
- package/dist/engine/engine.d.ts +2 -1
- package/dist/engine/engine.js +54 -56
- package/dist/engine/subagent-spawner.js +2 -2
- package/dist/engine/types.d.ts +9 -6
- package/dist/exceptions.d.ts +8 -0
- package/dist/exceptions.js +11 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.extension.d.ts +3 -3
- package/dist/index.extension.js +0 -1
- package/dist/index.js +6 -6
- package/dist/preset/index.d.ts +19 -26
- package/dist/preset/index.js +26 -66
- package/dist/product/define.js +8 -2
- package/dist/prompt/section-loader.d.ts +2 -8
- package/dist/prompt/section-loader.js +4 -17
- package/dist/protocol/client.d.ts +1 -0
- package/dist/protocol/server.d.ts +10 -11
- package/dist/protocol/server.js +33 -28
- package/dist/protocol/types.d.ts +5 -0
- package/dist/run/EngineRunner.d.ts +3 -2
- package/dist/run/EngineRunner.js +1 -1
- package/dist/run/RunManager.d.ts +3 -3
- package/dist/run/RunManager.js +6 -8
- package/dist/run/factory.d.ts +3 -3
- package/dist/run/factory.js +2 -2
- package/dist/session/session-manager.d.ts +1 -1
- package/dist/session/session-manager.js +3 -6
- package/dist/tool-system/capability-module.d.ts +0 -34
- package/dist/tool-system/capability-module.js +1 -53
- package/package.json +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ConfigError } from "../exceptions.js";
|
|
2
|
+
/** Resolve a preset by name (or the composition default), failing loud. */
|
|
3
|
+
export function resolvePresetFromComposition(composition, name) {
|
|
4
|
+
const resolvedName = name || composition.engine.defaultPreset;
|
|
5
|
+
const found = composition.engine.presets.find((p) => p.key === resolvedName);
|
|
6
|
+
if (found)
|
|
7
|
+
return found.value;
|
|
8
|
+
const allowed = composition.engine.presets.map((p) => p.key).join(", ");
|
|
9
|
+
throw new Error(`Unknown agent preset "${resolvedName}". Available presets: ${allowed}`);
|
|
10
|
+
}
|
|
11
|
+
/** All preset-tags tools — the composed catalog in effective order. */
|
|
12
|
+
export function compositionToolCatalog(composition) {
|
|
13
|
+
return composition.engine.tools.flatMap((t) => (t.kind === "preset-tags" ? [t.tool] : []));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Preset-tags tools force-joined to the ACTIVE preset regardless of its name.
|
|
17
|
+
* Rule: tools owned by modules that contribute no presets (pet-style catalog
|
|
18
|
+
* tools) — presets snapshot their tool lists from catalogs known at module
|
|
19
|
+
* authoring time, which can never include such packages. Modules that DO
|
|
20
|
+
* contribute presets (core, coding) reference their tools via preset tags
|
|
21
|
+
* already. Visibility stays gated by each tool's exposure.availability.
|
|
22
|
+
*/
|
|
23
|
+
export function presetInjectedTools(composition) {
|
|
24
|
+
const presetOwners = new Set(composition.engine.presets.map((p) => p.moduleId));
|
|
25
|
+
return composition.engine.tools.flatMap((t) => t.kind === "preset-tags" && !presetOwners.has(t.moduleId) ? [t.tool] : []);
|
|
26
|
+
}
|
|
27
|
+
/** Module-contributed named prompt sections as a plain record. */
|
|
28
|
+
export function compositionPromptSections(composition) {
|
|
29
|
+
return Object.fromEntries(composition.engine.promptSections.map((s) => [s.key, s.value]));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register always-exposure tools on the engine-local registry fork.
|
|
33
|
+
* Cross-module uniqueness is compiler-enforced; this guards collisions with
|
|
34
|
+
* runtime-registered tools.
|
|
35
|
+
*/
|
|
36
|
+
export function registerAlwaysTools(composition, registry) {
|
|
37
|
+
for (const contribution of composition.engine.tools) {
|
|
38
|
+
if (contribution.kind !== "always")
|
|
39
|
+
continue;
|
|
40
|
+
const name = contribution.tool.definition.name;
|
|
41
|
+
if (registry.hasTool(name)) {
|
|
42
|
+
throw new ConfigError(`Capability tool conflicts with registered tool: ${name}`, {
|
|
43
|
+
duplicateCapabilityTool: name,
|
|
44
|
+
capabilityId: contribution.moduleId,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
registry.registerTool(contribution.tool.definition, contribution.tool.execute);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** First non-null module instruction boundary, in module order. */
|
|
51
|
+
export function resolveCompositionInstructionBoundary(composition, cwd) {
|
|
52
|
+
for (const boundary of composition.engine.instructionBoundaries) {
|
|
53
|
+
const found = boundary.value(cwd);
|
|
54
|
+
if (found)
|
|
55
|
+
return found;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CompositionSnapshot, ResolvedComposition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Pure-data projection of a composition. Field construction order is the
|
|
4
|
+
* canonical serialization order — computeCompositionDigest() hashes the
|
|
5
|
+
* JSON directly, so never reorder fields without updating golden fixtures.
|
|
6
|
+
* Unkeyed by design: the snapshot carries no secrets (design §11.2).
|
|
7
|
+
*/
|
|
8
|
+
export declare function toCompositionSnapshot(composition: Pick<ResolvedComposition, "modules" | "engine" | "protocol">): CompositionSnapshot;
|
|
9
|
+
export declare function computeCompositionDigest(snapshot: CompositionSnapshot): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Pure-data projection of a composition. Field construction order is the
|
|
4
|
+
* canonical serialization order — computeCompositionDigest() hashes the
|
|
5
|
+
* JSON directly, so never reorder fields without updating golden fixtures.
|
|
6
|
+
* Unkeyed by design: the snapshot carries no secrets (design §11.2).
|
|
7
|
+
*/
|
|
8
|
+
export function toCompositionSnapshot(composition) {
|
|
9
|
+
return {
|
|
10
|
+
version: 1,
|
|
11
|
+
modules: composition.modules.map((m) => ({ id: m.id, order: m.order, source: m.source })),
|
|
12
|
+
tools: composition.engine.tools.map((t) => ({
|
|
13
|
+
name: t.tool.definition.name,
|
|
14
|
+
moduleId: t.moduleId,
|
|
15
|
+
exposure: t.kind,
|
|
16
|
+
presetTags: t.kind === "preset-tags" ? [...t.tool.exposure.presetTags] : [],
|
|
17
|
+
})),
|
|
18
|
+
presets: composition.engine.presets.map((p) => ({
|
|
19
|
+
name: p.key,
|
|
20
|
+
moduleId: p.moduleId,
|
|
21
|
+
isDefault: p.key === composition.engine.defaultPreset,
|
|
22
|
+
})),
|
|
23
|
+
promptSections: composition.engine.promptSections.map((s) => ({
|
|
24
|
+
name: s.key,
|
|
25
|
+
moduleId: s.moduleId,
|
|
26
|
+
})),
|
|
27
|
+
hooks: composition.engine.hooks.map((h) => ({
|
|
28
|
+
event: h.event,
|
|
29
|
+
name: h.name,
|
|
30
|
+
priority: h.priority,
|
|
31
|
+
moduleId: h.moduleId,
|
|
32
|
+
})),
|
|
33
|
+
behaviorProfiles: composition.engine.behaviorProfiles.map((p) => ({
|
|
34
|
+
id: p.key,
|
|
35
|
+
moduleId: p.moduleId,
|
|
36
|
+
})),
|
|
37
|
+
queries: composition.protocol.queries.map((q) => ({ type: q.key, moduleId: q.moduleId })),
|
|
38
|
+
observers: composition.protocol.observerFactories.map((o) => o.moduleId),
|
|
39
|
+
runValidators: composition.protocol.runValidators.map((v) => v.moduleId),
|
|
40
|
+
hiddenSessionKinds: composition.protocol.hiddenSessionKinds.map((k) => ({
|
|
41
|
+
kind: k.key,
|
|
42
|
+
moduleId: k.moduleId,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function computeCompositionDigest(snapshot) {
|
|
47
|
+
return createHash("sha256").update(JSON.stringify(snapshot)).digest("hex");
|
|
48
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentModule — the single trusted product-module interface that unifies
|
|
3
|
+
* CapabilityModule and ExtensionModule (design:
|
|
4
|
+
* docs/todo/agent-module-resolved-composition-design.md). Phase A only adds
|
|
5
|
+
* the types and the pure compiler; no production path consumes them yet.
|
|
6
|
+
*/
|
|
7
|
+
import type { CapabilityArtifactDetector, CapabilityDynamicContextProvider, CapabilityEngineHookContribution, CapabilityFileHistoryContribution, CapabilityInstructionBoundaryFinder, CapabilityToolSelectionContext, CapabilityToolServiceHost, SessionWorkspaceCapability } from "../capabilities/index.js";
|
|
8
|
+
import type { AgentPreset } from "../preset/index.js";
|
|
9
|
+
import type { BuiltinTool } from "../tool-system/builtin/index.js";
|
|
10
|
+
import type { ExtensionQueryHandler, ExtensionTool, ProtocolObserver, ProtocolObserverHost } from "../tool-system/capability-module.js";
|
|
11
|
+
import type { RunBehaviorProfile } from "../engine/run-types.js";
|
|
12
|
+
import type { HookEventName } from "../hooks/events.js";
|
|
13
|
+
/**
|
|
14
|
+
* One tool contribution with explicit exposure:
|
|
15
|
+
* - "preset-tags": full BuiltinTool metadata; joins the composed catalog.
|
|
16
|
+
* - "always": plain ExtensionTool; registered directly, always visible.
|
|
17
|
+
*/
|
|
18
|
+
export type AgentModuleToolContribution = {
|
|
19
|
+
readonly kind: "preset-tags";
|
|
20
|
+
readonly tool: BuiltinTool;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: "always";
|
|
23
|
+
readonly tool: ExtensionTool;
|
|
24
|
+
};
|
|
25
|
+
export interface AgentEngineContributions {
|
|
26
|
+
readonly tools?: readonly AgentModuleToolContribution[];
|
|
27
|
+
readonly presets?: readonly AgentPreset[];
|
|
28
|
+
/** Preset used when the host does not choose one. At most one module may declare it. */
|
|
29
|
+
readonly defaultPreset?: string;
|
|
30
|
+
readonly promptSections?: Readonly<Record<string, string>>;
|
|
31
|
+
readonly dynamicContextProviders?: readonly CapabilityDynamicContextProvider[];
|
|
32
|
+
readonly instructionBoundary?: CapabilityInstructionBoundaryFinder;
|
|
33
|
+
readonly artifactDetectors?: readonly CapabilityArtifactDetector[];
|
|
34
|
+
readonly fileHistory?: readonly CapabilityFileHistoryContribution[];
|
|
35
|
+
readonly sessionWorkspace?: SessionWorkspaceCapability;
|
|
36
|
+
readonly hooks?: readonly CapabilityEngineHookContribution[];
|
|
37
|
+
readonly behaviorProfiles?: readonly RunBehaviorProfile[];
|
|
38
|
+
readonly adjustToolSelection?: (names: Set<string>, context: CapabilityToolSelectionContext) => void;
|
|
39
|
+
/** Phase C renames this to privateService with owned lifetime. */
|
|
40
|
+
readonly createToolService?: (host: CapabilityToolServiceHost) => unknown;
|
|
41
|
+
}
|
|
42
|
+
export interface AgentProtocolContributions {
|
|
43
|
+
readonly queries?: Readonly<Record<string, ExtensionQueryHandler>>;
|
|
44
|
+
/** Existing name createProtocolObserver; renamed here by design. */
|
|
45
|
+
readonly createObserver?: (host: ProtocolObserverHost) => ProtocolObserver;
|
|
46
|
+
readonly validateRunParams?: (params: Record<string, unknown>) => string | null;
|
|
47
|
+
readonly hiddenSessionKinds?: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
export interface AgentModule {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly engine?: AgentEngineContributions;
|
|
52
|
+
readonly protocol?: AgentProtocolContributions;
|
|
53
|
+
}
|
|
54
|
+
export interface ResolvedModule {
|
|
55
|
+
readonly id: string;
|
|
56
|
+
readonly order: number;
|
|
57
|
+
readonly source: "core" | "host";
|
|
58
|
+
}
|
|
59
|
+
export interface ResolvedContribution<T> {
|
|
60
|
+
readonly key: string;
|
|
61
|
+
readonly moduleId: string;
|
|
62
|
+
readonly value: T;
|
|
63
|
+
}
|
|
64
|
+
export type ResolvedToolContribution = {
|
|
65
|
+
readonly kind: "preset-tags";
|
|
66
|
+
readonly moduleId: string;
|
|
67
|
+
readonly tool: BuiltinTool;
|
|
68
|
+
} | {
|
|
69
|
+
readonly kind: "always";
|
|
70
|
+
readonly moduleId: string;
|
|
71
|
+
readonly tool: ExtensionTool;
|
|
72
|
+
};
|
|
73
|
+
export interface ResolvedEngineHook {
|
|
74
|
+
readonly moduleId: string;
|
|
75
|
+
readonly event: HookEventName;
|
|
76
|
+
readonly handler: CapabilityEngineHookContribution["handler"];
|
|
77
|
+
readonly priority: number;
|
|
78
|
+
readonly name: string;
|
|
79
|
+
}
|
|
80
|
+
export interface ResolvedEngineComposition {
|
|
81
|
+
/**
|
|
82
|
+
* Effective registry order: every preset-tags tool (module order) first,
|
|
83
|
+
* then every always tool (module order) — mirrors the current engine's
|
|
84
|
+
* composeToolCatalog() + registerExtensionModules() sequence.
|
|
85
|
+
*/
|
|
86
|
+
readonly tools: readonly ResolvedToolContribution[];
|
|
87
|
+
readonly presets: readonly ResolvedContribution<AgentPreset>[];
|
|
88
|
+
readonly defaultPreset: string;
|
|
89
|
+
readonly promptSections: readonly ResolvedContribution<string>[];
|
|
90
|
+
readonly dynamicContextProviders: readonly ResolvedContribution<CapabilityDynamicContextProvider>[];
|
|
91
|
+
readonly instructionBoundaries: readonly ResolvedContribution<CapabilityInstructionBoundaryFinder>[];
|
|
92
|
+
readonly artifactDetectors: readonly ResolvedContribution<CapabilityArtifactDetector>[];
|
|
93
|
+
readonly fileHistory: readonly ResolvedContribution<CapabilityFileHistoryContribution>[];
|
|
94
|
+
readonly sessionWorkspaces: readonly ResolvedContribution<SessionWorkspaceCapability>[];
|
|
95
|
+
readonly hooks: readonly ResolvedEngineHook[];
|
|
96
|
+
readonly behaviorProfiles: readonly ResolvedContribution<RunBehaviorProfile>[];
|
|
97
|
+
readonly toolSelectionAdjusters: readonly ResolvedContribution<NonNullable<AgentEngineContributions["adjustToolSelection"]>>[];
|
|
98
|
+
readonly toolServices: readonly ResolvedContribution<NonNullable<AgentEngineContributions["createToolService"]>>[];
|
|
99
|
+
}
|
|
100
|
+
export interface ResolvedProtocolComposition {
|
|
101
|
+
readonly queries: readonly ResolvedContribution<ExtensionQueryHandler>[];
|
|
102
|
+
readonly observerFactories: readonly ResolvedContribution<(host: ProtocolObserverHost) => ProtocolObserver>[];
|
|
103
|
+
readonly runValidators: readonly ResolvedContribution<(params: Record<string, unknown>) => string | null>[];
|
|
104
|
+
readonly hiddenSessionKinds: readonly ResolvedContribution<string>[];
|
|
105
|
+
}
|
|
106
|
+
export interface CompositionDiagnostic {
|
|
107
|
+
readonly code: "empty_module" | "engine_only_module" | "protocol_only_module" | "core_preset_shadowed";
|
|
108
|
+
readonly moduleId: string;
|
|
109
|
+
readonly message: string;
|
|
110
|
+
}
|
|
111
|
+
export interface ResolvedComposition {
|
|
112
|
+
readonly version: 1;
|
|
113
|
+
readonly digest: string;
|
|
114
|
+
readonly modules: readonly ResolvedModule[];
|
|
115
|
+
readonly engine: ResolvedEngineComposition;
|
|
116
|
+
readonly protocol: ResolvedProtocolComposition;
|
|
117
|
+
readonly diagnostics: readonly CompositionDiagnostic[];
|
|
118
|
+
}
|
|
119
|
+
export interface CompileCompositionOptions {
|
|
120
|
+
/** Defaults to CORE_AGENT_MODULE. Overridable only for unit tests. */
|
|
121
|
+
readonly core?: AgentModule;
|
|
122
|
+
readonly modules?: readonly AgentModule[];
|
|
123
|
+
/** Module ids the host requires; missing ids are a compile error. */
|
|
124
|
+
readonly expectedModules?: readonly string[];
|
|
125
|
+
}
|
|
126
|
+
/** Pure-data projection; never contains functions, prompt bodies or paths. */
|
|
127
|
+
export interface CompositionSnapshot {
|
|
128
|
+
version: 1;
|
|
129
|
+
modules: Array<{
|
|
130
|
+
id: string;
|
|
131
|
+
order: number;
|
|
132
|
+
source: string;
|
|
133
|
+
}>;
|
|
134
|
+
tools: Array<{
|
|
135
|
+
name: string;
|
|
136
|
+
moduleId: string;
|
|
137
|
+
exposure: "preset-tags" | "always";
|
|
138
|
+
presetTags: string[];
|
|
139
|
+
}>;
|
|
140
|
+
presets: Array<{
|
|
141
|
+
name: string;
|
|
142
|
+
moduleId: string;
|
|
143
|
+
isDefault: boolean;
|
|
144
|
+
}>;
|
|
145
|
+
promptSections: Array<{
|
|
146
|
+
name: string;
|
|
147
|
+
moduleId: string;
|
|
148
|
+
}>;
|
|
149
|
+
hooks: Array<{
|
|
150
|
+
event: string;
|
|
151
|
+
name: string;
|
|
152
|
+
priority: number;
|
|
153
|
+
moduleId: string;
|
|
154
|
+
}>;
|
|
155
|
+
behaviorProfiles: Array<{
|
|
156
|
+
id: string;
|
|
157
|
+
moduleId: string;
|
|
158
|
+
}>;
|
|
159
|
+
queries: Array<{
|
|
160
|
+
type: string;
|
|
161
|
+
moduleId: string;
|
|
162
|
+
}>;
|
|
163
|
+
observers: string[];
|
|
164
|
+
runValidators: string[];
|
|
165
|
+
hiddenSessionKinds: Array<{
|
|
166
|
+
kind: string;
|
|
167
|
+
moduleId: string;
|
|
168
|
+
}>;
|
|
169
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/engine/engine.d.ts
CHANGED
|
@@ -83,7 +83,8 @@ export declare class Engine {
|
|
|
83
83
|
private runtimeToolRegistry;
|
|
84
84
|
/** Engine-local view containing only this Engine's capability modules. */
|
|
85
85
|
private toolRegistry;
|
|
86
|
-
|
|
86
|
+
/** Compiled module contributions — the single composition fact source. */
|
|
87
|
+
private readonly composition;
|
|
87
88
|
private readonly toolCatalog;
|
|
88
89
|
private readonly toolGuards;
|
|
89
90
|
/** Per-turn dynamic definition rewriters contributed by builtin exposures. */
|
package/dist/engine/engine.js
CHANGED
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { createLLMClient } from "../llm/client-factory.js";
|
|
5
5
|
import { ToolRegistry } from "../tool-system/registry.js";
|
|
6
|
-
import { queryExtensionModules, registerExtensionModules, } from "../tool-system/capability-module.js";
|
|
7
6
|
import { readLastTodoSnapshot } from "../tool-system/builtin/task.js";
|
|
8
7
|
import { getMergedCatalog } from "../model-catalog/index.js";
|
|
9
8
|
import { modelEntriesFromConnections } from "./model-connections-pool.js";
|
|
10
9
|
import { cumulativeCacheHitRate, foldRunUsage, normalizeCumulativeUsageCounters, } from "../session/usage.js";
|
|
11
10
|
import { enqueueSteerItem, consumeSteerItems, removeSteerItem, } from "./steer-queue.js";
|
|
12
11
|
import { RunEnvironmentResolver } from "./run-environment.js";
|
|
13
|
-
import { BUILTIN_TOOLS, } from "../tool-system/builtin/index.js";
|
|
14
12
|
import { asyncAgentRegistry } from "../tool-system/builtin/agent-registry.js";
|
|
15
13
|
import { skillToolDef } from "../tool-system/builtin/skill.js";
|
|
16
14
|
import { backgroundShellManager } from "../runtime/background-shell.js";
|
|
@@ -35,8 +33,10 @@ import { resolveFeatureFlags, } from "../settings/feature-flags.js";
|
|
|
35
33
|
import { effectiveBuiltinLists, effectiveDisabledList, effectiveProjectOverrides, } from "../capability-control/overlay.js";
|
|
36
34
|
import { computeEffectiveDisabledLists } from "../capability-control/disabled-lists.js";
|
|
37
35
|
import { registerFileHistoryHook } from "./file-history-hook.js";
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
36
|
+
import { resolveToolNamesForPreset } from "../preset/index.js";
|
|
37
|
+
import { compileComposition } from "../composition/compiler.js";
|
|
38
|
+
import { ConfigError } from "../exceptions.js";
|
|
39
|
+
import { compositionPromptSections, compositionToolCatalog, presetInjectedTools, registerAlwaysTools, resolveCompositionInstructionBoundary, resolvePresetFromComposition, } from "../composition/resolve-preset.js";
|
|
40
40
|
import { ModelPool } from "../llm/model-pool.js";
|
|
41
41
|
import { AgentDefinitionRegistry } from "../agent/agent-definition-registry.js";
|
|
42
42
|
import { defaultCacheDir } from "../llm/model-cache.js";
|
|
@@ -44,7 +44,6 @@ import { detectProviderFromApiKey, buildModelPool } from "../onboarding.js";
|
|
|
44
44
|
import { detectPastedNoise } from "../utils/task-sanitizer.js";
|
|
45
45
|
import { PromptCacheDiagnosticRecorder, promptCacheDropHint, } from "./prompt-cache-diagnostics.js";
|
|
46
46
|
import { buildRunUserMessageContent, prepareRunImageInput } from "./run-image-input.js";
|
|
47
|
-
import { ISOLATED_TASK_PROFILE, QUICK_CHAT_RESTRICTED_PROFILE, } from "./run-types.js";
|
|
48
47
|
import { createSubAgentSpawner } from "./subagent-spawner.js";
|
|
49
48
|
import { AuxiliaryPipeline, sameLlmIdentity } from "./auxiliary-pipeline.js";
|
|
50
49
|
import { PermissionController } from "./permission-controller.js";
|
|
@@ -152,7 +151,8 @@ export class Engine {
|
|
|
152
151
|
runtimeToolRegistry;
|
|
153
152
|
/** Engine-local view containing only this Engine's capability modules. */
|
|
154
153
|
toolRegistry;
|
|
155
|
-
|
|
154
|
+
/** Compiled module contributions — the single composition fact source. */
|
|
155
|
+
composition;
|
|
156
156
|
toolCatalog;
|
|
157
157
|
toolGuards;
|
|
158
158
|
/** Per-turn dynamic definition rewriters contributed by builtin exposures. */
|
|
@@ -400,9 +400,13 @@ export class Engine {
|
|
|
400
400
|
},
|
|
401
401
|
...(this.runtime ? { runtime: this.runtime } : {}),
|
|
402
402
|
});
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
if (config.composition && config.modules) {
|
|
404
|
+
throw new ConfigError("EngineConfig.composition is mutually exclusive with modules");
|
|
405
|
+
}
|
|
406
|
+
// Single composition fact source for every module contribution.
|
|
407
|
+
this.composition =
|
|
408
|
+
config.composition ?? compileComposition({ modules: config.modules ?? [] });
|
|
409
|
+
this.toolCatalog = compositionToolCatalog(this.composition);
|
|
406
410
|
this.toolGuards = new Map(this.toolCatalog.flatMap((tool) => tool.exposure.availability
|
|
407
411
|
? [[tool.definition.name, tool.exposure.availability]]
|
|
408
412
|
: []));
|
|
@@ -410,35 +414,31 @@ export class Engine {
|
|
|
410
414
|
? [[tool.definition.name, tool.exposure.rewriteDefinition]]
|
|
411
415
|
: []));
|
|
412
416
|
// Behavior profile registry: core defaults first, then host config, then
|
|
413
|
-
//
|
|
417
|
+
// module contributions — later registrations override earlier ones by id.
|
|
418
|
+
const moduleProfiles = this.composition.engine.behaviorProfiles;
|
|
414
419
|
this.behaviorProfiles = new Map([
|
|
415
|
-
|
|
416
|
-
ISOLATED_TASK_PROFILE,
|
|
420
|
+
...moduleProfiles.filter((p) => p.moduleId === "core").map((p) => p.value),
|
|
417
421
|
...(config.behaviorProfiles ?? []),
|
|
418
|
-
...(
|
|
422
|
+
...moduleProfiles.filter((p) => p.moduleId !== "core").map((p) => p.value),
|
|
419
423
|
].map((profile) => [profile.id, profile]));
|
|
420
|
-
this.capabilityPromptSections =
|
|
421
|
-
this.capabilityDynamicContextProviders =
|
|
422
|
-
this.preset =
|
|
423
|
-
//
|
|
424
|
-
//
|
|
425
|
-
//
|
|
426
|
-
// gated by
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
]);
|
|
430
|
-
if (extensionCatalogTools.length > 0) {
|
|
424
|
+
this.capabilityPromptSections = compositionPromptSections(this.composition);
|
|
425
|
+
this.capabilityDynamicContextProviders = this.composition.engine.dynamicContextProviders.map((c) => c.value);
|
|
426
|
+
this.preset = resolvePresetFromComposition(this.composition, config.preset);
|
|
427
|
+
// Catalog tools owned by modules that contribute no presets join the
|
|
428
|
+
// active preset regardless of its name: presets snapshot their tool lists
|
|
429
|
+
// from catalogs known at module authoring time, which can never include
|
|
430
|
+
// such packages. Visibility stays gated by exposure.availability.
|
|
431
|
+
const injectedTools = presetInjectedTools(this.composition);
|
|
432
|
+
if (injectedTools.length > 0) {
|
|
431
433
|
this.preset = {
|
|
432
434
|
...this.preset,
|
|
433
435
|
builtinTools: [
|
|
434
436
|
...this.preset.builtinTools,
|
|
435
|
-
...
|
|
437
|
+
...injectedTools.map((tool) => tool.definition.name),
|
|
436
438
|
],
|
|
437
439
|
defaultPermissionRules: [
|
|
438
440
|
...this.preset.defaultPermissionRules,
|
|
439
|
-
...
|
|
440
|
-
...(tool.exposure.defaultPermissionRules ?? []),
|
|
441
|
-
]),
|
|
441
|
+
...injectedTools.flatMap((tool) => [...(tool.exposure.defaultPermissionRules ?? [])]),
|
|
442
442
|
],
|
|
443
443
|
};
|
|
444
444
|
}
|
|
@@ -468,22 +468,22 @@ export class Engine {
|
|
|
468
468
|
this.runtimeToolRegistry =
|
|
469
469
|
config.runtime?.toolRegistry ??
|
|
470
470
|
new ToolRegistry({
|
|
471
|
-
builtinTools:
|
|
472
|
-
preset: this.preset
|
|
471
|
+
builtinTools: resolveToolNamesForPreset({
|
|
472
|
+
preset: this.preset,
|
|
473
473
|
host: config.builtinToolHost,
|
|
474
474
|
enabledBuiltinTools: [
|
|
475
475
|
...builtinLists.enabledBuiltinTools,
|
|
476
|
-
//
|
|
476
|
+
// Injected catalog tools are preset-agnostic (see preset merge
|
|
477
477
|
// above); their availability guards gate actual visibility.
|
|
478
|
-
...
|
|
478
|
+
...injectedTools.map((tool) => tool.definition.name),
|
|
479
479
|
],
|
|
480
480
|
disabledBuiltinTools: builtinLists.disabledBuiltinTools,
|
|
481
|
-
|
|
481
|
+
adjusters: this.composition.engine.toolSelectionAdjusters.map((a) => a.value),
|
|
482
482
|
}),
|
|
483
483
|
toolCatalog: this.toolCatalog,
|
|
484
484
|
});
|
|
485
485
|
this.toolRegistry = this.runtimeToolRegistry.fork();
|
|
486
|
-
|
|
486
|
+
registerAlwaysTools(this.composition, this.toolRegistry);
|
|
487
487
|
this.hooks = new HookRegistry();
|
|
488
488
|
// Installed-plugin hooks — declared in each plugin's hooks/hooks.json.
|
|
489
489
|
// Registered first (priority 80) so user-authored hooks at lower
|
|
@@ -506,15 +506,13 @@ export class Engine {
|
|
|
506
506
|
// settings.hooks → shell-command wrappers. Chain order:
|
|
507
507
|
// plugin (80) → shell (50) → capability (20) → SDK code (default 0).
|
|
508
508
|
this.registerSettingsHooks();
|
|
509
|
-
for (const hook of
|
|
509
|
+
for (const hook of this.composition.engine.hooks) {
|
|
510
510
|
this.hooks.register(hook.event, hook.handler, hook.priority, hook.name);
|
|
511
511
|
}
|
|
512
512
|
for (const hook of config.hooks ?? []) {
|
|
513
513
|
this.hooks.register(hook.event, hook.handler, hook.priority, hook.name);
|
|
514
514
|
}
|
|
515
|
-
this.sessionManager = new SessionManager(config.sessionStorageDir, this.
|
|
516
|
-
.map((capability) => capability.sessionWorkspace)
|
|
517
|
-
.find((candidate) => candidate !== undefined));
|
|
515
|
+
this.sessionManager = new SessionManager(config.sessionStorageDir, this.composition.engine.sessionWorkspaces[0]?.value);
|
|
518
516
|
// Initialize model pool — prefer runtime's shared pool, fall back to self-constructed.
|
|
519
517
|
this.modelPool = config.runtime?.modelPool ?? new ModelPool();
|
|
520
518
|
this.auxiliaryPipeline = new AuxiliaryPipeline({
|
|
@@ -666,8 +664,11 @@ export class Engine {
|
|
|
666
664
|
this.toolRegistry.registerTool(definition, executor);
|
|
667
665
|
}
|
|
668
666
|
/** Dispatch a host-installed capability query without teaching core its name. */
|
|
669
|
-
queryCapability(type, params = {}) {
|
|
670
|
-
|
|
667
|
+
async queryCapability(type, params = {}) {
|
|
668
|
+
const handler = this.composition.protocol.queries.find((q) => q.key === type)?.value;
|
|
669
|
+
if (!handler)
|
|
670
|
+
return { handled: false };
|
|
671
|
+
return { handled: true, data: await handler(params) };
|
|
671
672
|
}
|
|
672
673
|
/**
|
|
673
674
|
* Inject the askUser handler after construction. Used by AgentServer
|
|
@@ -1756,9 +1757,7 @@ export class Engine {
|
|
|
1756
1757
|
sessionDir: join(this.config.sessionStorageDir ?? sessionsRoot(), session.state.sessionId),
|
|
1757
1758
|
cwd,
|
|
1758
1759
|
getTurnSeq: () => session.state.turnSeq,
|
|
1759
|
-
contributions: this.
|
|
1760
|
-
...(capability.fileHistory ?? []),
|
|
1761
|
-
]),
|
|
1760
|
+
contributions: this.composition.engine.fileHistory.map((c) => c.value),
|
|
1762
1761
|
});
|
|
1763
1762
|
// Hook: agent start
|
|
1764
1763
|
await this.emitHook("on_agent_start", {
|
|
@@ -2004,7 +2003,7 @@ export class Engine {
|
|
|
2004
2003
|
sessionBrief: session.state.sessionBrief,
|
|
2005
2004
|
profileMemoryDir,
|
|
2006
2005
|
instructionCompatFileNames: compatFileNamesFrom(this.config.instructions),
|
|
2007
|
-
instructionBoundaryFinder: (scanCwd) =>
|
|
2006
|
+
instructionBoundaryFinder: (scanCwd) => resolveCompositionInstructionBoundary(this.composition, scanCwd),
|
|
2008
2007
|
disabledSkills,
|
|
2009
2008
|
disabledPlugins,
|
|
2010
2009
|
skillAllowlist: profileCanUseSkills ? toolCtx.skillAllowlist : [],
|
|
@@ -2558,22 +2557,23 @@ export class Engine {
|
|
|
2558
2557
|
// (rebuilt per turn from this.preset) reflects the new preset's system
|
|
2559
2558
|
// prompt / behavior. Only when the preset actually changed.
|
|
2560
2559
|
if (patch.preset !== undefined && patch.preset !== prevPresetName) {
|
|
2561
|
-
const nextPreset =
|
|
2560
|
+
const nextPreset = resolvePresetFromComposition(this.composition, this.config.preset);
|
|
2562
2561
|
// The builtin tool SET is ctor-frozen and may be shared via runtime — we
|
|
2563
2562
|
// do NOT rebuild it here. If the new preset implies a different builtin
|
|
2564
2563
|
// tool set, that part of the change only lands on session restart.
|
|
2565
|
-
const
|
|
2566
|
-
|
|
2564
|
+
const adjusters = this.composition.engine.toolSelectionAdjusters.map((a) => a.value);
|
|
2565
|
+
const prevTools = resolveToolNamesForPreset({
|
|
2566
|
+
preset: resolvePresetFromComposition(this.composition, prevPresetName),
|
|
2567
2567
|
host: this.config.builtinToolHost,
|
|
2568
|
-
|
|
2568
|
+
adjusters,
|
|
2569
2569
|
})
|
|
2570
2570
|
.slice()
|
|
2571
2571
|
.sort()
|
|
2572
2572
|
.join(",");
|
|
2573
|
-
const nextTools =
|
|
2574
|
-
preset: nextPreset
|
|
2573
|
+
const nextTools = resolveToolNamesForPreset({
|
|
2574
|
+
preset: nextPreset,
|
|
2575
2575
|
host: this.config.builtinToolHost,
|
|
2576
|
-
|
|
2576
|
+
adjusters,
|
|
2577
2577
|
})
|
|
2578
2578
|
.slice()
|
|
2579
2579
|
.sort()
|
|
@@ -3278,17 +3278,15 @@ export class Engine {
|
|
|
3278
3278
|
*/
|
|
3279
3279
|
buildToolContext(cwd = this.config.cwd ?? process.cwd(), explicitProfileOverrides, profileMemoryDir) {
|
|
3280
3280
|
const { disabledSkills, disabledPlugins } = this.readDisabledLists(cwd, explicitProfileOverrides);
|
|
3281
|
-
const capabilityServices = Object.fromEntries(this.
|
|
3282
|
-
|
|
3283
|
-
return [];
|
|
3284
|
-
const service = capability.createToolService({
|
|
3281
|
+
const capabilityServices = Object.fromEntries(this.composition.engine.toolServices.map(({ moduleId, value }) => {
|
|
3282
|
+
const service = value({
|
|
3285
3283
|
isSubAgent: this.config.isSubAgent === true,
|
|
3286
3284
|
settings: this.getSettingsManager(),
|
|
3287
3285
|
resolveSandbox: (cwd) => this.runEnvironmentResolver.resolveSandbox(cwd),
|
|
3288
3286
|
readShellEnv: (cwd) => this.runEnvironmentResolver.readShellEnv(cwd),
|
|
3289
3287
|
getSessionManager: () => this.sessionManager,
|
|
3290
3288
|
});
|
|
3291
|
-
return [
|
|
3289
|
+
return [moduleId, service];
|
|
3292
3290
|
}));
|
|
3293
3291
|
const ctx = {
|
|
3294
3292
|
shellEnv: this.runEnvironmentResolver.readShellEnv(cwd),
|
|
@@ -237,8 +237,8 @@ export function createSubAgentSpawner(deps) {
|
|
|
237
237
|
preset: deps.presetName,
|
|
238
238
|
enabledBuiltinTools: scope.enabled,
|
|
239
239
|
disabledBuiltinTools: scope.disabled,
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
composition: deps.parentConfig.composition,
|
|
241
|
+
modules: deps.parentConfig.modules,
|
|
242
242
|
builtinToolHost: deps.parentConfig.builtinToolHost,
|
|
243
243
|
customSystemPrompt: deps.parentConfig.customSystemPrompt,
|
|
244
244
|
appendSystemPrompt: [deps.parentConfig.appendSystemPrompt, request.appendSystemPrompt]
|
package/dist/engine/types.d.ts
CHANGED
|
@@ -21,8 +21,7 @@ import type { SettingsScope } from "../settings/manager.js";
|
|
|
21
21
|
import type { EngineRuntime } from "./runtime.js";
|
|
22
22
|
import type { HookEventName } from "../hooks/events.js";
|
|
23
23
|
import type { HookHandler } from "../hooks/registry.js";
|
|
24
|
-
import type {
|
|
25
|
-
import type { ExtensionModule } from "../tool-system/capability-module.js";
|
|
24
|
+
import type { AgentModule, ResolvedComposition } from "../composition/types.js";
|
|
26
25
|
import type { RunBehaviorProfile } from "./run-types.js";
|
|
27
26
|
import type { LegacyPetWorkDelegation } from "../types.js";
|
|
28
27
|
export interface EngineConfig {
|
|
@@ -45,10 +44,14 @@ export interface EngineConfig {
|
|
|
45
44
|
preset?: AgentPresetName;
|
|
46
45
|
enabledBuiltinTools?: string[];
|
|
47
46
|
disabledBuiltinTools?: string[];
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Precompiled composition from the host root — the single source of truth
|
|
49
|
+
* for module contributions. Mutually exclusive with modules / capabilities
|
|
50
|
+
* / extensionModules.
|
|
51
|
+
*/
|
|
52
|
+
composition?: ResolvedComposition;
|
|
53
|
+
/** AgentModules for library consumers; Engine compiles them once. */
|
|
54
|
+
modules?: readonly AgentModule[];
|
|
52
55
|
/**
|
|
53
56
|
* Named per-run behavior profiles selectable via EngineRunOptions.behaviorMode
|
|
54
57
|
* or a profile's activateForSessionKinds. Merged (by id, later wins) over the
|
package/dist/exceptions.d.ts
CHANGED
|
@@ -42,6 +42,14 @@ export declare class TranscriptError extends FrameworkError {
|
|
|
42
42
|
export declare class ConfigError extends FrameworkError {
|
|
43
43
|
constructor(message: string, details?: Record<string, unknown>);
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Thrown by compileComposition() on any conflicting or invalid module
|
|
47
|
+
* contribution. Structured details carry at least { code, key } plus the
|
|
48
|
+
* owning module ids so hosts can render actionable errors.
|
|
49
|
+
*/
|
|
50
|
+
export declare class CompositionError extends FrameworkError {
|
|
51
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
52
|
+
}
|
|
45
53
|
/**
|
|
46
54
|
* Thrown by `resolveSandboxBackend` when an explicit sandbox mode is
|
|
47
55
|
* requested but the corresponding backend is unavailable on this host
|
package/dist/exceptions.js
CHANGED
|
@@ -91,6 +91,17 @@ export class ConfigError extends FrameworkError {
|
|
|
91
91
|
this.name = "ConfigError";
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Thrown by compileComposition() on any conflicting or invalid module
|
|
96
|
+
* contribution. Structured details carry at least { code, key } plus the
|
|
97
|
+
* owning module ids so hosts can render actionable errors.
|
|
98
|
+
*/
|
|
99
|
+
export class CompositionError extends FrameworkError {
|
|
100
|
+
constructor(message, details) {
|
|
101
|
+
super(message, details);
|
|
102
|
+
this.name = "CompositionError";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
94
105
|
// ─── Sandbox Errors ───────────────────────────────────────────────
|
|
95
106
|
/**
|
|
96
107
|
* Thrown by `resolveSandboxBackend` when an explicit sandbox mode is
|