{"version":3,"file":"agent/progress/ai-act-progress.mjs","sources":["../../../../src/agent/progress/ai-act-progress.ts"],"sourcesContent":["import type { TaskRunnerEvent } from '@/task-runner';\nimport type {\n  AiActProgressAction,\n  AiActProgressData,\n  AiActProgressPhase,\n  ExecutionTask,\n} from '@/types';\n\n/**\n * Structured extraction helpers for aiAct progress notifications.\n *\n * This module turns a raw {@link ExecutionTask} into the structured\n * {@link AiActProgressAction} carried by progress events. It deliberately does\n * NOT build human-readable strings, truncate text for display, or format\n * coordinates into log lines - that is the consumer's job. Everything here is a\n * data transform that yields plain numbers/objects.\n */\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n// Keep params from bloating the progress payload without rendering them: this\n// only bounds the size of the structured value, it never formats it.\nconst maxCompactStringLength = 180;\n\nfunction compactProgressValue(value: unknown): unknown {\n  if (value === undefined || value === null) {\n    return value;\n  }\n\n  if (typeof value === 'string') {\n    return value.length > maxCompactStringLength\n      ? `${value.slice(0, maxCompactStringLength - 3)}...`\n      : value;\n  }\n\n  if (typeof value === 'number' || typeof value === 'boolean') {\n    return value;\n  }\n\n  if (Array.isArray(value)) {\n    return value.slice(0, 5).map(compactProgressValue);\n  }\n\n  if (isRecord(value) && typeof value.prompt === 'string') {\n    return compactProgressValue(value.prompt);\n  }\n\n  if (!isRecord(value)) {\n    return String(value);\n  }\n\n  const entries = Object.entries(value).slice(0, 6);\n  return Object.fromEntries(\n    entries.map(([key, entryValue]) => [key, compactProgressValue(entryValue)]),\n  );\n}\n\nfunction summarizeParam(param: unknown): unknown {\n  if (!param || typeof param !== 'object') {\n    return compactProgressValue(param);\n  }\n\n  const record = param as Record<string, unknown>;\n  if (typeof record.prompt === 'string') {\n    return compactProgressValue(record.prompt);\n  }\n  if (\n    record.locate &&\n    typeof record.locate === 'object' &&\n    record.locate !== null\n  ) {\n    const locate = record.locate as Record<string, unknown>;\n    return {\n      locate: compactProgressValue(locate.prompt),\n      ...Object.fromEntries(\n        Object.entries(record)\n          .filter(([key]) => key !== 'locate')\n          .slice(0, 4)\n          .map(([key, value]) => [key, compactProgressValue(value)]),\n      ),\n    };\n  }\n\n  return compactProgressValue(record);\n}\n\nexport function errorMessageForAiAct(error: unknown): string {\n  return error instanceof Error ? error.message : String(error);\n}\n\nfunction numberFromUnknown(value: unknown): number | undefined {\n  return typeof value === 'number' && Number.isFinite(value)\n    ? value\n    : undefined;\n}\n\nfunction bboxArrayFromProperty(\n  value: Record<string, unknown>,\n  key: string,\n): [number, number, number, number] | undefined {\n  const bbox = value[key];\n  if (!Array.isArray(bbox) || bbox.length < 4) {\n    return undefined;\n  }\n\n  const left = numberFromUnknown(bbox[0]);\n  const top = numberFromUnknown(bbox[1]);\n  const right = numberFromUnknown(bbox[2]);\n  const bottom = numberFromUnknown(bbox[3]);\n  if (\n    left === undefined ||\n    top === undefined ||\n    right === undefined ||\n    bottom === undefined\n  ) {\n    return undefined;\n  }\n\n  return [left, top, right, bottom];\n}\n\nfunction centerPointFromBbox(\n  bbox: readonly [number, number, number, number],\n): [number, number] {\n  return [\n    Math.floor((bbox[0] + bbox[2]) / 2),\n    Math.floor((bbox[1] + bbox[3]) / 2),\n  ];\n}\n\nfunction pointFromLocateLike(\n  value: Record<string, unknown>,\n): [number, number] | undefined {\n  const center = value.center;\n  if (Array.isArray(center) && center.length >= 2) {\n    const x = numberFromUnknown(center[0]);\n    const y = numberFromUnknown(center[1]);\n    if (x !== undefined && y !== undefined) {\n      return [x, y];\n    }\n  }\n\n  const point = value.point;\n  if (Array.isArray(point) && point.length >= 2) {\n    const x = numberFromUnknown(point[0]);\n    const y = numberFromUnknown(point[1]);\n    if (x !== undefined && y !== undefined) {\n      return [x, y];\n    }\n  }\n\n  const locatedPixelBbox = bboxArrayFromProperty(value, 'locatedPixelBbox');\n  if (locatedPixelBbox) {\n    return centerPointFromBbox(locatedPixelBbox);\n  }\n\n  const bbox = bboxArrayFromProperty(value, 'bbox');\n  if (bbox) {\n    return centerPointFromBbox(bbox);\n  }\n\n  return undefined;\n}\n\nfunction bboxFromLocateLike(\n  value: Record<string, unknown>,\n): [number, number, number, number] | undefined {\n  const locatedPixelBbox = bboxArrayFromProperty(value, 'locatedPixelBbox');\n  if (locatedPixelBbox) {\n    return locatedPixelBbox;\n  }\n\n  const bbox = bboxArrayFromProperty(value, 'bbox');\n  if (bbox) {\n    return bbox;\n  }\n\n  if (!isRecord(value.rect)) {\n    return undefined;\n  }\n\n  const left = numberFromUnknown(value.rect.left);\n  const top = numberFromUnknown(value.rect.top);\n  const width = numberFromUnknown(value.rect.width);\n  const height = numberFromUnknown(value.rect.height);\n  if (\n    left === undefined ||\n    top === undefined ||\n    width === undefined ||\n    height === undefined\n  ) {\n    return undefined;\n  }\n\n  return [left, top, left + width, top + height];\n}\n\nfunction targetTextFromLocateLike(value: Record<string, unknown>): string {\n  if (typeof value.description === 'string') {\n    return value.description;\n  }\n  if (typeof value.prompt === 'string') {\n    return value.prompt;\n  }\n  return '';\n}\n\nfunction isLocateLike(value: unknown): value is Record<string, unknown> {\n  if (!isRecord(value)) {\n    return false;\n  }\n\n  return (\n    'center' in value ||\n    'rect' in value ||\n    'point' in value ||\n    'bbox' in value ||\n    'prompt' in value ||\n    'description' in value\n  );\n}\n\nconst locatorParamKeys = ['locate', 'from', 'to', 'start', 'end'];\n\nfunction firstLocateLikeParam(\n  param: unknown,\n): Record<string, unknown> | undefined {\n  if (!isRecord(param)) {\n    return undefined;\n  }\n\n  for (const key of locatorParamKeys) {\n    const value = param[key];\n    if (isLocateLike(value)) {\n      return value;\n    }\n  }\n\n  return Object.values(param).find(isLocateLike);\n}\n\nfunction hasUnresolvedLocateLikeParam(param: unknown): boolean {\n  if (!isRecord(param)) {\n    return false;\n  }\n\n  return Object.entries(param).some(([key, value]) => {\n    if (locatorParamKeys.includes(key) && typeof value === 'string') {\n      return true;\n    }\n\n    return (\n      isLocateLike(value) &&\n      !pointFromLocateLike(value) &&\n      !bboxFromLocateLike(value)\n    );\n  });\n}\n\n/**\n * Extract the structured action descriptor for an Action Space task, or\n * `undefined` when the task is not a reportable action yet (e.g. a locate param\n * that has not been resolved to coordinates). Returns plain data only.\n */\nexport function extractProgressAction(\n  task: ExecutionTask,\n): AiActProgressAction | undefined {\n  if (\n    task.type !== 'Action Space' ||\n    task.subType === 'Finished' ||\n    task.subType === 'Error'\n  ) {\n    return undefined;\n  }\n\n  const name =\n    typeof task.subType === 'string' && task.subType.length > 0\n      ? task.subType\n      : 'Action';\n\n  const locate = firstLocateLikeParam(task.param);\n  if (locate) {\n    const point = pointFromLocateLike(locate);\n    if (point) {\n      const bbox = bboxFromLocateLike(locate);\n      const target = targetTextFromLocateLike(locate);\n      return {\n        name,\n        ...(target ? { target } : {}),\n        point,\n        ...(bbox ? { bbox } : {}),\n      };\n    }\n  }\n\n  // A locate-like param that has not resolved to a point/bbox is not reportable\n  // yet; skip it so the consumer never renders a half-resolved action.\n  if (hasUnresolvedLocateLikeParam(task.param)) {\n    return undefined;\n  }\n\n  const param = summarizeParam(task.param);\n  return {\n    name,\n    ...(param !== undefined && param !== '' ? { param } : {}),\n  };\n}\n\nexport type AiActProgressEmit = (\n  phase: AiActProgressPhase,\n  data: AiActProgressData,\n) => void | Promise<void>;\n\n/**\n * Translate the runner's native task-lifecycle events into aiAct action\n * progress for a single planning round.\n *\n * Returned as a closure so each action batch captures its own plan context\n * instead of the executor threading it through shared mutable state. The\n * mapping is deliberate and one-shot per transition: a `start` (coordinates are\n * resolved by the time an action starts) becomes the \"planned\" + \"running\"\n * pair, and `finish`/`error` become \"done\"/\"failed\".\n */\nexport function createAiActActionReporter(\n  planIndex: number,\n  planLimit: number,\n  emit: AiActProgressEmit,\n): (event: TaskRunnerEvent) => Promise<void> {\n  return async (event) => {\n    const action = extractProgressAction(event.task);\n    if (!action) {\n      return;\n    }\n\n    const base = { planIndex, planLimit, action };\n    const durationMs = event.task.timing?.cost;\n\n    switch (event.kind) {\n      case 'start':\n        await emit('plan_action', base);\n        await emit('action_running', base);\n        break;\n      case 'finish':\n        await emit('action_done', { ...base, durationMs });\n        break;\n      case 'error':\n        await emit('action_failed', {\n          ...base,\n          durationMs,\n          error: event.task.errorMessage,\n        });\n        break;\n      default:\n        break;\n    }\n  };\n}\n"],"names":["isRecord","value","Array","maxCompactStringLength","compactProgressValue","String","entries","Object","key","entryValue","summarizeParam","param","record","locate","errorMessageForAiAct","error","Error","numberFromUnknown","Number","undefined","bboxArrayFromProperty","bbox","left","top","right","bottom","centerPointFromBbox","Math","pointFromLocateLike","center","x","y","point","locatedPixelBbox","bboxFromLocateLike","width","height","targetTextFromLocateLike","isLocateLike","locatorParamKeys","firstLocateLikeParam","hasUnresolvedLocateLikeParam","extractProgressAction","task","name","target","createAiActActionReporter","planIndex","planLimit","emit","event","action","base","durationMs"],"mappings":"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"}