@otterware/openclaw-otter 0.1.1 → 0.1.2

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.
Files changed (3) hide show
  1. package/files.js +23 -0
  2. package/index.js +18 -0
  3. package/package.json +2 -1
package/files.js ADDED
@@ -0,0 +1,23 @@
1
+ import { open, realpath } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ export const MAX_FILE_BYTES = 50 * 1024 * 1024;
5
+
6
+ /** A file in the agent's workspace, whole: the gateway's own reader stops at images and small text. */
7
+ export async function readWorkspaceFile(workspace, requested) {
8
+ const root = await realpath(workspace);
9
+ const file = await realpath(path.resolve(root, requested)).catch(() => {
10
+ throw new Error("file not found");
11
+ });
12
+ if (!file.startsWith(root + path.sep)) throw new Error("file is outside the agent's workspace");
13
+ const handle = await open(file, "r");
14
+ try {
15
+ const stat = await handle.stat();
16
+ if (!stat.isFile()) throw new Error("file not found");
17
+ if (stat.size > MAX_FILE_BYTES) throw new Error("file is too large (50 MB max)");
18
+ const data = await handle.readFile();
19
+ return { name: path.basename(file), size: data.length, content: data.toString("base64") };
20
+ } finally {
21
+ await handle.close();
22
+ }
23
+ }
package/index.js CHANGED
@@ -4,6 +4,9 @@ import {
4
4
  createChatChannelPlugin,
5
5
  defineChannelPluginEntry,
6
6
  } from "openclaw/plugin-sdk/channel-core";
7
+ import { resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
8
+ import { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing";
9
+ import { readWorkspaceFile } from "./files.js";
7
10
  import { accountOf, inboxKey, OTTER_TARGET, pointerOf, tell } from "./otter.js";
8
11
 
9
12
  async function deliver(ctx, payload) {
@@ -59,4 +62,19 @@ export default defineChannelPluginEntry({
59
62
  name: "Otter",
60
63
  description: "Send what your agents want you to see to Otter.",
61
64
  plugin: otterChannel,
65
+ registerFull(api) {
66
+ // Otter's preview of a file an agent linked: PDFs and other files sessions.files.get won't send.
67
+ api.registerGatewayMethod(
68
+ "otter.files.get",
69
+ async ({ params, context }) => {
70
+ const { sessionKey, path } = params ?? {};
71
+ if (typeof sessionKey !== "string" || typeof path !== "string" || !path)
72
+ throw new Error("sessionKey and path are required");
73
+ const cfg = context?.getRuntimeConfig?.() ?? api.config;
74
+ const workspace = resolveAgentWorkspaceDir(cfg, resolveAgentIdFromSessionKey(sessionKey));
75
+ return { file: await readWorkspaceFile(workspace, path) };
76
+ },
77
+ { scope: "operator.read" },
78
+ );
79
+ },
62
80
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otterware/openclaw-otter",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Otter as an OpenClaw channel: what your agents send you waits in Otter, and Otter tells your devices.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -10,6 +10,7 @@
10
10
  },
11
11
  "files": [
12
12
  "index.js",
13
+ "files.js",
13
14
  "otter.js",
14
15
  "openclaw.plugin.json"
15
16
  ],