@segmentstream/agent 0.8.4 → 0.8.6
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 +19 -0
- package/dist/_chunks/{build-metadata-ByEgTqDs.mjs → build-metadata-BIjXU_y3.mjs} +1 -1
- package/dist/_chunks/workflow-serializable-BwttWNmY.mjs +715 -0
- package/dist/extension/lib/attachment-tables.mjs +3 -2
- package/dist/extension/lib/build-metadata.mjs +1 -1
- package/dist/extension/lib/conversations.mjs +10 -4
- package/dist/extension/lib/telegram/adapter.mjs +9 -4
- package/dist/extension/lib/telegram/confirmation-text.d.ts +2 -0
- package/dist/extension/lib/telegram/confirmation-text.mjs +6 -1
- package/dist/extension/lib/telegram/confirmations.mjs +3 -3
- package/dist/extension/lib/telegram/health.d.ts +4 -0
- package/dist/extension/lib/telegram/health.mjs +3 -2
- package/dist/extension/lib/telegram/held-approvals.d.ts +27 -0
- package/dist/extension/lib/telegram/held-approvals.mjs +51 -0
- package/dist/extension/lib/telegram/inbound-request.d.ts +1 -1
- package/dist/extension/lib/telegram/inbound.d.ts +2 -0
- package/dist/extension/lib/telegram/inbound.mjs +33 -0
- package/dist/extension/lib/telegram/lifecycle.mjs +1 -1
- package/dist/extension/lib/telegram/observed.d.ts +1 -1
- package/dist/extension/lib/telegram/sessions.d.ts +4 -0
- package/dist/extension/lib/workflow-serializable.d.ts +29 -0
- package/dist/extension/lib/workflow-serializable.mjs +8 -0
- package/dist/extension/tools/attachments_discard.d.ts +2 -24
- package/dist/extension/tools/attachments_discard.mjs +2 -1
- package/dist/extension/tools/attachments_list.d.ts +2 -24
- package/dist/extension/tools/attachments_list.mjs +3 -1
- package/dist/extension/tools/attachments_promote.d.ts +2 -28
- package/dist/extension/tools/attachments_promote.mjs +3 -2
- package/dist/extension/tools/attachments_read.mjs +3 -2
- package/dist/extension/tools/attachments_send.d.ts +1 -7
- package/dist/extension/tools/attachments_send.mjs +4 -3
- package/dist/extension/tools/attachments_table.d.ts +2 -62
- package/dist/extension/tools/attachments_table.mjs +3 -2
- package/dist/extension/tools/questions_ask.d.ts +3 -13
- package/dist/extension/tools/questions_ask.mjs +2 -1
- package/package.json +2 -2
|
@@ -115,8 +115,9 @@ function present(value) {
|
|
|
115
115
|
}
|
|
116
116
|
function detectedHeader(rows) {
|
|
117
117
|
const candidates = rows.slice(0, 50);
|
|
118
|
-
const width = candidates.reduce((maximum, row) => Math.max(maximum, row.
|
|
119
|
-
const
|
|
118
|
+
const width = candidates.reduce((maximum, row) => Math.max(maximum, row.findLastIndex(present) + 1), 0);
|
|
119
|
+
const minimumLabels = Math.min(width, 2);
|
|
120
|
+
const labels = candidates.findIndex((row) => row.filter(present).length >= minimumLabels && row.some(present) && row.filter(present).every((value) => typeof value === "string" && numeric(value) === null && dateValue(value, "day_first") === null && dateValue(value, "month_first") === null));
|
|
120
121
|
if (labels >= 0) return labels;
|
|
121
122
|
return -1;
|
|
122
123
|
}
|
|
@@ -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-BIjXU_y3.mjs";
|
|
8
8
|
export { agentBuild };
|
|
@@ -6,6 +6,7 @@ __eveDirname(__filename);
|
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { proxyEnvironment } from "./environment.mjs";
|
|
8
8
|
import { runtimeToken } from "./runtime-token.mjs";
|
|
9
|
+
import { r as workflowValue } from "../../_chunks/workflow-serializable-BwttWNmY.mjs";
|
|
9
10
|
function collapseConversationEvents(events) {
|
|
10
11
|
const latest = new Map();
|
|
11
12
|
for (const event of events) {
|
|
@@ -20,7 +21,7 @@ function collapseConversationEvents(events) {
|
|
|
20
21
|
return [...latest.values()];
|
|
21
22
|
}
|
|
22
23
|
function conversationEvent(input) {
|
|
23
|
-
return {
|
|
24
|
+
return workflowValue({
|
|
24
25
|
threadId: null,
|
|
25
26
|
participantIds: [],
|
|
26
27
|
senderId: null,
|
|
@@ -40,7 +41,12 @@ function conversationEvent(input) {
|
|
|
40
41
|
attachments: [],
|
|
41
42
|
at: new Date().toISOString(),
|
|
42
43
|
...input
|
|
43
|
-
}
|
|
44
|
+
}, {
|
|
45
|
+
boundary: "SDK conversation event",
|
|
46
|
+
eventType: input.kind,
|
|
47
|
+
toolName: input.toolName ?? void 0,
|
|
48
|
+
toolCallId: input.toolCallId ?? void 0
|
|
49
|
+
});
|
|
44
50
|
}
|
|
45
51
|
function conversations(input = {}) {
|
|
46
52
|
const environment = input.environment ?? process.env;
|
|
@@ -58,7 +64,7 @@ function conversations(input = {}) {
|
|
|
58
64
|
"x-segmentstream-organization-id": env.organizationId,
|
|
59
65
|
"x-segmentstream-runtime-identity": identity
|
|
60
66
|
},
|
|
61
|
-
body: JSON.stringify(body),
|
|
67
|
+
body: JSON.stringify(workflowValue(body, { boundary: "conversation archive" })),
|
|
62
68
|
signal: AbortSignal.timeout(15e3)
|
|
63
69
|
});
|
|
64
70
|
if (!response.ok) throw new Error(`Conversation archive ${path} failed (${response.status}); request ${response.headers.get("x-request-id") ?? "unknown"}.`);
|
|
@@ -88,7 +94,7 @@ function summarizeArguments(value) {
|
|
|
88
94
|
if (item !== null && typeof item === "object") return Object.fromEntries(Object.entries(item).slice(0, 30).map(([key, entry]) => [key, sensitive.test(key) ? "[redacted]" : visit(entry, depth + 1)]));
|
|
89
95
|
return typeof item === "string" ? item.replace(/(https?:\/\/)[^/@\s]+:[^/@\s]+@/gu, "$1[redacted]@").replace(/([?&](?:token|access_token|api_key|signature|secret|password)=)[^&#\s]*/giu, "$1[redacted]").replace(/\bBearer [A-Za-z0-9_.~+/-]+=*/giu, "Bearer [redacted]").slice(0, 500) : item;
|
|
90
96
|
};
|
|
91
|
-
return
|
|
97
|
+
return JSON.stringify(workflowValue(visit(value, 0), { boundary: "conversation arguments" })).slice(0, 4e3);
|
|
92
98
|
}
|
|
93
99
|
function retainedInboundEvidence(event) {
|
|
94
100
|
if (event.kind !== "inbound") return;
|
|
@@ -8,7 +8,7 @@ import { manifestOf } from "../../config.mjs";
|
|
|
8
8
|
import { appOrigin, channelsEnabled, proxyEnvironment, runtimeIdentityEnvironment, webhookSecret } from "../environment.mjs";
|
|
9
9
|
import { conversationLanguage, telegramPrincipal } from "./principal.mjs";
|
|
10
10
|
import { chooseModel } from "../../model.mjs";
|
|
11
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
11
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-BIjXU_y3.mjs";
|
|
12
12
|
import { confirmationLocale } from "./confirmation-text.mjs";
|
|
13
13
|
import { telegramSendScope } from "./send-queue.mjs";
|
|
14
14
|
import { d as failureText, h as withDeliveryLocale, i as withReplacedText, m as safeTelegramFetch, n as currentInboundRequest, p as reportTelegramError, r as runInboundRequest, t as InboundRequest } from "../../../_chunks/inbound-request-B98tr4Pd.mjs";
|
|
@@ -166,6 +166,7 @@ function segmentstreamTelegram(options) {
|
|
|
166
166
|
request: currentInboundRequest(),
|
|
167
167
|
dependencies: {
|
|
168
168
|
policy: settings().policy,
|
|
169
|
+
recoverHeldApprovals: options.confirmationMode?.() === "deferred",
|
|
169
170
|
...settings().attachmentLifecycle === void 0 ? {} : { lifecycle: (principal, memberId, message) => attachmentLifecycle({
|
|
170
171
|
configuration: settings().attachmentLifecycle,
|
|
171
172
|
principal,
|
|
@@ -252,7 +253,7 @@ function segmentstreamTelegram(options) {
|
|
|
252
253
|
} catch (error) {
|
|
253
254
|
recordGateDecision("inbound_message_failed");
|
|
254
255
|
const errorId = reportTelegramError("inbound_message_failed", error, { chatId: message.chat.id });
|
|
255
|
-
if (inbound?.lifecycleKey !== void 0) inbound.retryReference = errorId;
|
|
256
|
+
if (inbound?.retryReference !== void 0 || inbound?.lifecycleKey !== void 0) inbound.retryReference = errorId;
|
|
256
257
|
else await context.telegram.post(failureText(errorId));
|
|
257
258
|
return null;
|
|
258
259
|
} finally {
|
|
@@ -394,7 +395,11 @@ function segmentstreamTelegram(options) {
|
|
|
394
395
|
chats,
|
|
395
396
|
enabled: () => channelsEnabled(environment),
|
|
396
397
|
configured: () => options.settings() !== null,
|
|
397
|
-
verify: () => verify ??= runtimeTokenVerifier(runtimeIdentityEnvironment(environment))
|
|
398
|
+
verify: () => verify ??= runtimeTokenVerifier(runtimeIdentityEnvironment(environment)),
|
|
399
|
+
configuration: () => ({
|
|
400
|
+
confirmationMode: options.confirmationMode?.() ?? null,
|
|
401
|
+
attachmentLifecycle: options.settings()?.attachmentLifecycle !== void 0
|
|
402
|
+
})
|
|
398
403
|
})]
|
|
399
404
|
};
|
|
400
405
|
}
|
|
@@ -466,7 +471,7 @@ function gatedRoute(input) {
|
|
|
466
471
|
await Promise.all(pending);
|
|
467
472
|
}
|
|
468
473
|
if (inbound.retryReference !== void 0) return Response.json({
|
|
469
|
-
error: "
|
|
474
|
+
error: "telegram_turn_retry",
|
|
470
475
|
reference: inbound.retryReference
|
|
471
476
|
}, {
|
|
472
477
|
status: 503,
|
|
@@ -11,6 +11,7 @@ export interface ConfirmationCopy {
|
|
|
11
11
|
readonly cancelled: string;
|
|
12
12
|
readonly failed: string;
|
|
13
13
|
readonly expired?: string;
|
|
14
|
+
readonly interrupted?: string;
|
|
14
15
|
readonly edit?: string;
|
|
15
16
|
}
|
|
16
17
|
export interface ConfirmationText {
|
|
@@ -23,6 +24,7 @@ export interface ConfirmationText {
|
|
|
23
24
|
readonly completed: string;
|
|
24
25
|
readonly failed: string;
|
|
25
26
|
readonly expired: string;
|
|
27
|
+
readonly interrupted: string;
|
|
26
28
|
readonly edit: string;
|
|
27
29
|
}
|
|
28
30
|
export declare function confirmationLocale(principal: SessionAuthContext | null, fallback?: string): string;
|
|
@@ -38,7 +38,11 @@ function confirmationCopy(value) {
|
|
|
38
38
|
"cancelled",
|
|
39
39
|
"failed"
|
|
40
40
|
];
|
|
41
|
-
const optional = [
|
|
41
|
+
const optional = [
|
|
42
|
+
"expired",
|
|
43
|
+
"interrupted",
|
|
44
|
+
"edit"
|
|
45
|
+
];
|
|
42
46
|
const valid = (key) => {
|
|
43
47
|
const text = copy[key];
|
|
44
48
|
return typeof text === "string" && text === text.trim() && (key === "question" || !/[✅❌⌛⚠❓✏]/u.test(text)) && humanText(text, key === "question" ? 300 : 24) === text;
|
|
@@ -72,6 +76,7 @@ function renderConfirmation(description, copy) {
|
|
|
72
76
|
completed: copy === void 0 ? "✅" : `✅ ${copy.done}`,
|
|
73
77
|
failed: copy === void 0 ? "⚠️" : `⚠️ ${copy.failed}`,
|
|
74
78
|
expired: copy?.expired === void 0 ? "⌛" : `⌛ ${copy.expired}`,
|
|
79
|
+
interrupted: copy?.interrupted === void 0 ? "⏸" : `⏸ ${copy.interrupted}`,
|
|
75
80
|
edit: copy?.edit === void 0 ? "✏️" : `✏️ ${copy.edit}`
|
|
76
81
|
};
|
|
77
82
|
}
|
|
@@ -70,7 +70,7 @@ function routingConfirmationState(events, prompt, at) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
if (event.type === "input.resolved" && Array.isArray(data.resolutions)) {
|
|
73
|
-
for (const resolution of data.resolutions) if (object(resolution).requestId === prompt.requestId) state = object(resolution).outcome === "approved" ? "approved" : "cancelled";
|
|
73
|
+
for (const resolution of data.resolutions) if (object(resolution).requestId === prompt.requestId) state = object(resolution).outcome === "approved" ? "approved" : object(resolution).outcome === "ignored" ? "interrupted" : "cancelled";
|
|
74
74
|
}
|
|
75
75
|
if (event.type === "action.result" && callId !== void 0 && object(data.result).callId === callId) state = data.status === "completed" ? "completed" : "failed";
|
|
76
76
|
}
|
|
@@ -361,7 +361,7 @@ function telegramConfirmationEvents(archive, observed, deferredOptions) {
|
|
|
361
361
|
const [callId, message] = entry;
|
|
362
362
|
const copy = message.copy ?? renderConfirmation();
|
|
363
363
|
const reason = confirmations.get()[callId]?.cancellationReason;
|
|
364
|
-
const status = resolution.outcome === "approved" ? copy.executing : reason === "expired" ? copy.expired : copy.cancelled;
|
|
364
|
+
const status = resolution.outcome === "approved" ? copy.executing : reason === "expired" ? copy.expired : resolution.outcome === "ignored" ? copy.interrupted : copy.cancelled;
|
|
365
365
|
const text = message.exactPost ? chatPostCardStatus(message.text, status) : `${message.text}\n\n${status}`;
|
|
366
366
|
const edit = () => channel.telegram.editMessageText({
|
|
367
367
|
messageId: message.messageId,
|
|
@@ -370,7 +370,7 @@ function telegramConfirmationEvents(archive, observed, deferredOptions) {
|
|
|
370
370
|
});
|
|
371
371
|
const prompt = {
|
|
372
372
|
...messagePrompt(message),
|
|
373
|
-
state: resolution.outcome === "approved" ? "approved" : reason === "expired" ? "expired" : "cancelled"
|
|
373
|
+
state: resolution.outcome === "approved" ? "approved" : reason === "expired" ? "expired" : resolution.outcome === "ignored" ? "interrupted" : "cancelled"
|
|
374
374
|
};
|
|
375
375
|
message.prompt = prompt;
|
|
376
376
|
await withConfirmationPrompt(prompt, () => message.exactPost ? withChatPostCard(text, edit, [...message.previewLinks ?? [], ...telegramTextLinks(status)]) : withConfirmationText(text, edit));
|
|
@@ -9,4 +9,8 @@ export declare function healthRoute(input: {
|
|
|
9
9
|
readonly enabled: () => boolean;
|
|
10
10
|
readonly configured: () => boolean;
|
|
11
11
|
readonly verify: () => RuntimeTokenVerifier;
|
|
12
|
+
readonly configuration?: () => {
|
|
13
|
+
readonly confirmationMode: "deferred" | "held" | null;
|
|
14
|
+
readonly attachmentLifecycle: boolean;
|
|
15
|
+
};
|
|
12
16
|
}): RouteDefinition<TelegramChannelState>;
|
|
@@ -4,7 +4,7 @@ import { createRequire as __eveCreateRequire } from "node:module";
|
|
|
4
4
|
const __filename = __eveFileURLToPath(import.meta.url);
|
|
5
5
|
__eveDirname(__filename);
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
|
-
import { t as agentBuild } from "../../../_chunks/build-metadata-
|
|
7
|
+
import { t as agentBuild } from "../../../_chunks/build-metadata-BIjXU_y3.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";
|
|
@@ -16,7 +16,8 @@ function healthRoute(input) {
|
|
|
16
16
|
return Response.json({
|
|
17
17
|
status: registry.degraded ? "degraded" : "ok",
|
|
18
18
|
registry,
|
|
19
|
-
runtime: agentBuild()
|
|
19
|
+
runtime: agentBuild(),
|
|
20
|
+
...input.configuration === void 0 ? {} : { configuration: input.configuration() }
|
|
20
21
|
}, {
|
|
21
22
|
status: registry.degraded ? 503 : 200,
|
|
22
23
|
headers: { "cache-control": "no-store" }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CancelTurnResult } from "eve/channels";
|
|
2
|
+
import type { RecordedEvent } from "./sessions.js";
|
|
3
|
+
/** An approval is an input barrier, never permission to execute it while recovering a chat. */
|
|
4
|
+
export declare function heldApprovals(events: readonly RecordedEvent[]): {
|
|
5
|
+
requestId: string;
|
|
6
|
+
callId: string;
|
|
7
|
+
action: string;
|
|
8
|
+
turnId: string;
|
|
9
|
+
at: string;
|
|
10
|
+
}[];
|
|
11
|
+
/** Cancel the exact parked turn; never steer a new member into its permissions or old task. */
|
|
12
|
+
export declare function releaseHeldApproval(input: {
|
|
13
|
+
readonly events: readonly RecordedEvent[];
|
|
14
|
+
readonly addressed: boolean;
|
|
15
|
+
readonly now: number;
|
|
16
|
+
readonly cancel: (options: {
|
|
17
|
+
readonly turnId: string;
|
|
18
|
+
}) => Promise<CancelTurnResult>;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
status: string;
|
|
21
|
+
reason: string;
|
|
22
|
+
turnId: string;
|
|
23
|
+
startedAt: string;
|
|
24
|
+
actions: string[];
|
|
25
|
+
cancellation: "accepted";
|
|
26
|
+
executionRequested: boolean;
|
|
27
|
+
} | undefined>;
|
|
@@ -0,0 +1,51 @@
|
|
|
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 { object } from "../confirmation-description.mjs";
|
|
8
|
+
import { CONFIRMATION_TTL_MS } from "../confirmations.mjs";
|
|
9
|
+
function heldApprovals(events) {
|
|
10
|
+
const pending = new Map();
|
|
11
|
+
for (const event of events) {
|
|
12
|
+
const data = object(event.data);
|
|
13
|
+
if (event.type === "context.cleared" || event.type === "session.started") pending.clear();
|
|
14
|
+
if (event.type === "input.requested" && Array.isArray(data.requests)) for (const item of data.requests) {
|
|
15
|
+
const request = object(item);
|
|
16
|
+
const action = object(request.action);
|
|
17
|
+
if (request.kind === "tool-approval" && typeof request.requestId === "string" && typeof action.callId === "string" && typeof data.turnId === "string") pending.set(request.requestId, {
|
|
18
|
+
requestId: request.requestId,
|
|
19
|
+
callId: action.callId,
|
|
20
|
+
action: String(action.toolName ?? ""),
|
|
21
|
+
turnId: data.turnId,
|
|
22
|
+
at: event.meta.at
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
for (const [id, approval] of pending) if (event.type === "input.resolved" && Array.isArray(data.resolutions) && data.resolutions.some((item) => object(item).requestId === id) || event.type === "action.result" && object(data.result).callId === approval.callId || [
|
|
26
|
+
"turn.completed",
|
|
27
|
+
"turn.failed",
|
|
28
|
+
"turn.cancelled"
|
|
29
|
+
].includes(event.type) && data.turnId === approval.turnId) pending.delete(id);
|
|
30
|
+
}
|
|
31
|
+
return [...pending.values()];
|
|
32
|
+
}
|
|
33
|
+
async function releaseHeldApproval(input) {
|
|
34
|
+
const pending = heldApprovals(input.events);
|
|
35
|
+
if (new Set(pending.map((approval) => approval.turnId)).size !== 1) return;
|
|
36
|
+
const expired = pending.some((approval) => input.now - Date.parse(approval.at) >= CONFIRMATION_TTL_MS);
|
|
37
|
+
if (!input.addressed && !expired) return;
|
|
38
|
+
const turnId = pending[0].turnId;
|
|
39
|
+
const result = await input.cancel({ turnId });
|
|
40
|
+
if (result.status === "no_active_turn") return;
|
|
41
|
+
return {
|
|
42
|
+
status: "cancellation_requested",
|
|
43
|
+
reason: expired ? "expired" : "addressed",
|
|
44
|
+
turnId,
|
|
45
|
+
startedAt: pending[0].at,
|
|
46
|
+
actions: pending.map((approval) => approval.action),
|
|
47
|
+
cancellation: result.status,
|
|
48
|
+
executionRequested: false
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export { heldApprovals, releaseHeldApproval };
|
|
@@ -37,7 +37,7 @@ export declare class InboundRequest {
|
|
|
37
37
|
stopTyping: (() => void) | undefined;
|
|
38
38
|
lifecycle: ReturnType<typeof import("./lifecycle.js").attachmentLifecycle> | undefined;
|
|
39
39
|
lifecycleKey: string | undefined;
|
|
40
|
-
/**
|
|
40
|
+
/** A routed task must be redelivered if recovery or intake did not reach durable admission. */
|
|
41
41
|
retryReference: string | undefined;
|
|
42
42
|
lifecycleContext: string | undefined;
|
|
43
43
|
monitor: ((session: Awaited<ReturnType<ChannelSource<unknown>["send"]>>, marker: string) => void) | undefined;
|
|
@@ -39,6 +39,8 @@ import type { PdfTextExtractor } from "./pdf-text.js";
|
|
|
39
39
|
*/
|
|
40
40
|
export interface InboundDependencies {
|
|
41
41
|
readonly policy: TelegramPolicy;
|
|
42
|
+
/** Recover old held sessions only when the workspace has chosen non-blocking confirmations. */
|
|
43
|
+
readonly recoverHeldApprovals?: boolean;
|
|
42
44
|
readonly lifecycle?: (principal: import("eve/context").SessionAuthContext, memberId: string, message: TelegramMessage) => ReturnType<typeof attachmentLifecycle>;
|
|
43
45
|
readonly admission: () => AdmissionSettings;
|
|
44
46
|
readonly sessions: () => SessionSettings;
|
|
@@ -22,6 +22,7 @@ import { recordGateDecision, recordInboundContent, recordRouteDecision } from ".
|
|
|
22
22
|
import { chatContext } from "./chats.mjs";
|
|
23
23
|
import { admitMessage, localizedText } from "../admission.mjs";
|
|
24
24
|
import { attachmentsContext, inboundAttachments, stageFiles } from "./files.mjs";
|
|
25
|
+
import { heldApprovals, releaseHeldApproval } from "./held-approvals.mjs";
|
|
25
26
|
import { voiceOf, voiceText } from "./voice.mjs";
|
|
26
27
|
const UNKNOWN_PRIVATE = "🔗";
|
|
27
28
|
const UNKNOWN_IN_GROUP = "🔒";
|
|
@@ -721,6 +722,38 @@ async function handleInboundMessage(input) {
|
|
|
721
722
|
recordGateDecision("message_already_handled");
|
|
722
723
|
return null;
|
|
723
724
|
}
|
|
725
|
+
if (dependencies.recoverHeldApprovals === true && operations !== void 0 && dependencies.history !== void 0) {
|
|
726
|
+
let recoverySessionId;
|
|
727
|
+
try {
|
|
728
|
+
const session = await operations.resolveSession(address);
|
|
729
|
+
if (session !== void 0) {
|
|
730
|
+
recoverySessionId = session.id;
|
|
731
|
+
const previous = session.id === owner?.id ? questionHistory : await dependencies.history(session.id);
|
|
732
|
+
const recovery = heldApprovals(previous).length === 0 ? void 0 : await releaseHeldApproval({
|
|
733
|
+
events: await dependencies.history(session.id),
|
|
734
|
+
addressed: addressed !== void 0,
|
|
735
|
+
now: Date.now(),
|
|
736
|
+
cancel: (options) => {
|
|
737
|
+
if (session.cancel === void 0) throw new Error("The parked session does not support turn cancellation.");
|
|
738
|
+
return session.cancel(options);
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
if (recovery !== void 0) {
|
|
742
|
+
recordGateDecision("held_approval_cancellation_requested", "reply");
|
|
743
|
+
notes.push(`<approval_recovery>${JSON.stringify(recovery)}</approval_recovery>`);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
} catch (error) {
|
|
747
|
+
if (input.request !== void 0) {
|
|
748
|
+
input.request.retryReference = reportTelegramError("held_approval_release_failed", error, {
|
|
749
|
+
sessionId: recoverySessionId,
|
|
750
|
+
messageId: sent.messageId
|
|
751
|
+
});
|
|
752
|
+
await input.request.finishClaim?.(false);
|
|
753
|
+
}
|
|
754
|
+
throw error;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
724
757
|
if (voice !== void 0 && input.request !== void 0) input.request.text = text;
|
|
725
758
|
else if (voice !== void 0) notes.push(text);
|
|
726
759
|
if (answering && pending !== void 0 && input.request !== void 0) {
|
|
@@ -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-BIjXU_y3.mjs";
|
|
8
8
|
import { object } from "../confirmation-description.mjs";
|
|
9
9
|
import { n as currentInboundRequest, p as reportTelegramError } from "../../../_chunks/inbound-request-B98tr4Pd.mjs";
|
|
10
10
|
import { needsConfirmation } from "../confirmations.mjs";
|
|
@@ -62,7 +62,7 @@ export interface AgentMessage extends ObservedMessage {
|
|
|
62
62
|
}
|
|
63
63
|
/** Presentation only; no tool inputs, credential values or member identifiers. */
|
|
64
64
|
export interface PendingConfirmation {
|
|
65
|
-
readonly state?: "pending" | "approved" | "cancelled" | "expired" | "completed" | "failed";
|
|
65
|
+
readonly state?: "pending" | "approved" | "cancelled" | "interrupted" | "expired" | "completed" | "failed";
|
|
66
66
|
readonly action: string;
|
|
67
67
|
readonly requestedBy: string | null;
|
|
68
68
|
readonly at: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TelegramMessage } from "eve/channels/telegram";
|
|
2
|
+
import type { CancelTurnResult } from "eve/channels";
|
|
2
3
|
import type { SessionSettings } from "../../config.js";
|
|
3
4
|
/**
|
|
4
5
|
* Session policy for the Telegram channel (`agent-design.md`, section 4, and docs/agent.md,
|
|
@@ -56,6 +57,9 @@ export declare function historyOf(events: ReadonlyArray<RecordedEvent>): Session
|
|
|
56
57
|
export interface SessionOperations {
|
|
57
58
|
readonly resolveSession: (address: string) => Promise<{
|
|
58
59
|
readonly id: string;
|
|
60
|
+
readonly cancel?: (options: {
|
|
61
|
+
readonly turnId: string;
|
|
62
|
+
}) => Promise<CancelTurnResult>;
|
|
59
63
|
} | undefined>;
|
|
60
64
|
readonly from: (address: string) => {
|
|
61
65
|
compact(): Promise<unknown>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** JSON data produced by SDK tools and conversation archive events. */
|
|
2
|
+
export type WorkflowSerializable = null | boolean | number | string | WorkflowSerializable[] | {
|
|
3
|
+
[key: string]: WorkflowSerializable;
|
|
4
|
+
};
|
|
5
|
+
export interface SerializationIssue {
|
|
6
|
+
readonly path: string;
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
readonly cause?: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface SerializationContext {
|
|
11
|
+
readonly boundary: string;
|
|
12
|
+
readonly toolName?: string;
|
|
13
|
+
readonly toolCallId?: string;
|
|
14
|
+
readonly eventType?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Never mutate a provider result; read own data fields without invoking their getters.
|
|
18
|
+
* Undefined/functions/symbols disappear from
|
|
19
|
+
* objects and become null in arrays. An active-ancestor set breaks cycles without losing shared
|
|
20
|
+
* references. Limits also protect the durable writer from hostile proxies or excessively deep data.
|
|
21
|
+
*/
|
|
22
|
+
export declare function toWorkflowSerializable(value: unknown, report?: (issue: SerializationIssue) => void): WorkflowSerializable;
|
|
23
|
+
/** Log paths and types, never payloads, provider bodies or credential values. */
|
|
24
|
+
export declare function workflowValue(value: unknown, context: SerializationContext): WorkflowSerializable;
|
|
25
|
+
/** Normalize only results authored by this SDK; leave Eve's execution and approval policy intact. */
|
|
26
|
+
export declare function workflowToolResult(value: unknown, context: {
|
|
27
|
+
readonly toolName: string;
|
|
28
|
+
readonly callId: string;
|
|
29
|
+
}): WorkflowSerializable;
|
|
@@ -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 { n as workflowToolResult, r as workflowValue, t as toWorkflowSerializable } from "../../_chunks/workflow-serializable-BwttWNmY.mjs";
|
|
8
|
+
export { toWorkflowSerializable, workflowToolResult, workflowValue };
|
|
@@ -2,29 +2,7 @@
|
|
|
2
2
|
* `segmentstream__attachments_discard`: drops an attachment at once. It can no longer be read or
|
|
3
3
|
* promoted, and its file is deleted by the platform's maintenance.
|
|
4
4
|
*/
|
|
5
|
-
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, {
|
|
6
|
-
|
|
7
|
-
promotion?: {} | undefined;
|
|
8
|
-
expires_at?: string | undefined;
|
|
9
|
-
state?: string | undefined;
|
|
10
|
-
id: string;
|
|
11
|
-
filename: string;
|
|
12
|
-
content_type: string;
|
|
13
|
-
size: number;
|
|
14
|
-
sha256: string;
|
|
15
|
-
};
|
|
16
|
-
}> & {
|
|
17
|
-
execute(input: Record<string, unknown>, ctx: import("eve/tools").ToolContext): Promise<{
|
|
18
|
-
attachment: {
|
|
19
|
-
promotion?: {} | undefined;
|
|
20
|
-
expires_at?: string | undefined;
|
|
21
|
-
state?: string | undefined;
|
|
22
|
-
id: string;
|
|
23
|
-
filename: string;
|
|
24
|
-
content_type: string;
|
|
25
|
-
size: number;
|
|
26
|
-
sha256: string;
|
|
27
|
-
};
|
|
28
|
-
}>;
|
|
5
|
+
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, import("../lib/workflow-serializable.js").WorkflowSerializable> & {
|
|
6
|
+
execute(input: Record<string, unknown>, ctx: import("eve/tools").ToolContext): Promise<import("../lib/workflow-serializable.js").WorkflowSerializable>;
|
|
29
7
|
};
|
|
30
8
|
export default _default;
|
|
@@ -4,6 +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 { n as workflowToolResult } from "../../_chunks/workflow-serializable-BwttWNmY.mjs";
|
|
7
8
|
import { ID_INPUT, attachmentForModel, attachmentOwner, stringArgument, toolAttachments } from "../lib/attachment-tools.mjs";
|
|
8
9
|
import { defineTool } from "eve/tools";
|
|
9
10
|
var attachments_discard_default = defineTool({
|
|
@@ -16,7 +17,7 @@ var attachments_discard_default = defineTool({
|
|
|
16
17
|
sessionId: ctx.session.id
|
|
17
18
|
});
|
|
18
19
|
const attachment = await toolAttachments().discard(owner, stringArgument(input, "id"));
|
|
19
|
-
return { attachment: attachmentForModel(attachment) };
|
|
20
|
+
return workflowToolResult({ attachment: attachmentForModel(attachment) }, ctx);
|
|
20
21
|
}
|
|
21
22
|
});
|
|
22
23
|
export { attachments_discard_default as default };
|
|
@@ -2,29 +2,7 @@
|
|
|
2
2
|
* `segmentstream__attachments_list`: the files the member sent in this chat and session that are
|
|
3
3
|
* still available. Mounted with the extension, so it is there even with `defaultTools: false`.
|
|
4
4
|
*/
|
|
5
|
-
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, {
|
|
6
|
-
|
|
7
|
-
promotion?: {} | undefined;
|
|
8
|
-
expires_at?: string | undefined;
|
|
9
|
-
state?: string | undefined;
|
|
10
|
-
id: string;
|
|
11
|
-
filename: string;
|
|
12
|
-
content_type: string;
|
|
13
|
-
size: number;
|
|
14
|
-
sha256: string;
|
|
15
|
-
}[];
|
|
16
|
-
}> & {
|
|
17
|
-
execute(input: Record<string, unknown>, ctx: import("eve/tools").ToolContext): Promise<{
|
|
18
|
-
attachments: {
|
|
19
|
-
promotion?: {} | undefined;
|
|
20
|
-
expires_at?: string | undefined;
|
|
21
|
-
state?: string | undefined;
|
|
22
|
-
id: string;
|
|
23
|
-
filename: string;
|
|
24
|
-
content_type: string;
|
|
25
|
-
size: number;
|
|
26
|
-
sha256: string;
|
|
27
|
-
}[];
|
|
28
|
-
}>;
|
|
5
|
+
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, import("../lib/workflow-serializable.js").WorkflowSerializable> & {
|
|
6
|
+
execute(input: Record<string, unknown>, ctx: import("eve/tools").ToolContext): Promise<import("../lib/workflow-serializable.js").WorkflowSerializable>;
|
|
29
7
|
};
|
|
30
8
|
export default _default;
|
|
@@ -4,6 +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 { n as workflowToolResult } from "../../_chunks/workflow-serializable-BwttWNmY.mjs";
|
|
7
8
|
import { attachmentForModel, attachmentOwner, toolAttachments } from "../lib/attachment-tools.mjs";
|
|
8
9
|
import { defineTool } from "eve/tools";
|
|
9
10
|
var attachments_list_default = defineTool({
|
|
@@ -19,7 +20,8 @@ var attachments_list_default = defineTool({
|
|
|
19
20
|
principal: ctx.session.auth.current,
|
|
20
21
|
sessionId: ctx.session.id
|
|
21
22
|
});
|
|
22
|
-
|
|
23
|
+
const attachments = await toolAttachments().list(owner);
|
|
24
|
+
return workflowToolResult({ attachments: attachments.map(attachmentForModel) }, ctx);
|
|
23
25
|
}
|
|
24
26
|
});
|
|
25
27
|
export { attachments_list_default as default };
|
|
@@ -4,33 +4,7 @@
|
|
|
4
4
|
* hands the action the file already stored, so nothing is uploaded again, and a file whose SHA-256
|
|
5
5
|
* was already promoted through the same action is not stored twice.
|
|
6
6
|
*/
|
|
7
|
-
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, {
|
|
8
|
-
|
|
9
|
-
promotion?: {} | undefined;
|
|
10
|
-
expires_at?: string | undefined;
|
|
11
|
-
state?: string | undefined;
|
|
12
|
-
id: string;
|
|
13
|
-
filename: string;
|
|
14
|
-
content_type: string;
|
|
15
|
-
size: number;
|
|
16
|
-
sha256: string;
|
|
17
|
-
};
|
|
18
|
-
deduplicated: boolean;
|
|
19
|
-
result: unknown;
|
|
20
|
-
}> & {
|
|
21
|
-
execute(input: Record<string, unknown>, ctx: import("eve/tools").ToolContext): Promise<{
|
|
22
|
-
attachment: {
|
|
23
|
-
promotion?: {} | undefined;
|
|
24
|
-
expires_at?: string | undefined;
|
|
25
|
-
state?: string | undefined;
|
|
26
|
-
id: string;
|
|
27
|
-
filename: string;
|
|
28
|
-
content_type: string;
|
|
29
|
-
size: number;
|
|
30
|
-
sha256: string;
|
|
31
|
-
};
|
|
32
|
-
deduplicated: boolean;
|
|
33
|
-
result: unknown;
|
|
34
|
-
}>;
|
|
7
|
+
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, import("../lib/workflow-serializable.js").WorkflowSerializable> & {
|
|
8
|
+
execute(input: Record<string, unknown>, ctx: import("eve/tools").ToolContext): Promise<import("../lib/workflow-serializable.js").WorkflowSerializable>;
|
|
35
9
|
};
|
|
36
10
|
export default _default;
|
|
@@ -6,6 +6,7 @@ __eveDirname(__filename);
|
|
|
6
6
|
__eveCreateRequire(import.meta.url);
|
|
7
7
|
import { actionApproval } from "../lib/confirmations.mjs";
|
|
8
8
|
import { ontologyTools, promotionTarget } from "../lib/ontology-tools.mjs";
|
|
9
|
+
import { n as workflowToolResult } from "../../_chunks/workflow-serializable-BwttWNmY.mjs";
|
|
9
10
|
import { attachmentForModel, attachmentOwner, optionalObject, optionalString, stringArgument, toolAttachments } from "../lib/attachment-tools.mjs";
|
|
10
11
|
import { defineTool } from "eve/tools";
|
|
11
12
|
var attachments_promote_default = defineTool({
|
|
@@ -76,11 +77,11 @@ var attachments_promote_default = defineTool({
|
|
|
76
77
|
...field === void 0 ? {} : { field },
|
|
77
78
|
...recordId === void 0 ? {} : { recordId }
|
|
78
79
|
});
|
|
79
|
-
return {
|
|
80
|
+
return workflowToolResult({
|
|
80
81
|
attachment: attachmentForModel(promoted.attachment),
|
|
81
82
|
deduplicated: promoted.deduplicated,
|
|
82
83
|
result: promoted.result
|
|
83
|
-
};
|
|
84
|
+
}, ctx);
|
|
84
85
|
}
|
|
85
86
|
});
|
|
86
87
|
export { attachments_promote_default as default };
|
|
@@ -4,6 +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 { n as workflowToolResult } from "../../_chunks/workflow-serializable-BwttWNmY.mjs";
|
|
7
8
|
import { ID_INPUT, attachmentOwner, headerArgument, optionalString, pageInteger, readOutput, stringArgument, toolAttachments } from "../lib/attachment-tools.mjs";
|
|
8
9
|
import { readStoredFile } from "../lib/stored-files.mjs";
|
|
9
10
|
import { defineTool } from "eve/tools";
|
|
@@ -64,14 +65,14 @@ var attachments_read_default = defineTool({
|
|
|
64
65
|
id: stringArgument(input, "id"),
|
|
65
66
|
...optionalString(input, "property") === void 0 ? {} : { property: optionalString(input, "property") }
|
|
66
67
|
}, ctx.session.auth.current);
|
|
67
|
-
return readOutput(attachment, bytes, {
|
|
68
|
+
return workflowToolResult(await readOutput(attachment, bytes, {
|
|
68
69
|
sheet: optionalString(input, "sheet"),
|
|
69
70
|
offset: pageInteger(input.offset, 0),
|
|
70
71
|
...input.limit === void 0 ? {} : { limit: pageInteger(input.limit, 100, 5e4) },
|
|
71
72
|
character_offset: pageInteger(input.character_offset, 0),
|
|
72
73
|
...input.header_row === void 0 ? {} : { header_row: headerArgument(input.header_row) },
|
|
73
74
|
...input.date_order === "day_first" || input.date_order === "month_first" ? { date_order: input.date_order } : {}
|
|
74
|
-
});
|
|
75
|
+
}), ctx);
|
|
75
76
|
},
|
|
76
77
|
toModelOutput(output) {
|
|
77
78
|
if (output.kind !== "file") return {
|
|
@@ -1,8 +1,2 @@
|
|
|
1
|
-
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>,
|
|
2
|
-
readonly files: ReadonlyArray<import("../lib/telegram/attachments-send.js").SentFile>;
|
|
3
|
-
} | {
|
|
4
|
-
readonly error: string;
|
|
5
|
-
readonly detail: string;
|
|
6
|
-
readonly reference: string;
|
|
7
|
-
}>;
|
|
1
|
+
declare const _default: import("eve/tools").ToolDefinition<Record<string, unknown>, import("../lib/workflow-serializable.js").WorkflowSerializable>;
|
|
8
2
|
export default _default;
|