@segmentstream/agent 0.17.21 → 0.18.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 +47 -38
- package/dist/_chunks/{build-metadata-CEQMVxxj.mjs → build-metadata-PY8Xja6K.mjs} +1 -1
- package/dist/extension/_manifest.json +1 -0
- package/dist/extension/channels/telegram.mjs +1 -1
- package/dist/extension/config.d.ts +2 -4
- package/dist/extension/config.mjs +1 -2
- package/dist/extension/connections/ontology.d.ts +3 -0
- package/dist/extension/connections/ontology.mjs +19 -0
- package/dist/extension/hooks/ontology-files.d.ts +2 -0
- package/dist/extension/hooks/ontology-files.mjs +10 -0
- package/dist/extension/instructions/sandbox.mjs +6 -4
- package/dist/extension/instructions.md +16 -16
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/deferred-confirmations.d.ts +1 -4
- package/dist/extension/lib/deferred-confirmations.mjs +3 -89
- package/dist/extension/lib/ontology-connection.d.ts +4 -3
- package/dist/extension/lib/ontology-connection.mjs +6 -19
- package/dist/extension/lib/ontology-file-call.d.ts +10 -0
- package/dist/extension/lib/ontology-file-call.mjs +171 -0
- package/dist/extension/lib/ontology-tools.d.ts +0 -4
- package/dist/extension/lib/ontology-tools.mjs +0 -7
- package/dist/extension/lib/telegram/adapter.d.ts +1 -1
- package/dist/extension/lib/telegram/adapter.mjs +2 -2
- package/dist/extension/lib/telegram/health.d.ts +1 -1
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/dist/extension/schedules/confirmations.mjs +1 -1
- package/dist/extension/tools/ontology_call_file.d.ts +2 -0
- package/dist/extension/tools/ontology_call_file.mjs +11 -0
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.mjs +2 -2
- package/package.json +2 -2
- package/dist/extension/lib/ontology-arguments.d.ts +0 -28
- package/dist/extension/lib/ontology-arguments.mjs +0 -54
- package/dist/extension/lib/ontology-gateway.d.ts +0 -20
- package/dist/extension/lib/ontology-gateway.mjs +0 -52
- package/dist/extension/lib/ontology-metadata-read.d.ts +0 -15
- package/dist/extension/lib/ontology-metadata-read.mjs +0 -136
- package/dist/extension/tools/ontology.d.ts +0 -28
- package/dist/extension/tools/ontology.mjs +0 -137
|
@@ -0,0 +1,171 @@
|
|
|
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 { i as memberIdOf, u as runtimeEnvelope } from "../../_chunks/principal-Dmm-cXNF.mjs";
|
|
8
|
+
import { isChatPost } from "./chat-post-confirmation.mjs";
|
|
9
|
+
import { actionApproval, confirmations, inputHash } from "./confirmations.mjs";
|
|
10
|
+
import { ontologyTools } from "./ontology-tools.mjs";
|
|
11
|
+
import { sandboxFile } from "./sandbox-session.mjs";
|
|
12
|
+
import { defineState } from "eve/context";
|
|
13
|
+
import { defineTool } from "eve/tools";
|
|
14
|
+
const snapshots = defineState("segmentstream.ontologyFiles", () => ({}));
|
|
15
|
+
function receipt(saved, dispatched = saved.dispatched) {
|
|
16
|
+
return {
|
|
17
|
+
memberId: saved.memberId,
|
|
18
|
+
requestHash: saved.requestHash,
|
|
19
|
+
name: saved.name,
|
|
20
|
+
digest: saved.digest,
|
|
21
|
+
...dispatched ? { dispatched } : {}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function releaseOntologyFilePayloads() {
|
|
25
|
+
snapshots.update((all) => Object.fromEntries(Object.entries(all).map(([id, saved]) => [id, receipt(saved)])));
|
|
26
|
+
}
|
|
27
|
+
function releasePayload(callId) {
|
|
28
|
+
snapshots.update((all) => {
|
|
29
|
+
const saved = all[callId];
|
|
30
|
+
return saved === void 0 ? all : {
|
|
31
|
+
...all,
|
|
32
|
+
[callId]: receipt(saved)
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function ontologyFileCall(texts) {
|
|
37
|
+
const policy = (principal) => actionApproval({
|
|
38
|
+
labels: async (memberId, _action, input) => {
|
|
39
|
+
const saved = bound(input, memberId);
|
|
40
|
+
return ontologyTools({ principal }).labels(memberId, saved.name, saved.arguments);
|
|
41
|
+
},
|
|
42
|
+
describe: async (memberId, _action, input) => {
|
|
43
|
+
const saved = bound(input, memberId);
|
|
44
|
+
return ontologyTools({ principal }).describe(memberId, saved.name, saved.arguments);
|
|
45
|
+
},
|
|
46
|
+
texts
|
|
47
|
+
});
|
|
48
|
+
function bound(input, memberId) {
|
|
49
|
+
const saved = snapshots.get()[String(input.snapshot)];
|
|
50
|
+
if (saved === void 0 || saved.memberId !== memberId || saved.dispatched || saved.arguments === void 0) throw new Error("The file call is unavailable or already dispatched.");
|
|
51
|
+
return {
|
|
52
|
+
...saved,
|
|
53
|
+
arguments: saved.arguments
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function request(callId, input, memberId) {
|
|
57
|
+
const saved = snapshots.get()[callId];
|
|
58
|
+
if (saved === void 0 || saved.memberId !== memberId || saved.requestHash !== inputHash(input)) throw new Error("The file call belongs to another member or input.");
|
|
59
|
+
return {
|
|
60
|
+
snapshot: callId,
|
|
61
|
+
digest: saved.digest
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return defineTool({
|
|
65
|
+
deferred: true,
|
|
66
|
+
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.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
name: {
|
|
71
|
+
type: "string",
|
|
72
|
+
pattern: "^[a-z][a-z0-9_]*$",
|
|
73
|
+
description: "Bare ontology tool name."
|
|
74
|
+
},
|
|
75
|
+
arguments_file: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Absolute path of a JSON object inside /workspace; maximum 1 MiB."
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
required: ["name", "arguments_file"],
|
|
81
|
+
additionalProperties: false
|
|
82
|
+
},
|
|
83
|
+
approval: {
|
|
84
|
+
async request(ctx) {
|
|
85
|
+
try {
|
|
86
|
+
const memberId = memberIdOf(ctx.session.auth.current);
|
|
87
|
+
const input = ctx.toolInput;
|
|
88
|
+
if (memberId === void 0 || input === void 0 || isChatPost(input.name) || input.name.startsWith("ontology_") || input.name.includes("__") || !/^[a-z][a-z0-9_]*$/.test(input.name)) return {
|
|
89
|
+
type: "denied",
|
|
90
|
+
reason: "A paired member and a direct ontology tool are required."
|
|
91
|
+
};
|
|
92
|
+
if (snapshots.get()[ctx.callId] === void 0) {
|
|
93
|
+
const { content } = await sandboxFile(ctx, input.arguments_file, { maximumBytes: 1048576 });
|
|
94
|
+
const args = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content));
|
|
95
|
+
if (args === null || typeof args !== "object" || Array.isArray(args)) throw new Error("The file must contain a JSON object.");
|
|
96
|
+
if ("_segmentstream" in args) throw new Error("Runtime identity cannot be supplied in a file.");
|
|
97
|
+
snapshots.update((all) => ({
|
|
98
|
+
...all,
|
|
99
|
+
[ctx.callId]: {
|
|
100
|
+
memberId,
|
|
101
|
+
requestHash: inputHash(input),
|
|
102
|
+
name: input.name,
|
|
103
|
+
digest: inputHash(args),
|
|
104
|
+
arguments: args
|
|
105
|
+
}
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
const decision = await policy(ctx.session.auth.current).request({
|
|
109
|
+
...ctx,
|
|
110
|
+
toolInput: request(ctx.callId, input, memberId)
|
|
111
|
+
});
|
|
112
|
+
if (decision === "denied" || decision === false || typeof decision === "object" && decision?.type === "denied") {
|
|
113
|
+
const current = confirmations.get()[ctx.callId];
|
|
114
|
+
if (current?.status !== "pending" || current.expiresAt <= Date.now()) releasePayload(ctx.callId);
|
|
115
|
+
}
|
|
116
|
+
return decision;
|
|
117
|
+
} catch (cause) {
|
|
118
|
+
console.warn("The ontology file call could not be prepared.", cause);
|
|
119
|
+
return {
|
|
120
|
+
type: "denied",
|
|
121
|
+
reason: "The original JSON file call is unavailable. Prepare a new call."
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
async response(ctx) {
|
|
126
|
+
try {
|
|
127
|
+
const decision = await policy(ctx.request.principal).response({
|
|
128
|
+
...ctx,
|
|
129
|
+
request: {
|
|
130
|
+
...ctx.request,
|
|
131
|
+
toolInput: request(ctx.request.callId, ctx.request.toolInput, memberIdOf(ctx.request.principal))
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
if (decision.status === "allowed" && ctx.response.decision === "cancel") releasePayload(ctx.request.callId);
|
|
135
|
+
return decision;
|
|
136
|
+
} catch {
|
|
137
|
+
return {
|
|
138
|
+
status: "rejected",
|
|
139
|
+
reason: "The file call changed. Prepare a new call."
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
async execute(input, ctx) {
|
|
145
|
+
const memberId = memberIdOf(ctx.session.auth.current);
|
|
146
|
+
const saved = bound(request(ctx.callId, input, memberId), memberId);
|
|
147
|
+
const confirmation = confirmations.get()[ctx.callId];
|
|
148
|
+
if (confirmation !== void 0 && confirmation.status !== "consumed") throw new Error("The file call has not been confirmed.");
|
|
149
|
+
const result = await ontologyTools({
|
|
150
|
+
principal: ctx.session.auth.current,
|
|
151
|
+
envelope: runtimeEnvelope({
|
|
152
|
+
principal: ctx.session.auth.current,
|
|
153
|
+
sessionId: ctx.session.id,
|
|
154
|
+
callId: ctx.callId
|
|
155
|
+
}),
|
|
156
|
+
beforeCall: async () => {
|
|
157
|
+
bound({ snapshot: ctx.callId }, memberId);
|
|
158
|
+
snapshots.update((all) => ({
|
|
159
|
+
...all,
|
|
160
|
+
[ctx.callId]: receipt(saved, true)
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
}).rpc(memberId, "tools/call", {
|
|
164
|
+
name: saved.name,
|
|
165
|
+
arguments: saved.arguments
|
|
166
|
+
});
|
|
167
|
+
return result.structuredContent ?? result;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
export { ontologyFileCall, releaseOntologyFilePayloads };
|
|
@@ -37,10 +37,6 @@ export declare function ontologyTools(options?: {
|
|
|
37
37
|
rpc: (memberId: string, method: string, params: Record<string, unknown>, signal?: AbortSignal) => Promise<Record<string, unknown>>;
|
|
38
38
|
list(memberId: string): Promise<Record<string, unknown>[]>;
|
|
39
39
|
supportsRuntimeSource(memberId: string, signal?: AbortSignal): Promise<boolean>;
|
|
40
|
-
capabilities(memberId: string): Promise<{
|
|
41
|
-
chatPosting: boolean;
|
|
42
|
-
runtimeSource: boolean;
|
|
43
|
-
}>;
|
|
44
40
|
supportsChatPosting(memberId: string): Promise<boolean>;
|
|
45
41
|
labels(memberId: string, action: string, input?: Readonly<Record<string, unknown>>, signal?: AbortSignal): Promise<ActionAnnotations>;
|
|
46
42
|
describe(memberId: string, action: string, input: Readonly<Record<string, unknown>>): Promise<import("./confirmation-description.js").ConfirmationDescription>;
|
|
@@ -150,13 +150,6 @@ function ontologyTools(options = {}) {
|
|
|
150
150
|
if (!runtimeSources.has(memberId)) await rpc(memberId, "tools/list", {}, signal);
|
|
151
151
|
return runtimeSources.get(memberId) === true;
|
|
152
152
|
},
|
|
153
|
-
async capabilities(memberId) {
|
|
154
|
-
const result = await rpc(memberId, "tools/list", {});
|
|
155
|
-
return {
|
|
156
|
-
chatPosting: Array.isArray(result.tools) && result.tools.map(object).some(supportsChatPost),
|
|
157
|
-
runtimeSource: runtimeSources.get(memberId) === true
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
153
|
async supportsChatPosting(memberId) {
|
|
161
154
|
const result = await rpc(memberId, "tools/list", {});
|
|
162
155
|
return Array.isArray(result.tools) && result.tools.map(object).some(supportsChatPost);
|
|
@@ -33,7 +33,7 @@ export interface TelegramAdapterOptions {
|
|
|
33
33
|
/** The mounted `sessions`. */
|
|
34
34
|
readonly sessions: () => SessionSettings;
|
|
35
35
|
readonly admission?: () => AdmissionSettings;
|
|
36
|
-
readonly confirmationMode?: () => "deferred" | "held";
|
|
36
|
+
readonly confirmationMode?: () => "deferred" | "held" | "native";
|
|
37
37
|
readonly decide: DecideFunction;
|
|
38
38
|
readonly environment?: Environment;
|
|
39
39
|
readonly token?: RuntimeToken;
|
|
@@ -22,7 +22,7 @@ import { MAXIMUM_DOWNLOAD_BYTES, connectionProxy } from "../connection-proxy.mjs
|
|
|
22
22
|
import { dispatchStructuredMessage, structuredMessage } from "./structured.mjs";
|
|
23
23
|
import { scopedAddress, sessionPolicy } from "./sessions.mjs";
|
|
24
24
|
import { handleWorkspaceCallback, isWorkspaceCallback } from "./callbacks.mjs";
|
|
25
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
25
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-PY8Xja6K.mjs";
|
|
26
26
|
import { attachmentLifecycle } from "./lifecycle.mjs";
|
|
27
27
|
import { observedMessages } from "./observed.mjs";
|
|
28
28
|
import { expireDeferredCards, handleDeferredCallback, isDeferredCallback } from "./deferred-confirmations.mjs";
|
|
@@ -181,7 +181,7 @@ function segmentstreamTelegram(options) {
|
|
|
181
181
|
},
|
|
182
182
|
uploadPolicy: { maxBytes: MAXIMUM_DOWNLOAD_BYTES },
|
|
183
183
|
onMessage: async (context, message) => {
|
|
184
|
-
|
|
184
|
+
try {
|
|
185
185
|
await expireDeferredCards(context, {
|
|
186
186
|
environment,
|
|
187
187
|
token,
|
|
@@ -11,7 +11,7 @@ export declare function healthRoute(input: {
|
|
|
11
11
|
readonly configured: () => boolean;
|
|
12
12
|
readonly verify: () => RuntimeTokenVerifier;
|
|
13
13
|
readonly configuration?: () => {
|
|
14
|
-
readonly confirmationMode: "deferred" | "held" | null;
|
|
14
|
+
readonly confirmationMode: "deferred" | "held" | "native" | null;
|
|
15
15
|
readonly attachmentLifecycle: boolean;
|
|
16
16
|
};
|
|
17
17
|
}): RouteDefinition<TelegramChannelState>;
|
|
@@ -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-PY8Xja6K.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-Buuv7b1I.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-PY8Xja6K.mjs";
|
|
13
13
|
var AttachmentLifecycleNotPermitted = class extends Error {
|
|
14
14
|
code = "attachment_lifecycle_not_permitted";
|
|
15
15
|
};
|
|
@@ -13,7 +13,7 @@ var confirmations_default = defineSchedule({
|
|
|
13
13
|
cron: "* * * * *",
|
|
14
14
|
async run({ to }) {
|
|
15
15
|
const settings = segmentstream.config.channels.telegram;
|
|
16
|
-
if (!channelsEnabled(process.env) || !settings
|
|
16
|
+
if (!channelsEnabled(process.env) || !settings) return;
|
|
17
17
|
await expireScheduledConfirmations(settings.connection, async (record, result) => {
|
|
18
18
|
await to(telegram_default, {
|
|
19
19
|
chatId: record.data.chatId,
|
|
@@ -0,0 +1,11 @@
|
|
|
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 segmentstream from "../extension.mjs";
|
|
8
|
+
import { ontologyFileCall } from "../lib/ontology-file-call.mjs";
|
|
9
|
+
import { defineDynamic } from "eve/tools";
|
|
10
|
+
var ontology_call_file_default = defineDynamic({ events: { "turn.started": () => segmentstream.config.ontology.connection && segmentstream.config.sandbox ? ontologyFileCall(() => segmentstream.config.texts ?? {}) : null } });
|
|
11
|
+
export { ontology_call_file_default as default };
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -6,6 +6,6 @@ export { default as attachments_promote } from "../extension/tools/attachments_p
|
|
|
6
6
|
export { default as attachments_read } from "../extension/tools/attachments_read.js";
|
|
7
7
|
export { default as attachments_send } from "../extension/tools/attachments_send.js";
|
|
8
8
|
export { default as attachments_table } from "../extension/tools/attachments_table.js";
|
|
9
|
-
export { default as
|
|
9
|
+
export { default as ontology_call_file } from "../extension/tools/ontology_call_file.js";
|
|
10
10
|
export { default as questions_ask } from "../extension/tools/questions_ask.js";
|
|
11
11
|
export { default as sandbox } from "../extension/tools/sandbox.js";
|
package/dist/tools/index.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import attachments_promote_default from "../extension/tools/attachments_promote.
|
|
|
10
10
|
import attachments_read_default from "../extension/tools/attachments_read.mjs";
|
|
11
11
|
import attachments_send_default from "../extension/tools/attachments_send.mjs";
|
|
12
12
|
import attachments_table_default from "../extension/tools/attachments_table.mjs";
|
|
13
|
-
import
|
|
13
|
+
import ontology_call_file_default from "../extension/tools/ontology_call_file.mjs";
|
|
14
14
|
import questions_ask_default from "../extension/tools/questions_ask.mjs";
|
|
15
15
|
import sandbox_default from "../extension/tools/sandbox.mjs";
|
|
16
|
-
export { attachments_discard_default as attachments_discard, attachments_list_default as attachments_list, attachments_promote_default as attachments_promote, attachments_read_default as attachments_read, attachments_send_default as attachments_send, attachments_table_default as attachments_table,
|
|
16
|
+
export { attachments_discard_default as attachments_discard, attachments_list_default as attachments_list, attachments_promote_default as attachments_promote, attachments_read_default as attachments_read, attachments_send_default as attachments_send, attachments_table_default as attachments_table, ontology_call_file_default as ontology_call_file, questions_ask_default as questions_ask, sandbox_default as sandbox };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@chat-adapter/telegram": "4.41.0",
|
|
69
|
-
"@segmentstream-cloud/ontology": "0.58.
|
|
69
|
+
"@segmentstream-cloud/ontology": "0.58.1",
|
|
70
70
|
"@vercel/oidc": "^3.8.4",
|
|
71
71
|
"ai": "^7.0.128",
|
|
72
72
|
"csv-parse": "^7.0.3",
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type SandboxContext } from "./sandbox-session.js";
|
|
2
|
-
/**
|
|
3
|
-
* The arguments of `segmentstream__ontology_call`: inline as `arguments`, or, with the sandbox on,
|
|
4
|
-
* as `arguments_file`, the path of a JSON object a script wrote in the session's sandbox. A large
|
|
5
|
-
* payload computed in the sandbox then reaches the ontology byte for byte instead of being retyped
|
|
6
|
-
* by the model. The file is read through the same gate as every sandbox file the platform takes.
|
|
7
|
-
*/
|
|
8
|
-
/** The largest JSON file `arguments_file` may name. */
|
|
9
|
-
export declare const MAXIMUM_ARGUMENTS_FILE_BYTES: number;
|
|
10
|
-
export declare const ONTOLOGY_ARGUMENTS_ERROR_CODES: readonly ["ontology_arguments_ambiguous", "ontology_arguments_file_unavailable", "ontology_arguments_file_unreadable", "ontology_arguments_file_too_large", "ontology_arguments_file_invalid_json", "ontology_arguments_file_not_object"];
|
|
11
|
-
export type OntologyArgumentsErrorCode = (typeof ONTOLOGY_ARGUMENTS_ERROR_CODES)[number];
|
|
12
|
-
/** The model's arguments cannot be used; the message starts with the code the model reads. */
|
|
13
|
-
export declare class OntologyArgumentsError extends Error {
|
|
14
|
-
readonly name = "OntologyArgumentsError";
|
|
15
|
-
readonly code: OntologyArgumentsErrorCode;
|
|
16
|
-
constructor(code: OntologyArgumentsErrorCode, detail: string, options?: ErrorOptions);
|
|
17
|
-
}
|
|
18
|
-
export interface OntologyCallInput {
|
|
19
|
-
readonly arguments?: Record<string, unknown>;
|
|
20
|
-
readonly arguments_file?: string;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* The arguments an `ontology_call` runs with: `arguments`, the object in `arguments_file`, or an
|
|
24
|
-
* empty object when neither is given, as before `arguments_file` existed.
|
|
25
|
-
*/
|
|
26
|
-
export declare function ontologyCallArguments(input: OntologyCallInput, context: SandboxContext, options: {
|
|
27
|
-
readonly sandbox: boolean;
|
|
28
|
-
}): Promise<Record<string, unknown>>;
|
|
@@ -1,54 +0,0 @@
|
|
|
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 { SandboxFileRefused, SandboxFileTooLarge, SandboxUnavailableError, sandboxFile } from "./sandbox-session.mjs";
|
|
8
|
-
const MAXIMUM_ARGUMENTS_FILE_BYTES = 1048576;
|
|
9
|
-
const ONTOLOGY_ARGUMENTS_ERROR_CODES = [
|
|
10
|
-
"ontology_arguments_ambiguous",
|
|
11
|
-
"ontology_arguments_file_unavailable",
|
|
12
|
-
"ontology_arguments_file_unreadable",
|
|
13
|
-
"ontology_arguments_file_too_large",
|
|
14
|
-
"ontology_arguments_file_invalid_json",
|
|
15
|
-
"ontology_arguments_file_not_object"
|
|
16
|
-
];
|
|
17
|
-
var OntologyArgumentsError = class extends Error {
|
|
18
|
-
name = "OntologyArgumentsError";
|
|
19
|
-
code;
|
|
20
|
-
constructor(code, detail, options) {
|
|
21
|
-
super(`${code}: ${detail}`, options);
|
|
22
|
-
this.code = code;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
function isObject(value) {
|
|
26
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27
|
-
}
|
|
28
|
-
async function readArgumentsFile(context, path) {
|
|
29
|
-
let content;
|
|
30
|
-
try {
|
|
31
|
-
({content} = await sandboxFile(context, path, { maximumBytes: MAXIMUM_ARGUMENTS_FILE_BYTES }));
|
|
32
|
-
} catch (cause) {
|
|
33
|
-
if (cause instanceof SandboxUnavailableError) throw new OntologyArgumentsError("ontology_arguments_file_unavailable", cause.message, { cause });
|
|
34
|
-
if (cause instanceof SandboxFileTooLarge) throw new OntologyArgumentsError("ontology_arguments_file_too_large", `${path} is larger than ${MAXIMUM_ARGUMENTS_FILE_BYTES} bytes.`, { cause });
|
|
35
|
-
if (cause instanceof SandboxFileRefused) throw new OntologyArgumentsError("ontology_arguments_file_unreadable", cause.message, { cause });
|
|
36
|
-
throw cause;
|
|
37
|
-
}
|
|
38
|
-
let value;
|
|
39
|
-
try {
|
|
40
|
-
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content));
|
|
41
|
-
} catch (cause) {
|
|
42
|
-
throw new OntologyArgumentsError("ontology_arguments_file_invalid_json", `${path} is not a UTF-8 JSON document.`, { cause });
|
|
43
|
-
}
|
|
44
|
-
if (!isObject(value)) throw new OntologyArgumentsError("ontology_arguments_file_not_object", `${path} holds JSON ${value === null ? "null" : Array.isArray(value) ? "array" : typeof value}, not an object.`);
|
|
45
|
-
return value;
|
|
46
|
-
}
|
|
47
|
-
async function ontologyCallArguments(input, context, options) {
|
|
48
|
-
if (input.arguments_file === void 0) return input.arguments ?? {};
|
|
49
|
-
if (input.arguments !== void 0) throw new OntologyArgumentsError("ontology_arguments_ambiguous", "give arguments or arguments_file, not both.");
|
|
50
|
-
if (!options.sandbox) throw new OntologyArgumentsError("ontology_arguments_file_unavailable", "arguments_file needs the sandbox, which agent/segmentstream.json turns on with \"sandbox\": true.");
|
|
51
|
-
if (typeof input.arguments_file !== "string") throw new OntologyArgumentsError("ontology_arguments_file_unreadable", "arguments_file must be the absolute path of a file inside /workspace.");
|
|
52
|
-
return readArgumentsFile(context, input.arguments_file);
|
|
53
|
-
}
|
|
54
|
-
export { MAXIMUM_ARGUMENTS_FILE_BYTES, ONTOLOGY_ARGUMENTS_ERROR_CODES, OntologyArgumentsError, ontologyCallArguments };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ToolContext } from "eve/tools";
|
|
2
|
-
import { ontologyTools } from "./ontology-tools.js";
|
|
3
|
-
type Options = Omit<NonNullable<Parameters<typeof ontologyTools>[0]>, "principal">;
|
|
4
|
-
/** Metadata is requested only when the model uses it, never while registering its tools. */
|
|
5
|
-
export declare function ontologyMetadata(memberId: string, operation: "describe" | "discover", input: Record<string, unknown>, context: ToolContext, options?: Options): Promise<Record<string, unknown>>;
|
|
6
|
-
/** Ordinary record operations are not part of entity/action discovery. Inspect their
|
|
7
|
-
* real member-filtered MCP schemas on demand, never during dynamic registration. */
|
|
8
|
-
export declare function ontologyInspect(memberId: string, input: {
|
|
9
|
-
name?: string;
|
|
10
|
-
query?: string;
|
|
11
|
-
after?: string;
|
|
12
|
-
limit?: number;
|
|
13
|
-
}, context: ToolContext, options?: Options): Promise<{
|
|
14
|
-
next_after?: string | undefined;
|
|
15
|
-
tools: (Record<string, unknown> & {
|
|
16
|
-
name: string;
|
|
17
|
-
description: string;
|
|
18
|
-
})[];
|
|
19
|
-
}>;
|
|
20
|
-
export {};
|
|
@@ -1,52 +0,0 @@
|
|
|
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 { i as memberIdOf, u as runtimeEnvelope } from "../../_chunks/principal-Dmm-cXNF.mjs";
|
|
8
|
-
import { object } from "./confirmation-description.mjs";
|
|
9
|
-
import { readOntologyMetadata } from "./ontology-metadata-read.mjs";
|
|
10
|
-
async function ontologyMetadata(memberId, operation, input, context, options = {}) {
|
|
11
|
-
const principal = context.session.auth.current;
|
|
12
|
-
if (memberIdOf(principal) !== memberId) throw new Error("The ontology tool belongs to another member.");
|
|
13
|
-
const result = await readOntologyMetadata(memberId, {
|
|
14
|
-
method: "tools/call",
|
|
15
|
-
params: {
|
|
16
|
-
name: operation,
|
|
17
|
-
arguments: input
|
|
18
|
-
}
|
|
19
|
-
}, context, {
|
|
20
|
-
...options,
|
|
21
|
-
envelope: runtimeEnvelope({
|
|
22
|
-
principal,
|
|
23
|
-
sessionId: context.session.id,
|
|
24
|
-
callId: context.callId
|
|
25
|
-
})
|
|
26
|
-
});
|
|
27
|
-
return result.structuredContent === void 0 ? result : object(result.structuredContent);
|
|
28
|
-
}
|
|
29
|
-
async function ontologyInspect(memberId, input, context, options = {}) {
|
|
30
|
-
const principal = context.session.auth.current;
|
|
31
|
-
if (memberIdOf(principal) !== memberId) throw new Error("The ontology tool belongs to another member.");
|
|
32
|
-
const listing = await readOntologyMetadata(memberId, {
|
|
33
|
-
method: "tools/list",
|
|
34
|
-
params: {}
|
|
35
|
-
}, context, options);
|
|
36
|
-
const tools = (Array.isArray(listing.tools) ? listing.tools.map(object) : []).flatMap((tool) => typeof tool.name === "string" ? [{
|
|
37
|
-
...tool,
|
|
38
|
-
name: tool.name,
|
|
39
|
-
description: String(tool.description ?? "")
|
|
40
|
-
}] : []);
|
|
41
|
-
const words = input.query?.toLowerCase().split(/\s+/u).filter(Boolean) ?? [];
|
|
42
|
-
const matched = tools.filter((tool) => input.name !== void 0 ? tool.name === input.name : words.every((word) => `${tool.name} ${tool.description}`.toLowerCase().includes(word))).sort((a, b) => a.name.localeCompare(b.name));
|
|
43
|
-
if (input.name !== void 0 && matched.length === 0) throw new Error("The requested operation is not available to the current member.");
|
|
44
|
-
const remaining = matched.filter((tool) => input.after === void 0 || tool.name.localeCompare(input.after) > 0);
|
|
45
|
-
const limit = Math.min(50, Math.max(1, input.limit ?? 20));
|
|
46
|
-
const page = remaining.slice(0, limit);
|
|
47
|
-
return {
|
|
48
|
-
tools: page,
|
|
49
|
-
...remaining.length > limit ? { next_after: page.at(-1).name } : {}
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
export { ontologyInspect, ontologyMetadata };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ToolContext } from "eve/tools";
|
|
2
|
-
import { ontologyTools } from "./ontology-tools.js";
|
|
3
|
-
type Options = Omit<NonNullable<Parameters<typeof ontologyTools>[0]>, "principal">;
|
|
4
|
-
/** Only metadata reads enter this boundary. Never cache permission/prepare checks or retry actions. */
|
|
5
|
-
export declare function readOntologyMetadata(memberId: string, request: {
|
|
6
|
-
method: "tools/list";
|
|
7
|
-
params: Record<string, never>;
|
|
8
|
-
} | {
|
|
9
|
-
method: "tools/call";
|
|
10
|
-
params: {
|
|
11
|
-
name: "discover" | "describe";
|
|
12
|
-
arguments: Record<string, unknown>;
|
|
13
|
-
};
|
|
14
|
-
}, context: ToolContext, options?: Options): Promise<Record<string, unknown>>;
|
|
15
|
-
export {};
|
|
@@ -1,136 +0,0 @@
|
|
|
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 { appOrigin } from "./environment.mjs";
|
|
8
|
-
import { i as memberIdOf } from "../../_chunks/principal-Dmm-cXNF.mjs";
|
|
9
|
-
import { redactDiagnostic } from "./diagnostics.mjs";
|
|
10
|
-
import { object } from "./confirmation-description.mjs";
|
|
11
|
-
import { OntologyToolRejected, ontologyTools } from "./ontology-tools.mjs";
|
|
12
|
-
import { randomUUID } from "node:crypto";
|
|
13
|
-
import { isDeepStrictEqual } from "node:util";
|
|
14
|
-
const scopes = new Map();
|
|
15
|
-
const cache = new Map();
|
|
16
|
-
let cachedBytes = 0;
|
|
17
|
-
const CACHE_BYTES = 8388608;
|
|
18
|
-
const CACHE_TTL = 3e4;
|
|
19
|
-
const RUNTIME_SOURCE_TTL = 3e5;
|
|
20
|
-
const METADATA_TIMEOUT = 1e4;
|
|
21
|
-
function remove(key) {
|
|
22
|
-
cachedBytes -= cache.get(key)?.bytes ?? 0;
|
|
23
|
-
cache.delete(key);
|
|
24
|
-
}
|
|
25
|
-
function retryable(error, depth = 0) {
|
|
26
|
-
if (depth > 8) return false;
|
|
27
|
-
const value = object(error);
|
|
28
|
-
if (object(value.structuredContent).error === "internal_error") return true;
|
|
29
|
-
if (typeof value.status === "number") return value.status === 429 || value.status >= 500;
|
|
30
|
-
if ([
|
|
31
|
-
"TypeError",
|
|
32
|
-
"TimeoutError",
|
|
33
|
-
"AbortError"
|
|
34
|
-
].includes(String(value.name))) return true;
|
|
35
|
-
return value.cause !== void 0 && retryable(value.cause, depth + 1);
|
|
36
|
-
}
|
|
37
|
-
function invalidatesSnapshot(error, depth = 0) {
|
|
38
|
-
if (depth > 8) return false;
|
|
39
|
-
const value = object(error);
|
|
40
|
-
return value.status === 401 || value.status === 403 || [
|
|
41
|
-
"ontology_version_mismatch",
|
|
42
|
-
"forbidden",
|
|
43
|
-
"unauthorized",
|
|
44
|
-
"not_invited"
|
|
45
|
-
].includes(String(object(value.structuredContent).error)) || value.cause !== void 0 && invalidatesSnapshot(value.cause, depth + 1);
|
|
46
|
-
}
|
|
47
|
-
async function readOntologyMetadata(memberId, request, context, options = {}) {
|
|
48
|
-
const principal = context.session.auth.current;
|
|
49
|
-
if (memberIdOf(principal) !== memberId) throw new Error("The ontology tool belongs to another member.");
|
|
50
|
-
const session = context.session.id;
|
|
51
|
-
const args = request.method === "tools/call" ? request.params.arguments : {};
|
|
52
|
-
const scope = principal && typeof session === "string" && session !== "" ? JSON.stringify([
|
|
53
|
-
appOrigin(options.environment ?? process.env),
|
|
54
|
-
session,
|
|
55
|
-
memberId
|
|
56
|
-
]) : void 0;
|
|
57
|
-
let state = scope === void 0 ? void 0 : scopes.get(scope);
|
|
58
|
-
if (scope !== void 0 && principal) {
|
|
59
|
-
if (!state || !isDeepStrictEqual(state.principal, principal)) state = {
|
|
60
|
-
principal: structuredClone(principal),
|
|
61
|
-
generation: 0,
|
|
62
|
-
runtimeSources: new Map(),
|
|
63
|
-
runtimeSourcesUntil: 0
|
|
64
|
-
};
|
|
65
|
-
if (state.runtimeSourcesUntil <= Date.now()) {
|
|
66
|
-
state.runtimeSources.clear();
|
|
67
|
-
state.runtimeSourcesUntil = Date.now() + RUNTIME_SOURCE_TTL;
|
|
68
|
-
}
|
|
69
|
-
scopes.delete(scope);
|
|
70
|
-
scopes.set(scope, state);
|
|
71
|
-
while (scopes.size > 128) scopes.delete(scopes.keys().next().value);
|
|
72
|
-
}
|
|
73
|
-
const generation = state?.generation;
|
|
74
|
-
const key = state && args.expected_hash === void 0 ? JSON.stringify([scope, request]) : void 0;
|
|
75
|
-
const existing = key === void 0 ? void 0 : cache.get(key);
|
|
76
|
-
if (existing && existing.state === state && existing.generation === generation && existing.until > Date.now()) {
|
|
77
|
-
cache.delete(key);
|
|
78
|
-
cache.set(key, existing);
|
|
79
|
-
return structuredClone(existing.value);
|
|
80
|
-
}
|
|
81
|
-
if (key !== void 0) remove(key);
|
|
82
|
-
const client = ontologyTools({
|
|
83
|
-
...options,
|
|
84
|
-
principal,
|
|
85
|
-
...state ? { runtimeSources: state.runtimeSources } : {}
|
|
86
|
-
});
|
|
87
|
-
let attempts = 0;
|
|
88
|
-
for (;;) {
|
|
89
|
-
attempts++;
|
|
90
|
-
try {
|
|
91
|
-
const result = await client.rpc(memberId, request.method, request.params, AbortSignal.timeout(METADATA_TIMEOUT));
|
|
92
|
-
if (key !== void 0 && scope !== void 0 && state && scopes.get(scope) === state && state.generation === generation) {
|
|
93
|
-
const bytes = Buffer.byteLength(JSON.stringify(result));
|
|
94
|
-
if (bytes <= 2097152) {
|
|
95
|
-
while (cache.size && (cache.size >= 128 || cachedBytes + bytes > CACHE_BYTES)) remove(cache.keys().next().value);
|
|
96
|
-
remove(key);
|
|
97
|
-
cache.set(key, {
|
|
98
|
-
state,
|
|
99
|
-
generation: state.generation,
|
|
100
|
-
value: structuredClone(result),
|
|
101
|
-
until: Date.now() + CACHE_TTL,
|
|
102
|
-
bytes
|
|
103
|
-
});
|
|
104
|
-
cachedBytes += bytes;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return result;
|
|
108
|
-
} catch (cause) {
|
|
109
|
-
if (state && invalidatesSnapshot(cause)) {
|
|
110
|
-
state.generation++;
|
|
111
|
-
state.runtimeSources.clear();
|
|
112
|
-
for (const [cachedKey, entry] of cache) if (entry.state === state) remove(cachedKey);
|
|
113
|
-
}
|
|
114
|
-
const mayRetry = retryable(cause);
|
|
115
|
-
if (mayRetry && args.expected_hash === void 0 && attempts < 3) {
|
|
116
|
-
await new Promise((resolve) => setTimeout(resolve, attempts * 100));
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
const reference = randomUUID();
|
|
120
|
-
const publicReason = cause instanceof OntologyToolRejected ? `;${cause.message.slice(0, 4096)}` : "";
|
|
121
|
-
const error = Object.assign(new Error(`ontology_metadata_unavailable:${reference};retryable=${mayRetry}${publicReason}`, { cause }), {
|
|
122
|
-
code: "ontology_metadata_unavailable",
|
|
123
|
-
retryable: mayRetry,
|
|
124
|
-
reference,
|
|
125
|
-
attempts
|
|
126
|
-
});
|
|
127
|
-
console.error("[segmentstream] ontology_metadata_unavailable", {
|
|
128
|
-
reference,
|
|
129
|
-
attempts,
|
|
130
|
-
error: redactDiagnostic(error, new Set())
|
|
131
|
-
});
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
export { readOntologyMetadata };
|