@rowan-agent/agent 0.8.6 → 0.9.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 +77 -8
- package/dist/index.d.ts +16 -31
- package/dist/index.js +256 -211
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,24 +11,39 @@ import {
|
|
|
11
11
|
AgentRuntime,
|
|
12
12
|
createCoreTools,
|
|
13
13
|
InMemoryStore,
|
|
14
|
+
loadPhases,
|
|
15
|
+
loadSkills,
|
|
14
16
|
} from "@rowan-agent/agent";
|
|
15
17
|
|
|
18
|
+
const skills = await loadSkills("./.rowan/skills");
|
|
19
|
+
const phases = await loadPhases("./.rowan/phases");
|
|
16
20
|
const runtime = await AgentRuntime.init({
|
|
17
21
|
store: new InMemoryStore(),
|
|
18
22
|
});
|
|
19
23
|
|
|
20
24
|
const agentId = await runtime.createAgent({
|
|
21
25
|
identity: "example:v1", // Stable config snapshot identity, not the Agent ID
|
|
22
|
-
model: {
|
|
23
|
-
|
|
26
|
+
model: {
|
|
27
|
+
provider: "openai",
|
|
28
|
+
id: "gpt-4o",
|
|
29
|
+
protocol: "openai-responses",
|
|
30
|
+
baseUrl: "https://api.openai.com/v1",
|
|
31
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
32
|
+
},
|
|
24
33
|
definition: {
|
|
25
34
|
name: "workspace-assistant",
|
|
26
35
|
description: "Assist with the current workspace.",
|
|
27
|
-
|
|
36
|
+
prompt: "You are helpful.",
|
|
37
|
+
contexts: ["workspace"],
|
|
28
38
|
},
|
|
29
39
|
resources: {
|
|
30
40
|
tools: createCoreTools({ root: process.cwd() }),
|
|
31
|
-
skills
|
|
41
|
+
skills,
|
|
42
|
+
contexts: [{
|
|
43
|
+
name: "workspace",
|
|
44
|
+
value: { root: process.cwd() },
|
|
45
|
+
}],
|
|
46
|
+
phases,
|
|
32
47
|
},
|
|
33
48
|
});
|
|
34
49
|
|
|
@@ -126,7 +141,7 @@ await runtime.loadAgents({
|
|
|
126
141
|
values: [{
|
|
127
142
|
name: "workspace-assistant",
|
|
128
143
|
description: "Assist with the current workspace.",
|
|
129
|
-
|
|
144
|
+
prompt: "You are helpful.",
|
|
130
145
|
}],
|
|
131
146
|
});
|
|
132
147
|
await runtime.loadTools({
|
|
@@ -143,8 +158,13 @@ const agentId = await runtime.createAgent({
|
|
|
143
158
|
skills: [],
|
|
144
159
|
phases: [],
|
|
145
160
|
},
|
|
146
|
-
model: {
|
|
147
|
-
|
|
161
|
+
model: {
|
|
162
|
+
provider: "openai",
|
|
163
|
+
id: "gpt-4o",
|
|
164
|
+
protocol: "openai-responses",
|
|
165
|
+
baseUrl: "https://api.openai.com/v1",
|
|
166
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
167
|
+
},
|
|
148
168
|
});
|
|
149
169
|
```
|
|
150
170
|
|
|
@@ -156,4 +176,53 @@ Tool and `default` Phase are always available and cannot be overridden.
|
|
|
156
176
|
Extensions are Runtime-global. Load them only during `AgentRuntime.init()` via
|
|
157
177
|
`bootstrap`; after initialization they are frozen until the Runtime closes.
|
|
158
178
|
Definition name lists narrow the selected Tools, Skills, and Phases: omission
|
|
159
|
-
inherits all candidates, `[]` selects none, and missing names are skipped.
|
|
179
|
+
inherits all candidates, `[]` selects none, and missing names are skipped. The
|
|
180
|
+
same rule applies to `definition.contexts`.
|
|
181
|
+
|
|
182
|
+
### Resources and Definition
|
|
183
|
+
|
|
184
|
+
`resources` and `definition` have different jobs:
|
|
185
|
+
|
|
186
|
+
- `resources` supplies the concrete candidates available to one Agent. Its
|
|
187
|
+
Tools contain executable `execute()` functions; Skills and Phases contain
|
|
188
|
+
their loaded content; Contexts contain JSON-safe values.
|
|
189
|
+
- `definition` declares which candidates this Agent uses. `tools`, `skills`,
|
|
190
|
+
`contexts`, and `phases` are name-based selectors; they cannot create a
|
|
191
|
+
resource that is absent from `resources`.
|
|
192
|
+
|
|
193
|
+
For a single-process embedding, provide concrete resources directly and omit
|
|
194
|
+
the selectors when the Agent should use everything:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const agentId = await runtime.createAgent({
|
|
198
|
+
identity: "workspace:v1",
|
|
199
|
+
definition: {
|
|
200
|
+
name: "workspace-assistant",
|
|
201
|
+
description: "Assist with the current workspace.",
|
|
202
|
+
prompt: "You are helpful.",
|
|
203
|
+
},
|
|
204
|
+
resources: { tools, skills, contexts, phases },
|
|
205
|
+
model,
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Use selectors when several Agents share a candidate pool:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
definition: {
|
|
213
|
+
name: "read-only-assistant",
|
|
214
|
+
description: "Inspect the workspace without changing it.",
|
|
215
|
+
prompt: "You are helpful.",
|
|
216
|
+
tools: ["read"],
|
|
217
|
+
contexts: ["workspace"],
|
|
218
|
+
phases: { entryPhaseId: "review", phaseIds: ["review"] },
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
For process-boundary persistence, use the Resource Registry form shown above:
|
|
223
|
+
`resourceView` stores stable source IDs instead of executable resource
|
|
224
|
+
closures, and the Runtime resolves those sources into an immutable
|
|
225
|
+
Configuration Snapshot. This lets a restarted Runtime resolve the same
|
|
226
|
+
resource revisions while keeping each Run pinned to the snapshot that created
|
|
227
|
+
it. Direct `resources` are simpler for embedding; `resourceView` is the
|
|
228
|
+
declarative form for shared, reloadable, and restart-resolvable resources.
|
package/dist/index.d.ts
CHANGED
|
@@ -83,23 +83,6 @@ interface SourceInfo {
|
|
|
83
83
|
baseDir?: string;
|
|
84
84
|
displayName?: string;
|
|
85
85
|
}
|
|
86
|
-
/** Phase run function type for extensions */
|
|
87
|
-
type PhaseRun = (context: PhaseContext, execution: PhaseExecution) => Promise<PhaseOutput | void>;
|
|
88
|
-
/** Phase definition shape used by extensions */
|
|
89
|
-
type PhaseDefinition = {
|
|
90
|
-
name: string;
|
|
91
|
-
description: string;
|
|
92
|
-
run?: PhaseRun;
|
|
93
|
-
tools?: string[];
|
|
94
|
-
skills?: string[];
|
|
95
|
-
target?: string;
|
|
96
|
-
input?: Record<string, string>;
|
|
97
|
-
model?: string;
|
|
98
|
-
};
|
|
99
|
-
type PhaseRegistration = Omit<PhaseDefinition, 'run'> & {
|
|
100
|
-
/** Optional execution override — takes over model invocation */
|
|
101
|
-
run?: PhaseRun;
|
|
102
|
-
};
|
|
103
86
|
/**
|
|
104
87
|
* Tool definition for registering LLM-callable tools via `api.registerTool()`.
|
|
105
88
|
*
|
|
@@ -214,12 +197,6 @@ interface LoadedExtension {
|
|
|
214
197
|
interface ExtensionManifest {
|
|
215
198
|
entry?: string;
|
|
216
199
|
name?: string;
|
|
217
|
-
phase?: {
|
|
218
|
-
name?: string;
|
|
219
|
-
description?: string;
|
|
220
|
-
tools?: string[];
|
|
221
|
-
skills?: string[];
|
|
222
|
-
};
|
|
223
200
|
}
|
|
224
201
|
|
|
225
202
|
/**
|
|
@@ -438,8 +415,8 @@ interface ExtensionAPI {
|
|
|
438
415
|
off<K extends HookEventType>(eventType: K, handler: HookHandler<K>): void;
|
|
439
416
|
/** Register a custom LLM-callable tool. */
|
|
440
417
|
registerTool(tool: ToolDefinition): void;
|
|
441
|
-
/** Register a
|
|
442
|
-
registerPhase(
|
|
418
|
+
/** Register a Phase directory bundle. */
|
|
419
|
+
registerPhase(path: string): Promise<void>;
|
|
443
420
|
/** Register a model provider. */
|
|
444
421
|
registerProvider(config: _rowan_agent_models.ProviderConfig): void;
|
|
445
422
|
/** Unregister a model provider. */
|
|
@@ -552,8 +529,8 @@ interface Phase {
|
|
|
552
529
|
description: string;
|
|
553
530
|
/** Restricted tools (undefined = all tools available) */
|
|
554
531
|
tools?: string[];
|
|
555
|
-
/**
|
|
556
|
-
skills?:
|
|
532
|
+
/** Skills bundled directly inside this phase directory. Inline phases may omit this (equivalent to []). */
|
|
533
|
+
skills?: Skill[];
|
|
557
534
|
/** Forced next phase */
|
|
558
535
|
target?: string;
|
|
559
536
|
/** Expected input fields (key → description) */
|
|
@@ -627,11 +604,11 @@ type PhaseRegistrySelection = Readonly<{
|
|
|
627
604
|
type AgentDefinition = Readonly<{
|
|
628
605
|
name: string;
|
|
629
606
|
description: string;
|
|
630
|
-
|
|
607
|
+
prompt: string;
|
|
631
608
|
tools?: readonly string[];
|
|
632
609
|
skills?: readonly string[];
|
|
633
610
|
phases?: PhaseRegistrySelection;
|
|
634
|
-
|
|
611
|
+
contexts?: readonly string[];
|
|
635
612
|
model?: ModelRef;
|
|
636
613
|
}>;
|
|
637
614
|
/** Parse one Markdown definition using the same frontmatter vocabulary as Phase resources. */
|
|
@@ -1176,6 +1153,7 @@ declare class ExtensionRunner {
|
|
|
1176
1153
|
private createExtensionAPI;
|
|
1177
1154
|
private registerTool;
|
|
1178
1155
|
private registerPhase;
|
|
1156
|
+
private loadRegisteredPhase;
|
|
1179
1157
|
private registerProvider;
|
|
1180
1158
|
private unregisterProvider;
|
|
1181
1159
|
private flushPendingProviders;
|
|
@@ -1233,7 +1211,7 @@ declare class RuntimeBootstrapRegistry extends ResourceRegistry {
|
|
|
1233
1211
|
|
|
1234
1212
|
type DefinitionLayer = Readonly<{
|
|
1235
1213
|
description?: string;
|
|
1236
|
-
|
|
1214
|
+
prompt?: string;
|
|
1237
1215
|
model?: ModelRef;
|
|
1238
1216
|
tools?: readonly string[];
|
|
1239
1217
|
skills?: readonly string[];
|
|
@@ -2222,8 +2200,15 @@ declare class RuntimeError<Code extends RuntimeErrorCode = RuntimeErrorCode> ext
|
|
|
2222
2200
|
}
|
|
2223
2201
|
declare function isRuntimeError(value: unknown): value is AnyRuntimeError;
|
|
2224
2202
|
|
|
2203
|
+
declare function loadSkill(path: string): Promise<Skill>;
|
|
2225
2204
|
declare function loadSkills(targetPath: string): Promise<Skill[]>;
|
|
2226
2205
|
|
|
2206
|
+
/**
|
|
2207
|
+
* Load a single phase from a PHASE.md file or phase directory.
|
|
2208
|
+
*
|
|
2209
|
+
* If a directory is provided, the loader reads its PHASE.md.
|
|
2210
|
+
*/
|
|
2211
|
+
declare function loadPhase(targetPath: string): Promise<Phase>;
|
|
2227
2212
|
/**
|
|
2228
2213
|
* Load all phases from the target directory.
|
|
2229
2214
|
*
|
|
@@ -2269,4 +2254,4 @@ declare function parseFrontmatter<T = Record<string, unknown>>(raw: string): Fro
|
|
|
2269
2254
|
|
|
2270
2255
|
declare function createCoreTools(input?: CoreToolContext): Tool[];
|
|
2271
2256
|
|
|
2272
|
-
export { type AfterToolCall, type AgentConfig, type AgentConfigRequest, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentResources, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type CoreToolContext, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type FrontmatterResult, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryStore, type InputRequest, type InputRequestId, type InputRequiredCommit, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type Metadata, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecutionIdentity, type PhaseInvocation, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RunBoundary, type RunClaim, type RunEvent, type RunFailure, type RunId, type RunListCursor, type RunRecord, type RunSnapshot, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, type Skill, SqliteStore, type TextContent, type ThinkingContent, type Tool, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, brandConfigToken, createCoreTools, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhases, loadSkills, materializeConfigurationSnapshot, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
|
|
2257
|
+
export { type AfterToolCall, type AgentConfig, type AgentConfigRequest, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentResources, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type CoreToolContext, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type FrontmatterResult, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryStore, type InputRequest, type InputRequestId, type InputRequiredCommit, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type Metadata, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecutionIdentity, type PhaseInvocation, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RunBoundary, type RunClaim, type RunEvent, type RunFailure, type RunId, type RunListCursor, type RunRecord, type RunSnapshot, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, type Skill, SqliteStore, type TextContent, type ThinkingContent, type Tool, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, brandConfigToken, createCoreTools, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhases, loadSkill, loadSkills, materializeConfigurationSnapshot, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
|
package/dist/index.js
CHANGED
|
@@ -164,9 +164,6 @@ function buildPhaseEntry(p) {
|
|
|
164
164
|
if (p.tools && p.tools.length > 0) {
|
|
165
165
|
entry.available_tools = p.tools.join(", ");
|
|
166
166
|
}
|
|
167
|
-
if (p.skills && p.skills.length > 0) {
|
|
168
|
-
entry.available_skills = p.skills.join(", ");
|
|
169
|
-
}
|
|
170
167
|
if (p.input && Object.keys(p.input).length > 0) {
|
|
171
168
|
entry.required_input = Object.entries(p.input).map(([key, desc]) => `- ${key}: ${desc}`).join("\n");
|
|
172
169
|
}
|
|
@@ -985,9 +982,9 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
985
982
|
assertActive();
|
|
986
983
|
options?.registerTool?.(tool);
|
|
987
984
|
},
|
|
988
|
-
registerPhase: (registration) => {
|
|
985
|
+
registerPhase: async (registration) => {
|
|
989
986
|
assertActive();
|
|
990
|
-
options?.registerPhase?.(registration);
|
|
987
|
+
await options?.registerPhase?.(registration);
|
|
991
988
|
},
|
|
992
989
|
registerProvider: (config) => {
|
|
993
990
|
assertActive();
|
|
@@ -1037,21 +1034,23 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1037
1034
|
}
|
|
1038
1035
|
|
|
1039
1036
|
// src/harness/phases/loader.ts
|
|
1040
|
-
import { existsSync, statSync } from "fs";
|
|
1041
|
-
import { readdir } from "fs/promises";
|
|
1042
|
-
import { dirname as
|
|
1037
|
+
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
1038
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
1039
|
+
import { dirname as dirname4, join as join2, resolve as resolve4 } from "path";
|
|
1043
1040
|
|
|
1044
1041
|
// src/harness/definitions.ts
|
|
1045
1042
|
import { parseModelRef } from "@rowan-agent/models";
|
|
1046
1043
|
function assertAgentDefinition(value) {
|
|
1047
1044
|
if (!isRecord(value)) throw new TypeError("config.definition is invalid");
|
|
1045
|
+
if ("content" in value) throw new TypeError("definition.content is not supported; use definition.prompt");
|
|
1046
|
+
if ("context" in value) throw new TypeError("definition.context is not supported; use definition.contexts");
|
|
1048
1047
|
requiredString(value.name, "definition.name");
|
|
1049
1048
|
requiredString(value.description, "definition.description");
|
|
1050
|
-
requiredString(value.
|
|
1049
|
+
requiredString(value.prompt, "definition.prompt");
|
|
1051
1050
|
optionalStringList(value.tools, "definition.tools");
|
|
1052
1051
|
optionalStringList(value.skills, "definition.skills");
|
|
1053
1052
|
optionalPhaseRegistrySelection(value.phases, "definition.phases");
|
|
1054
|
-
optionalStringList(value.
|
|
1053
|
+
optionalStringList(value.contexts, "definition.contexts");
|
|
1055
1054
|
if ("extensions" in value) throw new TypeError("definition.extensions is not supported; Extensions are Runtime-global");
|
|
1056
1055
|
if ("entryPhase" in value) throw new TypeError("definition.entryPhase is not supported; use definition.phases.entryPhaseId");
|
|
1057
1056
|
if (value.model !== void 0) {
|
|
@@ -1064,17 +1063,19 @@ function parseAgentDefinition(raw) {
|
|
|
1064
1063
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
1065
1064
|
return normalizeAgentDefinition(frontmatter, body);
|
|
1066
1065
|
}
|
|
1067
|
-
function normalizeAgentDefinition(frontmatter,
|
|
1066
|
+
function normalizeAgentDefinition(frontmatter, prompt, options = {}) {
|
|
1067
|
+
if (frontmatter.content !== void 0) throw new TypeError("content is not supported; use prompt and the document body");
|
|
1068
|
+
if (frontmatter.context !== void 0) throw new TypeError("context is not supported; use contexts");
|
|
1068
1069
|
const name = frontmatter.name === void 0 && options.fallbackName ? options.fallbackName : requiredString(frontmatter.name, "name");
|
|
1069
1070
|
const description = requiredString(frontmatter.description, "description");
|
|
1070
|
-
const
|
|
1071
|
+
const normalizedPrompt = requiredString(prompt, "prompt");
|
|
1071
1072
|
const tools = optionalStringList(frontmatter.tools, "tools");
|
|
1072
1073
|
const skills = optionalStringList(frontmatter.skills, "skills");
|
|
1073
1074
|
const phases = optionalPhaseRegistrySelection(frontmatter.phases, "phases");
|
|
1074
1075
|
if (frontmatter.extensions !== void 0) {
|
|
1075
1076
|
throw new TypeError("extensions is not supported; Extensions are Runtime-global");
|
|
1076
1077
|
}
|
|
1077
|
-
const
|
|
1078
|
+
const contexts = optionalStringList(frontmatter.contexts, "contexts");
|
|
1078
1079
|
if (frontmatter.entryPhase !== void 0) {
|
|
1079
1080
|
throw new TypeError("entryPhase is not supported; use phases.entryPhaseId");
|
|
1080
1081
|
}
|
|
@@ -1082,11 +1083,11 @@ function normalizeAgentDefinition(frontmatter, content, options = {}) {
|
|
|
1082
1083
|
return {
|
|
1083
1084
|
name,
|
|
1084
1085
|
description,
|
|
1085
|
-
|
|
1086
|
+
prompt: normalizedPrompt,
|
|
1086
1087
|
...tools ? { tools } : {},
|
|
1087
1088
|
...skills ? { skills } : {},
|
|
1088
1089
|
...phases ? { phases } : {},
|
|
1089
|
-
...
|
|
1090
|
+
...contexts ? { contexts } : {},
|
|
1090
1091
|
...model ? { model } : {}
|
|
1091
1092
|
};
|
|
1092
1093
|
}
|
|
@@ -1122,9 +1123,8 @@ function optionalStringList(value, field) {
|
|
|
1122
1123
|
function optionalPhaseRegistrySelection(value, field) {
|
|
1123
1124
|
if (value === void 0) return void 0;
|
|
1124
1125
|
if (!isRecord(value)) throw new TypeError(`${field} must be an object`);
|
|
1125
|
-
if (!("entryPhaseId" in value)) throw new TypeError(`${field}.entryPhaseId is required`);
|
|
1126
1126
|
if (!("phaseIds" in value)) throw new TypeError(`${field}.phaseIds is required`);
|
|
1127
|
-
const entryPhaseId = value.entryPhaseId;
|
|
1127
|
+
const entryPhaseId = value.entryPhaseId ?? null;
|
|
1128
1128
|
if (entryPhaseId !== null && (typeof entryPhaseId !== "string" || entryPhaseId.trim() === "")) {
|
|
1129
1129
|
throw new TypeError(`${field}.entryPhaseId must be a non-empty string or null`);
|
|
1130
1130
|
}
|
|
@@ -1199,19 +1199,6 @@ function validateDescription(value) {
|
|
|
1199
1199
|
}
|
|
1200
1200
|
return { description: value, warnings: [], missing: false };
|
|
1201
1201
|
}
|
|
1202
|
-
function validateSkillReferences(value) {
|
|
1203
|
-
if (value === void 0) return [];
|
|
1204
|
-
if (!Array.isArray(value)) return ["skills must be an array"];
|
|
1205
|
-
const errors = [];
|
|
1206
|
-
for (const [index, skillId] of value.entries()) {
|
|
1207
|
-
if (typeof skillId !== "string") {
|
|
1208
|
-
errors.push(`skills[${index}] must be a string`);
|
|
1209
|
-
continue;
|
|
1210
|
-
}
|
|
1211
|
-
errors.push(...validateResourceId(skillId, `skills[${index}]`));
|
|
1212
|
-
}
|
|
1213
|
-
return errors;
|
|
1214
|
-
}
|
|
1215
1202
|
function validatePhaseTarget(value) {
|
|
1216
1203
|
if (value === void 0) return [];
|
|
1217
1204
|
if (typeof value !== "string") return ["target must be a string"];
|
|
@@ -1224,11 +1211,91 @@ function warnResourceDiagnostics(kind, filePath, diagnostics) {
|
|
|
1224
1211
|
}
|
|
1225
1212
|
}
|
|
1226
1213
|
|
|
1214
|
+
// src/harness/skills.ts
|
|
1215
|
+
import { existsSync, statSync } from "fs";
|
|
1216
|
+
import { readdir } from "fs/promises";
|
|
1217
|
+
import { dirname as dirname3, join, resolve as resolve3 } from "path";
|
|
1218
|
+
var SKILL_MARKER = "SKILL.md";
|
|
1219
|
+
function resolveSkillPath(input) {
|
|
1220
|
+
const resolved = resolve3(input);
|
|
1221
|
+
return existsSync(resolved) && statSync(resolved).isDirectory() ? join(resolved, SKILL_MARKER) : resolved;
|
|
1222
|
+
}
|
|
1223
|
+
async function loadSkill(path) {
|
|
1224
|
+
const resolved = resolveSkillPath(path);
|
|
1225
|
+
let loaded;
|
|
1226
|
+
try {
|
|
1227
|
+
loaded = await loadMarkdown(resolved);
|
|
1228
|
+
} catch (error) {
|
|
1229
|
+
if (!(error instanceof FrontmatterParseError)) throw error;
|
|
1230
|
+
warnResourceDiagnostics("skill", resolved, [`frontmatter could not be parsed: ${error.message}`]);
|
|
1231
|
+
throw new ResourceMetadataError("parse_failed", error.message);
|
|
1232
|
+
}
|
|
1233
|
+
const { frontmatter, body } = loaded;
|
|
1234
|
+
const metadata = frontmatter;
|
|
1235
|
+
const id = inferResourceName(resolved, SKILL_MARKER);
|
|
1236
|
+
const frontmatterName = typeof metadata.name === "string" ? metadata.name : void 0;
|
|
1237
|
+
const name = frontmatterName || id;
|
|
1238
|
+
const description = validateDescription(metadata.description);
|
|
1239
|
+
const diagnostics = validateResourceId(id);
|
|
1240
|
+
if (frontmatterName && frontmatterName !== id) {
|
|
1241
|
+
diagnostics.push(...validateResourceName(frontmatterName, id));
|
|
1242
|
+
}
|
|
1243
|
+
diagnostics.push(...description.warnings);
|
|
1244
|
+
warnResourceDiagnostics("skill", resolved, diagnostics);
|
|
1245
|
+
if (description.missing) {
|
|
1246
|
+
throw new ResourceMetadataError("invalid_metadata", "description is required");
|
|
1247
|
+
}
|
|
1248
|
+
return {
|
|
1249
|
+
name,
|
|
1250
|
+
description: description.description,
|
|
1251
|
+
filePath: resolved,
|
|
1252
|
+
baseDir: dirname3(resolved),
|
|
1253
|
+
content: body,
|
|
1254
|
+
disableModelInvocation: metadata["disable-model-invocation"] === true
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
async function loadSkills(targetPath) {
|
|
1258
|
+
const skillsDir = resolve3(targetPath);
|
|
1259
|
+
if (existsSync(skillsDir) && statSync(skillsDir).isFile()) {
|
|
1260
|
+
try {
|
|
1261
|
+
return [await loadSkill(skillsDir)];
|
|
1262
|
+
} catch (error) {
|
|
1263
|
+
if (error instanceof ResourceMetadataError) return [];
|
|
1264
|
+
throw error;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (existsSync(join(skillsDir, SKILL_MARKER))) {
|
|
1268
|
+
try {
|
|
1269
|
+
return [await loadSkill(skillsDir)];
|
|
1270
|
+
} catch (error) {
|
|
1271
|
+
if (error instanceof ResourceMetadataError) return [];
|
|
1272
|
+
throw error;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
1276
|
+
const skills = [];
|
|
1277
|
+
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
1278
|
+
if (!entry.isDirectory()) continue;
|
|
1279
|
+
const skillFile = join(skillsDir, entry.name, SKILL_MARKER);
|
|
1280
|
+
if (!existsSync(skillFile)) continue;
|
|
1281
|
+
try {
|
|
1282
|
+
const skill = await loadSkill(skillFile);
|
|
1283
|
+
skills.push(skill);
|
|
1284
|
+
} catch (error) {
|
|
1285
|
+
if (error instanceof ResourceMetadataError) continue;
|
|
1286
|
+
console.warn(`Failed to load skill "${entry.name}":`, error);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
return skills;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1227
1292
|
// src/harness/phases/loader.ts
|
|
1228
1293
|
var PHASE_MARKER = "PHASE.md";
|
|
1294
|
+
var SKILL_MARKER2 = "SKILL.md";
|
|
1295
|
+
var RESOURCE_MARKERS = /* @__PURE__ */ new Set([PHASE_MARKER, SKILL_MARKER2]);
|
|
1229
1296
|
function resolvePhasePath(input) {
|
|
1230
|
-
const resolved =
|
|
1231
|
-
return
|
|
1297
|
+
const resolved = resolve4(input);
|
|
1298
|
+
return existsSync2(resolved) && statSync2(resolved).isDirectory() ? join2(resolved, PHASE_MARKER) : resolved;
|
|
1232
1299
|
}
|
|
1233
1300
|
async function loadPhase(targetPath) {
|
|
1234
1301
|
const resolved = resolvePhasePath(targetPath);
|
|
@@ -1246,7 +1313,9 @@ async function loadPhase(targetPath) {
|
|
|
1246
1313
|
const frontmatterName = typeof metadata.name === "string" ? metadata.name : void 0;
|
|
1247
1314
|
let definition;
|
|
1248
1315
|
try {
|
|
1249
|
-
|
|
1316
|
+
const phaseMetadata = { ...metadata };
|
|
1317
|
+
delete phaseMetadata.skills;
|
|
1318
|
+
definition = normalizeAgentDefinition(phaseMetadata, body, { fallbackName: directoryName });
|
|
1250
1319
|
} catch (error) {
|
|
1251
1320
|
const message = error instanceof Error ? error.message : String(error);
|
|
1252
1321
|
warnResourceDiagnostics("phase", resolved, [message]);
|
|
@@ -1259,21 +1328,21 @@ async function loadPhase(targetPath) {
|
|
|
1259
1328
|
diagnostics.push(...validateResourceName(frontmatterName, directoryName));
|
|
1260
1329
|
}
|
|
1261
1330
|
diagnostics.push(...description.warnings);
|
|
1262
|
-
diagnostics.push(...validateSkillReferences(metadata.skills));
|
|
1263
1331
|
diagnostics.push(...validatePhaseTarget(metadata.target));
|
|
1264
1332
|
warnResourceDiagnostics("phase", resolved, diagnostics);
|
|
1265
|
-
const baseDir =
|
|
1333
|
+
const baseDir = dirname4(resolved);
|
|
1334
|
+
const skills = await loadPhaseSkills(baseDir);
|
|
1266
1335
|
const phase = {
|
|
1267
1336
|
name,
|
|
1268
1337
|
description: description.description,
|
|
1269
1338
|
tools: definition.tools ? [...definition.tools] : void 0,
|
|
1270
|
-
skills
|
|
1339
|
+
skills,
|
|
1271
1340
|
target: metadata.target,
|
|
1272
1341
|
input: metadata.input,
|
|
1273
1342
|
isolated: metadata.isolated,
|
|
1274
1343
|
filePath: resolved,
|
|
1275
1344
|
baseDir,
|
|
1276
|
-
content: definition.
|
|
1345
|
+
content: definition.prompt,
|
|
1277
1346
|
model: definition.model
|
|
1278
1347
|
};
|
|
1279
1348
|
const codePath = await discoverPhaseCode(baseDir);
|
|
@@ -1287,6 +1356,54 @@ async function loadPhase(targetPath) {
|
|
|
1287
1356
|
}
|
|
1288
1357
|
return phase;
|
|
1289
1358
|
}
|
|
1359
|
+
async function loadPhaseSkills(baseDir) {
|
|
1360
|
+
const entries = await readdir2(baseDir, { withFileTypes: true });
|
|
1361
|
+
const skills = [];
|
|
1362
|
+
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
1363
|
+
const entryPath = join2(baseDir, entry.name);
|
|
1364
|
+
if (!entry.isDirectory()) {
|
|
1365
|
+
if (RESOURCE_MARKERS.has(entry.name) && entry.name !== PHASE_MARKER) {
|
|
1366
|
+
throw invalidPhaseBundle(`resource marker ${entry.name} is not valid at the phase root`);
|
|
1367
|
+
}
|
|
1368
|
+
continue;
|
|
1369
|
+
}
|
|
1370
|
+
const markers = await findResourceMarkers(entryPath);
|
|
1371
|
+
const directSkillPath = join2(entryPath, SKILL_MARKER2);
|
|
1372
|
+
const hasDirectSkill = markers.includes(directSkillPath);
|
|
1373
|
+
if (!hasDirectSkill) {
|
|
1374
|
+
if (markers.length > 0) {
|
|
1375
|
+
throw invalidPhaseBundle(`resource marker ${markers[0]} is not a direct child Skill`);
|
|
1376
|
+
}
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
const nestedMarkers = markers.filter((marker) => marker !== directSkillPath);
|
|
1380
|
+
if (nestedMarkers.length > 0) {
|
|
1381
|
+
throw invalidPhaseBundle(`resource marker ${nestedMarkers[0]} is nested below a Skill bundle`);
|
|
1382
|
+
}
|
|
1383
|
+
const skill = await loadSkill(directSkillPath);
|
|
1384
|
+
if (skills.some((candidate) => candidate.name === skill.name)) {
|
|
1385
|
+
throw invalidPhaseBundle(`duplicate bundled Skill name "${skill.name}"`);
|
|
1386
|
+
}
|
|
1387
|
+
skills.push(skill);
|
|
1388
|
+
}
|
|
1389
|
+
return skills;
|
|
1390
|
+
}
|
|
1391
|
+
async function findResourceMarkers(directory) {
|
|
1392
|
+
const entries = await readdir2(directory, { withFileTypes: true });
|
|
1393
|
+
const markers = [];
|
|
1394
|
+
for (const entry of entries) {
|
|
1395
|
+
const entryPath = join2(directory, entry.name);
|
|
1396
|
+
if (entry.isDirectory()) {
|
|
1397
|
+
markers.push(...await findResourceMarkers(entryPath));
|
|
1398
|
+
} else if (RESOURCE_MARKERS.has(entry.name)) {
|
|
1399
|
+
markers.push(entryPath);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return markers;
|
|
1403
|
+
}
|
|
1404
|
+
function invalidPhaseBundle(message) {
|
|
1405
|
+
return new ResourceMetadataError("invalid_metadata", message);
|
|
1406
|
+
}
|
|
1290
1407
|
function readPhaseContent(phase) {
|
|
1291
1408
|
return formatResourceOutput({
|
|
1292
1409
|
type: "phase",
|
|
@@ -1298,8 +1415,8 @@ function readPhaseContent(phase) {
|
|
|
1298
1415
|
}
|
|
1299
1416
|
async function loadPhases(targetPath) {
|
|
1300
1417
|
const phases = /* @__PURE__ */ new Map();
|
|
1301
|
-
const phasesDir =
|
|
1302
|
-
if (
|
|
1418
|
+
const phasesDir = resolve4(targetPath);
|
|
1419
|
+
if (existsSync2(phasesDir) && statSync2(phasesDir).isFile()) {
|
|
1303
1420
|
try {
|
|
1304
1421
|
const phase = await loadPhase(phasesDir);
|
|
1305
1422
|
phases.set(phase.name, phase);
|
|
@@ -1308,7 +1425,7 @@ async function loadPhases(targetPath) {
|
|
|
1308
1425
|
}
|
|
1309
1426
|
return { phases, entryPhaseId: null };
|
|
1310
1427
|
}
|
|
1311
|
-
if (
|
|
1428
|
+
if (existsSync2(join2(phasesDir, PHASE_MARKER))) {
|
|
1312
1429
|
try {
|
|
1313
1430
|
const phase = await loadPhase(phasesDir);
|
|
1314
1431
|
phases.set(phase.name, phase);
|
|
@@ -1317,11 +1434,11 @@ async function loadPhases(targetPath) {
|
|
|
1317
1434
|
}
|
|
1318
1435
|
return { phases, entryPhaseId: null };
|
|
1319
1436
|
}
|
|
1320
|
-
const entries = await
|
|
1437
|
+
const entries = await readdir2(phasesDir, { withFileTypes: true });
|
|
1321
1438
|
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
1322
1439
|
if (!entry.isDirectory()) continue;
|
|
1323
|
-
const phaseFile =
|
|
1324
|
-
if (!
|
|
1440
|
+
const phaseFile = join2(phasesDir, entry.name, PHASE_MARKER);
|
|
1441
|
+
if (!existsSync2(phaseFile)) continue;
|
|
1325
1442
|
try {
|
|
1326
1443
|
const phase = await loadPhase(phaseFile);
|
|
1327
1444
|
phases.set(phase.name, phase);
|
|
@@ -1335,8 +1452,8 @@ async function loadPhases(targetPath) {
|
|
|
1335
1452
|
async function discoverPhaseCode(baseDir) {
|
|
1336
1453
|
const candidates = ["index.ts", "index.js"];
|
|
1337
1454
|
for (const candidate of candidates) {
|
|
1338
|
-
const fullPath =
|
|
1339
|
-
if (
|
|
1455
|
+
const fullPath = join2(baseDir, candidate);
|
|
1456
|
+
if (existsSync2(fullPath)) {
|
|
1340
1457
|
return fullPath;
|
|
1341
1458
|
}
|
|
1342
1459
|
}
|
|
@@ -1368,6 +1485,7 @@ function createDefaultPhase() {
|
|
|
1368
1485
|
description: "Executes concrete task operations and produces artifacts.",
|
|
1369
1486
|
filePath: "",
|
|
1370
1487
|
baseDir: "",
|
|
1488
|
+
skills: [],
|
|
1371
1489
|
content: "Execute tasks using current context.\nNo planning. No evaluation.\nRoute to next phase or stop when done."
|
|
1372
1490
|
};
|
|
1373
1491
|
}
|
|
@@ -1925,7 +2043,7 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
1925
2043
|
const toolExecutionManager = createToolExecutionManager();
|
|
1926
2044
|
const execution = createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry);
|
|
1927
2045
|
const phaseTools = selectPhaseTools(allTools, phase.tools);
|
|
1928
|
-
const phaseSkills =
|
|
2046
|
+
const phaseSkills = phase.name === DEFAULT_PHASE_ID ? config.context.skills : phase.skills ?? [];
|
|
1929
2047
|
let phaseContext = {
|
|
1930
2048
|
systemPrompt: config.context.systemPrompt,
|
|
1931
2049
|
messages: messageManager.visible(),
|
|
@@ -2204,7 +2322,7 @@ async function withRetry(fn, options = {}) {
|
|
|
2204
2322
|
}
|
|
2205
2323
|
const delayMs = getRetryDelay(attempt, baseDelayMs, maxDelayMs);
|
|
2206
2324
|
options.onRetry?.(attempt, error, delayMs);
|
|
2207
|
-
await new Promise((
|
|
2325
|
+
await new Promise((resolve8) => setTimeout(resolve8, delayMs));
|
|
2208
2326
|
if (options.signal?.aborted) {
|
|
2209
2327
|
throw lastError;
|
|
2210
2328
|
}
|
|
@@ -2216,7 +2334,7 @@ async function executePhase(ctx) {
|
|
|
2216
2334
|
const { phase, config, execution, registry, context } = ctx;
|
|
2217
2335
|
if (phase.factory) {
|
|
2218
2336
|
const api = createExtensionAPI(void 0, {
|
|
2219
|
-
registerPhase: () => {
|
|
2337
|
+
registerPhase: async () => {
|
|
2220
2338
|
},
|
|
2221
2339
|
registerProvider: () => {
|
|
2222
2340
|
},
|
|
@@ -2238,7 +2356,7 @@ async function executePhase(ctx) {
|
|
|
2238
2356
|
config.context.messages.push(createMessage(role, content));
|
|
2239
2357
|
},
|
|
2240
2358
|
getAvailableTools: () => config.context.tools.map((t) => ({ name: t.name, description: t.description })),
|
|
2241
|
-
getAvailableSkills: () =>
|
|
2359
|
+
getAvailableSkills: () => context.skills.map((s) => ({ name: s.name, description: s.description })),
|
|
2242
2360
|
getPhaseContent: (id) => registry.phases.get(id)?.content ?? "",
|
|
2243
2361
|
getAvailablePhases: () => Array.from(registry.phases.keys())
|
|
2244
2362
|
},
|
|
@@ -2416,7 +2534,7 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
|
|
|
2416
2534
|
const messages = [...context];
|
|
2417
2535
|
const allTools = buildToolsWithRouting(config, availablePhases);
|
|
2418
2536
|
const phaseTools = selectPhaseTools(allTools, phase.tools);
|
|
2419
|
-
const phaseSkills =
|
|
2537
|
+
const phaseSkills = phase.name === DEFAULT_PHASE_ID ? config.context.skills : phase.skills ?? [];
|
|
2420
2538
|
const systemPrompt = config.context.systemPrompt;
|
|
2421
2539
|
const phaseContext = {
|
|
2422
2540
|
systemPrompt,
|
|
@@ -2784,6 +2902,9 @@ function assertAgentConfigRequest(config) {
|
|
|
2784
2902
|
if (!config.definition || typeof config.definition.name !== "string" || config.definition.name.trim() === "") {
|
|
2785
2903
|
throw new TypeError("config.definition.name must be non-empty");
|
|
2786
2904
|
}
|
|
2905
|
+
if (config.definition.layer && "content" in config.definition.layer) {
|
|
2906
|
+
throw new TypeError("definition.layer.content is not supported; use definition.layer.prompt");
|
|
2907
|
+
}
|
|
2787
2908
|
const view = config.resourceView;
|
|
2788
2909
|
if (!view || !Array.isArray(view.agents) || !Array.isArray(view.tools) || !Array.isArray(view.skills) || !Array.isArray(view.phases)) {
|
|
2789
2910
|
throw new TypeError("config.resourceView is invalid");
|
|
@@ -2901,12 +3022,13 @@ function snapshotConfig(config) {
|
|
|
2901
3022
|
phaseIds: Object.freeze([...config.definition.phases.phaseIds])
|
|
2902
3023
|
})
|
|
2903
3024
|
} : {},
|
|
2904
|
-
...config.definition.
|
|
3025
|
+
...config.definition.contexts ? { contexts: Object.freeze([...config.definition.contexts]) } : {}
|
|
2905
3026
|
});
|
|
2906
3027
|
const resources = Object.freeze({
|
|
2907
3028
|
...config.resources,
|
|
2908
3029
|
tools: Object.freeze([...config.resources.tools]),
|
|
2909
3030
|
skills: Object.freeze([...config.resources.skills]),
|
|
3031
|
+
...config.resources.phases ? { phases: snapshotPhaseRegistry(config.resources.phases) } : {},
|
|
2910
3032
|
...config.resources.resourceView ? {
|
|
2911
3033
|
resourceView: Object.freeze({
|
|
2912
3034
|
agents: Object.freeze([...config.resources.resourceView.agents]),
|
|
@@ -2930,6 +3052,20 @@ function snapshotConfig(config) {
|
|
|
2930
3052
|
});
|
|
2931
3053
|
return Object.freeze({ ...config, definition, resources });
|
|
2932
3054
|
}
|
|
3055
|
+
function snapshotPhaseRegistry(registry) {
|
|
3056
|
+
const phases = /* @__PURE__ */ new Map();
|
|
3057
|
+
for (const [name, phase] of registry.phases) phases.set(name, snapshotPhase(phase));
|
|
3058
|
+
return { phases, entryPhaseId: registry.entryPhaseId };
|
|
3059
|
+
}
|
|
3060
|
+
function snapshotPhase(phase) {
|
|
3061
|
+
return Object.freeze({
|
|
3062
|
+
...phase,
|
|
3063
|
+
...phase.tools ? { tools: Object.freeze([...phase.tools]) } : {},
|
|
3064
|
+
skills: Object.freeze((phase.skills ?? []).map((skill) => Object.freeze({ ...skill }))),
|
|
3065
|
+
...phase.input ? { input: Object.freeze({ ...phase.input }) } : {},
|
|
3066
|
+
...phase.model ? { model: Object.freeze({ ...phase.model }) } : {}
|
|
3067
|
+
});
|
|
3068
|
+
}
|
|
2933
3069
|
function snapshotConfiguration(config) {
|
|
2934
3070
|
const layer = config.definition.layer;
|
|
2935
3071
|
const definition = Object.freeze({
|
|
@@ -3365,7 +3501,7 @@ function resolveDefinitionContext(config, assembled = {}) {
|
|
|
3365
3501
|
);
|
|
3366
3502
|
const contexts = selectNamedResources(
|
|
3367
3503
|
config.resources.contexts ?? [],
|
|
3368
|
-
config.definition.
|
|
3504
|
+
config.definition.contexts,
|
|
3369
3505
|
"Context"
|
|
3370
3506
|
);
|
|
3371
3507
|
const candidateRegistry = assembled.phases ?? config.resources.phases;
|
|
@@ -3381,7 +3517,7 @@ function resolveDefinitionContext(config, assembled = {}) {
|
|
|
3381
3517
|
console.warn(`Phase entry "${requestedEntry}" is not available; Rowan will use "default".`);
|
|
3382
3518
|
}
|
|
3383
3519
|
return {
|
|
3384
|
-
systemPrompt: [config.definition.
|
|
3520
|
+
systemPrompt: [config.definition.prompt, buildContextDescription(contexts)].filter((section) => section.length > 0).join("\n\n"),
|
|
3385
3521
|
tools,
|
|
3386
3522
|
skills,
|
|
3387
3523
|
phases: { phases, entryPhaseId }
|
|
@@ -3429,11 +3565,11 @@ function fromLoopResult(result) {
|
|
|
3429
3565
|
var MAX_BUFFERED_EVENTS = 128;
|
|
3430
3566
|
var MAX_BUFFERED_TEXT = 64 * 1024;
|
|
3431
3567
|
function deferred() {
|
|
3432
|
-
let
|
|
3568
|
+
let resolve8;
|
|
3433
3569
|
const promise = new Promise((done) => {
|
|
3434
|
-
|
|
3570
|
+
resolve8 = done;
|
|
3435
3571
|
});
|
|
3436
|
-
return { promise, resolve:
|
|
3572
|
+
return { promise, resolve: resolve8 };
|
|
3437
3573
|
}
|
|
3438
3574
|
var TransientRunEventSubscription = class {
|
|
3439
3575
|
queue = [];
|
|
@@ -3619,6 +3755,7 @@ var HooksManager = class {
|
|
|
3619
3755
|
|
|
3620
3756
|
// src/extensions/runner.ts
|
|
3621
3757
|
import { execFile } from "child_process";
|
|
3758
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
3622
3759
|
import {
|
|
3623
3760
|
registerModel,
|
|
3624
3761
|
unregisterProviderModels,
|
|
@@ -3650,9 +3787,6 @@ function createExtensionRuntime() {
|
|
|
3650
3787
|
};
|
|
3651
3788
|
}
|
|
3652
3789
|
|
|
3653
|
-
// src/extensions/runner.ts
|
|
3654
|
-
import { parseModelRef as parseModelRef2 } from "@rowan-agent/models";
|
|
3655
|
-
|
|
3656
3790
|
// src/extensions/event-bus.ts
|
|
3657
3791
|
function createEventBus() {
|
|
3658
3792
|
const listeners = /* @__PURE__ */ new Map();
|
|
@@ -3696,7 +3830,7 @@ function createEventBus() {
|
|
|
3696
3830
|
|
|
3697
3831
|
// src/extensions/runner.ts
|
|
3698
3832
|
async function execCommand(command, args, cwd, options) {
|
|
3699
|
-
return new Promise((
|
|
3833
|
+
return new Promise((resolve8, reject) => {
|
|
3700
3834
|
const child = execFile(
|
|
3701
3835
|
command,
|
|
3702
3836
|
args,
|
|
@@ -3711,7 +3845,7 @@ async function execCommand(command, args, cwd, options) {
|
|
|
3711
3845
|
reject(new Error("Command was aborted"));
|
|
3712
3846
|
return;
|
|
3713
3847
|
}
|
|
3714
|
-
|
|
3848
|
+
resolve8({
|
|
3715
3849
|
exitCode: typeof error?.code === "number" ? error.code : error ? 1 : 0,
|
|
3716
3850
|
stdout: stdout ?? "",
|
|
3717
3851
|
stderr: stderr ?? ""
|
|
@@ -3948,17 +4082,10 @@ var ExtensionRunner = class {
|
|
|
3948
4082
|
adaptToPhase(reg) {
|
|
3949
4083
|
const def = reg.definition;
|
|
3950
4084
|
return {
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
target: def.target,
|
|
3956
|
-
input: def.input,
|
|
3957
|
-
run: def.run,
|
|
3958
|
-
filePath: "",
|
|
3959
|
-
baseDir: "",
|
|
3960
|
-
content: "",
|
|
3961
|
-
...def.model ? { model: parseModelRef2(def.model) } : {}
|
|
4085
|
+
...def,
|
|
4086
|
+
...def.tools ? { tools: [...def.tools] } : {},
|
|
4087
|
+
skills: def.skills ? [...def.skills] : [],
|
|
4088
|
+
...def.input ? { input: { ...def.input } } : {}
|
|
3962
4089
|
};
|
|
3963
4090
|
}
|
|
3964
4091
|
// ---------------------------------------------------------------------------
|
|
@@ -4120,36 +4247,20 @@ var ExtensionRunner = class {
|
|
|
4120
4247
|
});
|
|
4121
4248
|
}
|
|
4122
4249
|
registerPhase(extension, registration) {
|
|
4123
|
-
if (typeof registration
|
|
4124
|
-
throw new Error(`Phase registration requires a
|
|
4125
|
-
}
|
|
4126
|
-
const name = registration.name;
|
|
4127
|
-
const description = validateDescription(registration.description);
|
|
4128
|
-
const errors = validateResourceId(name, "name");
|
|
4129
|
-
if (description.missing) errors.push(...description.warnings);
|
|
4130
|
-
errors.push(...validateSkillReferences(registration.skills));
|
|
4131
|
-
errors.push(...validatePhaseTarget(registration.target));
|
|
4132
|
-
if (errors.length > 0) {
|
|
4133
|
-
throw new Error(`Invalid phase registration "${name}": ${errors.join("; ")}`);
|
|
4134
|
-
}
|
|
4135
|
-
if (description.warnings.length > 0) {
|
|
4136
|
-
warnResourceDiagnostics("phase", `extension ${extension.path}`, description.warnings);
|
|
4250
|
+
if (typeof registration !== "string" || registration.length === 0) {
|
|
4251
|
+
throw new Error(`Phase registration requires a directory path.`);
|
|
4137
4252
|
}
|
|
4253
|
+
return this.loadRegisteredPhase(extension, registration);
|
|
4254
|
+
}
|
|
4255
|
+
async loadRegisteredPhase(extension, registration) {
|
|
4256
|
+
const extensionBase = extension.path.startsWith("<") ? this.cwd : dirname5(extension.path);
|
|
4257
|
+
const phase = await loadPhase(resolve5(extensionBase, registration));
|
|
4258
|
+
const name = phase.name;
|
|
4138
4259
|
if (this.phases.has(name)) {
|
|
4139
4260
|
throw new Error(`Duplicate phase name: ${name}`);
|
|
4140
4261
|
}
|
|
4141
|
-
const definition = {
|
|
4142
|
-
name,
|
|
4143
|
-
description: description.description,
|
|
4144
|
-
run: registration.run,
|
|
4145
|
-
...registration.tools ? { tools: registration.tools.slice() } : {},
|
|
4146
|
-
...registration.skills ? { skills: registration.skills.slice() } : {},
|
|
4147
|
-
...registration.target ? { target: registration.target } : {},
|
|
4148
|
-
...registration.input ? { input: { ...registration.input } } : {},
|
|
4149
|
-
...registration.model ? { model: registration.model } : {}
|
|
4150
|
-
};
|
|
4151
4262
|
const registered = {
|
|
4152
|
-
definition,
|
|
4263
|
+
definition: phase,
|
|
4153
4264
|
source: { extensionPath: extension.path }
|
|
4154
4265
|
};
|
|
4155
4266
|
this.phases.set(name, registered);
|
|
@@ -4208,10 +4319,10 @@ function createExtensionRunner(options) {
|
|
|
4208
4319
|
}
|
|
4209
4320
|
|
|
4210
4321
|
// src/extensions/loader.ts
|
|
4211
|
-
import { existsSync as
|
|
4212
|
-
import { readdir as
|
|
4322
|
+
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
4323
|
+
import { readdir as readdir3, readFile as readFile3, stat as stat2 } from "fs/promises";
|
|
4213
4324
|
import { fileURLToPath } from "url";
|
|
4214
|
-
import { basename as basename3, dirname as
|
|
4325
|
+
import { basename as basename3, dirname as dirname6, extname as extname2, join as join3, resolve as resolve6 } from "path";
|
|
4215
4326
|
import { createJiti } from "jiti";
|
|
4216
4327
|
function isExtensionFile(path) {
|
|
4217
4328
|
const extension = extname2(path).toLowerCase();
|
|
@@ -4221,8 +4332,8 @@ function isSyntheticPath(path) {
|
|
|
4221
4332
|
return path.startsWith("<") && path.endsWith(">");
|
|
4222
4333
|
}
|
|
4223
4334
|
function readManifestSync(dir) {
|
|
4224
|
-
const manifestPath =
|
|
4225
|
-
if (!
|
|
4335
|
+
const manifestPath = join3(dir, "package.json");
|
|
4336
|
+
if (!existsSync3(manifestPath)) {
|
|
4226
4337
|
return void 0;
|
|
4227
4338
|
}
|
|
4228
4339
|
try {
|
|
@@ -4231,8 +4342,7 @@ function readManifestSync(dir) {
|
|
|
4231
4342
|
const rowan = pkg.rowan;
|
|
4232
4343
|
if (!rowan) return void 0;
|
|
4233
4344
|
return {
|
|
4234
|
-
entry: rowan.extensions?.[0]
|
|
4235
|
-
phase: rowan.phase
|
|
4345
|
+
entry: rowan.extensions?.[0]
|
|
4236
4346
|
};
|
|
4237
4347
|
} catch {
|
|
4238
4348
|
return void 0;
|
|
@@ -4244,7 +4354,7 @@ function jitiAliases() {
|
|
|
4244
4354
|
return {};
|
|
4245
4355
|
}
|
|
4246
4356
|
const agentSourcePath = fileURLToPath(new URL("../index.ts", moduleUrl));
|
|
4247
|
-
if (!
|
|
4357
|
+
if (!existsSync3(agentSourcePath)) {
|
|
4248
4358
|
return {};
|
|
4249
4359
|
}
|
|
4250
4360
|
return { "@rowan-agent/agent": agentSourcePath };
|
|
@@ -4265,28 +4375,28 @@ async function loadExtensionModule(extensionPath) {
|
|
|
4265
4375
|
return typeof module === "function" ? module : void 0;
|
|
4266
4376
|
}
|
|
4267
4377
|
async function readPackageManifest(path) {
|
|
4268
|
-
if (!
|
|
4378
|
+
if (!existsSync3(path)) {
|
|
4269
4379
|
return void 0;
|
|
4270
4380
|
}
|
|
4271
4381
|
const content = await readFile3(path, "utf8");
|
|
4272
4382
|
return JSON.parse(content);
|
|
4273
4383
|
}
|
|
4274
4384
|
async function resolveExtensionEntries(dir) {
|
|
4275
|
-
const manifest = await readPackageManifest(
|
|
4385
|
+
const manifest = await readPackageManifest(join3(dir, "package.json"));
|
|
4276
4386
|
const declared = manifest?.rowan?.extensions;
|
|
4277
4387
|
if (declared && declared.length > 0) {
|
|
4278
|
-
return declared.map((entry) =>
|
|
4388
|
+
return declared.map((entry) => resolve6(dir, entry));
|
|
4279
4389
|
}
|
|
4280
4390
|
for (const name of ["index.ts", "index.js"]) {
|
|
4281
|
-
const entry =
|
|
4282
|
-
if (
|
|
4391
|
+
const entry = join3(dir, name);
|
|
4392
|
+
if (existsSync3(entry)) {
|
|
4283
4393
|
return [entry];
|
|
4284
4394
|
}
|
|
4285
4395
|
}
|
|
4286
4396
|
return void 0;
|
|
4287
4397
|
}
|
|
4288
4398
|
async function discoverExtensionsInDir(dir) {
|
|
4289
|
-
const entries = await
|
|
4399
|
+
const entries = await readdir3(dir, { withFileTypes: true }).catch((error) => {
|
|
4290
4400
|
if (error.code === "ENOENT") {
|
|
4291
4401
|
return [];
|
|
4292
4402
|
}
|
|
@@ -4294,7 +4404,7 @@ async function discoverExtensionsInDir(dir) {
|
|
|
4294
4404
|
});
|
|
4295
4405
|
const paths = [];
|
|
4296
4406
|
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
4297
|
-
const entryPath =
|
|
4407
|
+
const entryPath = join3(dir, entry.name);
|
|
4298
4408
|
if ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {
|
|
4299
4409
|
paths.push(entryPath);
|
|
4300
4410
|
continue;
|
|
@@ -4312,10 +4422,10 @@ async function discoverExtensionsInDir(dir) {
|
|
|
4312
4422
|
return paths;
|
|
4313
4423
|
}
|
|
4314
4424
|
function loadExtensionFromFactory(factory, cwd, extensionPath = "<inline>") {
|
|
4315
|
-
const resolvedCwd =
|
|
4316
|
-
const resolvedPath = isSyntheticPath(extensionPath) ? extensionPath :
|
|
4317
|
-
const name = isSyntheticPath(extensionPath) ? extensionPath : basename3(
|
|
4318
|
-
const manifestDir = isSyntheticPath(extensionPath) ? resolvedCwd :
|
|
4425
|
+
const resolvedCwd = resolve6(cwd);
|
|
4426
|
+
const resolvedPath = isSyntheticPath(extensionPath) ? extensionPath : resolve6(resolvedCwd, extensionPath);
|
|
4427
|
+
const name = isSyntheticPath(extensionPath) ? extensionPath : basename3(dirname6(resolvedPath)) || "unknown";
|
|
4428
|
+
const manifestDir = isSyntheticPath(extensionPath) ? resolvedCwd : dirname6(resolvedPath);
|
|
4319
4429
|
const manifest = readManifestSync(manifestDir);
|
|
4320
4430
|
return {
|
|
4321
4431
|
path: resolvedPath,
|
|
@@ -4327,9 +4437,9 @@ function loadExtensionFromFactory(factory, cwd, extensionPath = "<inline>") {
|
|
|
4327
4437
|
async function loadExtensions(paths, cwd) {
|
|
4328
4438
|
const extensions = [];
|
|
4329
4439
|
const errors = [];
|
|
4330
|
-
const resolvedCwd =
|
|
4440
|
+
const resolvedCwd = resolve6(cwd);
|
|
4331
4441
|
for (const path of paths) {
|
|
4332
|
-
const resolvedPath =
|
|
4442
|
+
const resolvedPath = resolve6(resolvedCwd, path);
|
|
4333
4443
|
try {
|
|
4334
4444
|
const factory = await loadExtensionModule(resolvedPath);
|
|
4335
4445
|
if (!factory) {
|
|
@@ -4350,10 +4460,10 @@ async function loadExtensions(paths, cwd) {
|
|
|
4350
4460
|
return { extensions, errors };
|
|
4351
4461
|
}
|
|
4352
4462
|
async function loadExtensionsFromPath(path) {
|
|
4353
|
-
const resolvedPath =
|
|
4463
|
+
const resolvedPath = resolve6(path);
|
|
4354
4464
|
const info = await stat2(resolvedPath);
|
|
4355
4465
|
if (!info.isDirectory()) {
|
|
4356
|
-
return loadExtensions([resolvedPath],
|
|
4466
|
+
return loadExtensions([resolvedPath], dirname6(resolvedPath));
|
|
4357
4467
|
}
|
|
4358
4468
|
const entries = await resolveExtensionEntries(resolvedPath) ?? await discoverExtensionsInDir(resolvedPath);
|
|
4359
4469
|
return loadExtensions(entries, resolvedPath);
|
|
@@ -4361,87 +4471,7 @@ async function loadExtensionsFromPath(path) {
|
|
|
4361
4471
|
|
|
4362
4472
|
// src/runtime/resource-registry.ts
|
|
4363
4473
|
import { stat as stat3, readdir as readdir4 } from "fs/promises";
|
|
4364
|
-
import { join as join4, resolve as
|
|
4365
|
-
|
|
4366
|
-
// src/harness/skills.ts
|
|
4367
|
-
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
4368
|
-
import { readdir as readdir3 } from "fs/promises";
|
|
4369
|
-
import { dirname as dirname5, join as join3, resolve as resolve5 } from "path";
|
|
4370
|
-
var SKILL_MARKER = "SKILL.md";
|
|
4371
|
-
function resolveSkillPath(input) {
|
|
4372
|
-
const resolved = resolve5(input);
|
|
4373
|
-
return existsSync3(resolved) && statSync2(resolved).isDirectory() ? join3(resolved, SKILL_MARKER) : resolved;
|
|
4374
|
-
}
|
|
4375
|
-
async function loadSkill(path) {
|
|
4376
|
-
const resolved = resolveSkillPath(path);
|
|
4377
|
-
let loaded;
|
|
4378
|
-
try {
|
|
4379
|
-
loaded = await loadMarkdown(resolved);
|
|
4380
|
-
} catch (error) {
|
|
4381
|
-
if (!(error instanceof FrontmatterParseError)) throw error;
|
|
4382
|
-
warnResourceDiagnostics("skill", resolved, [`frontmatter could not be parsed: ${error.message}`]);
|
|
4383
|
-
throw new ResourceMetadataError("parse_failed", error.message);
|
|
4384
|
-
}
|
|
4385
|
-
const { frontmatter, body } = loaded;
|
|
4386
|
-
const metadata = frontmatter;
|
|
4387
|
-
const id = inferResourceName(resolved, SKILL_MARKER);
|
|
4388
|
-
const frontmatterName = typeof metadata.name === "string" ? metadata.name : void 0;
|
|
4389
|
-
const name = frontmatterName || id;
|
|
4390
|
-
const description = validateDescription(metadata.description);
|
|
4391
|
-
const diagnostics = validateResourceId(id);
|
|
4392
|
-
if (frontmatterName && frontmatterName !== id) {
|
|
4393
|
-
diagnostics.push(...validateResourceName(frontmatterName, id));
|
|
4394
|
-
}
|
|
4395
|
-
diagnostics.push(...description.warnings);
|
|
4396
|
-
warnResourceDiagnostics("skill", resolved, diagnostics);
|
|
4397
|
-
if (description.missing) {
|
|
4398
|
-
throw new ResourceMetadataError("invalid_metadata", "description is required");
|
|
4399
|
-
}
|
|
4400
|
-
return {
|
|
4401
|
-
name,
|
|
4402
|
-
description: description.description,
|
|
4403
|
-
filePath: resolved,
|
|
4404
|
-
baseDir: dirname5(resolved),
|
|
4405
|
-
content: body,
|
|
4406
|
-
disableModelInvocation: metadata["disable-model-invocation"] === true
|
|
4407
|
-
};
|
|
4408
|
-
}
|
|
4409
|
-
async function loadSkills(targetPath) {
|
|
4410
|
-
const skillsDir = resolve5(targetPath);
|
|
4411
|
-
if (existsSync3(skillsDir) && statSync2(skillsDir).isFile()) {
|
|
4412
|
-
try {
|
|
4413
|
-
return [await loadSkill(skillsDir)];
|
|
4414
|
-
} catch (error) {
|
|
4415
|
-
if (error instanceof ResourceMetadataError) return [];
|
|
4416
|
-
throw error;
|
|
4417
|
-
}
|
|
4418
|
-
}
|
|
4419
|
-
if (existsSync3(join3(skillsDir, SKILL_MARKER))) {
|
|
4420
|
-
try {
|
|
4421
|
-
return [await loadSkill(skillsDir)];
|
|
4422
|
-
} catch (error) {
|
|
4423
|
-
if (error instanceof ResourceMetadataError) return [];
|
|
4424
|
-
throw error;
|
|
4425
|
-
}
|
|
4426
|
-
}
|
|
4427
|
-
const entries = await readdir3(skillsDir, { withFileTypes: true });
|
|
4428
|
-
const skills = [];
|
|
4429
|
-
for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
4430
|
-
if (!entry.isDirectory()) continue;
|
|
4431
|
-
const skillFile = join3(skillsDir, entry.name, SKILL_MARKER);
|
|
4432
|
-
if (!existsSync3(skillFile)) continue;
|
|
4433
|
-
try {
|
|
4434
|
-
const skill = await loadSkill(skillFile);
|
|
4435
|
-
skills.push(skill);
|
|
4436
|
-
} catch (error) {
|
|
4437
|
-
if (error instanceof ResourceMetadataError) continue;
|
|
4438
|
-
console.warn(`Failed to load skill "${entry.name}":`, error);
|
|
4439
|
-
}
|
|
4440
|
-
}
|
|
4441
|
-
return skills;
|
|
4442
|
-
}
|
|
4443
|
-
|
|
4444
|
-
// src/runtime/resource-registry.ts
|
|
4474
|
+
import { join as join4, resolve as resolve7 } from "path";
|
|
4445
4475
|
var ResourceRegistryError = class extends Error {
|
|
4446
4476
|
code;
|
|
4447
4477
|
constructor(code, message) {
|
|
@@ -4568,6 +4598,7 @@ var ResourceRegistry = class {
|
|
|
4568
4598
|
assertSourceId(sourceId);
|
|
4569
4599
|
const names = /* @__PURE__ */ new Set();
|
|
4570
4600
|
for (const value of values) {
|
|
4601
|
+
if (kind === "agent") assertAgentDefinition(value);
|
|
4571
4602
|
assertNamedResource(value, kind, sourceId);
|
|
4572
4603
|
if (isImplicitCoreName(kind, value.name) && sourceId !== "rowan.core") {
|
|
4573
4604
|
throw new ResourceRegistryError(
|
|
@@ -4584,11 +4615,12 @@ var ResourceRegistry = class {
|
|
|
4584
4615
|
names.add(value.name);
|
|
4585
4616
|
}
|
|
4586
4617
|
const revision = this.nextRevision(kind, sourceId);
|
|
4618
|
+
const snapshottedValues = values.map((value) => snapshotResourceValue(kind, value));
|
|
4587
4619
|
const record = {
|
|
4588
4620
|
kind,
|
|
4589
4621
|
sourceId,
|
|
4590
4622
|
revision,
|
|
4591
|
-
values: Object.freeze(
|
|
4623
|
+
values: Object.freeze(snapshottedValues)
|
|
4592
4624
|
};
|
|
4593
4625
|
let bySource = this.sources.get(kind);
|
|
4594
4626
|
if (!bySource) {
|
|
@@ -4658,6 +4690,18 @@ var ResourceRegistry = class {
|
|
|
4658
4690
|
return `${kind}:${sourceId}:${this.revisionSequence}`;
|
|
4659
4691
|
}
|
|
4660
4692
|
};
|
|
4693
|
+
function snapshotResourceValue(kind, value) {
|
|
4694
|
+
if (kind !== "phase") return value;
|
|
4695
|
+
const phase = value;
|
|
4696
|
+
const snapshot = {
|
|
4697
|
+
...phase,
|
|
4698
|
+
...phase.tools ? { tools: Object.freeze([...phase.tools]) } : {},
|
|
4699
|
+
skills: Object.freeze((phase.skills ?? []).map((skill) => Object.freeze({ ...skill }))),
|
|
4700
|
+
...phase.input ? { input: Object.freeze({ ...phase.input }) } : {},
|
|
4701
|
+
...phase.model ? { model: Object.freeze({ ...phase.model }) } : {}
|
|
4702
|
+
};
|
|
4703
|
+
return Object.freeze(snapshot);
|
|
4704
|
+
}
|
|
4661
4705
|
function assertSourceId(sourceId) {
|
|
4662
4706
|
if (typeof sourceId !== "string" || !SOURCE_ID.test(sourceId)) {
|
|
4663
4707
|
throw new ResourceRegistryError("invalid_source_id", `Invalid resource source "${String(sourceId)}".`);
|
|
@@ -4679,7 +4723,7 @@ function isImplicitCoreName(kind, name) {
|
|
|
4679
4723
|
return kind === "tool" && name === "route" || kind === "phase" && name === "default";
|
|
4680
4724
|
}
|
|
4681
4725
|
async function loadDirectoryValues(kind, directory, sourceId) {
|
|
4682
|
-
const root =
|
|
4726
|
+
const root = resolve7(directory);
|
|
4683
4727
|
let rootInfo;
|
|
4684
4728
|
try {
|
|
4685
4729
|
rootInfo = await stat3(root);
|
|
@@ -4922,7 +4966,7 @@ function resolveConfigurationSnapshot(registry, input) {
|
|
|
4922
4966
|
const tools = selectNamedResources(resolved.tools, definition.tools, "Tool");
|
|
4923
4967
|
const skills = selectNamedResources(resolved.skills, definition.skills, "Skill");
|
|
4924
4968
|
const phases = resolvePhases(resolved.phases, definition.phases);
|
|
4925
|
-
const contexts = selectNamedResources(input.contexts ?? [], base.
|
|
4969
|
+
const contexts = selectNamedResources(input.contexts ?? [], base.contexts, "Context");
|
|
4926
4970
|
return {
|
|
4927
4971
|
identity: input.identity,
|
|
4928
4972
|
definition,
|
|
@@ -4973,7 +5017,7 @@ function applyDefinitionLayer(base, layer) {
|
|
|
4973
5017
|
return {
|
|
4974
5018
|
...base,
|
|
4975
5019
|
...layer.description === void 0 ? {} : { description: layer.description },
|
|
4976
|
-
...layer.
|
|
5020
|
+
...layer.prompt === void 0 ? {} : { prompt: layer.prompt },
|
|
4977
5021
|
...layer.model === void 0 ? {} : { model: layer.model },
|
|
4978
5022
|
...layer.tools === void 0 ? {} : { tools: intersectNames(base.tools, layer.tools, "Tool") },
|
|
4979
5023
|
...layer.skills === void 0 ? {} : { skills: intersectNames(base.skills, layer.skills, "Skill") },
|
|
@@ -5001,9 +5045,8 @@ function intersectPhaseSelection(parent, layer) {
|
|
|
5001
5045
|
}
|
|
5002
5046
|
function resolvePhases(candidates, selection) {
|
|
5003
5047
|
const selected = selectNamedResources(candidates, selection?.phaseIds, "Phase");
|
|
5004
|
-
if (selected.length === 0 && selection === void 0) return void 0;
|
|
5005
5048
|
const entryPhaseId = selection?.entryPhaseId ?? null;
|
|
5006
|
-
if (entryPhaseId !== null && !selected.some(({ name }) => name === entryPhaseId)) {
|
|
5049
|
+
if (entryPhaseId !== null && entryPhaseId !== DEFAULT_PHASE_ID && !selected.some(({ name }) => name === entryPhaseId)) {
|
|
5007
5050
|
console.warn(`Phase entry "${entryPhaseId}" is not available and will be skipped.`);
|
|
5008
5051
|
return { phases: new Map(selected.map((phase) => [phase.name, phase])), entryPhaseId: null };
|
|
5009
5052
|
}
|
|
@@ -5618,7 +5661,7 @@ function boundaryFromSnapshot(snapshot) {
|
|
|
5618
5661
|
}
|
|
5619
5662
|
}
|
|
5620
5663
|
function delay(ms) {
|
|
5621
|
-
return new Promise((
|
|
5664
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
5622
5665
|
}
|
|
5623
5666
|
function normalizePhaseRegistry(registry) {
|
|
5624
5667
|
if (registry?.phases.has(DEFAULT_PHASE_ID) && registry.phases.get(DEFAULT_PHASE_ID)?.filePath !== "") {
|
|
@@ -5645,13 +5688,13 @@ function toJsonValue(value) {
|
|
|
5645
5688
|
return value;
|
|
5646
5689
|
}
|
|
5647
5690
|
function deferred2() {
|
|
5648
|
-
let
|
|
5691
|
+
let resolve8;
|
|
5649
5692
|
let reject;
|
|
5650
5693
|
const promise = new Promise((res, rej) => {
|
|
5651
|
-
|
|
5694
|
+
resolve8 = (value) => res(value);
|
|
5652
5695
|
reject = rej;
|
|
5653
5696
|
});
|
|
5654
|
-
return { promise, resolve:
|
|
5697
|
+
return { promise, resolve: resolve8, reject };
|
|
5655
5698
|
}
|
|
5656
5699
|
|
|
5657
5700
|
// src/runtime/durable-store.ts
|
|
@@ -7129,7 +7172,9 @@ export {
|
|
|
7129
7172
|
createCoreTools2 as createCoreTools,
|
|
7130
7173
|
isRuntimeError,
|
|
7131
7174
|
loadExtensionsFromPath as loadExtensions,
|
|
7175
|
+
loadPhase,
|
|
7132
7176
|
loadPhases,
|
|
7177
|
+
loadSkill,
|
|
7133
7178
|
loadSkills,
|
|
7134
7179
|
materializeConfigurationSnapshot,
|
|
7135
7180
|
parseAgentDefinition,
|