@segmentstream/agent 0.17.0 → 0.17.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.
- package/README.md +9 -6
- package/dist/_chunks/{build-metadata-DR4gACLZ.mjs → build-metadata-DeXkvn8O.mjs} +1 -1
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/ontology-metadata-read.mjs +13 -3
- package/dist/extension/lib/ontology-tools.d.ts +6 -0
- package/dist/extension/lib/ontology-tools.mjs +1 -1
- package/dist/extension/lib/sandbox-session.d.ts +11 -6
- package/dist/extension/lib/sandbox-session.mjs +11 -4
- package/dist/extension/lib/telegram/adapter.mjs +1 -1
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -209,7 +209,7 @@ continue using GET lookup. Starter templates and pins remain unchanged in this s
|
|
|
209
209
|
| `segmentstream__attachments_send` | `tools` | Sends readable stored ontology files into the current Telegram chat and topic. |
|
|
210
210
|
| `segmentstream__bash`, `_read_file`, `_write_file` | `tools` | With `"sandbox": true`: eve's file tools, only in the sandbox `@segmentstream/agent/sandbox` opened. |
|
|
211
211
|
| platform rules | `instructions` | Changes go through actions; `describe` indexes or inspects refs; `discover` searches metadata; tools are already narrowed; when to answer `[SILENT]`; how to handle attachments |
|
|
212
|
-
| sandbox rules | `instructions` | With `"sandbox": true`: working copies, file contents as data,
|
|
212
|
+
| sandbox rules | `instructions` | With `"sandbox": true`: working copies, file contents as data, script values unchanged through `arguments_file`, no network |
|
|
213
213
|
| sandbox cleanup | `hooks` | Deletes the session's sandbox when its history is cleared, such as by `sessions.idleResetHours`. |
|
|
214
214
|
|
|
215
215
|
### Sandbox
|
|
@@ -228,10 +228,13 @@ The selector opens each session's sandbox with `networkPolicy: "deny-all"` and 2
|
|
|
228
228
|
opening in session state. The file tools pass a gate first: the marker must name the current
|
|
229
229
|
session, or the call fails before eve's executor runs, so an agent without `sandbox.ts` never gets
|
|
230
230
|
a shell in eve's default sandbox, whose network is open. The first call of a turn replaces a sandbox
|
|
231
|
-
older than 24 hours through its handle, carrying over the attachments eve
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
older than 24 hours, or one without a marker, through its handle, carrying over the attachments eve
|
|
232
|
+
staged in the last 24 hours. eve keeps a session's sandbox across deployments, so a session that
|
|
233
|
+
opened one before the agent adopted `@segmentstream/agent/sandbox` gets the SDK's on its first
|
|
234
|
+
file-tool call; a reopened sandbox without the marker fails the call, and another session's marker
|
|
235
|
+
fails it without deleting anything. The cleanup hook deletes a sandbox only when the session
|
|
236
|
+
recorded opening one, so it never opens a sandbox to delete it; `compaction.completed` is ignored,
|
|
237
|
+
because eve also compacts mid-turn. eve's session-end cleanup deletes whatever remains.
|
|
235
238
|
|
|
236
239
|
`segmentstream__attachments_promote` takes `path`, a file inside `/workspace`, instead of `id`
|
|
237
240
|
while the sandbox is on. The runtime reads it through the gate, refusing a real path outside
|
|
@@ -612,7 +615,7 @@ Eve resolution, so member/topic routing survives a cold start. No second provide
|
|
|
612
615
|
|
|
613
616
|
## Release and migration
|
|
614
617
|
|
|
615
|
-
The coordinated release uses Agent SDK 0.17.
|
|
618
|
+
The coordinated release uses Agent SDK 0.17.2, Eve 0.76.3, Ontology SDK 0.53.0 and App SDK 0.25.0.
|
|
616
619
|
The compatible Cloud archive/API must be deployed first; migrations run only through its CI/CD gate.
|
|
617
620
|
Publish the ontology SDK before the agent SDK. Upgrade the workspace ontology before its agent,
|
|
618
621
|
with the declared Telegram provider mapping and explicit `agent_chat:post_message` grant.
|
|
@@ -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.17.
|
|
7
|
+
var version = "0.17.2";
|
|
8
8
|
function agentBuild(environment = process.env) {
|
|
9
9
|
return {
|
|
10
10
|
agent: version,
|
|
@@ -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-
|
|
7
|
+
import { t as agentBuild } from "../../_chunks/build-metadata-DeXkvn8O.mjs";
|
|
8
8
|
export { agentBuild };
|
|
@@ -16,6 +16,8 @@ const cache = new Map();
|
|
|
16
16
|
let cachedBytes = 0;
|
|
17
17
|
const CACHE_BYTES = 8388608;
|
|
18
18
|
const CACHE_TTL = 3e4;
|
|
19
|
+
const RUNTIME_SOURCE_TTL = 3e5;
|
|
20
|
+
const METADATA_TIMEOUT = 1e4;
|
|
19
21
|
function remove(key) {
|
|
20
22
|
cachedBytes -= cache.get(key)?.bytes ?? 0;
|
|
21
23
|
cache.delete(key);
|
|
@@ -56,8 +58,14 @@ async function readOntologyMetadata(memberId, request, context, options = {}) {
|
|
|
56
58
|
if (scope !== void 0 && principal) {
|
|
57
59
|
if (!state || !isDeepStrictEqual(state.principal, principal)) state = {
|
|
58
60
|
principal: structuredClone(principal),
|
|
59
|
-
generation: 0
|
|
61
|
+
generation: 0,
|
|
62
|
+
runtimeSources: new Map(),
|
|
63
|
+
runtimeSourcesUntil: 0
|
|
60
64
|
};
|
|
65
|
+
if (state.runtimeSourcesUntil <= Date.now()) {
|
|
66
|
+
state.runtimeSources.clear();
|
|
67
|
+
state.runtimeSourcesUntil = Date.now() + RUNTIME_SOURCE_TTL;
|
|
68
|
+
}
|
|
61
69
|
scopes.delete(scope);
|
|
62
70
|
scopes.set(scope, state);
|
|
63
71
|
while (scopes.size > 128) scopes.delete(scopes.keys().next().value);
|
|
@@ -73,13 +81,14 @@ async function readOntologyMetadata(memberId, request, context, options = {}) {
|
|
|
73
81
|
if (key !== void 0) remove(key);
|
|
74
82
|
const client = ontologyTools({
|
|
75
83
|
...options,
|
|
76
|
-
principal
|
|
84
|
+
principal,
|
|
85
|
+
...state ? { runtimeSources: state.runtimeSources } : {}
|
|
77
86
|
});
|
|
78
87
|
let attempts = 0;
|
|
79
88
|
for (;;) {
|
|
80
89
|
attempts++;
|
|
81
90
|
try {
|
|
82
|
-
const result = await client.rpc(memberId, request.method, request.params, AbortSignal.timeout(
|
|
91
|
+
const result = await client.rpc(memberId, request.method, request.params, AbortSignal.timeout(METADATA_TIMEOUT));
|
|
83
92
|
if (key !== void 0 && scope !== void 0 && state && scopes.get(scope) === state && state.generation === generation) {
|
|
84
93
|
const bytes = Buffer.byteLength(JSON.stringify(result));
|
|
85
94
|
if (bytes <= 2097152) {
|
|
@@ -99,6 +108,7 @@ async function readOntologyMetadata(memberId, request, context, options = {}) {
|
|
|
99
108
|
} catch (cause) {
|
|
100
109
|
if (state && invalidatesSnapshot(cause)) {
|
|
101
110
|
state.generation++;
|
|
111
|
+
state.runtimeSources.clear();
|
|
102
112
|
for (const [cachedKey, entry] of cache) if (entry.state === state) remove(cachedKey);
|
|
103
113
|
}
|
|
104
114
|
const mayRetry = retryable(cause);
|
|
@@ -20,6 +20,12 @@ export declare function ontologyTools(options?: {
|
|
|
20
20
|
readonly fetch?: typeof fetch;
|
|
21
21
|
/** Install a durable dispatch fence after safe metadata/auth work, immediately before the action request. */
|
|
22
22
|
readonly beforeCall?: (name: string) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* What a tools/list said about runtime-source support, per member, shared by the clients of
|
|
25
|
+
* one caller. A large catalog's listing takes megabytes and seconds; without it, every client
|
|
26
|
+
* lists the whole catalog again before its first call.
|
|
27
|
+
*/
|
|
28
|
+
readonly runtimeSources?: Map<string, boolean>;
|
|
23
29
|
}): {
|
|
24
30
|
rpc: (memberId: string, method: string, params: Record<string, unknown>, signal?: AbortSignal) => Promise<Record<string, unknown>>;
|
|
25
31
|
list(memberId: string): Promise<Record<string, unknown>[]>;
|
|
@@ -18,7 +18,7 @@ var OntologyActionNotPermitted = class extends Error {
|
|
|
18
18
|
code = "ontology_action_not_permitted";
|
|
19
19
|
};
|
|
20
20
|
function ontologyTools(options = {}) {
|
|
21
|
-
const runtimeSources = new Map();
|
|
21
|
+
const runtimeSources = options.runtimeSources ?? new Map();
|
|
22
22
|
async function rpc(memberId, method, params, signal) {
|
|
23
23
|
if (method === "tools/call") {
|
|
24
24
|
const envelope = options.envelope ?? runtimeEnvelope({ principal: memberIdOf(options.principal) === memberId ? options.principal : null });
|
|
@@ -5,9 +5,10 @@ import type { RuntimeSandboxSession, SandboxSession } from "eve/sandbox";
|
|
|
5
5
|
* writes, the session state recording when it opened, the gate every file tool passes and the
|
|
6
6
|
* cleanup. eve cannot say which environment a session's sandbox came from without opening it, and
|
|
7
7
|
* the configured environment object need not survive bundling, so the SDK's selector writes a
|
|
8
|
-
* marker into the sandbox it opens and the tools
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* marker into the sandbox it opens, and the tools replace a sandbox without one and refuse to run
|
|
9
|
+
* unless the replacement carries it. The marker guards against a missing or replaced
|
|
10
|
+
* `agent/agent/sandbox.ts`; it is not a boundary against the model, which can only reach the
|
|
11
|
+
* sandbox after the gate has passed.
|
|
11
12
|
*/
|
|
12
13
|
/** Where the SDK's selector records that it opened the sandbox. */
|
|
13
14
|
export declare const SANDBOX_MARKER_PATH = "/workspace/.segmentstream/sandbox.json";
|
|
@@ -66,9 +67,13 @@ export declare function initializeSandbox(sandbox: SandboxSession, input: {
|
|
|
66
67
|
/**
|
|
67
68
|
* The session's sandbox, once it has passed the gate: it must carry the SDK's marker for this
|
|
68
69
|
* session, so the file tools never run in eve's default sandbox, whose network is open. The first
|
|
69
|
-
* call in each turn checks the marker
|
|
70
|
-
* and reopened, carrying over the attachments staged within the last
|
|
71
|
-
* current turn stay where eve's references point.
|
|
70
|
+
* call in each turn checks the marker. A sandbox older than a day, or one without a marker, is
|
|
71
|
+
* deleted through its handle and reopened, carrying over the attachments staged within the last
|
|
72
|
+
* day so that the files of the current turn stay where eve's references point. eve keeps a
|
|
73
|
+
* session's sandbox across deployments, so a session that opened one before the agent adopted
|
|
74
|
+
* `@segmentstream/agent/sandbox`, through eve's default or the workspace's own selector, gets the
|
|
75
|
+
* SDK's on its first file-tool call; the reopened sandbox must carry the marker, or the call
|
|
76
|
+
* fails. Another session's marker fails at once: that sandbox is not this session's to delete.
|
|
72
77
|
*/
|
|
73
78
|
export declare function sessionSandbox(context: SandboxContext, options?: {
|
|
74
79
|
readonly now?: number;
|
|
@@ -54,9 +54,15 @@ async function initializeSandbox(sandbox, input) {
|
|
|
54
54
|
} catch {}
|
|
55
55
|
return marker;
|
|
56
56
|
}
|
|
57
|
+
async function sandboxMarker(sandbox) {
|
|
58
|
+
return parseSandboxMarker(await sandbox.readBinaryFile({ path: SANDBOX_MARKER_PATH }));
|
|
59
|
+
}
|
|
60
|
+
function sandboxUnavailable() {
|
|
61
|
+
return new SandboxUnavailableError("The sandbox tools are unavailable: this session's sandbox was not opened by @segmentstream/agent/sandbox. agent/agent/sandbox.ts must re-export it.");
|
|
62
|
+
}
|
|
57
63
|
async function verifiedMarker(sandbox, sessionId) {
|
|
58
|
-
const marker =
|
|
59
|
-
if (marker === void 0 || marker.sessionId !== sessionId) throw
|
|
64
|
+
const marker = await sandboxMarker(sandbox);
|
|
65
|
+
if (marker === void 0 || marker.sessionId !== sessionId) throw sandboxUnavailable();
|
|
60
66
|
return marker;
|
|
61
67
|
}
|
|
62
68
|
async function recentAttachments(sandbox, since) {
|
|
@@ -83,8 +89,9 @@ async function sessionSandbox(context, options = {}) {
|
|
|
83
89
|
const turn = context.session.turn.id;
|
|
84
90
|
const sandbox = await context.getSandbox();
|
|
85
91
|
if (record.get()?.checkedTurn === turn) return sandbox;
|
|
86
|
-
const marker = await
|
|
87
|
-
if (
|
|
92
|
+
const marker = await sandboxMarker(sandbox);
|
|
93
|
+
if (marker !== void 0 && marker.sessionId !== context.session.id) throw sandboxUnavailable();
|
|
94
|
+
if (marker !== void 0 && now - Date.parse(marker.openedAt) < 864e5) {
|
|
88
95
|
record.update(() => ({
|
|
89
96
|
openedAt: marker.openedAt,
|
|
90
97
|
checkedTurn: turn
|
|
@@ -20,7 +20,7 @@ import { archivedRoutingMessages } from "../group-routing/routing-context.mjs";
|
|
|
20
20
|
import { dispatchStructuredMessage, structuredMessage } from "./structured.mjs";
|
|
21
21
|
import { scopedAddress, sessionPolicy } from "./sessions.mjs";
|
|
22
22
|
import { handleWorkspaceCallback, isWorkspaceCallback } from "./callbacks.mjs";
|
|
23
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
23
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-DeXkvn8O.mjs";
|
|
24
24
|
import { attachmentLifecycle } from "./lifecycle.mjs";
|
|
25
25
|
import { observedMessages } from "./observed.mjs";
|
|
26
26
|
import { expireDeferredCards, handleDeferredCallback, isDeferredCallback } from "./deferred-confirmations.mjs";
|
|
@@ -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
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
7
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-DeXkvn8O.mjs";
|
|
8
8
|
import { runtimeRequestFailure } from "./runtime-request.mjs";
|
|
9
9
|
import { GET } from "eve/channels";
|
|
10
10
|
const HEALTH_ROUTE = "/eve/v1/telegram/health";
|
|
@@ -9,7 +9,7 @@ import { object } from "../confirmation-description.mjs";
|
|
|
9
9
|
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-RIRNBxUC.mjs";
|
|
10
10
|
import { needsConfirmation } from "../confirmations.mjs";
|
|
11
11
|
import { OntologyActionNotPermitted, actionToolName, ontologyTools } from "../ontology-tools.mjs";
|
|
12
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
12
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-DeXkvn8O.mjs";
|
|
13
13
|
var AttachmentLifecycleNotPermitted = class extends Error {
|
|
14
14
|
code = "attachment_lifecycle_not_permitted";
|
|
15
15
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
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",
|