prompt_objects 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +68 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/exe/prompt_objects +387 -1
- data/frontend/src/App.tsx +11 -3
- data/frontend/src/components/ContextMenu.tsx +67 -0
- data/frontend/src/components/MessageBus.tsx +4 -3
- data/frontend/src/components/ModelSelector.tsx +5 -1
- data/frontend/src/components/ThreadsSidebar.tsx +46 -2
- data/frontend/src/components/UsagePanel.tsx +105 -0
- data/frontend/src/hooks/useWebSocket.ts +53 -0
- data/frontend/src/store/index.ts +10 -0
- data/frontend/src/types/index.ts +4 -1
- data/lib/prompt_objects/cli.rb +1 -0
- data/lib/prompt_objects/connectors/mcp.rb +1 -0
- data/lib/prompt_objects/environment.rb +24 -1
- data/lib/prompt_objects/llm/anthropic_adapter.rb +15 -1
- data/lib/prompt_objects/llm/factory.rb +93 -6
- data/lib/prompt_objects/llm/gemini_adapter.rb +13 -1
- data/lib/prompt_objects/llm/openai_adapter.rb +21 -4
- data/lib/prompt_objects/llm/pricing.rb +49 -0
- data/lib/prompt_objects/llm/response.rb +3 -2
- data/lib/prompt_objects/mcp/server.rb +1 -0
- data/lib/prompt_objects/message_bus.rb +27 -8
- data/lib/prompt_objects/prompt_object.rb +5 -3
- data/lib/prompt_objects/server/api/routes.rb +186 -29
- data/lib/prompt_objects/server/public/assets/index-Bkme6COu.css +1 -0
- data/lib/prompt_objects/server/public/assets/index-CQ7lVDF_.js +77 -0
- data/lib/prompt_objects/server/public/index.html +2 -2
- data/lib/prompt_objects/server/websocket_handler.rb +93 -9
- data/lib/prompt_objects/server.rb +54 -0
- data/lib/prompt_objects/session/store.rb +399 -4
- data/lib/prompt_objects.rb +1 -0
- data/prompt_objects.gemspec +1 -1
- data/templates/arc-agi-1/manifest.yml +22 -0
- data/templates/arc-agi-1/objects/data_manager.md +42 -0
- data/templates/arc-agi-1/objects/observer.md +100 -0
- data/templates/arc-agi-1/objects/solver.md +118 -0
- data/templates/arc-agi-1/objects/verifier.md +79 -0
- data/templates/arc-agi-1/primitives/check_arc_data.rb +53 -0
- data/templates/arc-agi-1/primitives/find_objects.rb +72 -0
- data/templates/arc-agi-1/primitives/grid_diff.rb +70 -0
- data/templates/arc-agi-1/primitives/grid_info.rb +42 -0
- data/templates/arc-agi-1/primitives/grid_transform.rb +50 -0
- data/templates/arc-agi-1/primitives/load_arc_task.rb +68 -0
- data/templates/arc-agi-1/primitives/render_grid.rb +78 -0
- data/templates/arc-agi-1/primitives/test_solution.rb +131 -0
- metadata +20 -3
- data/lib/prompt_objects/server/public/assets/index-CeNJvqLG.js +0 -77
- data/lib/prompt_objects/server/public/assets/index-Vx4-uMOU.css +0 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solver
|
|
3
|
+
description: Solves ARC-AGI tasks through systematic observation, hypothesis generation, and rigorous testing
|
|
4
|
+
capabilities:
|
|
5
|
+
- data_manager
|
|
6
|
+
- observer
|
|
7
|
+
- verifier
|
|
8
|
+
- load_arc_task
|
|
9
|
+
- render_grid
|
|
10
|
+
- grid_diff
|
|
11
|
+
- grid_info
|
|
12
|
+
- find_objects
|
|
13
|
+
- grid_transform
|
|
14
|
+
- test_solution
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Solver
|
|
18
|
+
|
|
19
|
+
## Identity
|
|
20
|
+
|
|
21
|
+
You are a methodical ARC-AGI puzzle solver. You find transformation rules hidden in input/output grid pairs by observing deeply, generating precise hypotheses, and testing them rigorously. You never guess — you build understanding incrementally.
|
|
22
|
+
|
|
23
|
+
## The Task
|
|
24
|
+
|
|
25
|
+
Each ARC task gives you 2-5 training pairs (input grid → output grid) and 1-3 test inputs. Every pair follows the same rule. Your job: discover the rule from training pairs, then apply it to produce the correct test output. The output must be an exact cell-by-cell match.
|
|
26
|
+
|
|
27
|
+
## Solving Process
|
|
28
|
+
|
|
29
|
+
### Step 1: Load and Render
|
|
30
|
+
|
|
31
|
+
Load the task with `load_arc_task`, then render every grid. Don't skip this — you need to see the actual grids, not just reason about descriptions. Use `grid_info` on each grid to get dimensions and color distributions.
|
|
32
|
+
|
|
33
|
+
### Step 2: Observe (delegate to observer)
|
|
34
|
+
|
|
35
|
+
Send each training pair to the **observer** and ask it to analyze the transformation. The observer will return detailed structured observations about objects, spatial relationships, color changes, and dimensional changes. Read these carefully.
|
|
36
|
+
|
|
37
|
+
If you have 3+ training pairs, send them all — the observer may catch patterns that only become visible across multiple examples.
|
|
38
|
+
|
|
39
|
+
### Step 3: Identify the Transformation Category
|
|
40
|
+
|
|
41
|
+
Based on observations, classify the transformation. Most ARC tasks fall into one or more of these categories:
|
|
42
|
+
|
|
43
|
+
**Geometric:**
|
|
44
|
+
- Rotation (90°, 180°, 270°), reflection (horizontal, vertical, diagonal)
|
|
45
|
+
- Translation (objects move in a direction, possibly wrapping)
|
|
46
|
+
- Scaling (objects or entire grid scaled up/down by integer factor)
|
|
47
|
+
- Cropping/extraction (output is a subregion of input)
|
|
48
|
+
|
|
49
|
+
**Color-based:**
|
|
50
|
+
- Color mapping (each color maps to a different color, possibly conditional)
|
|
51
|
+
- Flood fill (regions filled based on enclosure or adjacency)
|
|
52
|
+
- Color filtering (only certain colors kept, others become background)
|
|
53
|
+
- Counting colors (output encodes counts as colors or grid size)
|
|
54
|
+
|
|
55
|
+
**Object-level:**
|
|
56
|
+
- Object detection + per-object operation (rotate each object, color by size, etc.)
|
|
57
|
+
- Object sorting/arrangement (by size, color, position)
|
|
58
|
+
- Object copying/stamping (pattern stamped at specific locations)
|
|
59
|
+
- Gravity/stacking (objects "fall" in a direction until hitting something)
|
|
60
|
+
- Object completion (complete a partially drawn shape)
|
|
61
|
+
|
|
62
|
+
**Pattern/structure:**
|
|
63
|
+
- Tiling/repetition (pattern repeated to fill grid)
|
|
64
|
+
- Symmetry completion (make grid symmetric along an axis)
|
|
65
|
+
- Border/frame operations (add, remove, or modify borders)
|
|
66
|
+
- Maze/path (draw path connecting points, following rules)
|
|
67
|
+
- Boolean composition (two patterns combined with AND/OR/XOR logic)
|
|
68
|
+
|
|
69
|
+
**Conditional/compositional:**
|
|
70
|
+
- Different rules for different objects (based on color, size, position)
|
|
71
|
+
- Multi-step transforms (first do X, then do Y)
|
|
72
|
+
- Rule inferred from a "key" region of the grid applied to the rest
|
|
73
|
+
|
|
74
|
+
### Step 4: Form a Precise Hypothesis
|
|
75
|
+
|
|
76
|
+
State your hypothesis explicitly before testing. Be specific: not "objects move" but "each non-background connected component moves right by 2 cells and down by 1 cell, wrapping at grid boundaries."
|
|
77
|
+
|
|
78
|
+
If you're unsure between multiple hypotheses, rank them by simplicity. ARC tasks are designed to have elegant rules — prefer the simpler explanation.
|
|
79
|
+
|
|
80
|
+
### Step 5: Test (delegate to verifier)
|
|
81
|
+
|
|
82
|
+
Send your hypothesis to the **verifier** along with the task data. The verifier will check your rule against every training pair and report exactly where it fails.
|
|
83
|
+
|
|
84
|
+
If verification fails:
|
|
85
|
+
- Read the failure report carefully — it tells you exactly which cells are wrong
|
|
86
|
+
- Use `grid_diff` yourself on the specific failing pair to see the discrepancy
|
|
87
|
+
- Revise your hypothesis to account for the discrepancy
|
|
88
|
+
- Test again
|
|
89
|
+
|
|
90
|
+
Iterate. Most tasks are solved within 2-4 hypothesis cycles.
|
|
91
|
+
|
|
92
|
+
### Step 6: Apply to Test Input
|
|
93
|
+
|
|
94
|
+
Once your hypothesis passes all training pairs, apply it to the test input. If the task has a test output available, validate with `test_solution`. If not, produce your answer grid.
|
|
95
|
+
|
|
96
|
+
## When You're Stuck
|
|
97
|
+
|
|
98
|
+
If you've tried 3+ hypotheses and none work:
|
|
99
|
+
|
|
100
|
+
1. **Re-observe**: Ask the observer to look again with a specific focus ("look at just the corners", "focus on objects of color 3", "describe the spatial relationship between the two largest objects")
|
|
101
|
+
|
|
102
|
+
2. **Simplify**: Maybe you're overcomplicating it. What's the simplest possible rule that explains at least one training pair?
|
|
103
|
+
|
|
104
|
+
3. **Create a tool**: If you need a computation that doesn't exist as a primitive (like "find the bounding box intersection of two objects" or "detect repeating pattern period"), create it with `create_primitive`. A deterministic Ruby tool that does exactly what you need is more reliable than trying to do the computation in your head.
|
|
105
|
+
|
|
106
|
+
4. **Create a specialist**: If the task needs a different kind of thinking — maybe a specialist that understands symmetry, or one focused on color logic — create a new PO with `create_capability`. Give it a focused prompt and the right primitives, then delegate to it. You're not limited to the POs you started with.
|
|
107
|
+
|
|
108
|
+
5. **Decompose**: Maybe the transform is two simpler transforms composed. Try to find an intermediate representation.
|
|
109
|
+
|
|
110
|
+
6. **Ask for help**: If truly stuck, use `ask_human`. Even a one-word hint ("symmetry", "gravity", "counting") can break the logjam.
|
|
111
|
+
|
|
112
|
+
## Grid Conventions
|
|
113
|
+
|
|
114
|
+
- Grids are 2D arrays of integers 0-9
|
|
115
|
+
- 0 is typically background (rendered as `.` by render_grid)
|
|
116
|
+
- Values 1-9 are colors (rendered as their digit)
|
|
117
|
+
- Grid sizes range from 1×1 to 30×30
|
|
118
|
+
- Input and output grids can be different sizes — this itself is a clue about the rule
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verifier
|
|
3
|
+
description: Rigorous hypothesis tester — checks proposed ARC transformation rules against all training pairs
|
|
4
|
+
capabilities:
|
|
5
|
+
- render_grid
|
|
6
|
+
- grid_diff
|
|
7
|
+
- grid_info
|
|
8
|
+
- find_objects
|
|
9
|
+
- grid_transform
|
|
10
|
+
- test_solution
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Verifier
|
|
14
|
+
|
|
15
|
+
## Identity
|
|
16
|
+
|
|
17
|
+
You are a rigorous verification specialist for ARC-AGI puzzle solving. When given a proposed transformation rule and a set of training pairs, your job is to check whether the rule actually works — not approximately, not mostly, but exactly. You are skeptical by nature. You look for where rules break.
|
|
18
|
+
|
|
19
|
+
## How You Work
|
|
20
|
+
|
|
21
|
+
When the solver sends you a hypothesis to verify:
|
|
22
|
+
|
|
23
|
+
### 1. Understand the Hypothesis
|
|
24
|
+
|
|
25
|
+
Restate the proposed rule in your own words to confirm understanding. If the rule is ambiguous, identify the ambiguity and test the most likely interpretation, noting the alternatives.
|
|
26
|
+
|
|
27
|
+
### 2. Test Each Training Pair
|
|
28
|
+
|
|
29
|
+
For each training pair:
|
|
30
|
+
1. Start with the input grid
|
|
31
|
+
2. Mentally (or programmatically) apply the proposed rule step by step
|
|
32
|
+
3. Compare your result with the expected output using `grid_diff`
|
|
33
|
+
4. If using `test_solution` with a grid, provide the grid directly
|
|
34
|
+
|
|
35
|
+
### 3. Report Results
|
|
36
|
+
|
|
37
|
+
For each pair, report:
|
|
38
|
+
- **PASS** or **FAIL**
|
|
39
|
+
- If FAIL: exactly which cells are wrong (coordinates, expected value, got value)
|
|
40
|
+
- If FAIL: whether the failure is systematic (same type of error across cells) or isolated
|
|
41
|
+
- If FAIL: what the wrong cells suggest about the rule (e.g., "the rule works for objects of color 1 but not color 3" or "the rule works except at grid boundaries" or "the rule gets the shape right but the position is offset by 1")
|
|
42
|
+
|
|
43
|
+
### 4. Overall Assessment
|
|
44
|
+
|
|
45
|
+
After testing all pairs:
|
|
46
|
+
- If all PASS: confirm the rule holds across all training pairs
|
|
47
|
+
- If some FAIL: summarize the pattern of failures. This is the most valuable part — the failure pattern is a clue to the correct rule
|
|
48
|
+
- If all FAIL: suggest what category of rule might work better based on what you observed
|
|
49
|
+
|
|
50
|
+
## Verification Strategies
|
|
51
|
+
|
|
52
|
+
### For geometric rules (rotation, reflection, translation):
|
|
53
|
+
- Use `grid_transform` to apply the transform and then `grid_diff` to compare
|
|
54
|
+
- Check edge handling — does the rule wrap, clip, or pad?
|
|
55
|
+
|
|
56
|
+
### For object-level rules:
|
|
57
|
+
- Use `find_objects` on both input and expected output
|
|
58
|
+
- Check object-by-object: does each input object map to the right output object?
|
|
59
|
+
- Pay attention to object ordering — is it by position, size, or color?
|
|
60
|
+
|
|
61
|
+
### For color-mapping rules:
|
|
62
|
+
- Check every cell, not just a sample
|
|
63
|
+
- Look for cells where the mapping is inconsistent — these reveal conditional rules
|
|
64
|
+
|
|
65
|
+
### For compositional rules:
|
|
66
|
+
- Verify each step independently
|
|
67
|
+
- The error might be in step 2 while step 1 is correct
|
|
68
|
+
|
|
69
|
+
## Important Principles
|
|
70
|
+
|
|
71
|
+
- **Never round up.** If 95% of cells match, the rule is WRONG. One wrong cell means the hypothesis needs refinement.
|
|
72
|
+
- **Failures are information.** A rule that's almost right is more valuable than no rule at all. Your failure analysis helps the solver converge.
|
|
73
|
+
- **Check assumptions.** If the rule says "all objects move right by 2," verify there isn't one object that moves by 3. Check every instance.
|
|
74
|
+
- **Dimensional awareness.** If the rule should produce a grid of different size than the input, verify the output dimensions match expectations.
|
|
75
|
+
- **Don't fix the rule.** Your job is to test, not to propose corrections. Report what's wrong and let the solver revise. (But if the fix is obvious — like "off by one in the x-direction" — you can note that.)
|
|
76
|
+
|
|
77
|
+
## Self-Improvement
|
|
78
|
+
|
|
79
|
+
You have universal capabilities available to you. If you find yourself repeatedly needing a verification operation that doesn't exist — like checking rotational equivalence, or testing whether a grid matches a pattern with tolerance for specific positions — create it with `create_primitive`. A purpose-built verification tool is faster and more reliable than manual cell-by-cell checking. If a category of rules needs a dedicated testing approach, you can create a specialist PO with `create_capability`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class CheckArcData < Primitive
|
|
6
|
+
DATA_DIR = File.expand_path("~/.prompt_objects/data/arc-agi-1")
|
|
7
|
+
TRAINING_DIR = File.join(DATA_DIR, "data", "training")
|
|
8
|
+
EVALUATION_DIR = File.join(DATA_DIR, "data", "evaluation")
|
|
9
|
+
REPO_URL = "https://github.com/fchollet/ARC-AGI.git"
|
|
10
|
+
|
|
11
|
+
def name
|
|
12
|
+
"check_arc_data"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def description
|
|
16
|
+
"Check if ARC-AGI-1 dataset is available locally. Returns status, paths, and setup instructions if missing."
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def parameters
|
|
20
|
+
{
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {},
|
|
23
|
+
required: []
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def receive(message, context:)
|
|
28
|
+
exists = Dir.exist?(TRAINING_DIR)
|
|
29
|
+
|
|
30
|
+
if exists
|
|
31
|
+
training_count = Dir.glob(File.join(TRAINING_DIR, "*.json")).length
|
|
32
|
+
eval_count = Dir.glob(File.join(EVALUATION_DIR, "*.json")).length
|
|
33
|
+
|
|
34
|
+
JSON.pretty_generate({
|
|
35
|
+
status: "available",
|
|
36
|
+
path: DATA_DIR,
|
|
37
|
+
training_tasks: training_count,
|
|
38
|
+
evaluation_tasks: eval_count,
|
|
39
|
+
training_dir: TRAINING_DIR,
|
|
40
|
+
evaluation_dir: EVALUATION_DIR
|
|
41
|
+
})
|
|
42
|
+
else
|
|
43
|
+
JSON.pretty_generate({
|
|
44
|
+
status: "missing",
|
|
45
|
+
expected_path: DATA_DIR,
|
|
46
|
+
setup_command: "git clone #{REPO_URL} #{DATA_DIR}",
|
|
47
|
+
message: "ARC-AGI-1 dataset not found. Run the setup command to download it, or ask the human to do so."
|
|
48
|
+
})
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class FindObjects < Primitive
|
|
6
|
+
def name
|
|
7
|
+
"find_objects"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def description
|
|
11
|
+
"Find connected objects (same-color adjacent cells) in a grid. Returns objects with color, cell count, and bounding box."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parameters
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
grid: { type: "array", description: "2D array of integers" },
|
|
19
|
+
background: { type: "integer", description: "Background color to ignore (default: 0)" }
|
|
20
|
+
},
|
|
21
|
+
required: ["grid"]
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def receive(message, context:)
|
|
26
|
+
grid = message[:grid] || message["grid"]
|
|
27
|
+
bg = message[:background] || message["background"] || 0
|
|
28
|
+
|
|
29
|
+
return "Error: grid is required" unless grid.is_a?(Array)
|
|
30
|
+
return "Error: grid is empty" if grid.empty?
|
|
31
|
+
|
|
32
|
+
rows = grid.length
|
|
33
|
+
cols = grid[0]&.length || 0
|
|
34
|
+
visited = Array.new(rows) { Array.new(cols, false) }
|
|
35
|
+
objects = []
|
|
36
|
+
|
|
37
|
+
rows.times do |r|
|
|
38
|
+
cols.times do |c|
|
|
39
|
+
next if visited[r][c] || grid[r][c] == bg
|
|
40
|
+
|
|
41
|
+
color = grid[r][c]
|
|
42
|
+
cells = []
|
|
43
|
+
queue = [[r, c]]
|
|
44
|
+
visited[r][c] = true
|
|
45
|
+
|
|
46
|
+
while (pos = queue.shift)
|
|
47
|
+
cr, cc = pos
|
|
48
|
+
cells << [cr, cc]
|
|
49
|
+
[[-1, 0], [1, 0], [0, -1], [0, 1]].each do |dr, dc|
|
|
50
|
+
nr, nc = cr + dr, cc + dc
|
|
51
|
+
next if nr < 0 || nr >= rows || nc < 0 || nc >= cols
|
|
52
|
+
next if visited[nr][nc] || grid[nr][nc] != color
|
|
53
|
+
visited[nr][nc] = true
|
|
54
|
+
queue << [nr, nc]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
rs = cells.map(&:first)
|
|
59
|
+
cs = cells.map(&:last)
|
|
60
|
+
objects << {
|
|
61
|
+
color: color,
|
|
62
|
+
cells: cells.length,
|
|
63
|
+
bounds: { top: rs.min, left: cs.min, bottom: rs.max, right: cs.max }
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
JSON.pretty_generate({ total_objects: objects.length, objects: objects })
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class GridDiff < Primitive
|
|
6
|
+
def name
|
|
7
|
+
"grid_diff"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def description
|
|
11
|
+
"Compare two ARC grids cell by cell. Shows which cells differ with coordinates and values."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parameters
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
grid_a: { type: "array", description: "First grid (2D array)" },
|
|
19
|
+
grid_b: { type: "array", description: "Second grid (2D array)" }
|
|
20
|
+
},
|
|
21
|
+
required: ["grid_a", "grid_b"]
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def receive(message, context:)
|
|
26
|
+
a = message[:grid_a] || message["grid_a"]
|
|
27
|
+
b = message[:grid_b] || message["grid_b"]
|
|
28
|
+
|
|
29
|
+
return "Error: grid_a and grid_b are required" unless a.is_a?(Array) && b.is_a?(Array)
|
|
30
|
+
|
|
31
|
+
rows_a, cols_a = a.length, a[0]&.length || 0
|
|
32
|
+
rows_b, cols_b = b.length, b[0]&.length || 0
|
|
33
|
+
|
|
34
|
+
lines = []
|
|
35
|
+
|
|
36
|
+
if rows_a != rows_b || cols_a != cols_b
|
|
37
|
+
lines << "DIMENSION MISMATCH: #{rows_a}x#{cols_a} vs #{rows_b}x#{cols_b}"
|
|
38
|
+
lines << ""
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
diffs = []
|
|
42
|
+
matching = 0
|
|
43
|
+
compare_rows = [rows_a, rows_b].min
|
|
44
|
+
compare_cols = [cols_a, cols_b].min
|
|
45
|
+
|
|
46
|
+
compare_rows.times do |r|
|
|
47
|
+
compare_cols.times do |c|
|
|
48
|
+
if a[r][c] == b[r][c]
|
|
49
|
+
matching += 1
|
|
50
|
+
else
|
|
51
|
+
diffs << "(#{r},#{c}): #{a[r][c]} -> #{b[r][c]}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
total = compare_rows * compare_cols
|
|
57
|
+
lines << "#{matching}/#{total} cells match (#{diffs.length} differ)"
|
|
58
|
+
|
|
59
|
+
if diffs.empty? && rows_a == rows_b && cols_a == cols_b
|
|
60
|
+
lines << "IDENTICAL"
|
|
61
|
+
else
|
|
62
|
+
diffs.first(30).each { |d| lines << " #{d}" }
|
|
63
|
+
lines << " ... and #{diffs.length - 30} more" if diffs.length > 30
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
lines.join("\n")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class GridInfo < Primitive
|
|
6
|
+
def name
|
|
7
|
+
"grid_info"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def description
|
|
11
|
+
"Get grid dimensions, color frequencies, and density."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parameters
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
grid: { type: "array", description: "2D array of integers" }
|
|
19
|
+
},
|
|
20
|
+
required: ["grid"]
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def receive(message, context:)
|
|
25
|
+
grid = message[:grid] || message["grid"]
|
|
26
|
+
return "Error: grid is required" unless grid.is_a?(Array)
|
|
27
|
+
return "Error: grid is empty" if grid.empty?
|
|
28
|
+
|
|
29
|
+
flat = grid.flatten
|
|
30
|
+
colors = flat.tally.sort.to_h
|
|
31
|
+
|
|
32
|
+
JSON.pretty_generate({
|
|
33
|
+
rows: grid.length,
|
|
34
|
+
cols: grid[0]&.length || 0,
|
|
35
|
+
total_cells: flat.length,
|
|
36
|
+
colors: colors,
|
|
37
|
+
non_background: flat.count { |c| c != 0 }
|
|
38
|
+
})
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class GridTransform < Primitive
|
|
6
|
+
def name
|
|
7
|
+
"grid_transform"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def description
|
|
11
|
+
"Apply geometric transforms to a grid: rotate_90, rotate_180, rotate_270, flip_h, flip_v, transpose."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parameters
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
grid: { type: "array", description: "2D array of integers" },
|
|
19
|
+
operation: {
|
|
20
|
+
type: "string",
|
|
21
|
+
enum: %w[rotate_90 rotate_180 rotate_270 flip_h flip_v transpose],
|
|
22
|
+
description: "Transformation to apply"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
required: ["grid", "operation"]
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def receive(message, context:)
|
|
30
|
+
grid = message[:grid] || message["grid"]
|
|
31
|
+
op = message[:operation] || message["operation"]
|
|
32
|
+
|
|
33
|
+
return "Error: grid is required" unless grid.is_a?(Array)
|
|
34
|
+
return "Error: operation is required" unless op
|
|
35
|
+
|
|
36
|
+
result = case op
|
|
37
|
+
when "rotate_90" then grid.transpose.map(&:reverse)
|
|
38
|
+
when "rotate_180" then grid.reverse.map(&:reverse)
|
|
39
|
+
when "rotate_270" then grid.transpose.reverse
|
|
40
|
+
when "flip_h" then grid.map(&:reverse)
|
|
41
|
+
when "flip_v" then grid.reverse
|
|
42
|
+
when "transpose" then grid.transpose
|
|
43
|
+
else return "Error: Unknown operation '#{op}'"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
JSON.generate(result)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class LoadArcTask < Primitive
|
|
6
|
+
def name
|
|
7
|
+
"load_arc_task"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def description
|
|
11
|
+
"Load an ARC-AGI task from a JSON file. Returns training pairs and test inputs with grid dimensions."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parameters
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
path: {
|
|
19
|
+
type: "string",
|
|
20
|
+
description: "Path to the ARC task JSON file"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
required: ["path"]
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def receive(message, context:)
|
|
28
|
+
path = message[:path] || message["path"]
|
|
29
|
+
return "Error: path is required" unless path
|
|
30
|
+
|
|
31
|
+
expanded = File.expand_path(path)
|
|
32
|
+
return "Error: File not found: #{path}" unless File.exist?(expanded)
|
|
33
|
+
|
|
34
|
+
data = JSON.parse(File.read(expanded, encoding: "UTF-8"))
|
|
35
|
+
train = data["train"] || []
|
|
36
|
+
test = data["test"] || []
|
|
37
|
+
|
|
38
|
+
result = {
|
|
39
|
+
task_id: File.basename(expanded, ".json"),
|
|
40
|
+
training_pairs: train.length,
|
|
41
|
+
test_inputs: test.length,
|
|
42
|
+
train: train.map.with_index { |pair, i|
|
|
43
|
+
{
|
|
44
|
+
pair: i,
|
|
45
|
+
input: pair["input"],
|
|
46
|
+
output: pair["output"],
|
|
47
|
+
input_size: "#{pair["input"].length}x#{pair["input"][0].length}",
|
|
48
|
+
output_size: "#{pair["output"].length}x#{pair["output"][0].length}"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
test: test.map.with_index { |t, i|
|
|
52
|
+
{
|
|
53
|
+
test: i,
|
|
54
|
+
input: t["input"],
|
|
55
|
+
input_size: "#{t["input"].length}x#{t["input"][0].length}"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
JSON.pretty_generate(result)
|
|
61
|
+
rescue JSON::ParserError => e
|
|
62
|
+
"Error: Invalid JSON - #{e.message}"
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
"Error loading task: #{e.message}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PromptObjects
|
|
4
|
+
module Primitives
|
|
5
|
+
class RenderGrid < Primitive
|
|
6
|
+
SYMBOLS = {
|
|
7
|
+
0 => ".", 1 => "1", 2 => "2", 3 => "3", 4 => "4",
|
|
8
|
+
5 => "5", 6 => "6", 7 => "7", 8 => "8", 9 => "9"
|
|
9
|
+
}.freeze
|
|
10
|
+
|
|
11
|
+
COLOR_NAMES = {
|
|
12
|
+
0 => "black", 1 => "blue", 2 => "red", 3 => "green", 4 => "yellow",
|
|
13
|
+
5 => "grey", 6 => "magenta", 7 => "orange", 8 => "cyan", 9 => "maroon"
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
def name
|
|
17
|
+
"render_grid"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def description
|
|
21
|
+
"Render an ARC grid as readable text with coordinates. Background (0) shown as dots, colors 1-9 as digits."
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def parameters
|
|
25
|
+
{
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
grid: {
|
|
29
|
+
type: "array",
|
|
30
|
+
description: "2D array of integers 0-9"
|
|
31
|
+
},
|
|
32
|
+
label: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Optional label to display above the grid"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
required: ["grid"]
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def receive(message, context:)
|
|
42
|
+
grid = message[:grid] || message["grid"]
|
|
43
|
+
label = message[:label] || message["label"]
|
|
44
|
+
|
|
45
|
+
return "Error: grid is required" unless grid.is_a?(Array)
|
|
46
|
+
return "Error: grid is empty" if grid.empty?
|
|
47
|
+
|
|
48
|
+
rows = grid.length
|
|
49
|
+
cols = grid[0]&.length || 0
|
|
50
|
+
lines = []
|
|
51
|
+
|
|
52
|
+
lines << label if label
|
|
53
|
+
lines << "#{rows}x#{cols}"
|
|
54
|
+
|
|
55
|
+
# Column headers
|
|
56
|
+
col_header = " " + (0...cols).map { |c| c.to_s.rjust(2) }.join
|
|
57
|
+
lines << col_header
|
|
58
|
+
lines << " " + "--" * cols
|
|
59
|
+
|
|
60
|
+
# Rows with line numbers
|
|
61
|
+
grid.each_with_index do |row, r|
|
|
62
|
+
cells = row.map { |v| (SYMBOLS[v] || "?").rjust(2) }.join
|
|
63
|
+
lines << "#{r.to_s.rjust(2)}|#{cells}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Color legend for non-background colors present
|
|
67
|
+
present = grid.flatten.uniq.sort - [0]
|
|
68
|
+
unless present.empty?
|
|
69
|
+
legend = present.map { |c| "#{c}=#{COLOR_NAMES[c]}" }.join(", ")
|
|
70
|
+
lines << ""
|
|
71
|
+
lines << "Colors: #{legend}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
lines.join("\n")
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|