diff --git a/apps/server/src/services/EventRuntime.ts b/apps/server/src/services/EventRuntime.ts index 88ac8991..fc34c876 100644 --- a/apps/server/src/services/EventRuntime.ts +++ b/apps/server/src/services/EventRuntime.ts @@ -72,6 +72,7 @@ import { type InferenceProvider, type InferenceRequest, type InferenceResponse, + type InferenceToolDescriptor, type LocalInferenceDriver, type KvCacheRef, type KvCacheScope, @@ -778,12 +779,26 @@ class EventRuntimeService { private createCanonicalReActAgentRuntime(): ReActAgentRuntime { return { async reason(context) { + const toolRefs = context.agent.toolRefs ?? []; + const tools: InferenceToolDescriptor[] = toolRefs + .map((toolRef) => { + const descriptor = getToolManager().describeTool(toolRef); + if (!descriptor) return null; + return { + id: descriptor.id ?? toolRef, + name: descriptor.name ?? toolRef, + description: descriptor.description ?? toolRef, + inputSchema: descriptor.inputSchema as Record, + } as InferenceToolDescriptor; + }) + .filter((tool): tool is InferenceToolDescriptor => tool !== null); return { runId: context.runId, stepId: context.stepId, sessionId: context.memoryScope?.sessionId, agentId: context.agent.id, modelAlias: context.agent.modelAlias, + ...(tools.length === 0 ? {} : { tools }), input: { instructions: context.agent.systemInstructions, messages: context.messages, @@ -892,6 +907,8 @@ class EventRuntimeService { const contractSnapshotRef = request.context.contractSnapshotRef ?? (await this.ensureRunToolSnapshot(request.context.runId)); + const contractSnapshot = await this.toolSnapshotStore.get(contractSnapshotRef); + const effectiveCapabilities = contractSnapshot?.effectiveCapabilities; return this.toolRunner.run({ ...request, toolId, @@ -900,6 +917,9 @@ class EventRuntimeService { userId, sessionId, contractSnapshotRef, + ...(effectiveCapabilities === undefined + ? {} + : { capabilitySnapshotRef: contractSnapshotRef }), principal: request.context.principal ?? { id: userId, principalId: userId, @@ -1916,14 +1936,28 @@ class EventRuntimeService { : []; const availableToolIds = spec.toolRefs ?? input.options?.tools?.map((tool) => tool.name) ?? []; const capabilityMetadata = asRecord(spec.metadata); + const allowedMCPServerIds = Array.from( + new Set( + availableToolIds + .map((toolRef) => { + const descriptor = getToolManager().describeTool(toolRef); + return descriptor?.serverId ?? descriptor?.capabilityId?.split('.')[0]; + }) + .filter((serverId): serverId is string => Boolean(serverId)), + ), + ); const effectiveCapabilities = createEffectiveAgentCapabilitySnapshot({ runId: input.runId, agentId: id, principalId: userId, tenantId: stringValue(asRecord(input.metadata)?.tenantId), domainId: runContext.domainPackId, - agent: capabilityConstraint(capabilityMetadata, availableToolIds, 'agent.policy'), - domain: capabilityConstraint(workflowState, availableToolIds, 'domain.policy'), + agent: capabilityConstraint(capabilityMetadata, availableToolIds, 'agent.policy', { + allowedMCPServerIds, + }), + domain: capabilityConstraint(workflowState, availableToolIds, 'domain.policy', { + allowedMCPServerIds, + }), activeSkills, }); this.runCapabilitySnapshots.set(input.runId, effectiveCapabilities); @@ -1954,9 +1988,11 @@ class EventRuntimeService { input.options?.model ?? this.resolveChatModel().model, systemInstructions, - promptResolution, + ...(promptResolution === undefined ? {} : { promptResolution }), activeSkills, - toolRefs: spec.toolRefs ?? input.options?.tools?.map((tool) => tool.name), + ...(spec.toolRefs ?? input.options?.tools?.map((tool) => tool.name) + ? { toolRefs: spec.toolRefs ?? input.options?.tools?.map((tool) => tool.name) } + : {}), }; } @@ -4875,7 +4911,8 @@ function stringList(input: unknown): string[] | undefined { function capabilityConstraint( source: Record | undefined, fallbackToolIds: string[], - defaultPolicyRef: string + defaultPolicyRef: string, + extras: { allowedMCPServerIds?: string[] } = {}, ): EffectiveAgentCapabilitySnapshotInput['agent'] { const memory = stringValue(source?.memoryAccess); const sideEffect = stringValue(source?.maximumSideEffectLevel); @@ -4894,7 +4931,10 @@ function capabilityConstraint( return { allowedToolIds: stringList(source?.allowedToolIds) ?? stringList(source?.allowedTools) ?? fallbackToolIds, - allowedMCPServerIds: stringList(source?.allowedMCPServerIds), + allowedMCPServerIds: + stringList(source?.allowedMCPServerIds)?.length + ? (stringList(source?.allowedMCPServerIds) as string[]) + : extras.allowedMCPServerIds ?? [], memoryAccess, allowedExecutionProfiles: stringList(source?.allowedExecutionProfiles) ?? [], maximumSideEffectLevel, diff --git a/packages/inference/src/agent-prompts.ts b/packages/inference/src/agent-prompts.ts index aa1597b0..2a9b546b 100644 --- a/packages/inference/src/agent-prompts.ts +++ b/packages/inference/src/agent-prompts.ts @@ -243,10 +243,10 @@ export class AgentPromptRegistry { templateContentHash: spec.contentHash!, scope: spec.scope ?? 'global', trustLevel: spec.trustLevel ?? 'reviewed', - ownerId: spec.ownerId, - tenantId: spec.tenantId, - provenance: spec.provenance, - metadata: spec.metadata, + ...(spec.ownerId === undefined ? {} : { ownerId: spec.ownerId }), + ...(spec.tenantId === undefined ? {} : { tenantId: spec.tenantId }), + ...(spec.provenance === undefined ? {} : { provenance: spec.provenance }), + ...(spec.metadata === undefined ? {} : { metadata: spec.metadata }), }); } return {