@segmentstream/agent 0.21.7 → 0.22.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/README.md CHANGED
@@ -264,6 +264,14 @@ Eve has no public connection API for reading arguments from a sandbox file. This
264
264
  has no discovery or inline-call API; ordinary calls use Eve. Chat posting is excluded.
265
265
  File-taking actions remain reachable through `segmentstream__attachments_promote`.
266
266
 
267
+ Set `save_result: true` on that file call to save a permitted read-only tool's exact JSON response
268
+ in the same session's verified sandbox. The response gives a generated `result_file`, byte size,
269
+ SHA-256 and query/paging metadata, without copying rows through the model. This mode refuses write
270
+ tools before dispatch and checks their read-only annotation again at execution. Files are limited
271
+ to 8 MiB; the query's existing permissions and bounds still apply. A file's row count covers that
272
+ result only: follow continuations or split truncated aggregate groups into disjoint filters before
273
+ combining and deduplicating them with a script. The file is temporary, like the sandbox itself.
274
+
267
275
  Under `eve dev` the sandbox is a Vercel Sandbox too and needs local Vercel credentials; without
268
276
  them the sandbox tools, and turns carrying files, fail.
269
277
 
@@ -4,7 +4,7 @@ import { createRequire as __eveCreateRequire } from "node:module";
4
4
  const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
- var version = "0.21.7";
7
+ var version = "0.22.0";
8
8
  function agentBuild(environment = process.env) {
9
9
  return {
10
10
  agent: version,
@@ -25,6 +25,12 @@ Downloads and package installs fail. For reading one file or exact totals over o
25
25
  Discover the target's schema through Eve first. Write the complete object to the file; never
26
26
  retype calculated amounts, dates or digests. The call snapshots the file before approval.
27
27
  Ordinary inline calls and chat posting use Eve's native ontology connection.
28
+ - To combine or deduplicate large ontology read results with a script, set \`save_result: true\`
29
+ on \`segmentstream__ontology_call_file\`. Write the normal read arguments into its JSON file;
30
+ the tool saves the exact response in this sandbox and returns \`result_file\`, its SHA-256 and
31
+ paging metadata. Scripts can read that JSON directly; do not retype rows. This mode accepts only
32
+ permitted read-only tools. A saved result's row count covers that result only. Follow its cursor
33
+ or split truncated aggregate groups into disjoint filters, verify coverage, then combine files.
28
34
  - A command still running after 30 seconds keeps running and returns status "running" with a
29
35
  directory under /tmp/.eve/jobs; check its stdout and exit files with later commands. Output over
30
36
  50 KiB is truncated: write large output to a file and read it in parts.
@@ -4,5 +4,5 @@ import { createRequire as __eveCreateRequire } from "node:module";
4
4
  const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
- import { t as agentBuild } from "../../_chunks/build-metadata-96xS1MkA.mjs";
7
+ import { t as agentBuild } from "../../_chunks/build-metadata-B_3wcMyz.mjs";
8
8
  export { agentBuild };
@@ -2,6 +2,7 @@ import type { TelegramTexts } from "./telegram/texts.js";
2
2
  export interface FileCall {
3
3
  readonly name: string;
4
4
  readonly arguments_file: string;
5
+ readonly save_result?: boolean;
5
6
  }
6
7
  export declare function releaseOntologyFilePayloads(): void;
7
8
  /** Eve has no public API for supplying connection arguments from a sandbox file. Keep this
@@ -10,6 +10,7 @@ import { isChatPost } from "./chat-post-confirmation.mjs";
10
10
  import { actionApproval, confirmations, inputHash } from "./confirmations.mjs";
11
11
  import { ontologyTools } from "./ontology-tools.mjs";
12
12
  import { sandboxFile } from "./sandbox-session.mjs";
13
+ import { saveOntologyResult } from "./ontology-result-file.mjs";
13
14
  import { defineState } from "eve/context";
14
15
  import { defineTool } from "eve/tools";
15
16
  const snapshots = defineState("segmentstream.ontologyFiles", () => ({}));
@@ -41,7 +42,9 @@ function ontologyFileCall(texts) {
41
42
  const policy = (principal) => actionApproval({
42
43
  labels: async (actor, _action, input) => {
43
44
  const saved = bound(input, ownerOf(actor));
44
- return ontologyTools({ principal }).labels(actor, saved.name, saved.arguments);
45
+ const labels = await ontologyTools({ principal }).labels(actor, saved.name, saved.arguments);
46
+ if (saved.saveResult && labels.readOnlyHint !== true) throw new Error("Saving a result requires a permitted read-only ontology tool.");
47
+ return labels;
45
48
  },
46
49
  describe: async (actor, _action, input) => {
47
50
  const saved = bound(input, ownerOf(actor));
@@ -67,7 +70,7 @@ function ontologyFileCall(texts) {
67
70
  }
68
71
  return defineTool({
69
72
  deferred: true,
70
- description: "Call an ontology tool with the complete JSON object computed in a sandbox file. Use only for script-generated arguments that must not be retyped. Find the real tool and its schema through Eve search first; ordinary inline calls use Eve directly. Chat posting is excluded.",
73
+ description: "Call an ontology tool with the complete JSON object computed in a sandbox file. Use for script-generated arguments, or set save_result to save a permitted read's exact JSON result in the isolated sandbox for scripts, without copying rows through the model. Find the real tool and its schema through Eve search first; ordinary inline calls use Eve. Chat posting is excluded. Saving a result never permits a write tool or expands query limits.",
71
74
  inputSchema: {
72
75
  type: "object",
73
76
  properties: {
@@ -79,6 +82,10 @@ function ontologyFileCall(texts) {
79
82
  arguments_file: {
80
83
  type: "string",
81
84
  description: "Absolute path of a JSON object inside /workspace; maximum 1 MiB."
85
+ },
86
+ save_result: {
87
+ type: "boolean",
88
+ description: "For read-only tools, save the exact result as JSON in this session's sandbox and return its generated path, digest and paging metadata instead of the rows. Maximum 8 MiB."
82
89
  }
83
90
  },
84
91
  required: ["name", "arguments_file"],
@@ -105,7 +112,8 @@ function ontologyFileCall(texts) {
105
112
  requestHash: inputHash(input),
106
113
  name: input.name,
107
114
  digest: inputHash(args),
108
- arguments: args
115
+ arguments: args,
116
+ ...input.save_result === true ? { saveResult: true } : {}
109
117
  }
110
118
  }));
111
119
  }
@@ -151,6 +159,7 @@ function ontologyFileCall(texts) {
151
159
  const saved = bound(request(ctx.callId, input, owner), owner);
152
160
  const confirmation = confirmations.get()[ctx.callId];
153
161
  if (confirmation !== void 0 && confirmation.status !== "consumed") throw new Error("The file call has not been confirmed.");
162
+ if (saved.saveResult && (await ontologyTools({ principal: ctx.session.auth.current }).labels(actor, saved.name, saved.arguments)).readOnlyHint !== true) throw new Error("Saving a result requires a permitted read-only ontology tool.");
154
163
  const result = await ontologyTools({
155
164
  principal: ctx.session.auth.current,
156
165
  envelope: runtimeEnvelope({
@@ -169,7 +178,8 @@ function ontologyFileCall(texts) {
169
178
  name: saved.name,
170
179
  arguments: saved.arguments
171
180
  });
172
- return result.structuredContent ?? result;
181
+ const output = result.structuredContent ?? result;
182
+ return saved.saveResult ? saveOntologyResult(ctx, output) : output;
173
183
  }
174
184
  });
175
185
  }
@@ -0,0 +1,10 @@
1
+ import { type SandboxContext } from "./sandbox-session.js";
2
+ /** Exact, caller-authorized read data goes only into the same session's verified sandbox.
3
+ * The generated directory cannot be chosen by a prompt or overwrite an authored file. */
4
+ export declare function saveOntologyResult(context: SandboxContext, result: unknown): Promise<{
5
+ row_count?: number | undefined;
6
+ row_count_scope?: string | undefined;
7
+ result_file: string;
8
+ bytes: number;
9
+ sha256: string;
10
+ }>;
@@ -0,0 +1,46 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { sessionSandbox } from "./sandbox-session.mjs";
8
+ import { createHash, randomUUID } from "node:crypto";
9
+ const MAXIMUM_BYTES = 8388608;
10
+ const METADATA = [
11
+ "deploymentId",
12
+ "definitionDigest",
13
+ "fields",
14
+ "execution",
15
+ "truncated",
16
+ "next_cursor",
17
+ "nextCursor",
18
+ "page_count",
19
+ "page_count_scope",
20
+ "total_scope"
21
+ ];
22
+ async function saveOntologyResult(context, result) {
23
+ const content = JSON.stringify(result);
24
+ if (content === void 0) throw new TypeError("The ontology read returned no JSON result.");
25
+ const bytes = Buffer.byteLength(content, "utf8");
26
+ if (bytes > MAXIMUM_BYTES) throw new RangeError("The ontology read result exceeds 8 MiB; request smaller groups or pages.");
27
+ const sandbox = await sessionSandbox(context);
28
+ const path = `/workspace/.segmentstream/results/${randomUUID()}/result.json`;
29
+ await sandbox.writeTextFile({
30
+ path,
31
+ content
32
+ });
33
+ const value = result !== null && typeof result === "object" && !Array.isArray(result) ? result : {};
34
+ const rows = Array.isArray(value.rows) ? value.rows : Array.isArray(value.items) ? value.items : void 0;
35
+ return {
36
+ result_file: path,
37
+ bytes,
38
+ sha256: createHash("sha256").update(content).digest("hex"),
39
+ ...rows === void 0 ? {} : {
40
+ row_count: rows.length,
41
+ row_count_scope: "result"
42
+ },
43
+ ...Object.fromEntries(METADATA.filter((key) => value[key] !== void 0).map((key) => [key, value[key]]))
44
+ };
45
+ }
46
+ export { saveOntologyResult };
@@ -24,7 +24,7 @@ import { MAXIMUM_DOWNLOAD_BYTES, connectionProxy } from "../connection-proxy.mjs
24
24
  import { dispatchStructuredMessage, structuredMessage } from "./structured.mjs";
25
25
  import { scopedAddress, sessionPolicy } from "./sessions.mjs";
26
26
  import { handleWorkspaceCallback, isWorkspaceCallback } from "./callbacks.mjs";
27
- import { t as agentBuild } from "../../../_chunks/build-metadata-96xS1MkA.mjs";
27
+ import { t as agentBuild } from "../../../_chunks/build-metadata-B_3wcMyz.mjs";
28
28
  import { attachmentLifecycle } from "./lifecycle.mjs";
29
29
  import { observedMessages } from "./observed.mjs";
30
30
  import { expireDeferredCards, handleDeferredCallback, isDeferredCallback } from "./deferred-confirmations.mjs";
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
5
5
  __eveDirname(__filename);
6
6
  __eveCreateRequire(import.meta.url);
7
7
  import { runtimeRequestFailure } from "./runtime-request.mjs";
8
- import { t as agentBuild } from "../../../_chunks/build-metadata-96xS1MkA.mjs";
8
+ import { t as agentBuild } from "../../../_chunks/build-metadata-B_3wcMyz.mjs";
9
9
  import { GET } from "eve/channels";
10
10
  const HEALTH_ROUTE = "/eve/v1/telegram/health";
11
11
  function healthRoute(input) {
@@ -10,7 +10,7 @@ import { n as currentInboundRequest, p as reportTelegramError } from "../../../_
10
10
  import { member } from "../actor.mjs";
11
11
  import { needsConfirmation } from "../confirmations.mjs";
12
12
  import { OntologyActionNotPermitted, actionToolName, ontologyTools } from "../ontology-tools.mjs";
13
- import { t as agentBuild } from "../../../_chunks/build-metadata-96xS1MkA.mjs";
13
+ import { t as agentBuild } from "../../../_chunks/build-metadata-B_3wcMyz.mjs";
14
14
  var AttachmentLifecycleNotPermitted = class extends Error {
15
15
  code = "attachment_lifecycle_not_permitted";
16
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segmentstream/agent",
3
- "version": "0.21.7",
3
+ "version": "0.22.0",
4
4
  "description": "Mount a SegmentStream workspace's agent on eve: the ontology as tools, acting as the member who writes, and Telegram through the workspace's connection.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "SegmentStream",