Skip to content

IterativeLoopOptions

NexusLabs.Needlr.AgentFramework

NexusLabs.Needlr.AgentFramework.Iterative

IterativeLoopOptions Class

Configuration for a single run of an IIterativeAgentLoop.

public sealed class IterativeLoopOptions

Inheritance System.Object 🡒 IterativeLoopOptions

Example

var options = new IterativeLoopOptions
{
    LoopName = "article-writer",
    Instructions = "You are a travel article writer...",
    Tools = [searchTool, writeTool, outlineTool],
    PromptFactory = ctx =>
    {
        var article = ctx.Workspace.FileExists("article.md")
            ? ctx.Workspace.ReadFile("article.md")
            : "(empty)";
        return $"Continue writing. Current article:\n{article}";
    },
    MaxIterations = 20,
    ToolResultMode = ToolResultMode.OneRoundTrip,
};

var result = await iterativeLoop.RunAsync(options, cancellationToken);

Remarks

At minimum, callers must provide Instructions (the system prompt), Tools (available tool functions), and PromptFactory (builds the user message each iteration from workspace state).

The loop terminates when any of these conditions is met (checked in order): 1. The System.Threading.CancellationToken is cancelled. 2. MaxIterations is reached. 3. IsComplete returns true. 4. The model produces a text response without requesting tool calls (natural completion).

Properties

IterativeLoopOptions.BudgetPressureInstruction Property

Gets or sets the instruction prepended to the user message on the budget-pressure finalization iteration.

public string BudgetPressureInstruction { get; set; }

Property Value

System.String

IterativeLoopOptions.BudgetPressureThreshold Property

Gets or sets the fraction of the token budget at which the loop injects a finalization instruction. When CurrentTokens divided by MaxTokens reaches this value, the loop prepends BudgetPressureInstruction to the next iteration's prompt and runs one final iteration before terminating with BudgetPressure.

public System.Nullable<double> BudgetPressureThreshold { get; set; }

Property Value

System.Nullable<System.Double>

Exceptions

System.ArgumentOutOfRangeException
Value is not between 0 and 1.

Remarks

Defaults to null (disabled). Set to e.g. 0.8 (80%) to give the agent one iteration to finalize cleanly before the hard budget limit cancels the chat client. Must be between 0.0 and 1.0 (exclusive) when set.

IterativeLoopOptions.ExecutionContext Property

An optional IAgentExecutionContext to use for bridging workspace state to DI-resolved tools.

public NexusLabs.Needlr.AgentFramework.Context.IAgentExecutionContext? ExecutionContext { get; set; }

Property Value

IAgentExecutionContext

Remarks

When set, the loop uses this context (and its workspace) for the IAgentExecutionContextAccessor scope. When null (the default), the loop auto-creates a context from the Workspace if an accessor is available via DI.

This is the bootstrap execution context only — it is NOT the same as the full application execution context. It exists solely so that DI-resolved tool classes can call accessor.Current.GetRequiredWorkspace() during loop execution.

IterativeLoopOptions.Instructions Property

Gets or sets the system prompt (instructions) for the agent. Sent as the system message on every LLM call. This is constant across all iterations.

public string Instructions { get; set; }

Property Value

System.String

IterativeLoopOptions.IsComplete Property

Gets or sets an optional predicate evaluated after each iteration. When it returns true, the loop terminates. The predicate receives the IterativeContext with updated workspace and tool results.

public System.Func<NexusLabs.Needlr.AgentFramework.Iterative.IterativeContext,bool>? IsComplete { get; set; }

Property Value

System.Func<IterativeContext,System.Boolean>

Remarks

Use this for domain-specific termination conditions. For example, checking whether a required workspace file exists, or whether a word count target has been reached.

IterativeLoopOptions.LoopName Property

Gets or sets a human-readable name for this loop run, used in diagnostics and progress events. Defaults to "iterative-loop".

public string LoopName { get; set; }

Property Value

System.String

IterativeLoopOptions.MaxIterations Property

Gets or sets the maximum number of iterations before the loop terminates. Defaults to 25. Set to a lower value for cost-sensitive workloads.

public int MaxIterations { get; set; }

Property Value

System.Int32

IterativeLoopOptions.MaxToolRoundsPerIteration Property

Gets or sets the maximum number of tool-calling rounds within a single iteration when ToolResultMode is MultiRound. Ignored for other modes. Defaults to 5.

public int MaxToolRoundsPerIteration { get; set; }

Property Value

System.Int32

Remarks

This is a safety valve to prevent unbounded within-iteration growth. After this many rounds of tool calls within one iteration, any remaining tool call requests are executed and stored in LastToolResults for the next iteration.

IterativeLoopOptions.MaxTotalToolCalls Property

Gets or sets the maximum cumulative tool call count across all iterations. When exceeded, the loop terminates with MaxToolCallsReached. Defaults to null (unlimited).

public System.Nullable<int> MaxTotalToolCalls { get; set; }

Property Value

System.Nullable<System.Int32>

Remarks

This is a safety guard against runaway tool-calling loops that stay under MaxIterations but make an excessive number of tool calls per iteration. Set this when token cost is proportional to tool call volume (e.g., web search or fetch tools).

IterativeLoopOptions.OnIterationEnd Property

Gets or sets an optional async callback invoked after each iteration completes. Receives the IterationRecord containing tool calls, tokens, and timing.

public System.Func<NexusLabs.Needlr.AgentFramework.Iterative.IterationRecord,System.Threading.Tasks.Task>? OnIterationEnd { get; set; }

Property Value

System.Func<IterationRecord,System.Threading.Tasks.Task>

Remarks

Fired after the IterationRecord is built and context is updated. Hook exceptions propagate to the caller.

IterativeLoopOptions.OnIterationStart Property

Gets or sets an optional async callback invoked at the start of each iteration, before the prompt factory runs. Receives the zero-based iteration number and the current IterativeContext.

public System.Func<int,NexusLabs.Needlr.AgentFramework.Iterative.IterativeContext,System.Threading.Tasks.Task>? OnIterationStart { get; set; }

Property Value

System.Func<System.Int32,IterativeContext,System.Threading.Tasks.Task>

Remarks

Use this for progress reporting (e.g., updating a SignalR client). Hook exceptions propagate directly to the caller — they are not caught by the loop's internal error handling.

IterativeLoopOptions.OnToolCall Property

Gets or sets an optional async callback invoked after each tool call completes. Receives the zero-based iteration number and the ToolCallResult.

public System.Func<int,NexusLabs.Needlr.AgentFramework.Iterative.ToolCallResult,System.Threading.Tasks.Task>? OnToolCall { get; set; }

Property Value

System.Func<System.Int32,ToolCallResult,System.Threading.Tasks.Task>

Remarks

Fired once per tool call, in execution order. Use for real-time progress updates such as streaming tool activity to a UI. Hook exceptions propagate to the caller.

IterativeLoopOptions.PromptFactory Property

Gets or sets the factory that builds the user message for each iteration. Called once at the start of every iteration with the current IterativeContext (which includes workspace state and last tool results).

public System.Func<NexusLabs.Needlr.AgentFramework.Iterative.IterativeContext,string> PromptFactory { get; set; }

Property Value

System.Func<IterativeContext,System.String>

Remarks

This is the core extensibility point. The prompt factory reads workspace files to understand current state, optionally includes data from LastToolResults, and returns a fresh user message.

The returned string becomes the sole user message — there is no conversation history. The workspace IS the memory.

IterativeLoopOptions.ToolFilter Property

Gets or sets an optional filter that narrows the tool list on each iteration. Receives the zero-based iteration number, the current IterativeContext, and the full Tools list. Returns the subset of tools the model should see for that iteration.

public System.Func<int,NexusLabs.Needlr.AgentFramework.Iterative.IterativeContext,System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.AI.AITool>,System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.AI.AITool>>? ToolFilter { get; set; }

Property Value

System.Func<System.Int32,IterativeContext,System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.AI.AITool>,System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.AI.AITool>>

Example

ToolFilter = (iteration, ctx, allTools) =>
{
    var phase = ctx.Workspace.ReadFile("status.json");
    var allowed = phase.Contains("research")
        ? new[] { "search" }
        : new[] { "add_leg", "book_hotel", "validate_trip" };
    return allTools.Where(t => allowed.Contains(t.Name)).ToList();
};

Remarks

Use this for phase-gating — restricting which tools are available based on the current workspace state. For example, a trip planner might offer only search during the research phase and only add_leg/book_hotel during the build phase.

When null (the default), all Tools are available on every iteration.

IterativeLoopOptions.ToolResultMode Property

Gets or sets how tool call results are fed back to the model within a single iteration. Defaults to OneRoundTrip.

public NexusLabs.Needlr.AgentFramework.Iterative.ToolResultMode ToolResultMode { get; set; }

Property Value

ToolResultMode

See Also

IterativeLoopOptions.Tools Property

Gets or sets the tools available to the model. The loop matches tool call requests from the model against this list by function name.

public System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.AI.AITool> Tools { get; set; }

Property Value

System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.AI.AITool>

Remarks

Tools are typically created via Microsoft.Extensions.AI.AIFunctionFactory or obtained from the agent framework's function discovery. The same tool instances are reused across all iterations.