{"version":3,"file":"delegation-request.d.ts","sourceRoot":"","sources":["../../../src/slash/delegation-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAKtE,MAAM,MAAM,6BAA6B,GACtC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,yBAAyB,CAAA;CAAE,GAChD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAqC1F,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,OAAO,GAAG,6BAA6B,CAsK3F","sourcesContent":["import type { SubagentDelegationRequest } from \"../api/delegation.ts\";\nimport { validateToolBudgetConfig } from \"../runs/shared/tool-budget.ts\";\nimport { resolveTurnBudgetConfig } from \"../runs/shared/turn-budget.ts\";\nimport { cloneJsonWithinByteLimit } from \"./delegation-json.ts\";\n\nexport type SubagentDelegationParseResult =\n\t| { ok: true; request: SubagentDelegationRequest }\n\t| { ok: false; requestId?: string; ownerRunId?: string; nodeId?: string; error: string };\n\nconst supportedFields = new Set([\n\t\"requestId\",\n\t\"ownerRunId\",\n\t\"nodeId\",\n\t\"agent\",\n\t\"task\",\n\t\"context\",\n\t\"cwd\",\n\t\"model\",\n\t\"thinking\",\n\t\"timeoutMs\",\n\t\"turnBudget\",\n\t\"toolBudget\",\n\t\"skill\",\n\t\"artifacts\",\n\t\"result\",\n]);\n\nconst thinkingLevels = new Set([\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"]);\nconst MAX_SCHEMA_BYTES = 64 * 1024;\nconst MAX_TASK_BYTES = 1024 * 1024;\nconst MAX_CWD_BYTES = 32 * 1024;\nconst MAX_SHORT_TEXT_BYTES = 1024;\nconst MAX_SKILL_ENTRIES = 256;\nconst MAX_SKILL_AGGREGATE_BYTES = 64 * 1024;\n\nfunction nonEmptyString(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction validateId(value: unknown): string | undefined {\n\tif (!nonEmptyString(value) || value.length > 256 || /[\\r\\n]/.test(value)) return undefined;\n\treturn value;\n}\n\nexport function parseSubagentDelegationRequest(data: unknown): SubagentDelegationParseResult {\n\tif (!data || typeof data !== \"object\" || Array.isArray(data)) {\n\t\treturn { ok: false, error: \"Delegation request must be an object.\" };\n\t}\n\tconst value = data as Record<string, unknown>;\n\tconst requestId = validateId(value.requestId);\n\tif (!requestId) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: \"Delegation requestId must be a non-empty string of at most 256 characters without newlines.\",\n\t\t};\n\t}\n\tconst ownerRunId = validateId(value.ownerRunId);\n\tif (!ownerRunId) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\trequestId,\n\t\t\terror: \"Delegation ownerRunId must be a non-empty string of at most 256 characters without newlines.\",\n\t\t};\n\t}\n\tconst nodeId = validateId(value.nodeId);\n\tif (!nodeId) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\trequestId,\n\t\t\townerRunId,\n\t\t\terror: \"Delegation nodeId must be a non-empty string of at most 256 characters without newlines.\",\n\t\t};\n\t}\n\tconst identity = { requestId, ownerRunId, nodeId };\n\tconst unsupportedField = Object.keys(value).find((key) => !supportedFields.has(key));\n\tif (unsupportedField) return { ok: false, ...identity, error: `Unsupported delegation field: ${unsupportedField}.` };\n\tif (!nonEmptyString(value.agent))\n\t\treturn { ok: false, ...identity, error: \"Delegation agent must be a non-empty string.\" };\n\tif (!nonEmptyString(value.task))\n\t\treturn { ok: false, ...identity, error: \"Delegation task must be a non-empty string.\" };\n\tif (value.context !== \"fresh\" && value.context !== \"fork\") {\n\t\treturn { ok: false, ...identity, error: \"Delegation context must be fresh or fork.\" };\n\t}\n\tif (!nonEmptyString(value.cwd))\n\t\treturn { ok: false, ...identity, error: \"Delegation cwd must be a non-empty string.\" };\n\tif (value.model !== undefined && !nonEmptyString(value.model)) {\n\t\treturn { ok: false, ...identity, error: \"model must be a non-empty string when provided.\" };\n\t}\n\tif (\n\t\tvalue.timeoutMs !== undefined &&\n\t\t(typeof value.timeoutMs !== \"number\" || !Number.isInteger(value.timeoutMs) || value.timeoutMs < 1)\n\t) {\n\t\treturn { ok: false, ...identity, error: \"timeoutMs must be an integer >= 1.\" };\n\t}\n\tconst timeoutMs = typeof value.timeoutMs === \"number\" ? value.timeoutMs : undefined;\n\tif (timeoutMs !== undefined && timeoutMs > 2_147_483_647) {\n\t\treturn { ok: false, ...identity, error: \"timeoutMs must be <= 2147483647.\" };\n\t}\n\tconst turnBudget = resolveTurnBudgetConfig(value.turnBudget);\n\tif (turnBudget.error) return { ok: false, ...identity, error: turnBudget.error };\n\tif (value.toolBudget && typeof value.toolBudget === \"object\" && !Array.isArray(value.toolBudget)) {\n\t\tconst unsupportedToolBudgetField = Object.keys(value.toolBudget).find(\n\t\t\t(key) => key !== \"soft\" && key !== \"hard\" && key !== \"block\",\n\t\t);\n\t\tif (unsupportedToolBudgetField) {\n\t\t\treturn { ok: false, ...identity, error: `toolBudget.${unsupportedToolBudgetField} is not supported.` };\n\t\t}\n\t}\n\tconst toolBudget = validateToolBudgetConfig(value.toolBudget, \"toolBudget\", { minimumHard: 0 });\n\tif (toolBudget.error) return { ok: false, ...identity, error: toolBudget.error };\n\tif (value.skill !== undefined) {\n\t\tconst validSkill =\n\t\t\ttypeof value.skill === \"boolean\" ||\n\t\t\tnonEmptyString(value.skill) ||\n\t\t\t(Array.isArray(value.skill) && value.skill.length > 0 && value.skill.every(nonEmptyString));\n\t\tif (!validSkill) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t...identity,\n\t\t\t\terror: \"skill must be a boolean, non-empty string, or non-empty string array.\",\n\t\t\t};\n\t\t}\n\t}\n\tif (value.artifacts !== undefined && typeof value.artifacts !== \"boolean\") {\n\t\treturn { ok: false, ...identity, error: \"artifacts must be a boolean.\" };\n\t}\n\tif (Buffer.byteLength(value.task as string, \"utf8\") > MAX_TASK_BYTES) {\n\t\treturn { ok: false, ...identity, error: \"Delegation task exceeds 1 MiB when UTF-8 encoded.\" };\n\t}\n\tif (Buffer.byteLength(value.cwd as string, \"utf8\") > MAX_CWD_BYTES) {\n\t\treturn { ok: false, ...identity, error: \"Delegation cwd exceeds 32 KiB when UTF-8 encoded.\" };\n\t}\n\tif (Buffer.byteLength(value.agent as string, \"utf8\") > MAX_SHORT_TEXT_BYTES) {\n\t\treturn { ok: false, ...identity, error: \"Delegation agent exceeds 1 KiB when UTF-8 encoded.\" };\n\t}\n\tif (typeof value.model === \"string\" && Buffer.byteLength(value.model, \"utf8\") > MAX_SHORT_TEXT_BYTES) {\n\t\treturn { ok: false, ...identity, error: \"Delegation model exceeds 1 KiB when UTF-8 encoded.\" };\n\t}\n\tconst skillEntries =\n\t\ttypeof value.skill === \"string\" ? [value.skill] : Array.isArray(value.skill) ? (value.skill as string[]) : [];\n\tif (skillEntries.length > MAX_SKILL_ENTRIES) {\n\t\treturn { ok: false, ...identity, error: \"Delegation skill supports at most 256 entries.\" };\n\t}\n\tif (skillEntries.some((entry) => Buffer.byteLength(entry, \"utf8\") > MAX_SHORT_TEXT_BYTES)) {\n\t\treturn { ok: false, ...identity, error: \"Delegation skill entry exceeds 1 KiB when UTF-8 encoded.\" };\n\t}\n\tif (skillEntries.reduce((total, entry) => total + Buffer.byteLength(entry, \"utf8\"), 0) > MAX_SKILL_AGGREGATE_BYTES) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\t...identity,\n\t\t\terror: \"Delegation skill entries exceed 64 KiB in aggregate when UTF-8 encoded.\",\n\t\t};\n\t}\n\tif (value.thinking !== undefined && (typeof value.thinking !== \"string\" || !thinkingLevels.has(value.thinking))) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\t...identity,\n\t\t\terror: \"thinking must be one of off, minimal, low, medium, high, xhigh, or max.\",\n\t\t};\n\t}\n\tif (!value.result || typeof value.result !== \"object\" || Array.isArray(value.result)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\t...identity,\n\t\t\terror: 'result must be { kind: \"text\" } or { kind: \"structured\", schema: object }.',\n\t\t};\n\t}\n\tconst result = value.result as Record<string, unknown>;\n\tlet structuredSchema: Record<string, unknown> | undefined;\n\tif (result.kind === \"text\") {\n\t\tconst unsupportedResultField = Object.keys(result).find((key) => key !== \"kind\");\n\t\tif (unsupportedResultField)\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t...identity,\n\t\t\t\terror: `result.${unsupportedResultField} is not supported for text results.`,\n\t\t\t};\n\t} else if (result.kind === \"structured\") {\n\t\tconst unsupportedResultField = Object.keys(result).find((key) => key !== \"kind\" && key !== \"schema\");\n\t\tif (unsupportedResultField)\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t...identity,\n\t\t\t\terror: `result.${unsupportedResultField} is not supported for structured results.`,\n\t\t\t};\n\t\tif (!result.schema || typeof result.schema !== \"object\" || Array.isArray(result.schema)) {\n\t\t\treturn { ok: false, ...identity, error: \"result.schema must be a JSON Schema object.\" };\n\t\t}\n\t\tconst inspectedSchema = cloneJsonWithinByteLimit(result.schema, MAX_SCHEMA_BYTES);\n\t\tif (inspectedSchema.ok === false) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\t...identity,\n\t\t\t\terror:\n\t\t\t\t\tinspectedSchema.reason === \"too_large\"\n\t\t\t\t\t\t? \"result.schema exceeds 64 KiB when encoded.\"\n\t\t\t\t\t\t: \"result.schema must be plain JSON data.\",\n\t\t\t};\n\t\t}\n\t\tstructuredSchema = inspectedSchema.value as Record<string, unknown>;\n\t} else {\n\t\treturn { ok: false, ...identity, error: \"result.kind must be text or structured.\" };\n\t}\n\treturn {\n\t\tok: true,\n\t\trequest: {\n\t\t\t...value,\n\t\t\tresult: structuredSchema ? { kind: \"structured\", schema: structuredSchema } : { kind: \"text\" },\n\t\t} as unknown as SubagentDelegationRequest,\n\t};\n}\n"]}