ReadSkillFile returns an AgentTool that reads a supporting file from a skill's directory.
(options ReadSkillOptions)
| 347 | // ReadSkillFile returns an AgentTool that reads a supporting file |
| 348 | // from a skill's directory. |
| 349 | func ReadSkillFile(options ReadSkillOptions) fantasy.AgentTool { |
| 350 | return fantasy.NewAgentTool( |
| 351 | "read_skill_file", |
| 352 | "Read a supporting file from a skill's directory "+ |
| 353 | "(e.g. roles/security-reviewer.md).", |
| 354 | func(ctx context.Context, args ReadSkillFileArgs, _ fantasy.ToolCall) (fantasy.ToolResponse, error) { |
| 355 | if args.Name == "" { |
| 356 | return fantasy.NewTextErrorResponse( |
| 357 | "name is required", |
| 358 | ), nil |
| 359 | } |
| 360 | if args.Path == "" { |
| 361 | return fantasy.NewTextErrorResponse( |
| 362 | "path is required", |
| 363 | ), nil |
| 364 | } |
| 365 | |
| 366 | resolved, err := resolveSkillAlias(options, args.Name) |
| 367 | if err != nil { |
| 368 | return skillResolveErrorResponse(args.Name, err), nil |
| 369 | } |
| 370 | if resolved.Source == skillspkg.SourcePersonal { |
| 371 | return fantasy.NewTextErrorResponse( |
| 372 | "read_skill_file is not supported for personal skills (no supporting files)", |
| 373 | ), nil |
| 374 | } |
| 375 | if resolved.Source != skillspkg.SourceWorkspace { |
| 376 | return skillNotFoundResponse(args.Name), nil |
| 377 | } |
| 378 | |
| 379 | skill, ok := findSkill(options.GetSkills, resolved.Name) |
| 380 | if !ok { |
| 381 | return skillNotFoundResponse(args.Name), nil |
| 382 | } |
| 383 | |
| 384 | // Validate the path early so we reject bad |
| 385 | // inputs before dialing the workspace agent. |
| 386 | if err := validateSkillFilePath(args.Path); err != nil { |
| 387 | return fantasy.NewTextErrorResponse( |
| 388 | err.Error(), |
| 389 | ), nil |
| 390 | } |
| 391 | |
| 392 | if options.GetWorkspaceConn == nil { |
| 393 | return fantasy.NewTextErrorResponse( |
| 394 | "workspace connection resolver is not configured", |
| 395 | ), nil |
| 396 | } |
| 397 | conn, err := options.GetWorkspaceConn(ctx) |
| 398 | if err != nil { |
| 399 | return fantasy.NewTextErrorResponse( |
| 400 | err.Error(), |
| 401 | ), nil |
| 402 | } |
| 403 | |
| 404 | content, err := LoadSkillFile( |
| 405 | ctx, conn, skill, args.Path, |
| 406 | ) |