@segmentstream/agent 0.5.4 → 0.6.3
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 +56 -18
- package/dist/extension/connections/ontology.mjs +2 -2
- package/dist/extension/instructions.md +10 -9
- package/dist/extension/lib/attachment-tools.mjs +1 -3
- package/dist/extension/lib/chat-post-confirmation.d.ts +23 -0
- package/dist/extension/lib/chat-post-confirmation.mjs +61 -0
- package/dist/extension/lib/confirmation-description.d.ts +2 -0
- package/dist/extension/lib/confirmations.d.ts +5 -0
- package/dist/extension/lib/confirmations.mjs +25 -5
- package/dist/extension/lib/conversations.d.ts +12 -1
- package/dist/extension/lib/conversations.mjs +4 -3
- package/dist/extension/lib/ontology-connection.d.ts +4 -0
- package/dist/extension/lib/ontology-connection.mjs +46 -3
- package/dist/extension/lib/ontology-tools.d.ts +1 -0
- package/dist/extension/lib/ontology-tools.mjs +27 -2
- package/dist/extension/lib/telegram/adapter.d.ts +1 -1
- package/dist/extension/lib/telegram/adapter.mjs +15 -26
- package/dist/extension/lib/telegram/chat-post-card.d.ts +15 -0
- package/dist/extension/lib/telegram/chat-post-card.mjs +65 -0
- package/dist/extension/lib/telegram/confirmations.d.ts +3 -2
- package/dist/extension/lib/telegram/confirmations.mjs +140 -21
- package/dist/extension/lib/telegram/customer-text.mjs +2 -1
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/inbound-request.d.ts +1 -1
- package/dist/extension/lib/telegram/runtime-request.d.ts +8 -0
- package/dist/extension/lib/telegram/runtime-request.mjs +36 -0
- package/package.json +1 -1
- package/dist/extension/lib/telegram/requests.d.ts +0 -80
- package/dist/extension/lib/telegram/requests.mjs +0 -186
|
@@ -1,186 +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 { TELEGRAM_AUTHENTICATOR } from "./principal.mjs";
|
|
8
|
-
import { formatAddress, scopedAddress } from "./sessions.mjs";
|
|
9
|
-
import { POST } from "eve/channels";
|
|
10
|
-
const MESSAGES_ROUTE = "/eve/v1/telegram/messages";
|
|
11
|
-
const MAX_REQUEST_MESSAGE_LENGTH = 4e3;
|
|
12
|
-
const CHAT_ID = /^-?\d{1,20}$/;
|
|
13
|
-
function isRecord(value) {
|
|
14
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
-
}
|
|
16
|
-
function isText(value) {
|
|
17
|
-
return typeof value === "string" && value.trim() !== "";
|
|
18
|
-
}
|
|
19
|
-
function user(value) {
|
|
20
|
-
return isRecord(value) && isText(value.id) && isText(value.name) ? {
|
|
21
|
-
id: value.id,
|
|
22
|
-
name: value.name
|
|
23
|
-
} : void 0;
|
|
24
|
-
}
|
|
25
|
-
function roles(value) {
|
|
26
|
-
if (value === void 0) return [];
|
|
27
|
-
return Array.isArray(value) && value.every((role) => typeof role === "string") ? value : void 0;
|
|
28
|
-
}
|
|
29
|
-
function agentRequest(value) {
|
|
30
|
-
if (!isRecord(value)) return;
|
|
31
|
-
const { target, message, requester } = value;
|
|
32
|
-
const person = value.person === null ? null : user(value.person);
|
|
33
|
-
const from = user(requester);
|
|
34
|
-
const held = isRecord(requester) ? roles(requester.roles) : void 0;
|
|
35
|
-
const actAs = isRecord(requester) ? requester.actAs : void 0;
|
|
36
|
-
const documentIds = value.documentIds;
|
|
37
|
-
if (!isRecord(target) || target.kind !== "group" && target.kind !== "private" || target.provider !== "telegram" || typeof target.chatId !== "string" || !CHAT_ID.test(target.chatId) || !isText(message) || message.length > MAX_REQUEST_MESSAGE_LENGTH || person === void 0 || from === void 0 || !isRecord(requester) || requester.kind !== "member" && requester.kind !== "service" || held === void 0 || actAs !== void 0 && typeof actAs !== "boolean" || documentIds !== void 0 && (!Array.isArray(documentIds) || documentIds.length > 10 || !documentIds.every((id) => typeof id === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)))) return;
|
|
38
|
-
return {
|
|
39
|
-
target: {
|
|
40
|
-
kind: target.kind,
|
|
41
|
-
provider: "telegram",
|
|
42
|
-
chatId: target.chatId
|
|
43
|
-
},
|
|
44
|
-
message,
|
|
45
|
-
...documentIds === void 0 ? {} : { documentIds },
|
|
46
|
-
person,
|
|
47
|
-
requester: {
|
|
48
|
-
...from,
|
|
49
|
-
kind: requester.kind,
|
|
50
|
-
roles: held,
|
|
51
|
-
actAs: actAs ?? requester.kind === "member"
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function requestPrincipal(request) {
|
|
56
|
-
const { requester, target } = request;
|
|
57
|
-
if (requester.kind === "member" && requester.actAs) return {
|
|
58
|
-
authenticator: TELEGRAM_AUTHENTICATOR,
|
|
59
|
-
issuer: "segmentstream",
|
|
60
|
-
principalId: `segmentstream:${requester.id}`,
|
|
61
|
-
principalType: "user",
|
|
62
|
-
subject: requester.id,
|
|
63
|
-
attributes: {
|
|
64
|
-
memberId: requester.id,
|
|
65
|
-
memberName: requester.name,
|
|
66
|
-
roles: requester.roles,
|
|
67
|
-
chatId: target.chatId,
|
|
68
|
-
chatType: target.kind
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
return {
|
|
72
|
-
authenticator: TELEGRAM_AUTHENTICATOR,
|
|
73
|
-
issuer: "segmentstream",
|
|
74
|
-
principalId: `segmentstream:${requester.kind}:${requester.id}`,
|
|
75
|
-
principalType: requester.kind === "member" ? "user" : "service",
|
|
76
|
-
subject: requester.id,
|
|
77
|
-
attributes: {
|
|
78
|
-
requesterId: requester.id,
|
|
79
|
-
requesterKind: requester.kind,
|
|
80
|
-
requesterName: requester.name,
|
|
81
|
-
roles: requester.roles,
|
|
82
|
-
chatId: target.chatId,
|
|
83
|
-
chatType: target.kind
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
function requestContext(request) {
|
|
88
|
-
const { requester, person } = request;
|
|
89
|
-
const to = person === null ? "" : ` to ${person.name} (user_id ${person.id})`;
|
|
90
|
-
const lines = [
|
|
91
|
-
"<agent_request>",
|
|
92
|
-
`A request from ${requester.name} (${requester.kind}, user_id ${requester.id}) arrived through the ontology action agent_chat.send_message; the message is the request.`,
|
|
93
|
-
"This turn already runs in the target chat. Your reply here is the message delivered to this chat. Do not look for or call agent_chat.send_message to deliver it, even if the ontology catalog is empty or that action is unavailable.",
|
|
94
|
-
`Write in this chat${to}, carry out the clear request, ask only for missing or ambiguous information, and handle the replies here.`,
|
|
95
|
-
"If the addressed person has a linked Telegram username, mention them with @username; otherwise address them by name without a tag. Never invent a username."
|
|
96
|
-
];
|
|
97
|
-
if (request.documentIds !== void 0 && request.documentIds.length > 0) lines.push(`documentIds: ${JSON.stringify(request.documentIds)}`, "Send these documents with the question using segmentstream__attachments_send in this chat. Use the question as the caption (at most 1024 characters), one question per message. In groups send documents only when the chat's purpose allows; never send restricted documents there.");
|
|
98
|
-
if (requester.kind === "service" || !requester.actAs) {
|
|
99
|
-
lines.push(`${requester.kind === "service" ? "The requester is a service, not a member" : "The requester has not paired a Telegram account with the agent"}, so this turn runs without a member and the ontology is not available in it. Each member who replies acts with their own permissions.`);
|
|
100
|
-
if (requester.kind === "member" && request.target.kind === "group") lines.push("Temporary attachments in this group are available through segmentstream__attachments_* when the requester is a current chat participant or chat administrator. Promotion still requires the requester's permission for the target ontology action.");
|
|
101
|
-
}
|
|
102
|
-
lines.push("</agent_request>");
|
|
103
|
-
return lines.join("\n");
|
|
104
|
-
}
|
|
105
|
-
function withContext(source, context) {
|
|
106
|
-
return {
|
|
107
|
-
...source,
|
|
108
|
-
send(message, options) {
|
|
109
|
-
return source.send(message, {
|
|
110
|
-
...options,
|
|
111
|
-
context: [...options.context ?? [], context]
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
function bearer(header) {
|
|
117
|
-
return (header === null ? null : /^Bearer\s+(\S+)$/i.exec(header.trim()))?.[1];
|
|
118
|
-
}
|
|
119
|
-
function error(code, status) {
|
|
120
|
-
return Response.json({ error: code }, { status });
|
|
121
|
-
}
|
|
122
|
-
async function runtimeRequestFailure(request, options) {
|
|
123
|
-
const log = options.log ?? ((message, detail) => console.warn(message, detail));
|
|
124
|
-
if (!options.enabled()) return error("channels_disabled", 503);
|
|
125
|
-
if (!options.configured()) return error("not_found", 404);
|
|
126
|
-
const token = bearer(request.headers.get("authorization"));
|
|
127
|
-
if (token === void 0) return error("unauthorized", 401);
|
|
128
|
-
let verifier;
|
|
129
|
-
try {
|
|
130
|
-
verifier = options.verify();
|
|
131
|
-
} catch (cause) {
|
|
132
|
-
log("The agent cannot verify requests: the runtime identity is not configured.", cause);
|
|
133
|
-
return error("unavailable", 503);
|
|
134
|
-
}
|
|
135
|
-
const verification = await verifier(token);
|
|
136
|
-
if (verification.status === "unavailable") {
|
|
137
|
-
log("The agent cannot verify requests: the runtime key set is unavailable.", verification.reason);
|
|
138
|
-
return error("unavailable", 503);
|
|
139
|
-
}
|
|
140
|
-
if (verification.status !== "valid") {
|
|
141
|
-
log("The agent refused a request with an invalid runtime token.", verification.reason);
|
|
142
|
-
return error("unauthorized", 401);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
function messagesRoute(input) {
|
|
146
|
-
return POST(MESSAGES_ROUTE, async (request, args) => {
|
|
147
|
-
const failure = await runtimeRequestFailure(request, input);
|
|
148
|
-
if (failure !== void 0) return failure;
|
|
149
|
-
let body;
|
|
150
|
-
try {
|
|
151
|
-
body = await request.json();
|
|
152
|
-
} catch {
|
|
153
|
-
return error("invalid_body", 400);
|
|
154
|
-
}
|
|
155
|
-
const parsed = agentRequest(body);
|
|
156
|
-
const receive = input.channel.receive;
|
|
157
|
-
if (parsed === void 0) return error("invalid_body", 400);
|
|
158
|
-
if (receive === void 0) throw new Error("eve's Telegram channel has no receive hook.");
|
|
159
|
-
const chatAddress = scopedAddress(formatAddress({
|
|
160
|
-
chatId: parsed.target.chatId,
|
|
161
|
-
messageThreadId: "",
|
|
162
|
-
conversationId: ""
|
|
163
|
-
}), input.scope());
|
|
164
|
-
await input.sessionPolicy.apply({
|
|
165
|
-
address: chatAddress,
|
|
166
|
-
operations: {
|
|
167
|
-
resolveSession: args.resolveSession,
|
|
168
|
-
from: args.from
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
const session = await receive({
|
|
172
|
-
target: { chatId: parsed.target.chatId },
|
|
173
|
-
message: parsed.message,
|
|
174
|
-
auth: requestPrincipal(parsed)
|
|
175
|
-
}, {
|
|
176
|
-
from: (address) => withContext(args.from(address), requestContext(parsed)),
|
|
177
|
-
resolveSession: args.resolveSession
|
|
178
|
-
});
|
|
179
|
-
input.sessionPolicy.delivered(chatAddress);
|
|
180
|
-
return Response.json({
|
|
181
|
-
delivered: true,
|
|
182
|
-
sessionId: session.id
|
|
183
|
-
}, { status: 202 });
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
export { MESSAGES_ROUTE, agentRequest, messagesRoute, requestContext, requestPrincipal, runtimeRequestFailure };
|