@segmentstream/agent 0.17.6 → 0.17.8
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/dist/_chunks/{build-metadata-BkfakQLL.mjs → build-metadata-CcDVc9Lu.mjs} +1 -1
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/file-grant.d.ts +3 -0
- package/dist/extension/lib/file-grant.mjs +25 -0
- package/dist/extension/lib/ontology-tools.d.ts +7 -0
- package/dist/extension/lib/ontology-tools.mjs +14 -1
- package/dist/extension/lib/stored-files.mjs +14 -5
- package/dist/extension/lib/telegram/adapter.mjs +1 -1
- package/dist/extension/lib/telegram/attachments-send.d.ts +3 -0
- package/dist/extension/lib/telegram/attachments-send.mjs +22 -6
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/package.json +2 -2
|
@@ -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.8";
|
|
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-CcDVc9Lu.mjs";
|
|
8
8
|
export { agentBuild };
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
const transientFileStatus = (status) => [
|
|
8
|
+
429,
|
|
9
|
+
502,
|
|
10
|
+
503,
|
|
11
|
+
504
|
|
12
|
+
].includes(status);
|
|
13
|
+
async function fetchFileGrant(send) {
|
|
14
|
+
for (let attempt = 0;; attempt++) {
|
|
15
|
+
const response = await send();
|
|
16
|
+
if (!transientFileStatus(response.status) || attempt === 2) return response;
|
|
17
|
+
const retryAfter = response.headers.get("retry-after");
|
|
18
|
+
const seconds = Number(retryAfter);
|
|
19
|
+
const delay = retryAfter === null ? 500 * 2 ** attempt : Number.isFinite(seconds) ? Math.max(0, seconds * 1e3) : Date.parse(retryAfter) - Date.now();
|
|
20
|
+
if (!Number.isFinite(delay) || delay < 0 || delay > 5e3) return response;
|
|
21
|
+
await response.body?.cancel();
|
|
22
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export { fetchFileGrant, transientFileStatus };
|
|
@@ -11,6 +11,13 @@ export declare class OntologyToolRejected extends Error {
|
|
|
11
11
|
export declare class OntologyActionNotPermitted extends Error {
|
|
12
12
|
readonly code = "ontology_action_not_permitted";
|
|
13
13
|
}
|
|
14
|
+
/** A known read-only file request can be repeated; action outcomes keep their existing fence. */
|
|
15
|
+
export declare class OntologyFileUnavailable extends Error {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly requestId: string | undefined;
|
|
18
|
+
readonly retryable = true;
|
|
19
|
+
constructor(code: string, requestId: string | undefined, options?: ErrorOptions);
|
|
20
|
+
}
|
|
14
21
|
/** A fresh, permission-filtered catalog. Listing tools cannot run an action's prepare step. */
|
|
15
22
|
export declare function ontologyTools(options?: {
|
|
16
23
|
readonly principal?: SessionAuthContext | null;
|
|
@@ -17,6 +17,16 @@ var OntologyToolRejected = class extends Error {
|
|
|
17
17
|
var OntologyActionNotPermitted = class extends Error {
|
|
18
18
|
code = "ontology_action_not_permitted";
|
|
19
19
|
};
|
|
20
|
+
var OntologyFileUnavailable = class extends Error {
|
|
21
|
+
code;
|
|
22
|
+
requestId;
|
|
23
|
+
retryable = true;
|
|
24
|
+
constructor(code, requestId, options) {
|
|
25
|
+
super(`${code}${requestId === void 0 ? "" : ` (${requestId})`}`, options);
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.requestId = requestId;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
20
30
|
function ontologyTools(options = {}) {
|
|
21
31
|
const runtimeSources = options.runtimeSources ?? new Map();
|
|
22
32
|
async function rpc(memberId, method, params, signal) {
|
|
@@ -61,6 +71,8 @@ function ontologyTools(options = {}) {
|
|
|
61
71
|
const result = object(body.result);
|
|
62
72
|
if (method === "tools/list" && Array.isArray(result.tools)) runtimeSources.set(memberId, result.tools.map(object).some((tool) => object(tool._meta)[RUNTIME_SOURCE_PROTOCOL] === 1));
|
|
63
73
|
if (result.isError === true) {
|
|
74
|
+
const failure = object(result.structuredContent);
|
|
75
|
+
if (method === "tools/call" && params.name === "files_download" && failure.retryable === true && ["ontology_updating", "storage_unavailable"].includes(String(failure.error))) throw new OntologyFileUnavailable(String(failure.error), typeof failure.request_id === "string" ? failure.request_id : void 0, { cause: result });
|
|
64
76
|
const message = (Array.isArray(result.content) ? result.content : []).map(object).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n");
|
|
65
77
|
if ([
|
|
66
78
|
"action_rejected",
|
|
@@ -87,6 +99,7 @@ function ontologyTools(options = {}) {
|
|
|
87
99
|
reference,
|
|
88
100
|
error: diagnostic
|
|
89
101
|
});
|
|
102
|
+
if (error instanceof OntologyFileUnavailable) throw new OntologyFileUnavailable(error.code, error.requestId, { cause: diagnostic });
|
|
90
103
|
if (error instanceof OntologyToolRejected) throw new OntologyToolRejected(String(object(diagnostic).message), { cause: diagnostic });
|
|
91
104
|
throw new Error(`The ontology request failed (${reference}).`, { cause: diagnostic });
|
|
92
105
|
}
|
|
@@ -246,4 +259,4 @@ function promotionTarget(input) {
|
|
|
246
259
|
}
|
|
247
260
|
};
|
|
248
261
|
}
|
|
249
|
-
export { OntologyActionNotPermitted, OntologyToolRejected, actionToolName, ontologyToolLabels, ontologyTools, promotionTarget };
|
|
262
|
+
export { OntologyActionNotPermitted, OntologyFileUnavailable, OntologyToolRejected, actionToolName, ontologyToolLabels, ontologyTools, promotionTarget };
|
|
@@ -7,18 +7,27 @@ __eveCreateRequire(import.meta.url);
|
|
|
7
7
|
import { i as memberIdOf } from "../../_chunks/principal-B6u41vIf.mjs";
|
|
8
8
|
import { redactDiagnostic } from "./diagnostics.mjs";
|
|
9
9
|
import { object } from "./confirmation-description.mjs";
|
|
10
|
-
import { ontologyTools } from "./ontology-tools.mjs";
|
|
10
|
+
import { OntologyFileUnavailable, ontologyTools } from "./ontology-tools.mjs";
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
12
|
async function readStoredFile(input, principal, options = {}) {
|
|
13
13
|
const memberId = memberIdOf(principal);
|
|
14
14
|
if (memberId === void 0) throw new Error("A current member is required to read a stored file.");
|
|
15
|
-
const
|
|
15
|
+
const tools = ontologyTools({
|
|
16
16
|
...options,
|
|
17
17
|
principal
|
|
18
|
-
}).rpc(memberId, "tools/call", {
|
|
19
|
-
name: "files_download",
|
|
20
|
-
arguments: input
|
|
21
18
|
});
|
|
19
|
+
const readGrant = async () => {
|
|
20
|
+
for (let attempt = 0;; attempt++) try {
|
|
21
|
+
return await tools.rpc(memberId, "tools/call", {
|
|
22
|
+
name: "files_download",
|
|
23
|
+
arguments: input
|
|
24
|
+
});
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (!(error instanceof OntologyFileUnavailable) || attempt === 2) throw error;
|
|
27
|
+
await new Promise((resolve) => setTimeout(resolve, error.code === "ontology_updating" ? 5e3 : 500 * 2 ** attempt));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const raw = await readGrant();
|
|
22
31
|
const result = object(raw.structuredContent), file = object(result.file), grant = object(result.download);
|
|
23
32
|
const headers = object(grant.headers);
|
|
24
33
|
const size = file.size;
|
|
@@ -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-CcDVc9Lu.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";
|
|
@@ -20,6 +20,9 @@ export interface SentFile {
|
|
|
20
20
|
readonly error?: string;
|
|
21
21
|
readonly detail?: string;
|
|
22
22
|
readonly reference?: string;
|
|
23
|
+
readonly status?: number;
|
|
24
|
+
readonly retryable?: boolean;
|
|
25
|
+
readonly requestId?: string;
|
|
23
26
|
}
|
|
24
27
|
/** Bare ids are document records; explicit references select other entities and file properties. */
|
|
25
28
|
export declare function sendAttachmentsInput(value: Record<string, unknown>): SendAttachmentsInput;
|
|
@@ -16,6 +16,7 @@ import { ACT_AS_HEADER } from "../ontology-connection.mjs";
|
|
|
16
16
|
import { AttachmentError, CONVERSATION_HEADER, SESSION_HEADER } from "../attachments.mjs";
|
|
17
17
|
import { TELEGRAM_PLACEHOLDER_TOKEN, TELEGRAM_PROXY_ORIGIN, telegramProxyFetch } from "./proxy-fetch.mjs";
|
|
18
18
|
import { attachmentOwner } from "../attachment-tools.mjs";
|
|
19
|
+
import { fetchFileGrant, transientFileStatus } from "../file-grant.mjs";
|
|
19
20
|
const MAXIMUM_PHOTO_BYTES = 10485760;
|
|
20
21
|
const MAXIMUM_DOCUMENT_BYTES = 52428800;
|
|
21
22
|
const PHOTOS = new Set([
|
|
@@ -133,12 +134,14 @@ async function sendAttachmentsInOrder(options) {
|
|
|
133
134
|
const uploads = [];
|
|
134
135
|
for (const [index, reference] of options.input.documentIds.entries()) {
|
|
135
136
|
let filename = "";
|
|
137
|
+
let requestId;
|
|
136
138
|
try {
|
|
137
|
-
const
|
|
139
|
+
const path = [
|
|
138
140
|
reference.entity,
|
|
139
141
|
reference.id,
|
|
140
142
|
...reference.property === void 0 ? [] : [reference.property]
|
|
141
|
-
].map(encodeURIComponent).join("/")
|
|
143
|
+
].map(encodeURIComponent).join("/");
|
|
144
|
+
const response = await fetchFileGrant(async () => fetchImpl(`${origin}/api/ontology/agent/files/${path}`, {
|
|
142
145
|
headers: {
|
|
143
146
|
authorization: `Bearer ${await token()}`,
|
|
144
147
|
[ACT_AS_HEADER]: owner.memberId,
|
|
@@ -147,10 +150,18 @@ async function sendAttachmentsInOrder(options) {
|
|
|
147
150
|
},
|
|
148
151
|
redirect: "error",
|
|
149
152
|
signal: AbortSignal.timeout(3e4)
|
|
150
|
-
});
|
|
153
|
+
}));
|
|
151
154
|
if (!response.ok) {
|
|
152
|
-
const
|
|
153
|
-
|
|
155
|
+
const body = await response.json().catch(() => void 0);
|
|
156
|
+
const upstream = isRecord(body) ? body : {};
|
|
157
|
+
const ref = upstream.request_id ?? upstream.requestId;
|
|
158
|
+
requestId = typeof ref === "string" ? ref : void 0;
|
|
159
|
+
const code = response.status === 404 ? "not_found" : response.status === 403 ? "forbidden" : response.status === 422 ? "unsupported" : response.status === 503 && upstream.error === "ontology_updating" ? "ontology_updating" : transientFileStatus(response.status) ? "retryable" : "unavailable";
|
|
160
|
+
throw new AttachmentError({
|
|
161
|
+
code,
|
|
162
|
+
message: code,
|
|
163
|
+
status: response.status
|
|
164
|
+
});
|
|
154
165
|
}
|
|
155
166
|
const answer = await response.json();
|
|
156
167
|
const file = isRecord(answer) ? answer.file : void 0;
|
|
@@ -191,7 +202,12 @@ async function sendAttachmentsInOrder(options) {
|
|
|
191
202
|
filename,
|
|
192
203
|
error: error instanceof AttachmentError ? error.code : "unavailable",
|
|
193
204
|
detail: failureText(errorId, "attachment", locale),
|
|
194
|
-
reference: errorId
|
|
205
|
+
reference: errorId,
|
|
206
|
+
...error instanceof AttachmentError && error.status !== void 0 ? {
|
|
207
|
+
status: error.status,
|
|
208
|
+
retryable: transientFileStatus(error.status)
|
|
209
|
+
} : {},
|
|
210
|
+
...requestId === void 0 ? {} : { requestId }
|
|
195
211
|
};
|
|
196
212
|
}
|
|
197
213
|
}
|
|
@@ -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-CcDVc9Lu.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-DxRm5LC8.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-CcDVc9Lu.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.8",
|
|
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.54.
|
|
69
|
+
"@segmentstream-cloud/ontology": "0.54.4",
|
|
70
70
|
"@vercel/oidc": "^3.8.4",
|
|
71
71
|
"ai": "^7.0.128",
|
|
72
72
|
"csv-parse": "^7.0.3",
|