Download frontend/utils/planKind.js from ruslanmv/gitpilot: direct link, hf CLI and curl.
- Browser
- Download file 2.73 kB
-
https://huggingface.co/spaces/ruslanmv/gitpilot/resolve/main/frontend/utils/planKind.js
- Command line
-
hf download hf://spaces/ruslanmv/gitpilot/frontend/utils/planKind.js
-
curl -L -o planKind.js https://huggingface.co/spaces/ruslanmv/gitpilot/resolve/main/frontend/utils/planKind.js
2.73 kB
| // frontend/utils/planKind.js | |
| // | |
| // Classify a /api/chat/plan response into the shape the chat should render. | |
| // Extracted from ChatPanel so it can be exercised directly — this decision | |
| // is the difference between showing a working plan and telling the user the | |
| // model failed, and it is far too easy to get subtly wrong inline. | |
| // | |
| // executable — there is something to approve and run: a deterministic | |
| // sandbox ExecutionPlan, or a step that CREATEs, MODIFYs, | |
| // DELETEs or EXECUTEs a file. | |
| // informational — every step only READs, and the summary is a real answer. | |
| // "What does this project do?" lands here: the READs were | |
| // the research, the summary is the reply. No approval | |
| // controls, because there is nothing to approve. | |
| // empty — no steps, or nothing actionable and nothing said. | |
| // Only this deserves the failure banner. | |
| export const PLACEHOLDER_SUMMARY = "Here is the proposed plan for your request."; | |
| /** File actions that mean "this plan does something". */ | |
| export const ACTIONABLE_FILE_ACTIONS = ["CREATE", "MODIFY", "DELETE", "EXECUTE"]; | |
| /** Steps live at the top level, or nested under `plan` on older responses. */ | |
| export function planSteps(data) { | |
| if (Array.isArray(data?.steps)) return data.steps; | |
| if (Array.isArray(data?.plan?.steps)) return data.plan.steps; | |
| return []; | |
| } | |
| /** The deterministic sandbox plan, if the backend attached one. */ | |
| export function executionPlanOf(data) { | |
| return data?.execution_plan || data?.plan?.execution_plan || null; | |
| } | |
| export function planSummary(data) { | |
| return data?.plan?.summary || data?.summary || data?.message || PLACEHOLDER_SUMMARY; | |
| } | |
| /** | |
| * @returns {"executable"|"informational"|"empty"} | |
| */ | |
| export function classifyPlan(data) { | |
| const steps = planSteps(data); | |
| // An ExecutionPlan is actionable by construction: the backend builds it in | |
| // pure Python from the resolved file path, never from model output. Its | |
| // presence is a stronger signal than anything in `steps`. | |
| const hasExecutable = | |
| Boolean(executionPlanOf(data)) || | |
| steps.some( | |
| (s) => | |
| Array.isArray(s?.files) && | |
| s.files.some((f) => ACTIONABLE_FILE_ACTIONS.includes(f?.action)), | |
| ); | |
| if (hasExecutable) return "executable"; | |
| const isReadOnly = | |
| steps.length > 0 && | |
| steps.every( | |
| (s) => | |
| !Array.isArray(s?.files) || | |
| s.files.length === 0 || | |
| s.files.every((f) => f?.action === "READ"), | |
| ); | |
| const summary = planSummary(data); | |
| const hasRealSummary = Boolean(summary) && summary !== PLACEHOLDER_SUMMARY; | |
| return isReadOnly && hasRealSummary ? "informational" : "empty"; | |
| } | |