@segmentstream/agent 0.12.1 → 0.13.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 +29 -22
- package/dist/_chunks/{build-metadata-Dl-ZJp5p.mjs → build-metadata-BLeBanNg.mjs} +1 -1
- package/dist/_chunks/{inbound-request-BrWspFw5.mjs → inbound-request-BXhiIph-.mjs} +21 -19
- package/dist/_chunks/{workflow-serializable-BxrXgxjc.mjs → workflow-serializable-DVQBWK8p.mjs} +87 -4
- package/dist/extension/_manifest.json +0 -1
- package/dist/extension/config.d.ts +18 -5
- package/dist/extension/config.mjs +138 -18
- package/dist/extension/extension.d.ts +7 -1
- package/dist/extension/hooks/authorization.d.ts +3 -0
- package/dist/extension/hooks/authorization.mjs +16 -0
- package/dist/extension/instructions.md +3 -4
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/chat-post-confirmation.d.ts +1 -0
- package/dist/extension/lib/chat-post-confirmation.mjs +4 -2
- package/dist/extension/lib/confirmation-outcome.d.ts +1 -1
- package/dist/extension/lib/confirmations.d.ts +2 -0
- package/dist/extension/lib/confirmations.mjs +7 -4
- package/dist/extension/lib/conversations.mjs +1 -1
- package/dist/extension/lib/deferred-confirmations.d.ts +3 -0
- package/dist/extension/lib/deferred-confirmations.mjs +2 -0
- package/dist/extension/lib/ontology-tools.mjs +1 -1
- package/dist/extension/lib/telegram/adapter.mjs +34 -7
- package/dist/extension/lib/telegram/attachment-description.mjs +1 -1
- package/dist/extension/lib/telegram/attachments-send.mjs +13 -10
- package/dist/extension/lib/telegram/chat-post-card.d.ts +1 -1
- package/dist/extension/lib/telegram/chat-post-card.mjs +13 -10
- package/dist/extension/lib/telegram/confirmation-expiry.d.ts +2 -1
- package/dist/extension/lib/telegram/confirmation-expiry.mjs +5 -4
- package/dist/extension/lib/telegram/confirmation-text.d.ts +1 -1
- package/dist/extension/lib/telegram/confirmation-text.mjs +18 -12
- package/dist/extension/lib/telegram/confirmations.mjs +24 -19
- package/dist/extension/lib/telegram/conversations.d.ts +2 -0
- package/dist/extension/lib/telegram/conversations.mjs +14 -1
- package/dist/extension/lib/telegram/customer-text.d.ts +9 -8
- package/dist/extension/lib/telegram/customer-text.mjs +1 -1
- package/dist/extension/lib/telegram/deferred-confirmations.mjs +10 -9
- package/dist/extension/lib/telegram/files.mjs +1 -1
- package/dist/extension/lib/telegram/health.mjs +1 -1
- package/dist/extension/lib/telegram/images.mjs +1 -1
- package/dist/extension/lib/telegram/inbound-request.mjs +1 -1
- package/dist/extension/lib/telegram/inbound.mjs +18 -17
- package/dist/extension/lib/telegram/lifecycle.mjs +2 -2
- package/dist/extension/lib/telegram/media-policy.mjs +1 -1
- package/dist/extension/lib/telegram/silent.mjs +1 -1
- package/dist/extension/lib/telegram/texts.d.ts +16 -0
- package/dist/extension/lib/telegram/texts.mjs +70 -0
- package/dist/extension/lib/telegram/turn-errors.d.ts +1 -1
- package/dist/extension/lib/telegram/turn-errors.mjs +37 -3
- package/dist/extension/lib/telegram/voice.mjs +1 -1
- package/dist/extension/lib/workflow-serializable.mjs +1 -1
- package/dist/extension/schedules/confirmations.mjs +1 -1
- package/dist/extension/tools/attachments_discard.mjs +1 -1
- package/dist/extension/tools/attachments_list.mjs +1 -1
- package/dist/extension/tools/attachments_promote.mjs +3 -1
- package/dist/extension/tools/attachments_read.mjs +1 -1
- package/dist/extension/tools/attachments_send.mjs +1 -1
- package/dist/extension/tools/attachments_table.mjs +1 -1
- package/dist/extension/tools/ontology.mjs +1 -1
- package/dist/extension/tools/questions_ask.mjs +1 -1
- package/package.json +2 -2
- package/dist/extension/connections/ontology.d.ts +0 -7
- package/dist/extension/connections/ontology.mjs +0 -11
package/README.md
CHANGED
|
@@ -189,13 +189,13 @@ continue using GET lookup. Starter templates and pins remain unchanged in this s
|
|
|
189
189
|
|
|
190
190
|
## What the extension contributes
|
|
191
191
|
|
|
192
|
-
| Name
|
|
193
|
-
|
|
|
194
|
-
| `
|
|
195
|
-
| `segmentstream__telegram`
|
|
196
|
-
| `segmentstream__attachments_list`, `_read`, `_promote`, `_discard`
|
|
197
|
-
| `segmentstream__attachments_send`
|
|
198
|
-
| platform rules
|
|
192
|
+
| Name | Slot | What it does |
|
|
193
|
+
| -------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
194
|
+
| `segmentstream__ontology_describe`, `_discover`, `_inspect`, `_call` | `tools` | Permission-filtered metadata, schema inspection and action calls as the current member. |
|
|
195
|
+
| `segmentstream__telegram` | `channels` | `POST /eve/v1/telegram`: Telegram through the connection, with pairing, routing and voice. |
|
|
196
|
+
| `segmentstream__attachments_list`, `_read`, `_promote`, `_discard` | `tools` | The member's temporary attachments in this chat: list, read, keep through an action, drop. |
|
|
197
|
+
| `segmentstream__attachments_send` | `tools` | Sends readable stored ontology files into the current Telegram chat and topic. |
|
|
198
|
+
| platform rules | `instructions` | Changes go through actions; `describe` indexes or inspects refs; `discover` searches metadata; tools are already narrowed; when to answer `[SILENT]`; how to handle attachments |
|
|
199
199
|
|
|
200
200
|
### The ontology
|
|
201
201
|
|
|
@@ -222,15 +222,17 @@ share a group chat's session never share a client.
|
|
|
222
222
|
proxy. The token stays in SegmentStream.
|
|
223
223
|
- **Webhook.** A webhook is accepted only with `X-Telegram-Bot-Api-Secret-Token` equal to
|
|
224
224
|
`SEGMENTSTREAM_AGENT_WEBHOOK_SECRET`, compared in constant time. The platform generates the
|
|
225
|
-
secret and registers the webhook after each production deployment
|
|
226
|
-
|
|
225
|
+
secret and registers the webhook after each production deployment. A workspace-supplied
|
|
226
|
+
`menuButton.text` enables the app menu button; omitting it resets the provider menu to its default
|
|
227
|
+
for Agent SDK 0.13 or later. Pre-0.13 archives without menu copy retain their existing provider menu.
|
|
227
228
|
- **Production only.** Outside `VERCEL_ENV=production` the route answers 200 and does nothing, so a
|
|
228
229
|
preview never answers a real chat. Without `channels.telegram` it answers 404.
|
|
229
230
|
- **Pairing.** Bots and channel posts are archived without starting turns. The sender's Telegram
|
|
230
231
|
account is checked on every message, so revocation takes effect immediately. Unlinked group
|
|
231
232
|
speech and attachment metadata remain raw context, including edits; no unlinked voice is decoded or gets
|
|
232
|
-
a reply. An unknown private sender gets
|
|
233
|
-
valid for ten minutes; revoked or inactive private senders
|
|
233
|
+
a reply. An unknown private sender gets the workspace pairing prompt and button to `/agent/connect?code=…`,
|
|
234
|
+
valid for ten minutes; revoked or inactive private senders receive configured refusal copy,
|
|
235
|
+
or no message when it is absent.
|
|
234
236
|
- **Who the agent is.** A paired sender's turn runs with the principal id `telegram:<user>`
|
|
235
237
|
(`telegram:<chat>:<user>` in groups) and the attributes `memberId`, `memberName`, `roles`,
|
|
236
238
|
`chatId`, `chatType` and `username`.
|
|
@@ -516,7 +518,7 @@ ontology SDK along with this extension. See the repository's
|
|
|
516
518
|
[conversation storage guide](../../docs/agent-conversation-storage.md) for APIs, retention,
|
|
517
519
|
eve's existing storage, and Telegram's delivery limits.
|
|
518
520
|
|
|
519
|
-
### Exact chat posting protocol
|
|
521
|
+
### Exact chat posting protocol
|
|
520
522
|
|
|
521
523
|
An authenticated `tools/list` advertises `_meta: { "segmentstream/chat-post": 1 }` on
|
|
522
524
|
`chat_post_message`. Without this marker,
|
|
@@ -525,12 +527,12 @@ missing/incomplete preview metadata is denied. The versioned connection has its
|
|
|
525
527
|
|
|
526
528
|
The runtime reads `me` for the server-derived `attribution`, and `chat_list({ chat })` for exactly
|
|
527
529
|
one eligible destination: `{ items: [{ id, title, provider, external_id }], next_cursor: null }`.
|
|
528
|
-
Provider is currently `telegram`. The final plain text is
|
|
530
|
+
Provider is currently `telegram`. The final plain text is `text + separator + attribution`, with a blank line as the neutral separator;
|
|
529
531
|
`reply_to` is optional. A preview digest is SHA-256 of the JSON array of chat ID, provider,
|
|
530
532
|
external ID, title, attribution, text, final text and nullable reply target, in that order.
|
|
531
533
|
The target/attribution are resolved again immediately before executing the frozen call.
|
|
532
534
|
|
|
533
|
-
|
|
535
|
+
The SDK constructs model-hidden `_segmentstream` metadata for approved runtime posts.
|
|
534
536
|
It contains `version: 1`, `session_id` and `call_id`. A consumed, unexpired chat approval additionally
|
|
535
537
|
supplies `operation_id`, source provider/chat/topic coordinates and `expected: { chat_id, digest }`.
|
|
536
538
|
The operation ID is `hq:` plus SHA-256 of the JSON array `[session_id, call_id]`; it stays stable
|
|
@@ -538,7 +540,8 @@ on replay and changes for a revision. The model cannot provide an idempotency ke
|
|
|
538
540
|
The ontology must authenticate runtime provenance, consume/remove the envelope before strict input
|
|
539
541
|
validation for ordinary tools, derive the posting key from the operation, and recompute attribution.
|
|
540
542
|
External OAuth/service callers still supply their own `idempotency_key` and cannot use this envelope.
|
|
541
|
-
|
|
543
|
+
The coordinated ontology SDK implements this protocol; deploy the compatible ontology before
|
|
544
|
+
using agent exact posting.
|
|
542
545
|
|
|
543
546
|
Source previews, accepted decisions and receipts use existing archive events with operation-linked
|
|
544
547
|
`toolCallId`/event IDs. A cancelled Edit carries its pending revision question in the authoritative
|
|
@@ -546,10 +549,12 @@ Eve resolution, so member/topic routing survives a cold start. No second provide
|
|
|
546
549
|
|
|
547
550
|
## Release and migration
|
|
548
551
|
|
|
549
|
-
The
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
552
|
+
The coordinated release uses Agent SDK 0.13.0, Eve 0.76.3, Ontology SDK 0.49.0 and App SDK 0.24.1.
|
|
553
|
+
The compatible Cloud archive/API must be deployed first; migrations run only through its CI/CD gate.
|
|
554
|
+
Publish the ontology SDK before the agent SDK. Upgrade the workspace ontology before its agent,
|
|
555
|
+
with the declared Telegram provider mapping and explicit `agent_chat:post_message` grant.
|
|
556
|
+
Supply the required workspace presentation before upgrading the agent to 0.13.x.
|
|
557
|
+
Older ontologies keep ordinary tools working without the extra envelope.
|
|
553
558
|
An older archive returning only `{stored:true}` cannot authorize a send.
|
|
554
559
|
|
|
555
560
|
Rollback
|
|
@@ -615,7 +620,7 @@ can redeliver the same source; the hook and attachment reservation must preserve
|
|
|
615
620
|
idempotent source membership, storage results and the single acknowledgement.
|
|
616
621
|
Such a failure must not become an HTTP success with no queued work.
|
|
617
622
|
|
|
618
|
-
###
|
|
623
|
+
### Deferred approvals and legacy recovery
|
|
619
624
|
|
|
620
625
|
Deferred mode supplies four eager tools: `segmentstream__ontology_discover`,
|
|
621
626
|
`segmentstream__ontology_describe`, `segmentstream__ontology_inspect` and `segmentstream__ontology_call`. Registration
|
|
@@ -636,11 +641,13 @@ actionable explanation. Reply delivery carries the owning turn's reply anchor
|
|
|
636
641
|
explicitly after restore. Omitting the version preserves existing closed lifecycle
|
|
637
642
|
data schemas; workspaces opt in only after their hook accepts the additional fields.
|
|
638
643
|
|
|
639
|
-
|
|
640
|
-
|
|
644
|
+
`confirmations.mode: "held"` is rejected. Already-running held turns still need recovery.
|
|
645
|
+
The Telegram adapter reads the owning session's
|
|
641
646
|
recorded approval inputs and requests cancellation of that exact turn before admitting a new
|
|
642
647
|
addressed message. It never approves the old call or reuses the old member's authorization.
|
|
643
648
|
Cancellation failure requests webhook replay; terminal/resolved approvals are left alone.
|
|
644
649
|
Deferred mode retains its ten-minute database deadline and minute expiry sweep. Runtime health
|
|
645
650
|
reports the effective confirmation mode and attachment-lifecycle presence behind its existing
|
|
646
651
|
runtime authentication; source pins and public health alone are not settings-adoption proof.
|
|
652
|
+
|
|
653
|
+
Telegram 0.13.0 requires workspace-authored pairing and confirmation text. See [workspace Telegram text](../../docs/agent.md#workspace-telegram-text) for keys, limits, neutral fallbacks and unsupported Eve buttons.
|
|
@@ -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.13.0";
|
|
8
8
|
function agentBuild(environment = process.env) {
|
|
9
9
|
return {
|
|
10
10
|
agent: version,
|
|
@@ -4,15 +4,16 @@ 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 { telegramText } from "../extension/lib/telegram/texts.mjs";
|
|
7
8
|
import { isTechnicalText } from "../extension/lib/customer-text-safety.mjs";
|
|
8
9
|
import { redactDiagnostic } from "../extension/lib/diagnostics.mjs";
|
|
9
10
|
import { isConfirmationText } from "../extension/lib/telegram/confirmation-text.mjs";
|
|
10
11
|
import { chatPostCardLinks, isExactChatPostCard } from "../extension/lib/telegram/chat-post-card.mjs";
|
|
11
12
|
import { plainTelegramText, splitTelegramText, telegramMarkdown } from "../extension/lib/telegram/format.mjs";
|
|
12
13
|
import { inTelegramSendQueue } from "../extension/lib/telegram/send-queue.mjs";
|
|
13
|
-
import { telegramPreviewOptions, telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
14
14
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
15
15
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
16
|
+
import { telegramPreviewOptions, telegramTextLinks } from "@segmentstream-cloud/ontology/telegram";
|
|
16
17
|
const deliveryLocale = new AsyncLocalStorage();
|
|
17
18
|
function withDeliveryLocale(locale, run, threadId, replyTo, chatId) {
|
|
18
19
|
return deliveryLocale.run({
|
|
@@ -28,15 +29,16 @@ function currentLocale() {
|
|
|
28
29
|
function currentThreadId() {
|
|
29
30
|
return deliveryLocale.getStore()?.threadId ?? currentInboundRequest()?.threadId;
|
|
30
31
|
}
|
|
31
|
-
function customerCopy() {
|
|
32
|
+
function customerCopy(locale = currentLocale()) {
|
|
32
33
|
return {
|
|
33
|
-
failed: "
|
|
34
|
-
recovery: "
|
|
35
|
-
attachment: "
|
|
36
|
-
authorization: "
|
|
37
|
-
response: "
|
|
38
|
-
connected: "
|
|
39
|
-
disconnected: "
|
|
34
|
+
failed: telegramText("notice", "failed", locale),
|
|
35
|
+
recovery: telegramText("notice", "recovery", locale),
|
|
36
|
+
attachment: telegramText("notice", "attachment", locale),
|
|
37
|
+
authorization: telegramText("notice", "authorization", locale),
|
|
38
|
+
response: telegramText("notice", "response", locale),
|
|
39
|
+
connected: telegramText("notice", "connected", locale),
|
|
40
|
+
disconnected: telegramText("notice", "disconnected", locale),
|
|
41
|
+
cancelled: telegramText("notice", "cancelled", locale)
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
function redactCredentials(value) {
|
|
@@ -46,7 +48,7 @@ function redactCredentials(value) {
|
|
|
46
48
|
return value;
|
|
47
49
|
}
|
|
48
50
|
function reportTelegramError(operation, error, metadata = {}, secrets = new Set()) {
|
|
49
|
-
const errorId = randomBytes(4).toString("hex")
|
|
51
|
+
const errorId = randomBytes(4).toString("hex");
|
|
50
52
|
const credentials = new Set([...secrets, ...[process.env.AI_GATEWAY_API_KEY, process.env.VERCEL_OIDC_TOKEN].filter((value) => value !== void 0)]);
|
|
51
53
|
console.error("[segmentstream] Telegram delivery diagnostic", {
|
|
52
54
|
...metadata,
|
|
@@ -57,8 +59,8 @@ function reportTelegramError(operation, error, metadata = {}, secrets = new Set(
|
|
|
57
59
|
return errorId;
|
|
58
60
|
}
|
|
59
61
|
function failureText(errorId, kind = "failed", _locale = currentLocale()) {
|
|
60
|
-
|
|
61
|
-
return `${
|
|
62
|
+
const text = customerCopy(_locale)[kind];
|
|
63
|
+
return text === void 0 ? errorId : `${text} ${errorId}`;
|
|
62
64
|
}
|
|
63
65
|
function customerText(text, locale = currentLocale()) {
|
|
64
66
|
if (!isTechnicalText(text)) return text;
|
|
@@ -118,6 +120,7 @@ function safeTelegramFetch(fetchImpl, scope = "telegram", previews = {}) {
|
|
|
118
120
|
"sendMessage",
|
|
119
121
|
"editMessageText",
|
|
120
122
|
"editMessageCaption",
|
|
123
|
+
"editMessageReplyMarkup",
|
|
121
124
|
"answerCallbackQuery",
|
|
122
125
|
"sendPhoto",
|
|
123
126
|
"sendDocument",
|
|
@@ -160,14 +163,13 @@ function safeTelegramFetch(fetchImpl, scope = "telegram", previews = {}) {
|
|
|
160
163
|
const markup = body.reply_markup;
|
|
161
164
|
if (Array.isArray(markup?.inline_keyboard)) {
|
|
162
165
|
if ((textBlocked || typeof body.text === "string" && body.text.length > 4096) && markup.inline_keyboard.some((row) => row.some((button) => typeof button.callback_data === "string" && button.callback_data.startsWith("ss-confirm:")))) throw new Error("Approval buttons require the complete, safe confirmation text.");
|
|
163
|
-
|
|
164
|
-
if (typeof button.text !== "string" || !isTechnicalText(button.text)) return
|
|
166
|
+
const rows = markup.inline_keyboard.map((row) => row.filter((button) => {
|
|
167
|
+
if (typeof button.text !== "string" || !isTechnicalText(button.text)) return true;
|
|
165
168
|
reportTelegramError("technical_button_label_blocked", { text: button.text });
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}));
|
|
169
|
+
return false;
|
|
170
|
+
})).filter((row) => row.length > 0);
|
|
171
|
+
if (rows.length === 0 && markup.inline_keyboard.length > 0) delete body.reply_markup;
|
|
172
|
+
else markup.inline_keyboard = rows;
|
|
171
173
|
}
|
|
172
174
|
const send = async () => {
|
|
173
175
|
const parts = url.endsWith("/sendMessage") && typeof body.text === "string" && !isExactChatPostCard(body.text) ? splitTelegramText({
|
package/dist/_chunks/{workflow-serializable-BxrXgxjc.mjs → workflow-serializable-DVQBWK8p.mjs}
RENAMED
|
@@ -12,9 +12,26 @@ function makeRedactor(values = []) {
|
|
|
12
12
|
return (input) => {
|
|
13
13
|
let text = input;
|
|
14
14
|
for (const value of secrets) text = text.replaceAll(value, "[REDACTED]");
|
|
15
|
-
return redactPrivateKeys(text).replace(/\bsscli_(?:access_|key_)?v1\.[a-f0-9-]{36}\.[A-Za-z0-9_-]{43}\b/gi, "[REDACTED CLI CREDENTIAL]").replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9+/_=.:~-]+/gi, "[REDACTED AUTHORIZATION]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[REDACTED JWT]").replace(/\b(?:sk|rk|vercel_blob_rw|vercel_blob_r|access_token|refresh_token)_[A-Za-z0-9._~-]{8,}/g, "[REDACTED]").replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[REDACTED]@").replace(/([?&](?:access_token|api_key|apikey|key|password|refresh_token|secret|token|signature|sig)=)[^&#\s]*/gi, "$1[REDACTED]").replace(/((?:["']?)(?:password|passwd|credential|secret|client_secret|api_key|access_token|refresh_token|authorization|cookie|set-cookie|token)(?:["']?)\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;})]+)/gi, "$1[REDACTED]").replace(/(Key\s*\([^)]*\)\s*=\s*)\([
|
|
15
|
+
return redactCopyContext(redactPrivateKeys(text)).replace(/\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?):\/\/\S+/gi, "[REDACTED CONNECTION URI]").replace(/\bsscli_(?:access_|key_)?v1\.[a-f0-9-]{36}\.[A-Za-z0-9_-]{43}\b/gi, "[REDACTED CLI CREDENTIAL]").replace(/\b(?:Bearer|Basic)\s+[A-Za-z0-9+/_=.:~-]+/gi, "[REDACTED AUTHORIZATION]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[REDACTED JWT]").replace(/\b(?:sk|rk|vercel_blob_rw|vercel_blob_r|access_token|refresh_token)_[A-Za-z0-9._~-]{8,}/g, "[REDACTED]").replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[REDACTED]@").replace(/([?&](?:access_token|api_key|apikey|key|password|refresh_token|secret|token|signature|sig)=)[^&#\s]*/gi, "$1[REDACTED]").replace(/((?:["']?)(?:password|passwd|credential|secret|client_secret|api_key|access_token|refresh_token|authorization|cookie|set-cookie|token)(?:["']?)\s*[:=]\s*)(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;})]+)/gi, "$1[REDACTED]").replace(/(Key\s*\([^)]*\)\s*=\s*)\([\s\S]*/gi, (match, prefix) => {
|
|
16
|
+
const end = Math.max(...[") already exists", ") is not present"].map((ending) => match.lastIndexOf(ending)));
|
|
17
|
+
return `${prefix}([REDACTED])${end < 0 ? "" : match.slice(end + 1)}`;
|
|
18
|
+
}).replace(/(Failing row contains\s+)[\s\S]*/gi, "$1[REDACTED]").replace(/(SQL statement\s+)[\s\S]*/gi, "$1[REDACTED]").replace(/(JSON data, line \d+:\s*)[\s\S]*/gi, "$1[REDACTED]").replace(/((?:Token|Escape sequence|but found)\s+")[\s\S]*/gi, (match, prefix) => {
|
|
19
|
+
const end = Math.max(match.lastIndexOf("\" is invalid"), match.lastIndexOf("\"."));
|
|
20
|
+
return `${prefix}[REDACTED]${end < 0 ? "\"" : match.slice(end)}`;
|
|
21
|
+
}).replace(/(invalid input syntax for [^:]+:\s*)"[^"]*"/gi, "$1[REDACTED]");
|
|
16
22
|
};
|
|
17
23
|
}
|
|
24
|
+
function redactCopyContext(text) {
|
|
25
|
+
const lines = /\bCOPY [^\n]*/gi;
|
|
26
|
+
let line;
|
|
27
|
+
while ((line = lines.exec(text)) !== null) {
|
|
28
|
+
const position = line[0].indexOf(", line ");
|
|
29
|
+
if (position < 0) continue;
|
|
30
|
+
const header = /^, line \d+(?:, column [^:\n]+)?:\s*/i.exec(line[0].slice(position));
|
|
31
|
+
return text.slice(0, line.index + (header ? position + header[0].length : 5)) + "[REDACTED]";
|
|
32
|
+
}
|
|
33
|
+
return text;
|
|
34
|
+
}
|
|
18
35
|
function environmentSecrets(env) {
|
|
19
36
|
return Object.entries(env).filter(([key]) => /(?:TOKEN|SECRET|PASSWORD|PRIVATE_KEY|API_KEY|COOKIE|SIGNING_KEY|DATABASE_URL|POSTGRES_URL|GRANT)/i.test(key)).map(([, value]) => value);
|
|
20
37
|
}
|
|
@@ -53,6 +70,12 @@ const FIELDS = [
|
|
|
53
70
|
"path",
|
|
54
71
|
"retryable",
|
|
55
72
|
"constraint",
|
|
73
|
+
"detail",
|
|
74
|
+
"hint",
|
|
75
|
+
"table",
|
|
76
|
+
"column",
|
|
77
|
+
"where",
|
|
78
|
+
"position",
|
|
56
79
|
"sqlState",
|
|
57
80
|
"field",
|
|
58
81
|
"expected",
|
|
@@ -91,6 +114,61 @@ function property(value, key) {
|
|
|
91
114
|
function scalar(value) {
|
|
92
115
|
return typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
93
116
|
}
|
|
117
|
+
function effectCause(value) {
|
|
118
|
+
if (property(value, "~effect/Cause") === "~effect/Cause") {
|
|
119
|
+
const reasons = property(value, "reasons");
|
|
120
|
+
if (Array.isArray(reasons)) return {
|
|
121
|
+
type: "EffectCause",
|
|
122
|
+
message: "Effect execution failed",
|
|
123
|
+
children: reasons.slice(0, MAX_NODES).map((error) => ({
|
|
124
|
+
error,
|
|
125
|
+
relation: "concurrent"
|
|
126
|
+
})),
|
|
127
|
+
limited: reasons.length > MAX_NODES
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const legacy = property(value, Symbol.for("effect/Cause")) !== void 0;
|
|
131
|
+
if (!legacy && property(value, "~effect/Cause/Reason") !== "~effect/Cause/Reason") return void 0;
|
|
132
|
+
const type = property(value, "_tag");
|
|
133
|
+
switch (type) {
|
|
134
|
+
case "Fail": return {
|
|
135
|
+
type,
|
|
136
|
+
message: "Typed failure",
|
|
137
|
+
children: [{
|
|
138
|
+
error: property(value, "error"),
|
|
139
|
+
relation: "cause"
|
|
140
|
+
}]
|
|
141
|
+
};
|
|
142
|
+
case "Die": return {
|
|
143
|
+
type,
|
|
144
|
+
message: "Unexpected defect",
|
|
145
|
+
children: [{
|
|
146
|
+
error: property(value, "defect"),
|
|
147
|
+
relation: "cause"
|
|
148
|
+
}]
|
|
149
|
+
};
|
|
150
|
+
case "Interrupt": return {
|
|
151
|
+
type,
|
|
152
|
+
message: "Fiber interrupted",
|
|
153
|
+
children: []
|
|
154
|
+
};
|
|
155
|
+
case "Empty": return legacy ? {
|
|
156
|
+
type,
|
|
157
|
+
message: "Empty Effect cause",
|
|
158
|
+
children: []
|
|
159
|
+
} : void 0;
|
|
160
|
+
case "Sequential":
|
|
161
|
+
case "Parallel": return legacy ? {
|
|
162
|
+
type,
|
|
163
|
+
message: `${type} Effect causes`,
|
|
164
|
+
children: ["left", "right"].map((key) => ({
|
|
165
|
+
error: property(value, key),
|
|
166
|
+
relation: type === "Parallel" ? "concurrent" : "cause"
|
|
167
|
+
}))
|
|
168
|
+
} : void 0;
|
|
169
|
+
default: return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
94
172
|
function ownValues(value) {
|
|
95
173
|
if (!value || typeof value !== "object") return [];
|
|
96
174
|
try {
|
|
@@ -118,6 +196,9 @@ function schemaInputRedactions(root) {
|
|
|
118
196
|
for (const secret of failureRedactions.get(value) ?? []) if (secret) values.add(secret);
|
|
119
197
|
}
|
|
120
198
|
if (property(value, "_tag") === "SchemaError" || property(value, "name") === "SchemaError") issues.push(property(value, "issue"));
|
|
199
|
+
const effect = effectCause(value);
|
|
200
|
+
if (effect?.limited) limited = true;
|
|
201
|
+
if (effect) errors.push(...effect.children.map((child) => child.error));
|
|
121
202
|
const explicit = property(value, links);
|
|
122
203
|
if (Array.isArray(explicit)) {
|
|
123
204
|
if (explicit.length > MAX_NODES) limited = true;
|
|
@@ -249,8 +330,9 @@ function createFailureReport(error, options) {
|
|
|
249
330
|
if (Array.isArray(inheritedOmissions)) {
|
|
250
331
|
for (const reason of inheritedOmissions.slice(0, 128)) if (typeof reason === "string") omissions.add(clean(reason));
|
|
251
332
|
}
|
|
252
|
-
const
|
|
253
|
-
const
|
|
333
|
+
const effect = effectCause(value);
|
|
334
|
+
const name = property(value, "_tag") ?? property(value, "name") ?? effect?.type;
|
|
335
|
+
const message = property(value, "message") ?? effect?.message;
|
|
254
336
|
const node = {
|
|
255
337
|
id,
|
|
256
338
|
type: typeof name === "string" ? clean(name) : "NonErrorThrow",
|
|
@@ -271,7 +353,8 @@ function createFailureReport(error, options) {
|
|
|
271
353
|
if (scalar(field)) details[key] = (key === "expected" || key === "actual") && isSensitiveField(String(property(value, "field") ?? "")) ? "[REDACTED]" : typeof field === "string" ? clean(field) : field;
|
|
272
354
|
}
|
|
273
355
|
if (Object.keys(details).length) node.details = details;
|
|
274
|
-
const children = [];
|
|
356
|
+
const children = effect?.children ?? [];
|
|
357
|
+
if (effect?.limited) omissions.add("Effect cause exceeded 1024 reasons");
|
|
275
358
|
const explicit = property(value, links);
|
|
276
359
|
if (Array.isArray(explicit)) {
|
|
277
360
|
for (const item of explicit.slice(0, MAX_NODES)) {
|
|
@@ -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 TelegramTexts } from "./lib/telegram/texts.js";
|
|
3
4
|
import type { AttachmentLifecycle } from "./lib/telegram/lifecycle.js";
|
|
4
5
|
import { type TelegramLinkPreviews } from "@segmentstream-cloud/ontology/telegram";
|
|
5
6
|
export declare const TELEGRAM_POLICIES: readonly ["mention", "smart"];
|
|
@@ -40,12 +41,13 @@ export interface FirstContactSettings {
|
|
|
40
41
|
readonly version: string;
|
|
41
42
|
readonly notice: LocalizedText;
|
|
42
43
|
}
|
|
43
|
-
export declare const ADMISSION_REPLY_KEYS: readonly ["limited", "perSenderLimited", "workspaceLimited", "registrationsLimited", "groupPairingRequired", "refused"];
|
|
44
|
+
export declare const ADMISSION_REPLY_KEYS: readonly ["pairingRequired", "pairingButton", "groupPairingButton", "limited", "perSenderLimited", "workspaceLimited", "registrationsLimited", "groupPairingRequired", "refused"];
|
|
44
45
|
export type AdmissionReplies = Partial<Record<(typeof ADMISSION_REPLY_KEYS)[number], LocalizedText>>;
|
|
45
46
|
export interface AdmissionSettings {
|
|
46
47
|
readonly firstContact: FirstContactSettings | null;
|
|
47
48
|
readonly limits: AdmissionLimits;
|
|
48
49
|
readonly replies: AdmissionReplies;
|
|
50
|
+
readonly texts?: TelegramTexts;
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* `agent/segmentstream.json` as authored. A JSON import widens string literals to `string` and
|
|
@@ -54,6 +56,7 @@ export interface AdmissionSettings {
|
|
|
54
56
|
*/
|
|
55
57
|
export interface SegmentStreamAgentConfigInput {
|
|
56
58
|
readonly groups?: GroupPolicyInput;
|
|
59
|
+
readonly texts?: TelegramTexts;
|
|
57
60
|
readonly firstContact?: FirstContactSettings;
|
|
58
61
|
readonly limits?: AdmissionLimitsInput;
|
|
59
62
|
readonly replies?: AdmissionReplies;
|
|
@@ -72,6 +75,9 @@ export interface SegmentStreamAgentConfigInput {
|
|
|
72
75
|
readonly linkPreviews?: string;
|
|
73
76
|
/** Additional exact HTTP(S) origins belonging to this workspace. */
|
|
74
77
|
readonly additionalOwnOrigins?: readonly string[];
|
|
78
|
+
readonly menuButton?: {
|
|
79
|
+
readonly text: LocalizedText;
|
|
80
|
+
};
|
|
75
81
|
readonly attachmentLifecycle?: Omit<AttachmentLifecycle, "contextVersion"> & {
|
|
76
82
|
readonly contextVersion?: number;
|
|
77
83
|
};
|
|
@@ -102,7 +108,7 @@ export interface SegmentStreamAgentConfigInput {
|
|
|
102
108
|
readonly connection?: boolean;
|
|
103
109
|
};
|
|
104
110
|
readonly confirmations?: {
|
|
105
|
-
/** `deferred` (default) returns immediately
|
|
111
|
+
/** `deferred` (default) returns immediately. Eve button approvals are unsupported. */
|
|
106
112
|
readonly mode?: string;
|
|
107
113
|
};
|
|
108
114
|
readonly sessions?: {
|
|
@@ -133,6 +139,9 @@ export interface TelegramSettings {
|
|
|
133
139
|
readonly linkPreviews?: TelegramLinkPreviews;
|
|
134
140
|
readonly additionalOwnOrigins?: readonly string[];
|
|
135
141
|
readonly attachmentLifecycle?: AttachmentLifecycle;
|
|
142
|
+
readonly menuButton?: {
|
|
143
|
+
readonly text: LocalizedText;
|
|
144
|
+
};
|
|
136
145
|
}
|
|
137
146
|
/** The chat models `segmentstream.model()` chooses between, as AI Gateway model ids. */
|
|
138
147
|
export interface ChatModelChoice {
|
|
@@ -175,7 +184,7 @@ export interface SegmentStreamAgentConfig extends AdmissionSettings {
|
|
|
175
184
|
readonly connection: boolean;
|
|
176
185
|
};
|
|
177
186
|
readonly confirmations: {
|
|
178
|
-
readonly mode: "deferred"
|
|
187
|
+
readonly mode: "deferred";
|
|
179
188
|
};
|
|
180
189
|
readonly sessions: SessionSettings;
|
|
181
190
|
}
|
|
@@ -196,8 +205,12 @@ export declare class SegmentStreamAgentConfigError extends Error {
|
|
|
196
205
|
readonly name = "SegmentStreamAgentConfigError";
|
|
197
206
|
constructor(issues: ReadonlyArray<ConfigIssue>);
|
|
198
207
|
}
|
|
208
|
+
/** Exact historical pins retain the pre-0.13 presentation contract at the archive boundary. */
|
|
209
|
+
export declare function isLegacyAgentArchive(version: string | undefined): boolean;
|
|
199
210
|
/** Validates the authored configuration and applies the defaults. */
|
|
200
|
-
export declare function validateConfig(input: unknown
|
|
211
|
+
export declare function validateConfig(input: unknown, options?: {
|
|
212
|
+
readonly archiveSdkVersion?: string;
|
|
213
|
+
}): Validation;
|
|
201
214
|
/**
|
|
202
215
|
* The Standard Schema eve validates the mount with. `types` exists only for type inference, as the
|
|
203
216
|
* Standard Schema specification allows.
|
|
@@ -206,7 +219,7 @@ export declare const configSchema: {
|
|
|
206
219
|
readonly "~standard": {
|
|
207
220
|
readonly version: 1;
|
|
208
221
|
readonly vendor: "segmentstream";
|
|
209
|
-
readonly validate:
|
|
222
|
+
readonly validate: (input: unknown) => Validation;
|
|
210
223
|
readonly types: {
|
|
211
224
|
readonly input: SegmentStreamAgentConfigInput;
|
|
212
225
|
readonly output: SegmentStreamAgentConfig;
|