@rowan-agent/agent 0.25.1 → 0.27.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/dist/index.d.ts CHANGED
@@ -11,6 +11,11 @@ type ModelInvokeOutput = {
11
11
  model?: ModelRef;
12
12
  usage?: LlmTokenUsage;
13
13
  };
14
+ type InternalModelLoopOptions = {
15
+ prompt: string;
16
+ tools?: readonly string[];
17
+ maxToolRounds?: number;
18
+ };
14
19
  /** Snapshot of phase-level context for restore */
15
20
  type PhaseContextSnapshot = {
16
21
  systemPrompt: string;
@@ -27,6 +32,7 @@ type PhaseExecution = {
27
32
  invokeModel(context: PhaseContext, options?: {
28
33
  output?: "reply" | "internal";
29
34
  }): Promise<ModelInvokeOutput>;
35
+ runInternalModelLoop(context: PhaseContext, options: InternalModelLoopOptions): Promise<ModelInvokeOutput>;
30
36
  reportStatus(status: PhaseStatus): Promise<void>;
31
37
  executeTool(context: AgentContext, toolCall: ToolCall): Promise<ToolResult>;
32
38
  executeTools(context: AgentContext, toolCalls: readonly ToolCall[], contentBlocks?: readonly ContentBlock[], meta?: {
@@ -3402,4 +3408,4 @@ declare function parseFrontmatter<T = Record<string, unknown>>(raw: string): Fro
3402
3408
 
3403
3409
  declare function createCoreTools(input?: CoreToolContext): Tool$1[];
3404
3410
 
3405
- export { type AfterToolCall, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, COMPACT_PHASE_ID, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type ContextCompactionRecord, type ContextStatus, type CoreToolContext, DEFAULT_PHASE_ID, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EntryPhaseSpec, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionCapability, type ExtensionCapabilityContribution, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, type ExtensionHost, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type ExtensionStateStore, type ExtensionToolContribution, type FrontmatterResult, type HistorySeed, type HookEvent, type HookEventType, type HookHandler, type HostApiExtension, InMemoryConfigProvider, InMemoryExtensionHost, InMemoryStore, type InteractionRecord, type InvocationCatalogEntry, type InvocationSource, type JsonObject, type JsonPrimitive, type JsonValue, type LiveInteractionEvent, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type MessageRevised, type MessageRevisionResult, type Metadata, type ModelRetry, type OpaqueId, type Outcome$1 as Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecution, type PhaseExecutionIdentity, type PhaseInput, type PhaseInvocation, type PhaseMessageManager, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseState, type PhaseStatus, type PhaseStatusState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RetentionResult, type RunBoundary, type RunClaim, type RunEndEvent, type RunEvent, type RunFailure, type RunId, type RunInteraction, RunInteractionBoundary, RunInteractionCancelledError, type RunInteractionDriver, type RunInteractionKind, type RunInteractionRequest, type RunInteractionState, type RunInteractionStatus, type RunListCursor, type RunRecord, type RunSnapshot, type RunStartEvent, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, STOP_PHASE_ID, type SettingsBadge, type SettingsControl, type SettingsDefinition, type SettingsItem, type SettingsOption, type SettingsSection, type Skill, type SkillRegistration, SqliteStore, type TextContent, type ThinkingContent, type ThinkingDelta, type Tool$1 as Tool, type ToolCallContext, type ToolCallDelta, type ToolCallId, type ToolCallPresentationInput, type ToolCallPresentationOutput, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, type WithdrawnUserInput, brandConfigToken, createCompactPhase, createCorePhases, createCoreTools, createDefaultPhase, createStopPhase, extensionSourceId, isConfigurationSnapshot, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhases, loadSkill, loadSkills, mergeToolCall, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
3411
+ export { type AfterToolCall, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, COMPACT_PHASE_ID, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type ContextCompactionRecord, type ContextStatus, type CoreToolContext, DEFAULT_PHASE_ID, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EntryPhaseSpec, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionCapability, type ExtensionCapabilityContribution, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, type ExtensionHost, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type ExtensionStateStore, type ExtensionToolContribution, type FrontmatterResult, type HistorySeed, type HookEvent, type HookEventType, type HookHandler, type HostApiExtension, InMemoryConfigProvider, InMemoryExtensionHost, InMemoryStore, type InteractionRecord, type InternalModelLoopOptions, type InvocationCatalogEntry, type InvocationSource, type JsonObject, type JsonPrimitive, type JsonValue, type LiveInteractionEvent, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type MessageRevised, type MessageRevisionResult, type Metadata, type ModelInvokeOutput, type ModelRetry, type OpaqueId, type Outcome$1 as Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecution, type PhaseExecutionIdentity, type PhaseInput, type PhaseInvocation, type PhaseMessageManager, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseState, type PhaseStatus, type PhaseStatusState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RetentionResult, type RunBoundary, type RunClaim, type RunEndEvent, type RunEvent, type RunFailure, type RunId, type RunInteraction, RunInteractionBoundary, RunInteractionCancelledError, type RunInteractionDriver, type RunInteractionKind, type RunInteractionRequest, type RunInteractionState, type RunInteractionStatus, type RunListCursor, type RunRecord, type RunSnapshot, type RunStartEvent, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, STOP_PHASE_ID, type SettingsBadge, type SettingsControl, type SettingsDefinition, type SettingsItem, type SettingsOption, type SettingsSection, type Skill, type SkillRegistration, SqliteStore, type TextContent, type ThinkingContent, type ThinkingDelta, type Tool$1 as Tool, type ToolCallContext, type ToolCallDelta, type ToolCallId, type ToolCallPresentationInput, type ToolCallPresentationOutput, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, type WithdrawnUserInput, brandConfigToken, createCompactPhase, createCorePhases, createCoreTools, createDefaultPhase, createStopPhase, extensionSourceId, isConfigurationSnapshot, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhases, loadSkill, loadSkills, mergeToolCall, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
package/dist/index.js CHANGED
@@ -2479,6 +2479,84 @@ function createStopPhase() {
2479
2479
  disableImplicitInvocation: false
2480
2480
  };
2481
2481
  }
2482
+ async function runInternalModelLoop(context, execution, phase, options) {
2483
+ const working = { ...context, messages: [...context.messages] };
2484
+ working.messages.push(createMessage("user", options.prompt, {
2485
+ kind: "phase_input",
2486
+ phase
2487
+ }));
2488
+ let result = await execution.invokeModel(working, { output: "internal" });
2489
+ const maxRounds = options.maxToolRounds ?? 8;
2490
+ const isAllowedTool = (name) => {
2491
+ if (name === PhaseRouteTool) return false;
2492
+ if (options.tools) {
2493
+ return options.tools.includes(name);
2494
+ }
2495
+ return context.tools.some((tool) => tool.name === name);
2496
+ };
2497
+ for (let attempt = 0; attempt < maxRounds && result.toolCalls.length > 0; attempt += 1) {
2498
+ if (!result.toolCalls.some((call) => isAllowedTool(call.name))) break;
2499
+ const normalizedCalls = result.toolCalls.map((call) => ({
2500
+ ...call,
2501
+ args: typeof call.args === "string" ? (() => {
2502
+ try {
2503
+ return JSON.parse(call.args);
2504
+ } catch {
2505
+ return call.args;
2506
+ }
2507
+ })() : call.args
2508
+ }));
2509
+ const toolUseParts = normalizedCalls.map((call) => ({
2510
+ type: "tool_use",
2511
+ id: call.id,
2512
+ name: call.name,
2513
+ input: call.args
2514
+ }));
2515
+ const assistantContent = result.contentBlocks.length > 0 ? contentBlocksToMessageContent(result.contentBlocks) : result.text ? [{ type: "text", text: result.text }, ...toolUseParts] : toolUseParts;
2516
+ working.messages.push(createMessage("assistant", assistantContent, {
2517
+ kind: "phase_tool",
2518
+ phase
2519
+ }));
2520
+ const allowedCalls = normalizedCalls.filter((call) => isAllowedTool(call.name));
2521
+ const executedResults = allowedCalls.length > 0 ? await execution.executeTools(
2522
+ working,
2523
+ allowedCalls,
2524
+ result.contentBlocks,
2525
+ result.model ? { model: result.model, usage: result.usage } : void 0
2526
+ ) : [];
2527
+ const executedByCallId = new Map(executedResults.map((r) => [r.toolCallId, r]));
2528
+ const createErrorResult = (call) => {
2529
+ const message = `Tool ${call.name} is not available in Phase ${phase}`;
2530
+ return {
2531
+ toolCallId: call.id,
2532
+ toolName: call.name,
2533
+ ok: false,
2534
+ error: message,
2535
+ content: message
2536
+ };
2537
+ };
2538
+ const toolResults = normalizedCalls.map((call) => {
2539
+ if (isAllowedTool(call.name)) {
2540
+ const executed = executedByCallId.get(call.id);
2541
+ if (executed) return executed;
2542
+ }
2543
+ return createErrorResult(call);
2544
+ });
2545
+ for (const toolResult2 of toolResults) {
2546
+ working.messages.push(createMessage("tool", [{
2547
+ type: "tool_result",
2548
+ toolUseId: toolResult2.toolCallId,
2549
+ content: JSON.stringify(toolResult2),
2550
+ isError: !toolResult2.ok
2551
+ }], {
2552
+ kind: "phase_tool",
2553
+ phase
2554
+ }));
2555
+ }
2556
+ result = await execution.invokeModel(working, { output: "internal" });
2557
+ }
2558
+ return result;
2559
+ }
2482
2560
  function createCompactPhase() {
2483
2561
  return {
2484
2562
  name: COMPACT_PHASE_ID,
@@ -2496,64 +2574,11 @@ function createCompactPhase() {
2496
2574
  kind: "compacting",
2497
2575
  message: "Compacting conversation context."
2498
2576
  });
2499
- const tools = context.tools.filter((tool) => tool.name === "read" || tool.name === "bash");
2500
- const working = { ...context, tools, skills: [...context.skills], messages: [...context.messages] };
2501
2577
  const instructions = compactInstructions(context);
2502
- if (instructions) {
2503
- working.messages.push(createMessage("user", `Additional compaction instructions:
2504
- ${instructions}`, {
2505
- kind: "phase_input",
2506
- phase: COMPACT_PHASE_ID
2507
- }));
2508
- }
2509
- let result = await execution.invokeModel(working, { output: "internal" });
2510
- for (let attempt = 0; attempt < 8 && result.toolCalls.length > 0; attempt += 1) {
2511
- const calls = result.toolCalls.filter((call) => tools.some((tool) => tool.name === call.name));
2512
- if (calls.length === 0) break;
2513
- const normalizedCalls = calls.map((call) => ({
2514
- ...call,
2515
- args: typeof call.args === "string" ? (() => {
2516
- try {
2517
- return JSON.parse(call.args);
2518
- } catch {
2519
- return call.args;
2520
- }
2521
- })() : call.args
2522
- }));
2523
- const assistantContent = result.contentBlocks.length > 0 ? contentBlocksToMessageContent(result.contentBlocks) : normalizedCalls.map((call) => ({ type: "tool_use", id: call.id, name: call.name, input: call.args }));
2524
- working.messages.push(createMessage("assistant", assistantContent, {
2525
- kind: "phase_tool",
2526
- phase: COMPACT_PHASE_ID
2527
- }));
2528
- for (const call of normalizedCalls) {
2529
- const tool = tools.find((candidate) => candidate.name === call.name);
2530
- let toolResult2;
2531
- try {
2532
- toolResult2 = await tool.execute(call.args, {
2533
- skills: working.skills,
2534
- toolCallId: call.id
2535
- });
2536
- } catch (error) {
2537
- toolResult2 = {
2538
- toolCallId: call.id,
2539
- toolName: call.name,
2540
- ok: false,
2541
- content: null,
2542
- error: error instanceof Error ? error.message : String(error)
2543
- };
2544
- }
2545
- working.messages.push(createMessage("tool", [{
2546
- type: "tool_result",
2547
- toolUseId: call.id,
2548
- content: JSON.stringify(toolResult2),
2549
- isError: !toolResult2.ok
2550
- }], {
2551
- kind: "phase_tool",
2552
- phase: COMPACT_PHASE_ID
2553
- }));
2554
- }
2555
- result = await execution.invokeModel(working, { output: "internal" });
2556
- }
2578
+ const result = await execution.runInternalModelLoop(context, {
2579
+ prompt: buildCompactionPrompt(instructions),
2580
+ tools: ["read", "bash"]
2581
+ });
2557
2582
  return {
2558
2583
  route: "stop",
2559
2584
  phase: COMPACT_PHASE_ID,
@@ -2571,6 +2596,22 @@ ${instructions}`, {
2571
2596
  }
2572
2597
  };
2573
2598
  }
2599
+ function buildCompactionPrompt(instructions) {
2600
+ const lines = [
2601
+ "The conversation above is to be summarized, not continued. Do not answer, carry out, or use Tools for any request in it.",
2602
+ "Output only the summary in a fixed structure:",
2603
+ "- Goal and state",
2604
+ "- Decisions with reasons",
2605
+ "- Open requests left unfinished",
2606
+ "- Files and archive references",
2607
+ "- Facts to keep"
2608
+ ];
2609
+ if (instructions) {
2610
+ lines.push("", `Additional compaction instructions:
2611
+ ${instructions}`);
2612
+ }
2613
+ return lines.join("\n");
2614
+ }
2574
2615
  function compactInstructions(context) {
2575
2616
  const payload = context.state.payload;
2576
2617
  if (typeof payload === "object" && payload !== null && "instructions" in payload) {
@@ -3735,7 +3776,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3735
3776
  return result;
3736
3777
  });
3737
3778
  };
3738
- return {
3779
+ const execution = {
3739
3780
  interaction,
3740
3781
  messages: messageManager,
3741
3782
  snapshot() {
@@ -3849,6 +3890,9 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3849
3890
  await config.onModelTranscript?.(result.transcript, { phase: phase.name, model: phase.model ?? config.model });
3850
3891
  return result;
3851
3892
  },
3893
+ async runInternalModelLoop(phaseContext, options) {
3894
+ return runInternalModelLoop(phaseContext, execution, phase.name, options);
3895
+ },
3852
3896
  async reportStatus(status) {
3853
3897
  await config.onPhaseStatus?.(phase.name, status);
3854
3898
  },
@@ -3882,6 +3926,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
3882
3926
  });
3883
3927
  }
3884
3928
  };
3929
+ return execution;
3885
3930
  }
3886
3931
  function parallelPhaseReply(produced) {
3887
3932
  const last = [...produced].reverse().find((message) => message.role === "assistant");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.25.1",
3
+ "version": "0.27.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",