@rowan-agent/agent 0.16.0 → 0.16.2
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 +6 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.js +93 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -183,10 +183,12 @@ const agentId = await runtime.createAgent({
|
|
|
183
183
|
Each `load*()` call replaces one source atomically; use `directory` or inline
|
|
184
184
|
`values`. `resourceView` controls visibility, so same-name resources can live
|
|
185
185
|
in isolated sources but collide when selected together. The Runtime supplies the
|
|
186
|
-
core `read`/`bash`/`edit`/`write
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
core `read`/`bash`/`edit`/`write` Tools and built-in `default`/`stop`/`compact` Phases.
|
|
187
|
+
Host-defined resources (including Tools and Phases registered by Extensions) replace
|
|
188
|
+
built-ins by name, retaining the built-in status (replaced Core Tools remain always
|
|
189
|
+
available without explicit Definition selection; replaced Core Phases retain their
|
|
190
|
+
built-in role). Reserved control names (`route` for Tools, `continue` for Phases)
|
|
191
|
+
cannot be claimed by host sources.
|
|
190
192
|
|
|
191
193
|
Extensions are Runtime-global. Load them only during `AgentRuntime.init()` via
|
|
192
194
|
`bootstrap`; after initialization they are frozen until the Runtime closes.
|
package/dist/index.d.ts
CHANGED
|
@@ -269,6 +269,10 @@ interface ToolDefinition {
|
|
|
269
269
|
description: string;
|
|
270
270
|
/** Parameter schema (JSON Schema) */
|
|
271
271
|
parameters: Record<string, unknown>;
|
|
272
|
+
/** Optional: one-line snippet shown in the system prompt tool list */
|
|
273
|
+
promptSnippet?: string;
|
|
274
|
+
/** Optional: additional guidelines appended to system prompt */
|
|
275
|
+
promptGuidelines?: string[];
|
|
272
276
|
/** Execute the tool */
|
|
273
277
|
execute: (args: unknown, context: ToolInvocationContext, signal?: AbortSignal) => Promise<ToolExecutionResult$1>;
|
|
274
278
|
/** Optional: per-tool execution mode override */
|
|
@@ -955,6 +959,8 @@ type Tool$1 = Readonly<{
|
|
|
955
959
|
core?: boolean;
|
|
956
960
|
description: string;
|
|
957
961
|
parameters: Type.TSchema;
|
|
962
|
+
promptSnippet?: string;
|
|
963
|
+
promptGuidelines?: readonly string[];
|
|
958
964
|
execute(args: JsonValue, context: ToolInvocationContext, signal: AbortSignal): Promise<ToolExecutionResult>;
|
|
959
965
|
}>;
|
|
960
966
|
type ContextCandidate = Readonly<{
|
package/dist/index.js
CHANGED
|
@@ -738,8 +738,8 @@ function createReadTool(context) {
|
|
|
738
738
|
[truncated]` : formatted;
|
|
739
739
|
const archivePath = await spillResult(context, "read", fullFormatted);
|
|
740
740
|
content += `
|
|
741
|
-
|
|
742
|
-
|
|
741
|
+
|
|
742
|
+
[Full result: ${archivePath}, offset 0]`;
|
|
743
743
|
if (lineTruncated) {
|
|
744
744
|
content += `
|
|
745
745
|
Showing lines ${requestedOffset}-${selectedLineEnd} of ${sourceLines.length}. Use offset=${selectedLineEnd + 1} to continue.`;
|
|
@@ -896,8 +896,8 @@ function createBashTool(context) {
|
|
|
896
896
|
[truncated]` : output;
|
|
897
897
|
const archivePath = await spillResult(context, "bash", output);
|
|
898
898
|
content += `
|
|
899
|
-
|
|
900
|
-
|
|
899
|
+
|
|
900
|
+
[Full result: ${archivePath}, offset 0]`;
|
|
901
901
|
return toolResult({
|
|
902
902
|
context: toolContext,
|
|
903
903
|
toolName: "bash",
|
|
@@ -925,12 +925,15 @@ function createCoreTools(input = {}) {
|
|
|
925
925
|
}
|
|
926
926
|
|
|
927
927
|
// src/runtime/core-tools.ts
|
|
928
|
+
var CORE_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "edit", "write", "bash"]);
|
|
928
929
|
function createRuntimeCoreTools(input = {}) {
|
|
929
930
|
return createCoreTools(input).map((tool) => ({
|
|
930
931
|
name: tool.name,
|
|
931
932
|
core: true,
|
|
932
933
|
description: tool.description,
|
|
933
934
|
parameters: tool.parameters,
|
|
935
|
+
...tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {},
|
|
936
|
+
...tool.promptGuidelines ? { promptGuidelines: tool.promptGuidelines } : {},
|
|
934
937
|
execute: async (args, context, signal) => {
|
|
935
938
|
const result = await tool.execute(args, { skills: [], toolCallId: context.toolCallId }, signal);
|
|
936
939
|
return result.ok ? { ok: true, content: result.content } : { ok: false, content: result.content, error: result.error ?? "Tool failed." };
|
|
@@ -2010,6 +2013,7 @@ async function loadPhaseCode(codePath) {
|
|
|
2010
2013
|
var DEFAULT_PHASE_ID = "default";
|
|
2011
2014
|
var STOP_PHASE_ID = "stop";
|
|
2012
2015
|
var COMPACT_PHASE_ID = "compact";
|
|
2016
|
+
var CORE_PHASE_NAMES = /* @__PURE__ */ new Set([DEFAULT_PHASE_ID, STOP_PHASE_ID, COMPACT_PHASE_ID]);
|
|
2013
2017
|
function createDefaultPhase() {
|
|
2014
2018
|
return {
|
|
2015
2019
|
name: DEFAULT_PHASE_ID,
|
|
@@ -2062,7 +2066,7 @@ function createCompactPhase() {
|
|
|
2062
2066
|
kind: "compacting",
|
|
2063
2067
|
message: "Compacting conversation context."
|
|
2064
2068
|
});
|
|
2065
|
-
const tools = context.tools.filter((tool) => tool.
|
|
2069
|
+
const tools = context.tools.filter((tool) => tool.name === "read" || tool.name === "bash");
|
|
2066
2070
|
const working = { ...context, tools, skills: [...context.skills], messages: [...context.messages] };
|
|
2067
2071
|
const instructions = compactInstructions(context);
|
|
2068
2072
|
if (instructions) {
|
|
@@ -3800,7 +3804,7 @@ function resolveConfigurationSnapshot(registry, input) {
|
|
|
3800
3804
|
const selectedContexts = selectNamedResources(input.contexts ?? [], base.contexts, "Context");
|
|
3801
3805
|
const additionalContexts = deduplicateContexts(input.additionalContexts ?? [], selectedContexts);
|
|
3802
3806
|
const definition = applyDefinitionLayer(base, layer);
|
|
3803
|
-
const tools =
|
|
3807
|
+
const tools = resolveTools(resolved.tools, definition.tools);
|
|
3804
3808
|
const skills = mergeSkills(
|
|
3805
3809
|
selectNamedResources(resolved.skills, definition.skills, "Skill"),
|
|
3806
3810
|
definition.bundledSkills
|
|
@@ -3873,11 +3877,20 @@ function intersectPhaseSelection(parent, layer) {
|
|
|
3873
3877
|
phaseIds: layer.phaseIds.filter((name) => parentNames.has(name))
|
|
3874
3878
|
};
|
|
3875
3879
|
}
|
|
3880
|
+
function resolveCoreResources(candidates, selection, coreNames, kind) {
|
|
3881
|
+
const core = candidates.filter((item) => item.core || coreNames.has(item.name));
|
|
3882
|
+
const authoredSelection = selection ? selection.filter((name) => !coreNames.has(name)) : void 0;
|
|
3883
|
+
const authored = candidates.filter((item) => !coreNames.has(item.name) && !item.core);
|
|
3884
|
+
return [
|
|
3885
|
+
...core.map((item) => item.core ? item : { ...item, core: true }),
|
|
3886
|
+
...selectNamedResources(authored, authoredSelection, kind)
|
|
3887
|
+
];
|
|
3888
|
+
}
|
|
3889
|
+
function resolveTools(candidates, selection) {
|
|
3890
|
+
return resolveCoreResources(candidates, selection, CORE_TOOL_NAMES, "Tool");
|
|
3891
|
+
}
|
|
3876
3892
|
function resolvePhases(candidates, selection) {
|
|
3877
|
-
const
|
|
3878
|
-
const core = candidates.filter((phase) => phase.core || coreNames.has(phase.name));
|
|
3879
|
-
const authored = candidates.filter((phase) => !coreNames.has(phase.name) && !phase.core);
|
|
3880
|
-
const selected = [...core, ...selectNamedResources(authored, selection?.phaseIds, "Phase")];
|
|
3893
|
+
const selected = resolveCoreResources(candidates, selection?.phaseIds, CORE_PHASE_NAMES, "Phase");
|
|
3881
3894
|
const entryPhaseId = selection?.entryPhaseId ?? null;
|
|
3882
3895
|
if (entryPhaseId !== null && entryPhaseId !== DEFAULT_PHASE_ID && !selected.some(({ name }) => name === entryPhaseId)) {
|
|
3883
3896
|
console.warn(`Phase entry "${entryPhaseId}" is not available and will be skipped.`);
|
|
@@ -4547,6 +4560,8 @@ function projectTool(tool, agentId, runId) {
|
|
|
4547
4560
|
...tool.core ? { core: true } : {},
|
|
4548
4561
|
description: tool.description,
|
|
4549
4562
|
parameters: tool.parameters,
|
|
4563
|
+
...tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {},
|
|
4564
|
+
...tool.promptGuidelines ? { promptGuidelines: [...tool.promptGuidelines] } : {},
|
|
4550
4565
|
execute: async (args, context, signal) => {
|
|
4551
4566
|
const result = await tool.execute(args, {
|
|
4552
4567
|
agentId,
|
|
@@ -4569,10 +4584,12 @@ function assembleRegisteredExtensions(snapshot, runner, options = {}) {
|
|
|
4569
4584
|
root: snapshot.cwd,
|
|
4570
4585
|
...options.toolArchiveDir ? { archiveDir: options.toolArchiveDir } : {}
|
|
4571
4586
|
});
|
|
4572
|
-
const
|
|
4587
|
+
const replacingNames = new Set(
|
|
4588
|
+
snapshot.resources.tools.filter((tool) => tool.core).map((tool) => tool.name)
|
|
4589
|
+
);
|
|
4573
4590
|
const tools = [
|
|
4574
|
-
...snapshot.resources.tools
|
|
4575
|
-
...coreTools
|
|
4591
|
+
...snapshot.resources.tools,
|
|
4592
|
+
...coreTools.filter((tool) => !replacingNames.has(tool.name))
|
|
4576
4593
|
];
|
|
4577
4594
|
const context = resolveDefinitionContext(snapshot, tools);
|
|
4578
4595
|
return {
|
|
@@ -4620,8 +4637,9 @@ function assembleRegisteredExtensions(snapshot, runner, options = {}) {
|
|
|
4620
4637
|
function resolveDefinitionContext(snapshot, assembled) {
|
|
4621
4638
|
const coreTools = assembled.filter((tool) => tool.core);
|
|
4622
4639
|
const authoredTools = assembled.filter((tool) => !tool.core);
|
|
4640
|
+
const authoredSelection = snapshot.definition.tools ? snapshot.definition.tools.filter((name) => !assembled.some((t) => t.core && t.name === name)) : void 0;
|
|
4623
4641
|
const tools = [
|
|
4624
|
-
...selectNamedResources(authoredTools,
|
|
4642
|
+
...selectNamedResources(authoredTools, authoredSelection, "Tool"),
|
|
4625
4643
|
...coreTools
|
|
4626
4644
|
];
|
|
4627
4645
|
const skills = mergeSkills(
|
|
@@ -4633,14 +4651,12 @@ function resolveDefinitionContext(snapshot, assembled) {
|
|
|
4633
4651
|
...snapshot.additionalContexts
|
|
4634
4652
|
];
|
|
4635
4653
|
const phaseCandidates = [...snapshot.resources.phases?.phases.values() ?? []];
|
|
4636
|
-
const
|
|
4654
|
+
const corePhases = phaseCandidates.filter((phase) => phase.core);
|
|
4655
|
+
const authoredPhases = phaseCandidates.filter((phase) => !phase.core);
|
|
4656
|
+
const authoredPhaseIds = snapshot.definition.phases?.phaseIds ? snapshot.definition.phases.phaseIds.filter((name) => !corePhases.some((p) => p.name === name)) : void 0;
|
|
4637
4657
|
const selectedPhases = [
|
|
4638
|
-
...
|
|
4639
|
-
...selectNamedResources(
|
|
4640
|
-
phaseCandidates.filter((phase) => !phase.core && !coreNames.has(phase.name)),
|
|
4641
|
-
snapshot.definition.phases?.phaseIds,
|
|
4642
|
-
"Phase"
|
|
4643
|
-
)
|
|
4658
|
+
...corePhases,
|
|
4659
|
+
...selectNamedResources(authoredPhases, authoredPhaseIds, "Phase")
|
|
4644
4660
|
];
|
|
4645
4661
|
const phases = new Map(selectedPhases.map((phase) => [phase.name, phase]));
|
|
4646
4662
|
const requestedEntry = snapshot.definition.phases ? snapshot.definition.phases.entryPhaseId : snapshot.resources.phases?.entryPhaseId ?? null;
|
|
@@ -6076,8 +6092,16 @@ var ResourceRegistry = class {
|
|
|
6076
6092
|
}
|
|
6077
6093
|
withImplicit(kind, sourceIds) {
|
|
6078
6094
|
const combined = [...sourceIds];
|
|
6095
|
+
let hasCore = false;
|
|
6079
6096
|
for (const sourceId of this.implicitSources.get(kind) ?? []) {
|
|
6080
|
-
if (
|
|
6097
|
+
if (sourceId === "rowan.core") {
|
|
6098
|
+
hasCore = true;
|
|
6099
|
+
} else if (!combined.includes(sourceId)) {
|
|
6100
|
+
combined.push(sourceId);
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6103
|
+
if (hasCore && !combined.includes("rowan.core")) {
|
|
6104
|
+
combined.push("rowan.core");
|
|
6081
6105
|
}
|
|
6082
6106
|
return combined;
|
|
6083
6107
|
}
|
|
@@ -6108,6 +6132,12 @@ var ResourceRegistry = class {
|
|
|
6108
6132
|
`${capitalize(kind)} resource "${value.name}" is reserved by Rowan core.`
|
|
6109
6133
|
);
|
|
6110
6134
|
}
|
|
6135
|
+
if (kind === "phase" && value.name === "continue") {
|
|
6136
|
+
throw new ResourceRegistryError(
|
|
6137
|
+
"resource_collision",
|
|
6138
|
+
`Phase resource "continue" is reserved by Rowan routing controls.`
|
|
6139
|
+
);
|
|
6140
|
+
}
|
|
6111
6141
|
if (names.has(value.name)) {
|
|
6112
6142
|
throw new ResourceRegistryError(
|
|
6113
6143
|
"resource_collision",
|
|
@@ -6142,6 +6172,12 @@ var ResourceRegistry = class {
|
|
|
6142
6172
|
for (const source of this.sourcesFor(kind, sourceIds)) {
|
|
6143
6173
|
for (const value of source.values) {
|
|
6144
6174
|
if (names.has(value.name)) {
|
|
6175
|
+
if (source.sourceId === "rowan.core") {
|
|
6176
|
+
continue;
|
|
6177
|
+
}
|
|
6178
|
+
if (source.sourceId === "rowan.extensions" && isCoreResourceName(kind, value.name)) {
|
|
6179
|
+
continue;
|
|
6180
|
+
}
|
|
6145
6181
|
throw new ResourceRegistryError(
|
|
6146
6182
|
"resource_collision",
|
|
6147
6183
|
`Duplicate ${capitalize(kind)} resource "${value.name}" in Resource View.`
|
|
@@ -6161,7 +6197,15 @@ var ResourceRegistry = class {
|
|
|
6161
6197
|
const refs = [];
|
|
6162
6198
|
for (const source of this.sourcesFor(kind, sourceIds)) {
|
|
6163
6199
|
for (const value of source.values) {
|
|
6164
|
-
if (seenNames.has(value.name))
|
|
6200
|
+
if (seenNames.has(value.name)) {
|
|
6201
|
+
if (source.sourceId === "rowan.core") {
|
|
6202
|
+
continue;
|
|
6203
|
+
}
|
|
6204
|
+
if (source.sourceId === "rowan.extensions" && isCoreResourceName(kind, value.name)) {
|
|
6205
|
+
continue;
|
|
6206
|
+
}
|
|
6207
|
+
throw new ResourceRegistryError("resource_collision", `Duplicate ${capitalize(kind)} resource "${value.name}" in Resource View.`);
|
|
6208
|
+
}
|
|
6165
6209
|
seenNames.add(value.name);
|
|
6166
6210
|
refs.push({ kind, sourceId: source.sourceId, name: value.name });
|
|
6167
6211
|
}
|
|
@@ -6231,7 +6275,10 @@ function capitalize(value) {
|
|
|
6231
6275
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
6232
6276
|
}
|
|
6233
6277
|
function isImplicitCoreName(kind, name) {
|
|
6234
|
-
return kind === "tool" && name === "route"
|
|
6278
|
+
return kind === "tool" && name === "route";
|
|
6279
|
+
}
|
|
6280
|
+
function isCoreResourceName(kind, name) {
|
|
6281
|
+
return kind === "tool" && CORE_TOOL_NAMES.has(name) || kind === "phase" && CORE_PHASE_NAMES.has(name);
|
|
6235
6282
|
}
|
|
6236
6283
|
async function loadDirectoryValues(kind, directory, sourceId) {
|
|
6237
6284
|
const root = resolve7(directory);
|
|
@@ -6466,6 +6513,8 @@ function adaptExtensionTool(input) {
|
|
|
6466
6513
|
name: definition.name,
|
|
6467
6514
|
description: definition.description,
|
|
6468
6515
|
parameters: definition.parameters,
|
|
6516
|
+
...definition.promptSnippet ? { promptSnippet: definition.promptSnippet } : {},
|
|
6517
|
+
...definition.promptGuidelines ? { promptGuidelines: definition.promptGuidelines } : {},
|
|
6469
6518
|
execute: async (args, context, signal) => {
|
|
6470
6519
|
const result = await definition.execute(args, context, signal);
|
|
6471
6520
|
const content = JSON.parse(JSON.stringify(result.content));
|
|
@@ -6527,7 +6576,7 @@ async function spillLargeToolResult(result, archiveDir, toolName) {
|
|
|
6527
6576
|
const serialized = typeof result.content === "string" ? result.content : JSON.stringify(result.content, null, 2);
|
|
6528
6577
|
if (serialized === void 0) return result;
|
|
6529
6578
|
const bytes = new TextEncoder().encode(serialized);
|
|
6530
|
-
if (bytes.byteLength <= MAX_INLINE_TOOL_RESULT_BYTES ||
|
|
6579
|
+
if (bytes.byteLength <= MAX_INLINE_TOOL_RESULT_BYTES || /(?:\[Full result:\s+[^\]]+\]|\nFull result:\s+\S+)/.test(serialized)) {
|
|
6531
6580
|
return result;
|
|
6532
6581
|
}
|
|
6533
6582
|
const toolDir = archiveDir;
|
|
@@ -6542,8 +6591,8 @@ async function spillLargeToolResult(result, archiveDir, toolName) {
|
|
|
6542
6591
|
...result,
|
|
6543
6592
|
content: `${preview}
|
|
6544
6593
|
[truncated]
|
|
6545
|
-
|
|
6546
|
-
|
|
6594
|
+
|
|
6595
|
+
[Full result: ${path}, offset 0]`
|
|
6547
6596
|
};
|
|
6548
6597
|
}
|
|
6549
6598
|
var AgentRuntime = class _AgentRuntime {
|
|
@@ -8059,23 +8108,29 @@ function isContextOverflowError(error) {
|
|
|
8059
8108
|
}
|
|
8060
8109
|
function normalizePhaseRegistry(registry) {
|
|
8061
8110
|
const core = createCorePhases();
|
|
8062
|
-
const coreNames =
|
|
8063
|
-
for (const [name, phase] of registry?.phases ?? []) {
|
|
8064
|
-
if (coreNames.has(name) && !phase.core) {
|
|
8065
|
-
throw new TypeError(`Configured Phase collides with Rowan built-in Phase "${name}".`);
|
|
8066
|
-
}
|
|
8067
|
-
}
|
|
8111
|
+
const coreNames = CORE_PHASE_NAMES;
|
|
8068
8112
|
for (const [name] of registry?.phases ?? []) {
|
|
8069
8113
|
if (name === "continue") {
|
|
8070
8114
|
throw new TypeError(`Configured Phase name "${name}" is reserved by Rowan routing controls.`);
|
|
8071
8115
|
}
|
|
8072
8116
|
}
|
|
8073
|
-
const
|
|
8117
|
+
const configuredPhases = registry?.phases ?? /* @__PURE__ */ new Map();
|
|
8118
|
+
const phases = /* @__PURE__ */ new Map();
|
|
8119
|
+
for (const corePhase of core) {
|
|
8120
|
+
const configured = configuredPhases.get(corePhase.name);
|
|
8121
|
+
if (configured) {
|
|
8122
|
+
phases.set(corePhase.name, configured.core ? configured : { ...configured, core: true });
|
|
8123
|
+
} else {
|
|
8124
|
+
phases.set(corePhase.name, corePhase);
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
for (const [name, phase] of configuredPhases) {
|
|
8128
|
+
if (!coreNames.has(name)) {
|
|
8129
|
+
phases.set(name, phase);
|
|
8130
|
+
}
|
|
8131
|
+
}
|
|
8074
8132
|
return {
|
|
8075
|
-
phases
|
|
8076
|
-
...core.map((phase) => [phase.name, phase]),
|
|
8077
|
-
...authored
|
|
8078
|
-
]),
|
|
8133
|
+
phases,
|
|
8079
8134
|
entryPhaseId: registry?.entryPhaseId ?? DEFAULT_PHASE_ID
|
|
8080
8135
|
};
|
|
8081
8136
|
}
|