@segmentstream/agent 0.13.0 → 0.14.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 +1 -1
- package/dist/_chunks/{build-metadata-BLeBanNg.mjs → build-metadata-BB2uSGsI.mjs} +1 -1
- package/dist/_chunks/principal-VFQWqe5S.mjs +126 -0
- package/dist/extension/config.d.ts +5 -0
- package/dist/extension/config.mjs +30 -1
- package/dist/extension/hooks/authorization.mjs +2 -2
- package/dist/extension/lib/attachment-tools.mjs +1 -1
- package/dist/extension/lib/attachments.d.ts +2 -0
- package/dist/extension/lib/attachments.mjs +1 -0
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/confirmations.mjs +1 -1
- package/dist/extension/lib/conversation-runtime.mjs +1 -1
- package/dist/extension/lib/deferred-confirmations.d.ts +2 -0
- package/dist/extension/lib/deferred-confirmations.mjs +21 -10
- package/dist/extension/lib/ontology-connection.d.ts +1 -0
- package/dist/extension/lib/ontology-connection.mjs +18 -12
- package/dist/extension/lib/ontology-gateway.mjs +9 -2
- package/dist/extension/lib/ontology-metadata-read.mjs +1 -1
- package/dist/extension/lib/ontology-tools.d.ts +9 -2
- package/dist/extension/lib/ontology-tools.mjs +28 -4
- package/dist/extension/lib/runtime-envelope.d.ts +28 -0
- package/dist/extension/lib/runtime-envelope.mjs +8 -0
- package/dist/extension/lib/stored-files.mjs +1 -1
- package/dist/extension/lib/telegram/adapter.mjs +21 -6
- package/dist/extension/lib/telegram/attachments-send.mjs +2 -2
- package/dist/extension/lib/telegram/callbacks.d.ts +18 -0
- package/dist/extension/lib/telegram/callbacks.mjs +155 -0
- package/dist/extension/lib/telegram/confirmation-expiry.mjs +2 -2
- package/dist/extension/lib/telegram/confirmations.mjs +4 -4
- package/dist/extension/lib/telegram/conversations.mjs +1 -1
- package/dist/extension/lib/telegram/deferred-confirmations.mjs +4 -4
- package/dist/extension/lib/telegram/files.mjs +1 -1
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/inbound.mjs +8 -4
- package/dist/extension/lib/telegram/lifecycle.mjs +14 -2
- package/dist/extension/lib/telegram/principal.d.ts +1 -0
- package/dist/extension/lib/telegram/principal.mjs +1 -49
- package/dist/extension/lib/telegram/sessions.d.ts +3 -1
- package/dist/extension/lib/telegram/silent.mjs +2 -2
- package/dist/extension/lib/telegram/turn-errors.mjs +1 -1
- package/dist/extension/lib/telegram/workspace-action.d.ts +21 -0
- package/dist/extension/lib/telegram/workspace-action.mjs +23 -0
- package/dist/extension/model.mjs +1 -1
- package/dist/extension/tools/attachments_promote.mjs +6 -0
- package/dist/extension/tools/ontology.mjs +1 -1
- package/dist/extension/tools/questions_ask.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -549,7 +549,7 @@ Eve resolution, so member/topic routing survives a cold start. No second provide
|
|
|
549
549
|
|
|
550
550
|
## Release and migration
|
|
551
551
|
|
|
552
|
-
The coordinated release uses Agent SDK 0.
|
|
552
|
+
The coordinated release uses Agent SDK 0.14.0, Eve 0.76.3, Ontology SDK 0.50.0 and App SDK 0.24.1.
|
|
553
553
|
The compatible Cloud archive/API must be deployed first; migrations run only through its CI/CD gate.
|
|
554
554
|
Publish the ontology SDK before the agent SDK. Upgrade the workspace ontology before its agent,
|
|
555
555
|
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.
|
|
7
|
+
var version = "0.14.0";
|
|
8
8
|
function agentBuild(environment = process.env) {
|
|
9
9
|
return {
|
|
10
10
|
agent: version,
|
|
@@ -0,0 +1,126 @@
|
|
|
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 { n as currentInboundRequest } from "./inbound-request-BXhiIph-.mjs";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
function telegramRuntimeSource(message, files, callbackQueryId) {
|
|
10
|
+
const attachments = [];
|
|
11
|
+
for (const file of message.attachments) {
|
|
12
|
+
const staged = files?.get(file.fileId);
|
|
13
|
+
if (staged?.status !== "stored" || attachments.length >= 10) continue;
|
|
14
|
+
let kind = file.kind;
|
|
15
|
+
for (const candidate of [
|
|
16
|
+
"voice",
|
|
17
|
+
"audio",
|
|
18
|
+
"video",
|
|
19
|
+
"video_note",
|
|
20
|
+
"sticker",
|
|
21
|
+
"animation"
|
|
22
|
+
]) {
|
|
23
|
+
const raw = message.raw[candidate];
|
|
24
|
+
if (raw !== null && typeof raw === "object" && !Array.isArray(raw) && raw.file_id === file.fileId) kind = candidate;
|
|
25
|
+
}
|
|
26
|
+
attachments.push({
|
|
27
|
+
file_id: file.fileId,
|
|
28
|
+
kind,
|
|
29
|
+
staged_id: staged.attachment.id,
|
|
30
|
+
...file.fileUniqueId === void 0 ? {} : { file_unique_id: file.fileUniqueId },
|
|
31
|
+
media_type: staged.attachment.contentType
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
provider: "telegram",
|
|
36
|
+
chat_id: message.chat.id,
|
|
37
|
+
thread_id: String(message.messageThreadId ?? ""),
|
|
38
|
+
message_id: message.messageId,
|
|
39
|
+
...message.replyToMessage === void 0 ? {} : { reply_to_message_id: message.replyToMessage.messageId },
|
|
40
|
+
...message.from === void 0 ? {} : { sender: message.from.id },
|
|
41
|
+
...callbackQueryId === void 0 ? {} : { callback_query_id: callbackQueryId },
|
|
42
|
+
...attachments.length === 0 ? {} : { attachments }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function principalRuntimeSource(principal) {
|
|
46
|
+
if (principal?.authenticator !== "segmentstream-telegram") return;
|
|
47
|
+
const value = principal.attributes.segmentstreamRuntimeSource;
|
|
48
|
+
if (typeof value !== "string") return;
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(value);
|
|
51
|
+
} catch {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function runtimeEnvelope(input = {}) {
|
|
56
|
+
const source = input.source ?? principalRuntimeSource(input.principal);
|
|
57
|
+
return {
|
|
58
|
+
version: 1,
|
|
59
|
+
session_id: input.sessionId ?? randomUUID(),
|
|
60
|
+
call_id: input.callId ?? randomUUID(),
|
|
61
|
+
...source === void 0 ? {} : { source }
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function compatibleRuntimeEnvelope(envelope, extended) {
|
|
65
|
+
const source = envelope.source;
|
|
66
|
+
return extended || source === void 0 ? envelope : {
|
|
67
|
+
...envelope,
|
|
68
|
+
source: {
|
|
69
|
+
provider: source.provider,
|
|
70
|
+
chat_id: source.chat_id,
|
|
71
|
+
thread_id: source.thread_id
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const RUNTIME_SOURCE_PROTOCOL = "segmentstream/runtime-source";
|
|
76
|
+
const TELEGRAM_AUTHENTICATOR = "segmentstream-telegram";
|
|
77
|
+
function isGroup(message) {
|
|
78
|
+
return message.chat.type === "group" || message.chat.type === "supergroup";
|
|
79
|
+
}
|
|
80
|
+
function telegramPrincipal(input) {
|
|
81
|
+
const { message, member } = input;
|
|
82
|
+
const sender = message.from.id;
|
|
83
|
+
const attributes = {
|
|
84
|
+
memberId: member.id,
|
|
85
|
+
segmentstreamRuntimeSource: JSON.stringify(telegramRuntimeSource(message, currentInboundRequest()?.files, input.callbackQueryId)),
|
|
86
|
+
identityProvider: "telegram",
|
|
87
|
+
roles: member.roles,
|
|
88
|
+
chatId: message.chat.id,
|
|
89
|
+
chatType: message.chat.type
|
|
90
|
+
};
|
|
91
|
+
if (member.name !== null) attributes.memberName = member.name;
|
|
92
|
+
if (message.messageThreadId !== void 0) attributes.messageThreadId = String(message.messageThreadId);
|
|
93
|
+
if (message.from.username !== void 0) attributes.username = message.from.username;
|
|
94
|
+
const locale = member.locale ?? message.from.languageCode;
|
|
95
|
+
if (locale !== void 0) attributes.locale = locale;
|
|
96
|
+
const language = input.conversationLanguage ?? conversationLanguage([message.text || message.caption]);
|
|
97
|
+
if (language !== void 0) attributes.conversationLanguage = language;
|
|
98
|
+
return {
|
|
99
|
+
authenticator: TELEGRAM_AUTHENTICATOR,
|
|
100
|
+
issuer: "telegram",
|
|
101
|
+
principalId: isGroup(message) ? `telegram:${message.chat.id}:${sender}` : `telegram:${sender}`,
|
|
102
|
+
principalType: "user",
|
|
103
|
+
subject: sender,
|
|
104
|
+
attributes
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function conversationLanguage(texts) {
|
|
108
|
+
for (const text of texts) {
|
|
109
|
+
if (/[\u0430-\u044f\u0451]/iu.test(text)) return "ru";
|
|
110
|
+
if ((text.match(/\b[a-z]+\b/gi)?.length ?? 0) >= 3) return "en";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function memberIdOf(principal) {
|
|
114
|
+
const memberId = principal?.attributes.memberId;
|
|
115
|
+
return typeof memberId === "string" && memberId !== "" ? memberId : void 0;
|
|
116
|
+
}
|
|
117
|
+
function rolesOf(principal) {
|
|
118
|
+
const roles = principal?.attributes.roles;
|
|
119
|
+
if (typeof roles === "string") return [roles];
|
|
120
|
+
return roles ?? [];
|
|
121
|
+
}
|
|
122
|
+
function identityProviderOf(principal) {
|
|
123
|
+
const provider = principal?.attributes.identityProvider;
|
|
124
|
+
return typeof provider === "string" && provider !== "" ? provider : void 0;
|
|
125
|
+
}
|
|
126
|
+
export { rolesOf as a, compatibleRuntimeEnvelope as c, telegramRuntimeSource as d, memberIdOf as i, principalRuntimeSource as l, conversationLanguage as n, telegramPrincipal as o, identityProviderOf as r, RUNTIME_SOURCE_PROTOCOL as s, TELEGRAM_AUTHENTICATOR as t, runtimeEnvelope as u };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GroupPolicyInput } from "@segmentstream-cloud/ontology/groups";
|
|
2
2
|
import { type GroupPolicy } from "./lib/group-routing/policy.js";
|
|
3
|
+
import type { WorkspaceActionHook } from "./lib/telegram/workspace-action.js";
|
|
3
4
|
import { type TelegramTexts } from "./lib/telegram/texts.js";
|
|
4
5
|
import type { AttachmentLifecycle } from "./lib/telegram/lifecycle.js";
|
|
5
6
|
import { type TelegramLinkPreviews } from "@segmentstream-cloud/ontology/telegram";
|
|
@@ -75,6 +76,9 @@ export interface SegmentStreamAgentConfigInput {
|
|
|
75
76
|
readonly linkPreviews?: string;
|
|
76
77
|
/** Additional exact HTTP(S) origins belonging to this workspace. */
|
|
77
78
|
readonly additionalOwnOrigins?: readonly string[];
|
|
79
|
+
readonly callbacks?: Omit<WorkspaceActionHook, "contextVersion"> & {
|
|
80
|
+
readonly contextVersion: number;
|
|
81
|
+
};
|
|
78
82
|
readonly menuButton?: {
|
|
79
83
|
readonly text: LocalizedText;
|
|
80
84
|
};
|
|
@@ -134,6 +138,7 @@ export interface TelegramSettings {
|
|
|
134
138
|
readonly topicScope?: boolean;
|
|
135
139
|
readonly commandsAddress?: boolean;
|
|
136
140
|
};
|
|
141
|
+
readonly callbacks?: WorkspaceActionHook;
|
|
137
142
|
readonly connection: string;
|
|
138
143
|
readonly policy: TelegramPolicy;
|
|
139
144
|
readonly linkPreviews?: TelegramLinkPreviews;
|
|
@@ -79,7 +79,8 @@ function telegramSettings(value, issues) {
|
|
|
79
79
|
"linkPreviews",
|
|
80
80
|
"additionalOwnOrigins",
|
|
81
81
|
"attachmentLifecycle",
|
|
82
|
-
"menuButton"
|
|
82
|
+
"menuButton",
|
|
83
|
+
"callbacks"
|
|
83
84
|
],
|
|
84
85
|
issues
|
|
85
86
|
});
|
|
@@ -122,6 +123,7 @@ function telegramSettings(value, issues) {
|
|
|
122
123
|
message: "must be an array of HTTP(S) origins without paths, credentials, queries or fragments",
|
|
123
124
|
path: [...path, "additionalOwnOrigins"]
|
|
124
125
|
});
|
|
126
|
+
const callbacks = workspaceHook(telegram.callbacks, [...path, "callbacks"], issues);
|
|
125
127
|
const menuButton = section({
|
|
126
128
|
value: telegram.menuButton,
|
|
127
129
|
path: [...path, "menuButton"],
|
|
@@ -159,6 +161,7 @@ function telegramSettings(value, issues) {
|
|
|
159
161
|
connection,
|
|
160
162
|
policy,
|
|
161
163
|
...signalSettings === void 0 ? {} : { groups: signalSettings },
|
|
164
|
+
...callbacks === void 0 ? {} : { callbacks },
|
|
162
165
|
linkPreviews,
|
|
163
166
|
additionalOwnOrigins,
|
|
164
167
|
...menuText === void 0 ? {} : { menuButton: { text: menuText } },
|
|
@@ -169,6 +172,32 @@ function telegramSettings(value, issues) {
|
|
|
169
172
|
} }
|
|
170
173
|
} : null;
|
|
171
174
|
}
|
|
175
|
+
function workspaceHook(value, path, issues) {
|
|
176
|
+
const configured = section({
|
|
177
|
+
value,
|
|
178
|
+
path,
|
|
179
|
+
allowed: [
|
|
180
|
+
"entity",
|
|
181
|
+
"action",
|
|
182
|
+
"contextVersion"
|
|
183
|
+
],
|
|
184
|
+
issues
|
|
185
|
+
});
|
|
186
|
+
if (configured === void 0) return;
|
|
187
|
+
for (const key of ["entity", "action"]) if (typeof configured[key] !== "string" || !/^(?:[a-z][a-zA-Z0-9]*|[a-z][a-z0-9]*(?:_[a-z0-9]+)*)$/.test(String(configured[key]))) issues.push({
|
|
188
|
+
message: "must name an ontology entity or action",
|
|
189
|
+
path: [...path, key]
|
|
190
|
+
});
|
|
191
|
+
if (configured.contextVersion !== 2) issues.push({
|
|
192
|
+
message: "must be 2",
|
|
193
|
+
path: [...path, "contextVersion"]
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
entity: String(configured.entity),
|
|
197
|
+
action: String(configured.action),
|
|
198
|
+
contextVersion: 2
|
|
199
|
+
};
|
|
200
|
+
}
|
|
172
201
|
function modelId(input) {
|
|
173
202
|
if (input.value === void 0) return input.fallback;
|
|
174
203
|
if (typeof input.value !== "string" || input.value === "" || input.value !== input.value.trim()) {
|
|
@@ -5,9 +5,9 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { localizedText } from "../lib/admission.mjs";
|
|
8
|
-
import "
|
|
9
|
-
import segmentstream from "../extension.mjs";
|
|
8
|
+
import "../../_chunks/principal-VFQWqe5S.mjs";
|
|
10
9
|
import { confirmationLocale } from "../lib/telegram/confirmation-text.mjs";
|
|
10
|
+
import segmentstream from "../extension.mjs";
|
|
11
11
|
import { defineHook } from "eve/hooks";
|
|
12
12
|
var authorization_default = defineHook({ events: { "authorization.required": (event, context) => {
|
|
13
13
|
const principal = context.session.auth.current;
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { appOrigin } from "./environment.mjs";
|
|
8
|
-
import { memberIdOf } from "
|
|
8
|
+
import { i as memberIdOf } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
9
9
|
import { runtimeToken } from "./runtime-token.mjs";
|
|
10
10
|
import { agentAttachments } from "./attachments.mjs";
|
|
11
11
|
import { telegramConversation } from "./telegram/files.mjs";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RuntimeEnvelope } from "./runtime-envelope.js";
|
|
1
2
|
import type { RuntimeToken } from "./runtime-token.js";
|
|
2
3
|
/**
|
|
3
4
|
* The ontology service's attachment routes (`docs/agent.md`, "Attachments"). A file a member sends
|
|
@@ -35,6 +36,7 @@ export interface Attachment {
|
|
|
35
36
|
readonly promotion: unknown;
|
|
36
37
|
}
|
|
37
38
|
export interface PromotionRequest {
|
|
39
|
+
readonly runtime?: RuntimeEnvelope;
|
|
38
40
|
readonly entity: string;
|
|
39
41
|
readonly action: string;
|
|
40
42
|
readonly input?: Readonly<Record<string, unknown>>;
|
|
@@ -192,6 +192,7 @@ function agentAttachments(input) {
|
|
|
192
192
|
const answer = await call(owner, `/${encodeURIComponent(id)}/promote`, "promotion", {
|
|
193
193
|
entity: request.entity,
|
|
194
194
|
action: request.action,
|
|
195
|
+
...request.runtime === void 0 ? {} : { _meta: { _segmentstream: request.runtime } },
|
|
195
196
|
input: request.input ?? {},
|
|
196
197
|
...request.field === void 0 ? {} : { field: request.field },
|
|
197
198
|
...request.recordId === void 0 ? {} : { record_id: request.recordId }
|
|
@@ -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-BB2uSGsI.mjs";
|
|
8
8
|
export { agentBuild };
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { withTelegramTexts } from "./telegram/texts.mjs";
|
|
8
|
-
import { memberIdOf } from "
|
|
8
|
+
import { i as memberIdOf } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
9
9
|
import { confirmationCopy, confirmationLocale, renderConfirmation } from "./telegram/confirmation-text.mjs";
|
|
10
10
|
import { chatPostCard } from "./telegram/chat-post-card.mjs";
|
|
11
11
|
import { chatPostDigest, isChatPost } from "./chat-post-confirmation.mjs";
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { ENDS_CONVERSATION_INSTRUCTIONS } from "./group-routing/conversation-prompt.mjs";
|
|
8
|
-
import { memberIdOf } from "
|
|
8
|
+
import { i as memberIdOf } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
9
9
|
import { n as contentText, t as CONTENT_CAPS } from "../../_chunks/content-CvFsrmSD.mjs";
|
|
10
10
|
import { conversationEvent, conversations, summarizeArguments } from "./conversations.mjs";
|
|
11
11
|
import { parseAddress } from "./telegram/sessions.mjs";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RuntimeEnvelope } from "./runtime-envelope.js";
|
|
1
2
|
import type { ToolContext } from "eve/tools";
|
|
2
3
|
import { type Confirmation } from "./confirmations.js";
|
|
3
4
|
import { type Environment } from "./environment.js";
|
|
@@ -11,6 +12,7 @@ export interface DeferredConfirmation {
|
|
|
11
12
|
readonly expiresAt: number;
|
|
12
13
|
readonly status: "pending" | "approved" | "cancelled" | "expired" | "done" | "failed";
|
|
13
14
|
readonly data: {
|
|
15
|
+
readonly runtimeSource?: RuntimeEnvelope["source"];
|
|
14
16
|
readonly action: string;
|
|
15
17
|
readonly input: Readonly<Record<string, unknown>>;
|
|
16
18
|
readonly confirmation: Confirmation;
|
|
@@ -5,10 +5,10 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { appOrigin } from "./environment.mjs";
|
|
8
|
-
import { memberIdOf } from "
|
|
9
|
-
import { runtimeToken } from "./runtime-token.mjs";
|
|
8
|
+
import { i as memberIdOf, l as principalRuntimeSource, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
10
9
|
import { redactDiagnostic } from "./diagnostics.mjs";
|
|
11
10
|
import { humanText, object } from "./confirmation-description.mjs";
|
|
11
|
+
import { runtimeToken } from "./runtime-token.mjs";
|
|
12
12
|
import { chatPostDigest, chatPostOperationId, isChatPost } from "./chat-post-confirmation.mjs";
|
|
13
13
|
import { actionApproval, inputHash } from "./confirmations.mjs";
|
|
14
14
|
import { ontologyTools } from "./ontology-tools.mjs";
|
|
@@ -37,7 +37,7 @@ function deferredConfirmations(options = {}) {
|
|
|
37
37
|
}
|
|
38
38
|
async function executeDeferredTool(memberId, action, input, ctx, options = {}) {
|
|
39
39
|
if (memberIdOf(ctx.session.auth.current) !== memberId) throw new Error("The ontology tool belongs to another member.");
|
|
40
|
-
|
|
40
|
+
input = Object.fromEntries(Object.entries(input).filter(([key]) => key !== "_segmentstream"));
|
|
41
41
|
const principal = ctx.session.auth.current;
|
|
42
42
|
const attributes = principal?.attributes;
|
|
43
43
|
const id = chatPostOperationId(ctx.session.id, ctx.callId);
|
|
@@ -56,7 +56,15 @@ async function executeDeferredTool(memberId, action, input, ctx, options = {}) {
|
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
58
|
if (existing !== null) return boundResult(existing);
|
|
59
|
-
const tools = ontologyTools(
|
|
59
|
+
const tools = ontologyTools({
|
|
60
|
+
...options,
|
|
61
|
+
principal: ctx.session.auth.current,
|
|
62
|
+
envelope: runtimeEnvelope({
|
|
63
|
+
principal: ctx.session.auth.current,
|
|
64
|
+
sessionId: ctx.session.id,
|
|
65
|
+
callId: ctx.callId
|
|
66
|
+
})
|
|
67
|
+
});
|
|
60
68
|
let saved = {};
|
|
61
69
|
const result = await actionApproval({
|
|
62
70
|
...tools,
|
|
@@ -96,6 +104,7 @@ async function executeDeferredTool(memberId, action, input, ctx, options = {}) {
|
|
|
96
104
|
data: {
|
|
97
105
|
action,
|
|
98
106
|
input,
|
|
107
|
+
...principalRuntimeSource(principal) === void 0 ? {} : { runtimeSource: principalRuntimeSource(principal) },
|
|
99
108
|
confirmation,
|
|
100
109
|
sessionId: ctx.session.id,
|
|
101
110
|
callId: ctx.callId,
|
|
@@ -125,11 +134,13 @@ async function runDeferredAction(record, options) {
|
|
|
125
134
|
session_id: record.data.sessionId,
|
|
126
135
|
call_id: record.data.callId,
|
|
127
136
|
operation_id: record.id,
|
|
137
|
+
...record.data.runtimeSource === void 0 ? {} : { source: record.data.runtimeSource },
|
|
128
138
|
...preview ? {
|
|
129
139
|
source: {
|
|
130
140
|
provider: "telegram",
|
|
131
141
|
chat_id: record.data.chatId,
|
|
132
|
-
thread_id: record.data.threadId
|
|
142
|
+
thread_id: record.data.threadId,
|
|
143
|
+
...record.data.runtimeSource
|
|
133
144
|
},
|
|
134
145
|
expected: {
|
|
135
146
|
chat_id: preview.chatId,
|
|
@@ -137,12 +148,12 @@ async function runDeferredAction(record, options) {
|
|
|
137
148
|
}
|
|
138
149
|
} : {}
|
|
139
150
|
};
|
|
140
|
-
const result = await
|
|
151
|
+
const result = await ontologyTools({
|
|
152
|
+
...options,
|
|
153
|
+
envelope
|
|
154
|
+
}).rpc(record.memberId, "tools/call", {
|
|
141
155
|
name: record.data.action.split("__").at(-1),
|
|
142
|
-
arguments:
|
|
143
|
-
...record.data.input,
|
|
144
|
-
_segmentstream: envelope
|
|
145
|
-
}
|
|
156
|
+
arguments: record.data.input
|
|
146
157
|
});
|
|
147
158
|
const output = result.structuredContent;
|
|
148
159
|
if (result.isError === true || (output?.validation)?.ok === false || preview !== void 0 && output?.status !== "sent") throw new Error("The confirmed action did not complete; its outcome may be uncertain.", { cause: result });
|
|
@@ -36,6 +36,7 @@ export declare function ontologyConnection(input: {
|
|
|
36
36
|
readonly fetch?: typeof fetch;
|
|
37
37
|
/** Set only by the authenticated catalog handshake, never by model input. */
|
|
38
38
|
readonly chatPosting?: boolean;
|
|
39
|
+
readonly runtimeSource?: boolean;
|
|
39
40
|
}): McpClientConnectionDefinition | null;
|
|
40
41
|
/** Negotiate before opening Eve's client: old strict schemas never receive the new envelope. */
|
|
41
42
|
export declare function ontologyConnectionForTurn(input: Parameters<typeof ontologyConnection>[0]): Promise<McpClientConnectionDefinition | null>;
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { appOrigin } from "./environment.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { c as compatibleRuntimeEnvelope, i as memberIdOf, r as identityProviderOf, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
9
9
|
import { runtimeToken, tokenExpiry } from "./runtime-token.mjs";
|
|
10
10
|
import { CHAT_POST_ENVELOPE, chatPostDigest, chatPostOperationId, isChatPost } from "./chat-post-confirmation.mjs";
|
|
11
11
|
import { actionApproval, confirmations } from "./confirmations.mjs";
|
|
@@ -31,21 +31,23 @@ function ontologyConnection(input) {
|
|
|
31
31
|
if (memberId === void 0) return null;
|
|
32
32
|
const origin = appOrigin(input.environment ?? process.env);
|
|
33
33
|
const token = input.token ?? runtimeToken;
|
|
34
|
+
const chatProtocol = input.chatPosting ? ":chat-post-v1" : "";
|
|
35
|
+
const sourceProtocol = input.runtimeSource ? ":runtime-source-v1" : "";
|
|
34
36
|
return defineMcpClientConnection({
|
|
35
37
|
url: `${origin}/mcp`,
|
|
36
38
|
description: DESCRIPTION,
|
|
37
|
-
instanceKey: `${origin}/mcp#member:${memberId}${
|
|
39
|
+
instanceKey: `${origin}/mcp#member:${memberId}${chatProtocol}${sourceProtocol}`,
|
|
38
40
|
approval: actionApproval(ontologyTools(input)),
|
|
39
|
-
...input.chatPosting ? { toolCall: { providedArguments: { [CHAT_POST_ENVELOPE]: (ctx) => {
|
|
41
|
+
...input.chatPosting || input.runtimeSource ? { toolCall: { providedArguments: { [CHAT_POST_ENVELOPE]: (ctx) => {
|
|
40
42
|
actAsHeaders({
|
|
41
43
|
principal: ctx.session.auth.current,
|
|
42
44
|
expectedMemberId: memberId
|
|
43
45
|
});
|
|
44
|
-
const base = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
46
|
+
const base = compatibleRuntimeEnvelope(runtimeEnvelope({
|
|
47
|
+
principal: ctx.session.auth.current,
|
|
48
|
+
sessionId: ctx.session.id,
|
|
49
|
+
callId: ctx.callId
|
|
50
|
+
}), input.runtimeSource === true);
|
|
49
51
|
if (!isChatPost(ctx.toolName)) return base;
|
|
50
52
|
const saved = confirmations.get()[ctx.callId];
|
|
51
53
|
const preview = saved?.description?.chatPost;
|
|
@@ -56,7 +58,8 @@ function ontologyConnection(input) {
|
|
|
56
58
|
source: {
|
|
57
59
|
provider: "telegram",
|
|
58
60
|
chat_id: saved.source.chatId,
|
|
59
|
-
thread_id: saved.source.threadId
|
|
61
|
+
thread_id: saved.source.threadId,
|
|
62
|
+
...base.source
|
|
60
63
|
},
|
|
61
64
|
expected: {
|
|
62
65
|
chat_id: preview.chatId,
|
|
@@ -84,15 +87,18 @@ function ontologyConnection(input) {
|
|
|
84
87
|
async function ontologyConnectionForTurn(input) {
|
|
85
88
|
const memberId = memberIdOf(input.principal);
|
|
86
89
|
if (memberId === void 0) return null;
|
|
87
|
-
let
|
|
90
|
+
let capabilities = {
|
|
91
|
+
chatPosting: false,
|
|
92
|
+
runtimeSource: false
|
|
93
|
+
};
|
|
88
94
|
try {
|
|
89
|
-
|
|
95
|
+
capabilities = await ontologyTools(input).capabilities(memberId);
|
|
90
96
|
} catch (error) {
|
|
91
97
|
console.warn("Chat posting capability unavailable; keeping the compatible ontology connection.", error);
|
|
92
98
|
}
|
|
93
99
|
return ontologyConnection({
|
|
94
100
|
...input,
|
|
95
|
-
|
|
101
|
+
...capabilities
|
|
96
102
|
});
|
|
97
103
|
}
|
|
98
104
|
export { ACT_AS_HEADER, MemberRequiredError, actAsHeaders, ontologyConnection, ontologyConnectionForTurn };
|
|
@@ -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 { memberIdOf } from "
|
|
7
|
+
import { i as memberIdOf, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
8
8
|
import { object } from "./confirmation-description.mjs";
|
|
9
9
|
import { readOntologyMetadata } from "./ontology-metadata-read.mjs";
|
|
10
10
|
async function ontologyMetadata(memberId, operation, input, context, options = {}) {
|
|
@@ -16,7 +16,14 @@ async function ontologyMetadata(memberId, operation, input, context, options = {
|
|
|
16
16
|
name: operation,
|
|
17
17
|
arguments: input
|
|
18
18
|
}
|
|
19
|
-
}, context,
|
|
19
|
+
}, context, {
|
|
20
|
+
...options,
|
|
21
|
+
envelope: runtimeEnvelope({
|
|
22
|
+
principal,
|
|
23
|
+
sessionId: context.session.id,
|
|
24
|
+
callId: context.callId
|
|
25
|
+
})
|
|
26
|
+
});
|
|
20
27
|
return result.structuredContent === void 0 ? result : object(result.structuredContent);
|
|
21
28
|
}
|
|
22
29
|
async function ontologyInspect(memberId, input, context, options = {}) {
|
|
@@ -5,7 +5,7 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { appOrigin } from "./environment.mjs";
|
|
8
|
-
import { memberIdOf } from "
|
|
8
|
+
import { i as memberIdOf } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
9
9
|
import { redactDiagnostic } from "./diagnostics.mjs";
|
|
10
10
|
import { object } from "./confirmation-description.mjs";
|
|
11
11
|
import { OntologyToolRejected, ontologyTools } from "./ontology-tools.mjs";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RuntimeEnvelope } from "./runtime-envelope.js";
|
|
1
2
|
import type { SessionAuthContext } from "eve/context";
|
|
2
3
|
import type { ActionAnnotations } from "./confirmations.js";
|
|
3
4
|
import { type Environment } from "./environment.js";
|
|
@@ -13,17 +14,23 @@ export declare class OntologyActionNotPermitted extends Error {
|
|
|
13
14
|
/** A fresh, permission-filtered catalog. Listing tools cannot run an action's prepare step. */
|
|
14
15
|
export declare function ontologyTools(options?: {
|
|
15
16
|
readonly principal?: SessionAuthContext | null;
|
|
17
|
+
readonly envelope?: RuntimeEnvelope;
|
|
16
18
|
readonly environment?: Environment;
|
|
17
19
|
readonly token?: RuntimeToken;
|
|
18
20
|
readonly fetch?: typeof fetch;
|
|
19
21
|
}): {
|
|
20
22
|
rpc: (memberId: string, method: string, params: Record<string, unknown>, signal?: AbortSignal) => Promise<Record<string, unknown>>;
|
|
21
23
|
list(memberId: string): Promise<Record<string, unknown>[]>;
|
|
24
|
+
supportsRuntimeSource(memberId: string, signal?: AbortSignal): Promise<boolean>;
|
|
25
|
+
capabilities(memberId: string): Promise<{
|
|
26
|
+
chatPosting: boolean;
|
|
27
|
+
runtimeSource: boolean;
|
|
28
|
+
}>;
|
|
22
29
|
supportsChatPosting(memberId: string): Promise<boolean>;
|
|
23
|
-
labels(memberId: string, action: string, input?: Readonly<Record<string, unknown
|
|
30
|
+
labels(memberId: string, action: string, input?: Readonly<Record<string, unknown>>, signal?: AbortSignal): Promise<ActionAnnotations>;
|
|
24
31
|
describe(memberId: string, action: string, input: Readonly<Record<string, unknown>>): Promise<import("./confirmation-description.js").ConfirmationDescription>;
|
|
25
32
|
};
|
|
26
|
-
export declare function ontologyToolLabels(options?: Parameters<typeof ontologyTools>[0]): (memberId: string, action: string, input?: Readonly<Record<string, unknown
|
|
33
|
+
export declare function ontologyToolLabels(options?: Parameters<typeof ontologyTools>[0]): (memberId: string, action: string, input?: Readonly<Record<string, unknown>>, signal?: AbortSignal) => Promise<ActionAnnotations>;
|
|
27
34
|
/** MCP normalizes an authored camelCase action to snake_case. */
|
|
28
35
|
export declare function actionToolName(entity: string, action: string): string;
|
|
29
36
|
/** One target contract for native and MCP attachment promotion; never trust supplied safety hints. */
|
|
@@ -5,10 +5,10 @@ const __filename = __eveFileURLToPath(import.meta.url);
|
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { appOrigin } from "./environment.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import { runtimeToken } from "./runtime-token.mjs";
|
|
8
|
+
import { c as compatibleRuntimeEnvelope, i as memberIdOf, r as identityProviderOf, s as RUNTIME_SOURCE_PROTOCOL, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
10
9
|
import { redactDiagnostic } from "./diagnostics.mjs";
|
|
11
10
|
import { describeConfirmation, object } from "./confirmation-description.mjs";
|
|
11
|
+
import { runtimeToken } from "./runtime-token.mjs";
|
|
12
12
|
import { describeChatPost, isChatPost, supportsChatPost } from "./chat-post-confirmation.mjs";
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
var OntologyToolRejected = class extends Error {
|
|
@@ -18,7 +18,19 @@ 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
22
|
async function rpc(memberId, method, params, signal) {
|
|
23
|
+
if (method === "tools/call") {
|
|
24
|
+
const envelope = options.envelope ?? runtimeEnvelope({ principal: memberIdOf(options.principal) === memberId ? options.principal : null });
|
|
25
|
+
if (envelope.source !== void 0 && !runtimeSources.has(memberId)) await rpc(memberId, "tools/list", {}, signal);
|
|
26
|
+
params = {
|
|
27
|
+
...params,
|
|
28
|
+
arguments: {
|
|
29
|
+
...object(params.arguments),
|
|
30
|
+
_segmentstream: compatibleRuntimeEnvelope(envelope, runtimeSources.get(memberId) === true)
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
22
34
|
const provider = memberIdOf(options.principal) === memberId ? identityProviderOf(options.principal) : void 0;
|
|
23
35
|
const credential = await (options.token ?? runtimeToken)();
|
|
24
36
|
const secrets = new Set([credential]);
|
|
@@ -46,6 +58,7 @@ function ontologyTools(options = {}) {
|
|
|
46
58
|
const body = object(await response.json());
|
|
47
59
|
if (body.error !== void 0) throw new Error("Ontology metadata unavailable.", { cause: body.error });
|
|
48
60
|
const result = object(body.result);
|
|
61
|
+
if (method === "tools/list" && Array.isArray(result.tools)) runtimeSources.set(memberId, result.tools.map(object).some((tool) => object(tool._meta)[RUNTIME_SOURCE_PROTOCOL] === 1));
|
|
49
62
|
if (result.isError === true) {
|
|
50
63
|
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");
|
|
51
64
|
if ([
|
|
@@ -119,12 +132,23 @@ function ontologyTools(options = {}) {
|
|
|
119
132
|
const result = await rpc(memberId, "tools/list", {});
|
|
120
133
|
return Array.isArray(result.tools) ? result.tools.map(object) : [];
|
|
121
134
|
},
|
|
135
|
+
async supportsRuntimeSource(memberId, signal) {
|
|
136
|
+
if (!runtimeSources.has(memberId)) await rpc(memberId, "tools/list", {}, signal);
|
|
137
|
+
return runtimeSources.get(memberId) === true;
|
|
138
|
+
},
|
|
139
|
+
async capabilities(memberId) {
|
|
140
|
+
const result = await rpc(memberId, "tools/list", {});
|
|
141
|
+
return {
|
|
142
|
+
chatPosting: Array.isArray(result.tools) && result.tools.map(object).some(supportsChatPost),
|
|
143
|
+
runtimeSource: runtimeSources.get(memberId) === true
|
|
144
|
+
};
|
|
145
|
+
},
|
|
122
146
|
async supportsChatPosting(memberId) {
|
|
123
147
|
const result = await rpc(memberId, "tools/list", {});
|
|
124
148
|
return Array.isArray(result.tools) && result.tools.map(object).some(supportsChatPost);
|
|
125
149
|
},
|
|
126
|
-
async labels(memberId, action, input = {}) {
|
|
127
|
-
const { tool } = await resolve(memberId, action, input);
|
|
150
|
+
async labels(memberId, action, input = {}, signal) {
|
|
151
|
+
const { tool } = await resolve(memberId, action, input, signal);
|
|
128
152
|
return {
|
|
129
153
|
...object(tool.annotations),
|
|
130
154
|
confirmation: object(object(tool.inputSchema).properties)._confirmation !== void 0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RuntimeSource } from "@segmentstream-cloud/ontology";
|
|
2
|
+
import type { SessionAuthContext } from "eve/context";
|
|
3
|
+
import type { TelegramMessage } from "eve/channels/telegram";
|
|
4
|
+
import type { StagedFile } from "./telegram/inbound-request.js";
|
|
5
|
+
export type RuntimeEnvelope = {
|
|
6
|
+
readonly version: 1;
|
|
7
|
+
readonly session_id: string;
|
|
8
|
+
readonly call_id: string;
|
|
9
|
+
readonly operation_id?: string;
|
|
10
|
+
readonly source?: RuntimeSource;
|
|
11
|
+
readonly expected?: {
|
|
12
|
+
readonly chat_id: string;
|
|
13
|
+
readonly digest: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/** The source comes from the verified Telegram message and admitted storage results. */
|
|
17
|
+
export declare function telegramRuntimeSource(message: Pick<TelegramMessage, "chat" | "messageId" | "messageThreadId" | "replyToMessage" | "from" | "raw" | "attachments">, files?: ReadonlyMap<string, StagedFile>, callbackQueryId?: string): RuntimeSource;
|
|
18
|
+
/** Session auth is SDK-owned; no tool argument is read while rebuilding provenance. */
|
|
19
|
+
export declare function principalRuntimeSource(principal?: SessionAuthContext | null): RuntimeSource | undefined;
|
|
20
|
+
export declare function runtimeEnvelope(input?: {
|
|
21
|
+
readonly principal?: SessionAuthContext | null;
|
|
22
|
+
readonly sessionId?: string;
|
|
23
|
+
readonly callId?: string;
|
|
24
|
+
readonly source?: RuntimeSource;
|
|
25
|
+
}): RuntimeEnvelope;
|
|
26
|
+
/** Older strict ontology schemas accept only the original chat identity fields. */
|
|
27
|
+
export declare function compatibleRuntimeEnvelope(envelope: RuntimeEnvelope, extended: boolean): RuntimeEnvelope;
|
|
28
|
+
export declare const RUNTIME_SOURCE_PROTOCOL = "segmentstream/runtime-source";
|
|
@@ -0,0 +1,8 @@
|
|
|
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 { c as compatibleRuntimeEnvelope, d as telegramRuntimeSource, l as principalRuntimeSource, s as RUNTIME_SOURCE_PROTOCOL, u as runtimeEnvelope } from "../../_chunks/principal-VFQWqe5S.mjs";
|
|
8
|
+
export { RUNTIME_SOURCE_PROTOCOL, compatibleRuntimeEnvelope, principalRuntimeSource, runtimeEnvelope, telegramRuntimeSource };
|