Skip to main content

DefaultEngineDeps

@forge/monorepo


@forge/monorepo / backend/src / DefaultEngineDeps

Type Alias: DefaultEngineDeps

DefaultEngineDeps = object

Defined in: backend/src/agents/engine.ts:86

Properties

approvals?

readonly optional approvals?: RunApprovals

Defined in: backend/src/agents/engine.ts:128

The approval loop. Absent means no HITL: tool calls go straight to buildTools' own execute, which is how every caller behaved before this existed.

Present means the loop owns tool execution for the turn — deliberately, and not as a layer on top of the caller's execute. A gated call has to be routed through the loop rather than merely observed after the fact, because by the time a refusal has been thrown there is nothing left to pause on.


buildTools?

optional buildTools?: (context, manifest) => Promise<readonly ModelTurnTool[]>

Defined in: backend/src/agents/engine.ts:116

The tools the model may call this turn (already permission-filtered / guarded on execute).

Parameters

context

ExecutionContext

manifest

AgentManifest

Returns

Promise<readonly ModelTurnTool[]>


catalogBudget?

readonly optional catalogBudget?: TokenBudget

Defined in: backend/src/agents/engine.ts:146

A ceiling in tokens on the tool list handed to the model — REQ-045 (#204), task #210, AC-3.

Here rather than only in the registry because this is where the tokens are actually spent: the registry's catalogue is what a client renders, and buildTools is what reaches the provider. A budget enforced in one and not the other would be a budget a deployment believes it has.

Absent means no ceiling, which stays the default — a runtime that silently withheld tools from a model nobody had asked it to withhold would be making a correctness decision on the host's behalf.


citations?

readonly optional citations?: CitationEmitter

Defined in: backend/src/agents/engine.ts:168

Turns a tool's citation candidates into citation parts — #165.

Optional. createCitationEmitter, CitationPart, the frontend's renderer and the groundedness graders all existed, and nothing put a citation into a run: there was no path from a tool that read a passage to a part on the message. Supply this and a tool returning { citations: [...] } produces citation parts; leave it out and the field is ignored, exactly as before.

The emitter, not a raw mapper, because emission is where the access check lives: a citation carries an excerpt, so emitting one the reader may not see leaks the text and not merely the existence of the source.


connectionConsent?

readonly optional connectionConsent?: (input) => Promise<{ expiresAt: string; loginUrl: string; scopes: readonly string[]; } | null>

Defined in: backend/src/agents/engine.ts:185

Turns "this run needs a connection" into somewhere to send a person — task #264.

Optional, and its absence means today's behaviour: the tool call fails and the run fails with it. That is the correct default, not a degraded one — a host with no OAuth flow wired has no login URL to offer, and pausing a run for a consent screen nobody can reach would hang it for ever.

Returning null says the same thing for one provider: this one is token-only, so fail rather than pause. That decision comes from ToolkitAuth.modes, which is why #260 kept AuthMode separate from CredentialScheme — an OAuth token is presented as a bearer, so the wire format cannot answer it.

Parameters

input
context

ExecutionContext

need

ConnectionNeed

Returns

Promise<{ expiresAt: string; loginUrl: string; scopes: readonly string[]; } | null>


guardrails?

readonly optional guardrails?: readonly Guardrail[]

Defined in: backend/src/agents/engine.ts:135

Checks a deployment adds — REQ-046 (#205).

Absent means no inspection, which is the current behaviour and stays the default: a runtime that imposed a model call on every turn to moderate it would be making a cost decision that belongs to the host.


loadHistory

loadHistory: (context, run) => Promise<readonly TurnMessage[]>

Defined in: backend/src/agents/engine.ts:114

Conversation history as neutral turn messages, oldest first.

Parameters

context

ExecutionContext

run

Run

Returns

Promise<readonly TurnMessage[]>


loadManifest

loadManifest: (input) => Promise<AgentManifest>

Defined in: backend/src/agents/engine.ts:88

Load the manifest the run executes (by agent id + version), so history is never rewritten.

Parameters

input
agentId

string

context

ExecutionContext

version

number

Returns

Promise<AgentManifest>


now?

readonly optional now?: () => number

Defined in: backend/src/agents/engine.ts:171

Returns

number


questions?

readonly optional questions?: object

Defined in: backend/src/agents/engine.ts:154

The question side of resumption — #163.

Optional and symmetrical with approvals. Without it a run that parked on a question resumes with no idea it was answered, and the model asks the same question again — the person picks an option and gets the picker back. approvals has had a resume path from the start; this is the half that was missing.

answered()

answered(input): Promise<PendingQuestion | null>

Parameters
input
runId

RunId

tenantId

TenantId

Returns

Promise<PendingQuestion | null>


resolveModel

resolveModel: (manifest, context) => ResolvedModelInfo | Promise<ResolvedModelInfo>

Defined in: backend/src/agents/engine.ts:109

The model this turn runs on, decided from the manifest and the context.

May return a promise, and that is not a convenience — it is what makes the context parameter usable for the thing it exists for. A host serving several tenants keeps each tenant's provider and key in a database or a secrets store, so resolving per tenant means I/O; declared synchronously, the parameter was passed and could not be acted on.

ShareFlow hit this directly: a workspace configuring its own provider was served the deployment's model on every conversational turn, silently, with the cost landing on the platform's account (Rise-Experts/social_share#462). It worked around it by returning a lazy model that does the lookup inside the AI SDK's own async middleware — which works, but leaves modelId, definition and price resolved before anyone knows which provider will serve the turn, so the usage ledger labels a tenant's tokens with the deployment's model id.

Awaiting here fixes the whole record rather than the routing alone.

Additive. Every existing synchronous resolver keeps working unchanged: await on a non-promise yields the value.

Parameters

manifest

AgentManifest

context

ExecutionContext

Returns

ResolvedModelInfo | Promise<ResolvedModelInfo>


retry?

readonly optional retry?: RetryPolicy

Defined in: backend/src/agents/engine.ts:169


sleep?

readonly optional sleep?: (ms) => Promise<void>

Defined in: backend/src/agents/engine.ts:170

Parameters

ms

number

Returns

Promise<void>


streamTurn?

readonly optional streamTurn?: (req) => AsyncIterable<NeutralStreamChunk>

Defined in: backend/src/agents/engine.ts:173

The streaming primitive. Defaults to the models-layer streamModelTurn; overridden in tests.

Parameters

req

ModelTurnRequest

Returns

AsyncIterable<NeutralStreamChunk>


systemPrompt?

optional systemPrompt?: (manifest, context) => Promise<string> | string

Defined in: backend/src/agents/engine.ts:118

System prompt; defaults to the manifest instructions.

Parameters

manifest

AgentManifest

context

ExecutionContext

Returns

Promise<string> | string