(execCtx ExecutionContext, input any)
| 306 | } |
| 307 | |
| 308 | func (t *NotebookEditTool) ValidateInput(execCtx ExecutionContext, input any) (bool, string) { |
| 309 | in := deref[NotebookEditInput](input) |
| 310 | path := resolveToolPath(execCtx, in.NotebookPath) |
| 311 | if ok, msg := checkAllowedWriteRoots(path, execCtx["allowed_write_roots"]); !ok { |
| 312 | return false, msg |
| 313 | } |
| 314 | info, err := os.Stat(path) |
| 315 | if err != nil { |
| 316 | hint := "" |
| 317 | if !filepath.IsAbs(path) { |
| 318 | hint = " (path is relative — use absolute paths)" |
| 319 | } |
| 320 | return false, "File not found: " + in.NotebookPath + hint |
| 321 | } |
| 322 | if !info.Mode().IsRegular() { |
| 323 | return false, "Not a file: " + in.NotebookPath |
| 324 | } |
| 325 | if !strings.EqualFold(filepath.Ext(path), ".ipynb") { |
| 326 | return false, "Not a notebook file: " + in.NotebookPath + ". notebook_edit only works with .ipynb files." |
| 327 | } |
| 328 | mode := notebookEditMode(in.EditMode) |
| 329 | if mode == "insert" && in.CellType == nil { |
| 330 | return false, "cell_type is required when edit_mode=insert. Specify 'code' or 'markdown'." |
| 331 | } |
| 332 | if in.CellType != nil && *in.CellType != "code" && *in.CellType != "markdown" { |
| 333 | return false, "cell_type must be 'code' or 'markdown'." |
| 334 | } |
| 335 | if mode != "replace" && mode != "insert" && mode != "delete" { |
| 336 | return false, "edit_mode must be 'replace', 'insert', or 'delete'." |
| 337 | } |
| 338 | return true, "" |
| 339 | } |
| 340 | |
| 341 | func (t *NotebookEditTool) Execute(_ context.Context, execCtx ExecutionContext, input any) (string, error) { |
| 342 | in := deref[NotebookEditInput](input) |
nothing calls this directly
no test coverage detected