Class: RobotLab::To::Guards::WriteGuard

Inherits:
Hook
  • Object
show all
Defined in:
lib/robot_lab/to/guards/write_guard.rb

Overview

Refuses Write on a file that already exists, redirecting the model to Edit, and normalizes root-bare paths to cwd. Ported from little-coder write-guard: small models rewrite whole files and destroy content; the whitepaper notes this refusal fires on ~57% of Polyglot exercises.

Tool names matched (case-insensitive): "write".

Constant Summary collapse

WRITE_TOOLS =
%w[write].freeze

Class Method Summary collapse

Class Method Details

.around_tool_call(ctx) ⇒ Object

Block the write when the target already exists.



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/robot_lab/to/guards/write_guard.rb', line 34

def around_tool_call(ctx)
  unless write_tool?(ctx.tool_name)
    return yield
  end

  resolved = PathResolution.resolve(ctx.tool_args)
  if resolved && File.exist?(resolved)
    ctx.tool_result = edit_recipe(resolved)
    return ctx.tool_result
  end

  yield
end

.before_tool_call(ctx) ⇒ Object

Normalize the path in place before the tool runs (applies even when we don't block — e.g. the "/foo.md" -> cwd rewrite).



22
23
24
25
26
27
28
29
30
31
# File 'lib/robot_lab/to/guards/write_guard.rb', line 22

def before_tool_call(ctx)
  return unless write_tool?(ctx.tool_name)

  args = ctx.tool_args
  resolved = PathResolution.resolve(args)
  return unless resolved

  key = PathResolution::PATH_KEYS.find { |k| args.key?(k) || args.key?(k.to_sym) }
  args[key] = resolved if key
end

.edit_recipe(resolved) ⇒ String

The message returned to the model in place of the refused write.

Parameters:

  • resolved (String)

Returns:

  • (String)


58
59
60
61
62
63
64
65
66
# File 'lib/robot_lab/to/guards/write_guard.rb', line 58

def edit_recipe(resolved)
  <<~MSG
    Write refused — #{resolved} already exists. Write is for creating
    NEW files only. To change an existing file, Read it first to get the
    exact current text, then use Edit with that text as oldText
    (whitespace and indentation must match). Do NOT retry Write; it will
    be refused again.
  MSG
end

.write_tool?(tool_name) ⇒ Boolean

Parameters:

  • tool_name (String)

Returns:

  • (Boolean)


50
51
52
# File 'lib/robot_lab/to/guards/write_guard.rb', line 50

def write_tool?(tool_name)
  WRITE_TOOLS.include?(tool_name.to_s.downcase)
end