@runtypelabs/cli 1.8.2 → 1.8.3

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.
package/README.md CHANGED
@@ -62,6 +62,14 @@ runtype marathon agent_abc123 --goal "Write integration tests for the API" \
62
62
  # Override the agent's configured model
63
63
  runtype marathon "Code Builder" --goal "Build a calculator" --model claude-sonnet-4-5
64
64
 
65
+ # Enable built-in tools for the task (web search, scraping, image generation, etc.)
66
+ runtype marathon "Code Builder" --goal "Search the web and summarize" --tools exa
67
+ runtype marathon "Code Builder" -g "Find docs and scrape them" --tools exa firecrawl
68
+
69
+ # Combine tools with other options
70
+ runtype marathon "Code Builder" --goal "Research and generate images" \
71
+ --tools exa dalle --max-sessions 5
72
+
65
73
  # Enable sandboxed code execution tooling for the task (QuickJS or Daytona)
66
74
  runtype marathon "Code Builder" --goal "Compute totals from this dataset" --sandbox quickjs
67
75
  runtype marathon "Code Builder" -g "Generate a script and run it" --sandbox daytona
@@ -124,6 +132,42 @@ runtype marathon "Code Builder" --goal "Fix the bug" \
124
132
  runtype marathon "Code Builder" --goal "Fix the bug" --tool-context full-inline
125
133
  ```
126
134
 
135
+ #### Built-in Tools
136
+
137
+ The `--tools` (or `-t`) flag enables built-in platform tools during agent execution. Tools are validated at startup against the built-in tools registry, and compatibility is checked against all models used in the task (including planning and execution phase models).
138
+
139
+ ```bash
140
+ # Enable a single tool
141
+ runtype marathon "Code Builder" --goal "Search the web" --tools exa
142
+
143
+ # Enable multiple tools (space-separated)
144
+ runtype marathon "Code Builder" --goal "Research and generate" --tools exa firecrawl dalle
145
+
146
+ # Short flag
147
+ runtype marathon "Code Builder" -g "Scrape docs" -t firecrawl
148
+ ```
149
+
150
+ **Available tools:**
151
+
152
+ | Tool ID | Description |
153
+ | ---------------- | ------------------------------------------- |
154
+ | `exa` | Semantic web search |
155
+ | `firecrawl` | Web scraping and content extraction |
156
+ | `dalle` | DALL-E image generation |
157
+ | `elevenlabs-tts` | Text-to-speech via ElevenLabs |
158
+ | `elevenlabs-stt` | Speech-to-text transcription via ElevenLabs |
159
+
160
+ **Not available via CLI:**
161
+
162
+ - `openai_web_search`, `anthropic_web_search`, `anthropic_web_fetch` — provider-native tools handled automatically by compatible models
163
+ - `vector-search` — requires additional configuration (use the dashboard instead)
164
+
165
+ **Validation behavior:**
166
+
167
+ - Unknown tool IDs produce an error listing all available tools
168
+ - Tools incompatible with the selected model(s) are rejected with a specific error
169
+ - All validation errors are reported together so you can fix them in one pass
170
+
127
171
  ## Configuration
128
172
 
129
173
  ```bash
package/dist/index.js CHANGED
@@ -8785,6 +8785,7 @@ var BORDER_H = "\u2500";
8785
8785
  var CORNERS = { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518" };
8786
8786
  var BORDER_V = "\u2502";
8787
8787
  var TICK_MS = 100;
8788
+ var DIR_RIGHT_ZWJ = "\u200D\u27A1\uFE0F";
8788
8789
  function useRunnerTrack({
8789
8790
  width,
8790
8791
  isAnimating,
@@ -8794,13 +8795,18 @@ function useRunnerTrack({
8794
8795
  showFinish = true,
8795
8796
  initialPosition = 0,
8796
8797
  initialLaps = 0,
8797
- onPositionChange
8798
+ onPositionChange,
8799
+ contentRows = 0
8798
8800
  }) {
8799
8801
  const innerWidth = Math.max(4, width - 2);
8800
- const perimeter = innerWidth * 2;
8801
- const [position, setPosition] = useState11(
8802
- () => Math.min(initialPosition, perimeter - 1)
8803
- );
8802
+ const trackWidth = innerWidth - 1;
8803
+ const cR = Math.max(0, contentRows);
8804
+ const perimeter = trackWidth * 2 + cR * 2;
8805
+ const finishPosition = Math.floor(innerWidth / 2);
8806
+ const [position, setPosition] = useState11(() => {
8807
+ const startPos = initialPosition === 0 && initialLaps === 0 ? finishPosition : initialPosition;
8808
+ return Math.min(startPos, perimeter - 1);
8809
+ });
8804
8810
  const [laps, setLaps] = useState11(initialLaps);
8805
8811
  const [elapsed, setElapsed] = useState11(0);
8806
8812
  const startTimeRef = useRef4(Date.now());
@@ -8834,15 +8840,21 @@ function useRunnerTrack({
8834
8840
  }, TICK_MS);
8835
8841
  return () => clearInterval(interval);
8836
8842
  }, [isAnimating, perimeter, laps]);
8837
- const finishPosition = Math.floor(innerWidth / 2);
8838
- const getRowCol = useCallback3(
8843
+ const getPosition = useCallback3(
8839
8844
  (pos) => {
8840
- if (pos < innerWidth) {
8841
- return { row: "top", col: pos };
8845
+ if (pos < trackWidth) {
8846
+ return { segment: "top", col: pos };
8842
8847
  }
8843
- return { row: "bottom", col: innerWidth - 1 - (pos - innerWidth) };
8848
+ if (cR > 0 && pos < trackWidth + cR) {
8849
+ return { segment: "right", row: pos - trackWidth };
8850
+ }
8851
+ const bottomStart = trackWidth + cR;
8852
+ if (pos < bottomStart + trackWidth) {
8853
+ return { segment: "bottom", col: trackWidth - 1 - (pos - bottomStart) };
8854
+ }
8855
+ return { segment: "left", row: cR - 1 - (pos - bottomStart - trackWidth) };
8844
8856
  },
8845
- [innerWidth]
8857
+ [trackWidth, cR]
8846
8858
  );
8847
8859
  const topCells = Array(innerWidth).fill(BORDER_H);
8848
8860
  const bottomCells = Array(innerWidth).fill(BORDER_H);
@@ -8852,23 +8864,43 @@ function useRunnerTrack({
8852
8864
  topCells[finishPosition + 1] = "";
8853
8865
  }
8854
8866
  }
8867
+ const leftBorderMap = /* @__PURE__ */ new Map();
8868
+ const rightBorderMap = /* @__PURE__ */ new Map();
8869
+ const runnerPosObj = getPosition(position);
8870
+ const facingRight = runnerPosObj.segment === "top" || runnerPosObj.segment === "left";
8871
+ const directionalRunner = facingRight ? runnerChar + DIR_RIGHT_ZWJ : runnerChar;
8855
8872
  if (showRunner) {
8856
8873
  for (let i = 0; i < TRAIL_CHARS.length; i++) {
8857
8874
  const trailPos = (position - 1 - i + perimeter) % perimeter;
8858
- const { row, col } = getRowCol(trailPos);
8859
- if (showFinish && row === "top" && col === finishPosition) continue;
8860
- const cells = row === "top" ? topCells : bottomCells;
8861
- cells[col] = TRAIL_CHARS[i];
8875
+ const tPos = getPosition(trailPos);
8876
+ if (tPos.segment === "top") {
8877
+ if (showFinish && (tPos.col === finishPosition || tPos.col === finishPosition + 1))
8878
+ continue;
8879
+ topCells[tPos.col] = TRAIL_CHARS[i];
8880
+ } else if (tPos.segment === "bottom") {
8881
+ bottomCells[tPos.col] = TRAIL_CHARS[i];
8882
+ } else if (tPos.segment === "right") {
8883
+ rightBorderMap.set(tPos.row, TRAIL_CHARS[i]);
8884
+ } else {
8885
+ leftBorderMap.set(tPos.row, TRAIL_CHARS[i]);
8886
+ }
8862
8887
  }
8863
8888
  }
8864
- const runnerPos = getRowCol(position);
8865
8889
  if (showRunner) {
8866
- const runnerCells = runnerPos.row === "top" ? topCells : bottomCells;
8867
- if (!(showFinish && runnerPos.row === "top" && runnerPos.col === finishPosition)) {
8868
- runnerCells[runnerPos.col] = runnerChar;
8869
- if (runnerPos.col + 1 < innerWidth) {
8870
- runnerCells[runnerPos.col + 1] = "";
8890
+ if (runnerPosObj.segment === "top") {
8891
+ const hitsFinish = showFinish && (runnerPosObj.col === finishPosition || runnerPosObj.col === finishPosition + 1);
8892
+ if (!hitsFinish) {
8893
+ topCells[runnerPosObj.col] = directionalRunner;
8894
+ if (runnerPosObj.col + 1 < innerWidth) {
8895
+ topCells[runnerPosObj.col + 1] = "";
8896
+ }
8897
+ }
8898
+ } else if (runnerPosObj.segment === "bottom") {
8899
+ bottomCells[runnerPosObj.col] = directionalRunner;
8900
+ if (runnerPosObj.col + 1 < innerWidth) {
8901
+ bottomCells[runnerPosObj.col + 1] = "";
8871
8902
  }
8903
+ } else {
8872
8904
  }
8873
8905
  }
8874
8906
  const minutes = Math.floor(elapsed / 60);
@@ -8877,7 +8909,8 @@ function useRunnerTrack({
8877
8909
  const lapStart = Math.max(0, Math.floor((innerWidth - lapText.length) / 2));
8878
8910
  for (let i = 0; i < lapText.length && lapStart + i < innerWidth; i++) {
8879
8911
  const col = lapStart + i;
8880
- if (runnerPos.row === "bottom" && (col === runnerPos.col || col === runnerPos.col + 1)) continue;
8912
+ if (runnerPosObj.segment === "bottom" && (col === runnerPosObj.col || col === runnerPosObj.col + 1))
8913
+ continue;
8881
8914
  bottomCells[col] = lapText[i];
8882
8915
  }
8883
8916
  const buildRowSegments = (cells, cornerLeft, cornerRight) => {
@@ -8888,7 +8921,7 @@ function useRunnerTrack({
8888
8921
  for (const cell of cells) {
8889
8922
  if (cell === "") continue;
8890
8923
  let cellColor;
8891
- if (cell === runnerChar || cell === finishChar) {
8924
+ if (cell === runnerChar || cell === directionalRunner || cell === finishChar) {
8892
8925
  cellColor = void 0;
8893
8926
  } else if (TRAIL_CHARS.includes(cell)) {
8894
8927
  cellColor = theme8.accent;
@@ -8909,7 +8942,15 @@ function useRunnerTrack({
8909
8942
  };
8910
8943
  const topSegments = buildRowSegments(topCells, CORNERS.tl, CORNERS.tr);
8911
8944
  const bottomSegments = buildRowSegments(bottomCells, CORNERS.bl, CORNERS.br);
8912
- const borderSegments = (content, contentVisualWidth) => {
8945
+ const borderSegments = (content, contentVisualWidth, rowIndex) => {
8946
+ const leftDecor = rowIndex !== void 0 ? leftBorderMap.get(rowIndex) : void 0;
8947
+ const rightDecor = rowIndex !== void 0 ? rightBorderMap.get(rowIndex) : void 0;
8948
+ const leftChar = leftDecor ?? BORDER_V;
8949
+ const rightChar = rightDecor ?? BORDER_V;
8950
+ const borderCharColor = (char) => {
8951
+ if (TRAIL_CHARS.includes(char)) return theme8.accent;
8952
+ return theme8.border;
8953
+ };
8913
8954
  let truncated = content;
8914
8955
  if (contentVisualWidth > innerWidth) {
8915
8956
  truncated = [];
@@ -8928,10 +8969,10 @@ function useRunnerTrack({
8928
8969
  const truncatedWidth = truncated.reduce((sum, s) => sum + s.text.length, 0);
8929
8970
  const rightPad = Math.max(0, innerWidth - truncatedWidth);
8930
8971
  return [
8931
- { text: BORDER_V, color: theme8.border },
8972
+ { text: leftChar, color: borderCharColor(leftChar) },
8932
8973
  ...truncated,
8933
8974
  ...rightPad > 0 ? [{ text: " ".repeat(rightPad) }] : [],
8934
- { text: BORDER_V, color: theme8.border }
8975
+ { text: rightChar, color: borderCharColor(rightChar) }
8935
8976
  ];
8936
8977
  };
8937
8978
  return { topSegments, bottomSegments, innerWidth, borderSegments };
@@ -8965,6 +9006,9 @@ function SessionHeader({
8965
9006
  const showName = sessionName && sessionName !== `Marathon #${sessionCount}`;
8966
9007
  const separator = theme9.separator ?? " \xB7 ";
8967
9008
  const resolvedWidth = trackWidth ?? 40;
9009
+ let contentRowCount = 1;
9010
+ if (previewUrl) contentRowCount++;
9011
+ if (goal) contentRowCount++;
8968
9012
  const { topSegments, bottomSegments, innerWidth, borderSegments } = useRunnerTrack({
8969
9013
  width: resolvedWidth,
8970
9014
  isAnimating,
@@ -8974,7 +9018,8 @@ function SessionHeader({
8974
9018
  showFinish,
8975
9019
  initialPosition: runnerPosition,
8976
9020
  initialLaps: runnerLaps,
8977
- onPositionChange: onRunnerPositionChange
9021
+ onPositionChange: onRunnerPositionChange,
9022
+ contentRows: contentRowCount
8978
9023
  });
8979
9024
  const titleText = `Marathon #${sessionCount}`;
8980
9025
  const nameText = showName ? ` (${sessionName})` : "";
@@ -8988,15 +9033,17 @@ function SessionHeader({
8988
9033
  { text: modelText, color: theme9.textMuted },
8989
9034
  { text: costText, color: theme9.warning }
8990
9035
  ];
9036
+ let rowIdx = 0;
8991
9037
  const rows = [
8992
9038
  topSegments,
8993
- borderSegments(infoSegments, infoVisualWidth)
9039
+ borderSegments(infoSegments, infoVisualWidth, rowIdx++)
8994
9040
  ];
8995
9041
  if (previewUrl) {
8996
9042
  const previewText = ` Preview: ${previewUrl}`;
8997
9043
  rows.push(borderSegments(
8998
9044
  [{ text: previewText, color: theme9.accent }],
8999
- previewText.length
9045
+ previewText.length,
9046
+ rowIdx++
9000
9047
  ));
9001
9048
  }
9002
9049
  if (goal) {
@@ -9005,11 +9052,12 @@ function SessionHeader({
9005
9052
  const goalText = ` ${displayGoal}`;
9006
9053
  rows.push(borderSegments(
9007
9054
  [{ text: goalText, color: theme9.textMuted }],
9008
- goalText.length
9055
+ goalText.length,
9056
+ rowIdx++
9009
9057
  ));
9010
9058
  }
9011
9059
  rows.push(bottomSegments);
9012
- return /* @__PURE__ */ jsx8(Box7, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { children: rows.map((row, rowIdx) => rowIdx === 0 ? renderSegments(row) : ["\n", ...renderSegments(row)]) }) });
9060
+ return /* @__PURE__ */ jsx8(Box7, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { children: rows.map((row, rowIdx2) => rowIdx2 === 0 ? renderSegments(row) : ["\n", ...renderSegments(row)]) }) });
9013
9061
  }
9014
9062
 
9015
9063
  // src/ink/marathon/SessionTabs.tsx