{"version":3,"file":"subagent-runtime.d.ts","sourceRoot":"","sources":["../../src/core/subagent-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { ModelRegistry } from \"./model-registry.js\";\nimport {\n\tgetCanonicalSubagentRegistry,\n\ttype ResolvedSubagent,\n\tresolveSubagentModel,\n\ttype SubagentBudget,\n\ttype SubagentDefinition,\n\ttype SubagentExecutionMode,\n\ttype SubagentModelResolution,\n\ttype SubagentResolutionError,\n\tvalidateSubagentOutput,\n} from \"./subagent-registry.js\";\n\nexport interface SubagentContextPacket {\n\tobjective: string;\n\troleContract: string;\n\tacceptanceCriteria: string[];\n\tselectedEvidenceIds: string[];\n\tselectedFileReferences: string[];\n\tconstraints: string[];\n\teffectiveAllowedTools: string[];\n\teffectiveDeniedEffects: string[];\n\teffectiveExecutionMode: SubagentExecutionMode;\n\teffectiveBudget: SubagentBudget;\n\trequiredOutputSchema: string;\n\tparentRunId: string;\n\tchildRunId: string;\n}\n\nexport interface ParentSubagentPolicy {\n\tallowedTools?: readonly string[];\n\tdeniedEffects?: readonly string[];\n\texecutionMode?: SubagentExecutionMode;\n\tbudget?: SubagentBudget;\n\trecursionDepth?: number;\n\tmaxConcurrentChildren?: number;\n}\n\nexport interface ResolvedSubagentInvocation {\n\tcanonicalAgentName: string;\n\tsource: \"builtin\" | \"user\" | \"workspace\";\n\tdefinitionVersion: number;\n\tprovider: string;\n\tconfiguredModel: string;\n\tresolvedModel: string;\n\tmodelResolutionKind: SubagentModelResolution[\"resolutionKind\"];\n\texecutionMode: SubagentExecutionMode;\n\teffectiveAllowedTools: string[];\n\teffectiveDeniedEffects: string[];\n\teffectiveBudget: SubagentBudget;\n\trecursionDepth: number;\n\tinputSchemaId: string;\n\toutputSchemaId: string;\n\tparentRunId: string;\n\tchildRunId: string;\n\tdefinition: SubagentDefinition;\n}\n\nexport type SubagentRuntimeErrorCode =\n\t| \"SUBAGENT_RESOLUTION_FAILED\"\n\t| \"SUBAGENT_PERMISSION_CONFLICT\"\n\t| \"SUBAGENT_BUDGET_EXCEEDED\"\n\t| \"SUBAGENT_RECURSION_LIMIT\"\n\t| \"SUBAGENT_OUTPUT_INVALID\";\n\nexport class SubagentRuntimeError extends Error {\n\treadonly code: SubagentRuntimeErrorCode;\n\treadonly details: Record<string, unknown>;\n\n\tconstructor(code: SubagentRuntimeErrorCode, message: string, details: Record<string, unknown> = {}) {\n\t\tsuper(message);\n\t\tthis.name = \"SubagentRuntimeError\";\n\t\tthis.code = code;\n\t\tthis.details = details;\n\t}\n}\n\nfunction minimumBudget(child: SubagentBudget, parent?: SubagentBudget): SubagentBudget {\n\tif (!parent) return { ...child };\n\tconst keys: Array<keyof SubagentBudget> = [\n\t\t\"maxModelTurns\",\n\t\t\"maxToolCalls\",\n\t\t\"maxWallTimeMs\",\n\t\t\"maxInputTokens\",\n\t\t\"maxOutputTokens\",\n\t\t\"maxCostUsd\",\n\t\t\"maxAffectedFiles\",\n\t];\n\tconst result: SubagentBudget = {};\n\tfor (const key of keys) {\n\t\tconst childValue = child[key];\n\t\tconst parentValue = parent[key];\n\t\tif (childValue !== undefined && parentValue !== undefined) result[key] = Math.min(childValue, parentValue);\n\t\telse result[key] = childValue ?? parentValue;\n\t}\n\treturn result;\n}\n\nfunction modeRank(mode: SubagentExecutionMode): number {\n\treturn mode === \"observe\" ? 0 : mode === \"plan\" ? 1 : 2;\n}\n\nfunction effectiveMode(child: SubagentExecutionMode, parent?: SubagentExecutionMode): SubagentExecutionMode {\n\tif (!parent || modeRank(child) <= modeRank(parent)) return child;\n\tthrow new SubagentRuntimeError(\n\t\t\"SUBAGENT_PERMISSION_CONFLICT\",\n\t\t`Child execution mode ${child} exceeds parent mode ${parent}`,\n\t\t{ childMode: child, parentMode: parent },\n\t);\n}\n\nfunction resolveAvailableModelIds(modelRegistry?: ModelRegistry): string[] | undefined {\n\tif (!modelRegistry) return undefined;\n\treturn modelRegistry.getAll().flatMap((model) => [model.id, `${model.provider}/${model.id}`]);\n}\n\nfunction resolveDefinition(requestedAgent: string, availableModels?: readonly string[]): ResolvedSubagent {\n\tconst result = getCanonicalSubagentRegistry().resolve(requestedAgent, { availableModels });\n\tif (\"code\" in result) {\n\t\tthrow new SubagentRuntimeError(\"SUBAGENT_RESOLUTION_FAILED\", `${result.code}: ${requestedAgent}`, { ...result });\n\t}\n\treturn result;\n}\n\nexport function resolveSubagentInvocation(options: {\n\trequestedAgent: string;\n\tparentRunId: string;\n\tchildRunId?: string;\n\tparentPolicy?: ParentSubagentPolicy;\n\tmodelRegistry?: ModelRegistry;\n\tsource?: \"builtin\" | \"user\" | \"workspace\";\n}): ResolvedSubagentInvocation {\n\tconst childRunId = options.childRunId ?? randomUUID();\n\tconst availableModels = resolveAvailableModelIds(options.modelRegistry);\n\tconst resolved = resolveDefinition(options.requestedAgent, availableModels);\n\tconst definition = resolved.definition;\n\tconst parent = options.parentPolicy;\n\n\tif (parent?.allowedTools) {\n\t\tconst allowed = new Set(parent.allowedTools);\n\t\tconst denied = definition.allowedTools.filter((tool) => !allowed.has(tool));\n\t\tif (denied.length > 0) {\n\t\t\tthrow new SubagentRuntimeError(\"SUBAGENT_PERMISSION_CONFLICT\", \"Child requested tools denied by parent\", {\n\t\t\t\trequestedAgent: options.requestedAgent,\n\t\t\t\tdeniedTools: denied,\n\t\t\t});\n\t\t}\n\t}\n\tif (parent?.deniedEffects) {\n\t\tconst childDenied = new Set(definition.deniedEffects);\n\t\tconst broadened = parent.deniedEffects.filter((effect) => !childDenied.has(effect));\n\t\tif (broadened.length > 0) {\n\t\t\tthrow new SubagentRuntimeError(\"SUBAGENT_PERMISSION_CONFLICT\", \"Child policy is not contained by parent\", {\n\t\t\t\tbroadenedEffects: broadened,\n\t\t\t});\n\t\t}\n\t}\n\tconst depth = parent?.recursionDepth ?? 0;\n\tif (depth > definition.recursion.maximumDepth) {\n\t\tthrow new SubagentRuntimeError(\"SUBAGENT_RECURSION_LIMIT\", \"Subagent recursion depth exceeded\", {\n\t\t\tdepth,\n\t\t\tmaximumDepth: definition.recursion.maximumDepth,\n\t\t});\n\t}\n\tconst budget = minimumBudget(definition.budget, parent?.budget);\n\tfor (const [key, value] of Object.entries(budget)) {\n\t\tif (value !== undefined && value < 0) {\n\t\t\tthrow new SubagentRuntimeError(\"SUBAGENT_BUDGET_EXCEEDED\", `Invalid effective budget: ${key}`);\n\t\t}\n\t}\n\treturn {\n\t\tcanonicalAgentName: definition.name,\n\t\tsource: options.source ?? \"builtin\",\n\t\tdefinitionVersion: definition.version,\n\t\tprovider: resolved.model.resolvedProvider,\n\t\tconfiguredModel: resolved.model.configuredModel,\n\t\tresolvedModel: resolved.model.resolvedModel,\n\t\tmodelResolutionKind: resolved.model.resolutionKind,\n\t\texecutionMode: effectiveMode(definition.executionMode, parent?.executionMode),\n\t\teffectiveAllowedTools: parent?.allowedTools\n\t\t\t? definition.allowedTools.filter((tool) => parent.allowedTools?.includes(tool))\n\t\t\t: [...definition.allowedTools],\n\t\teffectiveDeniedEffects: [...new Set([...(parent?.deniedEffects ?? []), ...definition.deniedEffects])],\n\t\teffectiveBudget: budget,\n\t\trecursionDepth: depth + 1,\n\t\tinputSchemaId: definition.inputSchema,\n\t\toutputSchemaId: definition.outputSchema,\n\t\tparentRunId: options.parentRunId,\n\t\tchildRunId,\n\t\tdefinition: structuredClone(definition),\n\t};\n}\n\nexport function createSubagentContextPacket(options: {\n\tinvocation: ResolvedSubagentInvocation;\n\tobjective: string;\n\troleContract?: string;\n\tacceptanceCriteria?: readonly string[];\n\tselectedEvidenceIds?: readonly string[];\n\tselectedFileReferences?: readonly string[];\n\tconstraints?: readonly string[];\n}): SubagentContextPacket {\n\tconst { invocation } = options;\n\treturn Object.freeze({\n\t\tobjective: options.objective,\n\t\troleContract: options.roleContract ?? invocation.definition.description,\n\t\tacceptanceCriteria: [...(options.acceptanceCriteria ?? [])],\n\t\tselectedEvidenceIds: [...(options.selectedEvidenceIds ?? [])],\n\t\tselectedFileReferences: [...(options.selectedFileReferences ?? [])],\n\t\tconstraints: [...(options.constraints ?? [])],\n\t\teffectiveAllowedTools: [...invocation.effectiveAllowedTools],\n\t\teffectiveDeniedEffects: [...invocation.effectiveDeniedEffects],\n\t\teffectiveExecutionMode: invocation.executionMode,\n\t\teffectiveBudget: { ...invocation.effectiveBudget },\n\t\trequiredOutputSchema: invocation.outputSchemaId,\n\t\tparentRunId: invocation.parentRunId,\n\t\tchildRunId: invocation.childRunId,\n\t});\n}\n\nfunction parseStructuredOutput(raw: unknown): unknown {\n\tif (typeof raw !== \"string\") return raw;\n\tconst trimmed = raw.trim();\n\ttry {\n\t\treturn JSON.parse(trimmed) as unknown;\n\t} catch {\n\t\tconst fenced = trimmed.match(/```(?:json)?\\s*([\\s\\S]*?)```/iu)?.[1];\n\t\tif (!fenced) return raw;\n\t\ttry {\n\t\t\treturn JSON.parse(fenced.trim()) as unknown;\n\t\t} catch {\n\t\t\treturn raw;\n\t\t}\n\t}\n}\n\nexport function validateParentSubagentOutput(options: { invocation: ResolvedSubagentInvocation; rawOutput: unknown }): {\n\tvalue: Record<string, unknown>;\n\tsanitizedRawOutput: string;\n} {\n\tconst parsed = parseStructuredOutput(options.rawOutput);\n\tconst result = validateSubagentOutput(options.invocation.outputSchemaId, parsed);\n\tif (!result.valid) {\n\t\tthrow new SubagentRuntimeError(\n\t\t\t\"SUBAGENT_OUTPUT_INVALID\",\n\t\t\t`SUBAGENT_OUTPUT_INVALID: child output failed parent schema validation`,\n\t\t\t{\n\t\t\t\tagent: options.invocation.canonicalAgentName,\n\t\t\t\tschema: options.invocation.outputSchemaId,\n\t\t\t},\n\t\t);\n\t}\n\tif (options.invocation.canonicalAgentName === \"cavecrew-investigator\") {\n\t\tconst changed = result.value.filesChanged;\n\t\tif (changed !== undefined && (!Array.isArray(changed) || changed.length !== 0)) {\n\t\t\tthrow new SubagentRuntimeError(\"SUBAGENT_OUTPUT_INVALID\", \"Investigator output claims files changed\");\n\t\t}\n\t}\n\tif (options.invocation.canonicalAgentName === \"cavecrew-builder\") {\n\t\tconst status = result.value.status;\n\t\tconst filesChanged = result.value.filesChanged;\n\t\tif (status === \"implemented\" && typeof result.value.transactionId !== \"string\") {\n\t\t\tthrow new SubagentRuntimeError(\"SUBAGENT_OUTPUT_INVALID\", \"Builder implemented result requires transactionId\");\n\t\t}\n\t\tif (\n\t\t\t!Array.isArray(filesChanged) ||\n\t\t\tfilesChanged.length > (options.invocation.effectiveBudget.maxAffectedFiles ?? 2)\n\t\t) {\n\t\t\tthrow new SubagentRuntimeError(\"SUBAGENT_OUTPUT_INVALID\", \"Builder output exceeds affected-file limit\");\n\t\t}\n\t}\n\treturn {\n\t\tvalue: result.value,\n\t\tsanitizedRawOutput: typeof options.rawOutput === \"string\" ? options.rawOutput.slice(0, 16_000) : \"[structured]\",\n\t};\n}\n\nexport function getResolvedModelForDispatch(\n\tdefinition: SubagentDefinition,\n\tmodelRegistry?: ModelRegistry,\n): SubagentModelResolution {\n\tconst resolved = resolveSubagentModel(definition, resolveAvailableModelIds(modelRegistry));\n\tif (!resolved.ok)\n\t\tthrow new SubagentRuntimeError(\"SUBAGENT_RESOLUTION_FAILED\", resolved.error.code, { ...resolved.error });\n\treturn resolved.value;\n}\n\nexport type { SubagentResolutionError };\n"]}