@theokit/sdk-tools 0.26.3 → 0.27.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c18c655: `createViewImageTool` reaches consumers.
8
+
9
+ The tool was committed on 2026-08-14, three days after `0.26.3` went to the registry, and no version
10
+ was cut — so the published `0.26.3` and the source at `0.26.3` were different packages. Anyone
11
+ resolving the range got a build without the image tool, and `@theokit/agents` could not forward what
12
+ its dependency did not ship.
13
+
14
+ The measurable cost: TheoCode wrote `packages/agent/src/tools/view-image.ts` by hand — the only local
15
+ tool in a ten-tool registry where the other nine are framework built-ins.
16
+
17
+ Note for consumers migrating off a hand-rolled equivalent: this `toModelOutput` returns the image
18
+ block ALONE on success, and leaves a failure as text so the model can read the reason and retry.
19
+ An implementation that also emitted a leading text line will change what the model receives.
20
+
3
21
  ## 0.26.3
4
22
 
5
23
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -2627,6 +2627,86 @@ function createUpdatePlanTool() {
2627
2627
  }
2628
2628
  });
2629
2629
  }
2630
+ var MEDIA_TYPES = /* @__PURE__ */ new Map([
2631
+ [".png", "image/png"],
2632
+ [".jpg", "image/jpeg"],
2633
+ [".jpeg", "image/jpeg"],
2634
+ [".gif", "image/gif"],
2635
+ [".webp", "image/webp"]
2636
+ ]);
2637
+ var DEFAULT_MAX_IMAGE_BYTES = 5 * 1024 * 1024;
2638
+ var json = (result) => JSON.stringify(result);
2639
+ function createViewImageTool(options) {
2640
+ const { projectRoot } = options;
2641
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_IMAGE_BYTES;
2642
+ return sdk.Tool.create({
2643
+ name: options.name ?? "view_image",
2644
+ description: options.description ?? "Read an image file from the project and show it to the model. Supports png, jpeg, gif and webp.",
2645
+ inputSchema: zod.z.object({
2646
+ path: zod.z.string().describe("Path to the image, relative to the project root.")
2647
+ }),
2648
+ handler: (input) => {
2649
+ const refused = checkPathScope(input.path, projectRoot);
2650
+ if (refused !== null) return refused;
2651
+ if (isForbiddenAtAnyDepth(input.path)) {
2652
+ return json({ ok: false, error: "path_traversal", path: input.path });
2653
+ }
2654
+ const mediaType = MEDIA_TYPES.get(path.extname(input.path).toLowerCase());
2655
+ if (mediaType === void 0) {
2656
+ return json({
2657
+ ok: false,
2658
+ error: "unsupported_image_type",
2659
+ path: input.path,
2660
+ supported: [...MEDIA_TYPES.keys()]
2661
+ });
2662
+ }
2663
+ const absolute = pathSafety.safePathJoin(projectRoot, input.path);
2664
+ let bytes;
2665
+ try {
2666
+ bytes = fs.statSync(absolute).size;
2667
+ } catch {
2668
+ return json({ ok: false, error: "not_found", path: input.path });
2669
+ }
2670
+ if (bytes > maxBytes) {
2671
+ return json({
2672
+ ok: false,
2673
+ error: "image_too_large",
2674
+ path: input.path,
2675
+ bytes,
2676
+ limit_bytes: maxBytes
2677
+ });
2678
+ }
2679
+ return json({
2680
+ ok: true,
2681
+ path: input.path,
2682
+ media_type: mediaType,
2683
+ bytes,
2684
+ data: fs.readFileSync(absolute).toString("base64")
2685
+ });
2686
+ },
2687
+ /**
2688
+ * Turn a successful read into an image block.
2689
+ *
2690
+ * A failed read stays TEXT on purpose: the model needs to read "not_found" and try another path,
2691
+ * and an error is not something to look at.
2692
+ */
2693
+ toModelOutput: (output) => {
2694
+ let result;
2695
+ try {
2696
+ result = JSON.parse(output);
2697
+ } catch {
2698
+ return output;
2699
+ }
2700
+ if (result.ok !== true) return output;
2701
+ return [
2702
+ {
2703
+ type: "image",
2704
+ source: { type: "base64", media_type: result.media_type, data: result.data }
2705
+ }
2706
+ ];
2707
+ }
2708
+ });
2709
+ }
2630
2710
  var DEFAULT_TIMEOUT_MS4 = 3e4;
2631
2711
  var MAX_BODY_BYTES = 1 * 1024 * 1024;
2632
2712
  function createWebFetchTool(opts) {
@@ -2768,8 +2848,8 @@ function createBraveWebSearchAdapter(opts = {}) {
2768
2848
  headers: { "X-Subscription-Token": apiKey, Accept: "application/json" }
2769
2849
  });
2770
2850
  if (!res.ok) throw new Error(`brave_search_failed: HTTP ${res.status}`);
2771
- const json = await res.json();
2772
- const results = json?.web?.results ?? [];
2851
+ const json2 = await res.json();
2852
+ const results = json2?.web?.results ?? [];
2773
2853
  return results.map((r) => ({
2774
2854
  title: String(r?.title ?? ""),
2775
2855
  url: String(r?.url ?? ""),
@@ -2931,6 +3011,7 @@ async function isBinaryFile(absolutePath) {
2931
3011
 
2932
3012
  exports.CatastrophicCommandError = CatastrophicCommandError;
2933
3013
  exports.ContextMatchError = ContextMatchError;
3014
+ exports.DEFAULT_MAX_IMAGE_BYTES = DEFAULT_MAX_IMAGE_BYTES;
2934
3015
  exports.DEFAULT_TOOL_GUIDANCE = DEFAULT_TOOL_GUIDANCE;
2935
3016
  exports.ReadTracker = ReadTracker;
2936
3017
  exports.ReasoningTools = ReasoningTools;
@@ -2959,6 +3040,7 @@ exports.createSessionArtifactStore = createSessionArtifactStore;
2959
3040
  exports.createShellTool = createShellTool;
2960
3041
  exports.createTodolistTool = createTodolistTool;
2961
3042
  exports.createUpdatePlanTool = createUpdatePlanTool;
3043
+ exports.createViewImageTool = createViewImageTool;
2962
3044
  exports.createWebFetchTool = createWebFetchTool;
2963
3045
  exports.createWebSearchTool = createWebSearchTool;
2964
3046
  exports.createWriteFileTool = createWriteFileTool;