agent-relay-server 0.121.5 → 0.122.1
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/docs/openapi.json +1 -1
- package/package.json +6 -6
- package/public/assets/{MessageBubble-CLqxCG9b.js → MessageBubble-DRdUD-kW.js} +2 -2
- package/public/assets/{MessageBubble-CLqxCG9b.js.map → MessageBubble-DRdUD-kW.js.map} +1 -1
- package/public/assets/{PlanGraphPanel-BkkToFEb.js → PlanGraphPanel-siKMPCln.js} +2 -2
- package/public/assets/{PlanGraphPanel-BkkToFEb.js.map → PlanGraphPanel-siKMPCln.js.map} +1 -1
- package/public/assets/{activity-D-ocGQGs.js → activity-D3MNcSaV.js} +2 -2
- package/public/assets/{activity-D-ocGQGs.js.map → activity-D3MNcSaV.js.map} +1 -1
- package/public/assets/{agent-profiles-CRPgYTyb.js → agent-profiles-CKzttq6G.js} +2 -2
- package/public/assets/{agent-profiles-CRPgYTyb.js.map → agent-profiles-CKzttq6G.js.map} +1 -1
- package/public/assets/{agent-type-icon-CeEoMouY.js → agent-type-icon-0ZJRP1Vy.js} +2 -2
- package/public/assets/{agent-type-icon-CeEoMouY.js.map → agent-type-icon-0ZJRP1Vy.js.map} +1 -1
- package/public/assets/{agents-Chw5E_2q.js → agents-CuVj_rfG.js} +2 -2
- package/public/assets/{agents-Chw5E_2q.js.map → agents-CuVj_rfG.js.map} +1 -1
- package/public/assets/{analytics-BmNDG0hR.js → analytics-iob6C27d.js} +2 -2
- package/public/assets/{analytics-BmNDG0hR.js.map → analytics-iob6C27d.js.map} +1 -1
- package/public/assets/{automation-D7g90kTv.js → automation-B2ixxs4q.js} +2 -2
- package/public/assets/{automation-D7g90kTv.js.map → automation-B2ixxs4q.js.map} +1 -1
- package/public/assets/{branch-state-badge-Bv7DhLBZ.js → branch-state-badge-CafBJWKo.js} +2 -2
- package/public/assets/{branch-state-badge-Bv7DhLBZ.js.map → branch-state-badge-CafBJWKo.js.map} +1 -1
- package/public/assets/{channels-CLwPeEPi.js → channels-C-WsbL2H.js} +2 -2
- package/public/assets/{channels-CLwPeEPi.js.map → channels-C-WsbL2H.js.map} +1 -1
- package/public/assets/{chat-Cgj7VKzc.js → chat-DeoVTVob.js} +2 -2
- package/public/assets/{chat-Cgj7VKzc.js.map → chat-DeoVTVob.js.map} +1 -1
- package/public/assets/{connectors-Br6fiTny.js → connectors-C2Ac03LJ.js} +2 -2
- package/public/assets/{connectors-Br6fiTny.js.map → connectors-C2Ac03LJ.js.map} +1 -1
- package/public/assets/display-CJzSoTMq.js +3 -0
- package/public/assets/display-CJzSoTMq.js.map +1 -0
- package/public/assets/{formatted-body-CmkuD23M.js → formatted-body-35XBOY5L.js} +3 -3
- package/public/assets/{formatted-body-CmkuD23M.js.map → formatted-body-35XBOY5L.js.map} +1 -1
- package/public/assets/{formatted-body-impl-DbdFmbwW.js → formatted-body-impl-RmDxI5Ux.js} +2 -2
- package/public/assets/{formatted-body-impl-DbdFmbwW.js.map → formatted-body-impl-RmDxI5Ux.js.map} +1 -1
- package/public/assets/index-D0xMQQb_.js +25 -0
- package/public/assets/{index-D9OogaB5.js.map → index-D0xMQQb_.js.map} +1 -1
- package/public/assets/{insights-qvaPqWCV.js → insights-B643SFvm.js} +2 -2
- package/public/assets/{insights-qvaPqWCV.js.map → insights-B643SFvm.js.map} +1 -1
- package/public/assets/{integrations-DYEGSqq_.js → integrations-hFIHeCF4.js} +2 -2
- package/public/assets/{integrations-DYEGSqq_.js.map → integrations-hFIHeCF4.js.map} +1 -1
- package/public/assets/{maintenance-C0HIEB-J.js → maintenance-CURvdp_Z.js} +2 -2
- package/public/assets/{maintenance-C0HIEB-J.js.map → maintenance-CURvdp_Z.js.map} +1 -1
- package/public/assets/{managed-agents-DdS7aI38.js → managed-agents-DrZtdlSn.js} +2 -2
- package/public/assets/{managed-agents-DdS7aI38.js.map → managed-agents-DrZtdlSn.js.map} +1 -1
- package/public/assets/{markdown-preview-impl-BnXMH1z1.js → markdown-preview-impl-CVDO--ek.js} +2 -2
- package/public/assets/{markdown-preview-impl-BnXMH1z1.js.map → markdown-preview-impl-CVDO--ek.js.map} +1 -1
- package/public/assets/{memory-CSwx7bz8.js → memory-Bm7dt_Qf.js} +2 -2
- package/public/assets/{memory-CSwx7bz8.js.map → memory-Bm7dt_Qf.js.map} +1 -1
- package/public/assets/{messages-Be9CmvDv.js → messages-DTq4i2KZ.js} +2 -2
- package/public/assets/{messages-Be9CmvDv.js.map → messages-DTq4i2KZ.js.map} +1 -1
- package/public/assets/{orchestrators-BgtvvHvo.js → orchestrators-Dra318Ap.js} +2 -2
- package/public/assets/{orchestrators-BgtvvHvo.js.map → orchestrators-Dra318Ap.js.map} +1 -1
- package/public/assets/{overview-BvhbPWtF.js → overview-yr1Vmk64.js} +2 -2
- package/public/assets/{overview-BvhbPWtF.js.map → overview-yr1Vmk64.js.map} +1 -1
- package/public/assets/{pairs-CpXSOMx0.js → pairs-mnlKDBGp.js} +2 -2
- package/public/assets/{pairs-CpXSOMx0.js.map → pairs-mnlKDBGp.js.map} +1 -1
- package/public/assets/projects-Dzdf-gkK.js +2 -0
- package/public/assets/{projects-DdPNPFJI.js.map → projects-Dzdf-gkK.js.map} +1 -1
- package/public/assets/prompt-settings-ByL8SNCi.js +2 -0
- package/public/assets/{prompt-settings-BpZse7-X.js.map → prompt-settings-ByL8SNCi.js.map} +1 -1
- package/public/assets/{registry-pb1gTZEg.js → registry-CXWyOtpr.js} +2 -2
- package/public/assets/{registry-pb1gTZEg.js.map → registry-CXWyOtpr.js.map} +1 -1
- package/public/assets/{security-BgcX1n9D.js → security-0SBsc_4W.js} +2 -2
- package/public/assets/{security-BgcX1n9D.js.map → security-0SBsc_4W.js.map} +1 -1
- package/public/assets/{select-DZPVpKPv.js → select-Bw5z2KJ_.js} +2 -2
- package/public/assets/{select-DZPVpKPv.js.map → select-Bw5z2KJ_.js.map} +1 -1
- package/public/assets/{settings-hd5kzdRB.js → settings-78Cyq_tA.js} +4 -4
- package/public/assets/{settings-hd5kzdRB.js.map → settings-78Cyq_tA.js.map} +1 -1
- package/public/assets/{store-DKTLubBT.js → store-BPrVuKiv.js} +4 -4
- package/public/assets/store-BPrVuKiv.js.map +1 -0
- package/public/assets/{tasks-C5d2LU5E.js → tasks-Cg2MMeri.js} +2 -2
- package/public/assets/{tasks-C5d2LU5E.js.map → tasks-Cg2MMeri.js.map} +1 -1
- package/public/assets/teams-DWv6UwFV.js +2 -0
- package/public/assets/{teams-B8f2pGJe.js.map → teams-DWv6UwFV.js.map} +1 -1
- package/public/assets/{terminal-viewer-impl-CxAscH0U.js → terminal-viewer-impl-DBLDjbIg.js} +2 -2
- package/public/assets/{terminal-viewer-impl-CxAscH0U.js.map → terminal-viewer-impl-DBLDjbIg.js.map} +1 -1
- package/public/assets/{types-uVOXgvMT.js → types-BeJUSfDj.js} +2 -2
- package/public/assets/types-BeJUSfDj.js.map +1 -0
- package/public/assets/{user-avatar-Dw6mzWhv.js → user-avatar-BsOLyVJj.js} +2 -2
- package/public/assets/{user-avatar-Dw6mzWhv.js.map → user-avatar-BsOLyVJj.js.map} +1 -1
- package/public/assets/{work-queue-9imc7aNK.js → work-queue-DmwvnF6F.js} +2 -2
- package/public/assets/{work-queue-9imc7aNK.js.map → work-queue-DmwvnF6F.js.map} +1 -1
- package/public/assets/{workspaces-CLYc3yF3.js → workspaces-dIBivJN8.js} +2 -2
- package/public/assets/{workspaces-CLYc3yF3.js.map → workspaces-dIBivJN8.js.map} +1 -1
- package/public/index.html +6 -6
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +44 -938
- package/runner/src/adapter.ts +53 -18
- package/runner/src/adapters/claude-delivery.ts +127 -0
- package/runner/src/adapters/claude-quota-harvest.ts +92 -0
- package/runner/src/adapters/claude-session-probe.ts +225 -0
- package/runner/src/adapters/claude-status-detectors.ts +147 -0
- package/runner/src/adapters/claude-transcript-tail.ts +128 -0
- package/runner/src/adapters/claude-transcript.ts +414 -0
- package/runner/src/adapters/claude.ts +672 -0
- package/runner/src/adapters/codex-agent-message-capture.ts +139 -0
- package/runner/src/adapters/codex-client.ts +279 -0
- package/runner/src/adapters/codex.ts +1345 -0
- package/runner/src/attachment-cache.ts +189 -0
- package/runner/src/busy-reconciler.ts +102 -0
- package/runner/src/claim-tracker.ts +140 -0
- package/runner/src/claude-prompt-gates.ts +268 -0
- package/runner/src/config.ts +1 -4
- package/runner/src/context-probe-state.ts +6 -0
- package/runner/src/continuation-archive.ts +179 -0
- package/runner/src/control-server.ts +639 -0
- package/runner/src/index.ts +396 -0
- package/runner/src/launch-assembly.ts +508 -0
- package/runner/src/liveness.ts +50 -0
- package/runner/src/logger.ts +99 -0
- package/runner/src/mcp-outbox.ts +120 -0
- package/runner/src/message-body-config/config.ts +3 -0
- package/runner/src/message-body-config.ts +1 -0
- package/runner/src/native-self-resume.ts +202 -0
- package/runner/src/outbox.ts +342 -0
- package/runner/src/process-meta.ts +9 -0
- package/runner/src/profile-home.ts +260 -0
- package/runner/src/profile-projection.ts +305 -0
- package/runner/src/providers.ts +20 -0
- package/runner/src/provisioning.ts +314 -0
- package/runner/src/quota.ts +40 -0
- package/runner/src/rate-limit.ts +189 -0
- package/runner/src/relay-injection-events.ts +102 -0
- package/runner/src/relay-instructions.ts +60 -0
- package/runner/src/relay-mcp-proxy.ts +383 -0
- package/runner/src/relay-mcp.ts +156 -0
- package/runner/src/reply-obligation-cache.ts +136 -0
- package/runner/src/response-capture-report.ts +63 -0
- package/runner/src/runner-core.ts +2409 -0
- package/runner/src/runner-helpers.ts +435 -0
- package/runner/src/runner-insights.ts +105 -0
- package/runner/src/runner.ts +14 -0
- package/runner/src/session-destroy.ts +22 -0
- package/runner/src/session-insights.ts +118 -0
- package/runner/src/session-scratch.ts +271 -0
- package/runner/src/template-resolver.ts +29 -0
- package/runner/src/version.ts +43 -0
- package/src/agent-card-projection.ts +5 -1
- package/src/agent-command-activity.ts +39 -0
- package/src/automations/reconcile.ts +2 -2
- package/src/cli/workspace.ts +3 -1
- package/src/config.ts +10 -1
- package/src/db/agents.ts +118 -37
- package/src/db/message-reads.ts +50 -0
- package/src/db/messages.ts +48 -9
- package/src/db/migrations.ts +54 -0
- package/src/db/provider-quota-burn.ts +96 -67
- package/src/db/provider-quotas.ts +29 -7
- package/src/db/scheduled-timers.ts +21 -0
- package/src/db/schema.ts +1 -0
- package/src/db/tasks.ts +33 -3
- package/src/db/work-evidence.ts +10 -7
- package/src/event-loop-lag.ts +15 -0
- package/src/gate-resolver.ts +19 -1
- package/src/maintenance/jobs.ts +23 -6
- package/src/managed-policy.ts +5 -12
- package/src/mcp-plan-tools.ts +13 -1
- package/src/project-instructions.ts +36 -2
- package/src/quota-advisory.ts +6 -4
- package/src/quota-band-transition.ts +23 -14
- package/src/routes/agent-sessions.ts +39 -7
- package/src/routes/agents.ts +3 -2
- package/src/routes/tasks.ts +16 -4
- package/src/routes/workspaces.ts +35 -10
- package/src/services/plan-graph.ts +27 -9
- package/src/services/register-agent.ts +12 -12
- package/src/services/send-message.ts +43 -15
- package/src/services/spawn-agent.ts +3 -0
- package/src/spawn-command.ts +8 -0
- package/src/spawn-targets.ts +19 -34
- package/src/sse.ts +25 -3
- package/src/workspace-merge.ts +25 -5
- package/src/workspace-orphans.ts +13 -6
- package/public/assets/display-exQDWum3.js +0 -3
- package/public/assets/display-exQDWum3.js.map +0 -1
- package/public/assets/index-D9OogaB5.js +0 -25
- package/public/assets/projects-DdPNPFJI.js +0 -2
- package/public/assets/prompt-settings-BpZse7-X.js +0 -2
- package/public/assets/store-DKTLubBT.js.map +0 -1
- package/public/assets/teams-B8f2pGJe.js +0 -2
- package/public/assets/types-uVOXgvMT.js.map +0 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { ReplyObligation } from "agent-relay-sdk";
|
|
2
|
+
import { errMessage } from "agent-relay-sdk";
|
|
3
|
+
import { logger } from "./logger";
|
|
4
|
+
|
|
5
|
+
// Phase 2 (#196) — the crux. The Claude Stop hook used to ask the server, synchronously
|
|
6
|
+
// and in the hot path, "does this agent owe a reply?" before clearing the turn. A slow
|
|
7
|
+
// server answer (the unindexed reply_to scan, #199) blew the hook's timeout and wedged the
|
|
8
|
+
// agent in `busy` forever. The fix: the hook asks the Runner, the Runner answers instantly
|
|
9
|
+
// from this local snapshot, and the snapshot is refreshed from the server only in the
|
|
10
|
+
// background — never on the path that ends a turn.
|
|
11
|
+
//
|
|
12
|
+
// Design rules:
|
|
13
|
+
// - `get()` is synchronous, never throws, never touches the network.
|
|
14
|
+
// - `refresh()` is the only thing that talks to the server; it coalesces concurrent calls
|
|
15
|
+
// and, on failure, keeps the last-known snapshot (stale-but-serving beats blocking).
|
|
16
|
+
// - A background interval keeps the snapshot warm; `markDirty()` requests an extra,
|
|
17
|
+
// debounced refresh when state likely just changed (a message arrived, a turn ended).
|
|
18
|
+
|
|
19
|
+
// #418 — the human `user` sink is NOT delivered via an explicit relay reply: the agent's
|
|
20
|
+
// turn is mirrored to the dashboard chat by the session-mirror lane (always, for managed
|
|
21
|
+
// agents). So an explicit `/reply` to `user` double-delivers — the operator sees the mirrored
|
|
22
|
+
// turn AND the explicit copy. Only agent↔agent / spawner obligations (#413) need an explicit
|
|
23
|
+
// reply to clear and reach their recipient. This is the single home for that distinction —
|
|
24
|
+
// both the Claude Stop-hook nag (control-server) and the non-claude re-injection (runner)
|
|
25
|
+
// gate on it, so the rule must not drift between them.
|
|
26
|
+
export function obligationRequiresExplicitReply(obligation: ReplyObligation): boolean {
|
|
27
|
+
if (obligation.source === "spawn-obligation") return false;
|
|
28
|
+
return obligation.from !== "user";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function responseCaptureReplyRoute(
|
|
32
|
+
obligations: ReplyObligation[],
|
|
33
|
+
currentTurnStartedAt?: number,
|
|
34
|
+
opts: { suppressUser?: boolean } = {},
|
|
35
|
+
): { replyToMessageId?: number; to: string } | null {
|
|
36
|
+
const eligible = [...obligations].reverse()
|
|
37
|
+
.filter((o) => currentTurnStartedAt === undefined || o.createdAt <= currentTurnStartedAt);
|
|
38
|
+
const explicit = eligible.find(obligationRequiresExplicitReply);
|
|
39
|
+
if (explicit) return { replyToMessageId: explicit.messageId, to: explicit.from };
|
|
40
|
+
const user = eligible.find((o) => o.from === "user");
|
|
41
|
+
if (!user) return { to: "user" };
|
|
42
|
+
return opts.suppressUser ? null : { replyToMessageId: user.messageId, to: "user" };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type ReplyObligationFetch = () => Promise<ReplyObligation[]>;
|
|
46
|
+
|
|
47
|
+
interface ReplyObligationCacheOptions {
|
|
48
|
+
fetch: ReplyObligationFetch;
|
|
49
|
+
// Background freshness backstop. Default 10s — well under any turn cadence, cheap.
|
|
50
|
+
intervalMs?: number;
|
|
51
|
+
// Debounce window for markDirty()-triggered refreshes so a burst of events
|
|
52
|
+
// (e.g. a fan-out of messages) collapses into one server round-trip.
|
|
53
|
+
dirtyDebounceMs?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const DEFAULT_INTERVAL_MS = 10_000;
|
|
57
|
+
const DEFAULT_DIRTY_DEBOUNCE_MS = 400;
|
|
58
|
+
|
|
59
|
+
export class ReplyObligationCache {
|
|
60
|
+
private readonly fetch: ReplyObligationFetch;
|
|
61
|
+
private readonly intervalMs: number;
|
|
62
|
+
private readonly dirtyDebounceMs: number;
|
|
63
|
+
|
|
64
|
+
private snapshot: ReplyObligation[] = [];
|
|
65
|
+
private lastRefreshedAt = 0;
|
|
66
|
+
private inFlight: Promise<void> | null = null;
|
|
67
|
+
private intervalTimer?: ReturnType<typeof setInterval>;
|
|
68
|
+
private dirtyTimer?: ReturnType<typeof setTimeout>;
|
|
69
|
+
private stopped = false;
|
|
70
|
+
|
|
71
|
+
constructor(options: ReplyObligationCacheOptions) {
|
|
72
|
+
this.fetch = options.fetch;
|
|
73
|
+
this.intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
74
|
+
this.dirtyDebounceMs = options.dirtyDebounceMs ?? DEFAULT_DIRTY_DEBOUNCE_MS;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Synchronous, hot-path-safe read. Returns a copy so callers can't mutate the snapshot.
|
|
78
|
+
get(): ReplyObligation[] {
|
|
79
|
+
return this.snapshot.slice();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getLastRefreshedAt(): number {
|
|
83
|
+
return this.lastRefreshedAt;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Begin the background freshness loop and prime the first snapshot immediately.
|
|
87
|
+
start(): void {
|
|
88
|
+
if (this.intervalTimer || this.stopped) return;
|
|
89
|
+
void this.refresh();
|
|
90
|
+
this.intervalTimer = setInterval(() => { void this.refresh(); }, this.intervalMs);
|
|
91
|
+
// Don't keep the process alive solely for cache refreshes.
|
|
92
|
+
this.intervalTimer.unref?.();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
stop(): void {
|
|
96
|
+
this.stopped = true;
|
|
97
|
+
if (this.intervalTimer) clearInterval(this.intervalTimer);
|
|
98
|
+
this.intervalTimer = undefined;
|
|
99
|
+
if (this.dirtyTimer) clearTimeout(this.dirtyTimer);
|
|
100
|
+
this.dirtyTimer = undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Request a refresh because state likely changed (message arrived / turn ended).
|
|
104
|
+
// Debounced so a burst collapses into a single server round-trip.
|
|
105
|
+
markDirty(): void {
|
|
106
|
+
if (this.stopped || this.dirtyTimer) return;
|
|
107
|
+
this.dirtyTimer = setTimeout(() => {
|
|
108
|
+
this.dirtyTimer = undefined;
|
|
109
|
+
void this.refresh();
|
|
110
|
+
}, this.dirtyDebounceMs);
|
|
111
|
+
this.dirtyTimer.unref?.();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Fetch from the server and replace the snapshot. Coalesces concurrent callers onto a
|
|
115
|
+
// single in-flight request. Never rejects — a failed fetch leaves the prior snapshot in
|
|
116
|
+
// place (the hook keeps getting an answer even while the server is down).
|
|
117
|
+
refresh(): Promise<void> {
|
|
118
|
+
if (this.stopped) return Promise.resolve();
|
|
119
|
+
if (this.inFlight) return this.inFlight;
|
|
120
|
+
this.inFlight = this.doRefresh().finally(() => { this.inFlight = null; });
|
|
121
|
+
return this.inFlight;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private async doRefresh(): Promise<void> {
|
|
125
|
+
try {
|
|
126
|
+
const obligations = await this.fetch();
|
|
127
|
+
if (this.stopped) return;
|
|
128
|
+
this.snapshot = Array.isArray(obligations) ? obligations : [];
|
|
129
|
+
this.lastRefreshedAt = Date.now();
|
|
130
|
+
} catch (error) {
|
|
131
|
+
// Server-down is a non-event: keep serving the last snapshot. Debug, not error —
|
|
132
|
+
// this is expected during outages and must not spam the log.
|
|
133
|
+
logger.debug("obligation-cache", `refresh failed, serving cached snapshot (${this.snapshot.length}): ${errMessage(error)}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { MessageSessionMeta, SendMessageInput } from "agent-relay-sdk";
|
|
2
|
+
|
|
3
|
+
interface ReportOutbox {
|
|
4
|
+
enqueue(record: { kind: string; idempotencyKey?: string; payload: SendMessageInput }): void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type SessionPublisher = (input: {
|
|
8
|
+
from: string;
|
|
9
|
+
to: string;
|
|
10
|
+
body: string;
|
|
11
|
+
session: MessageSessionMeta;
|
|
12
|
+
replyTo?: number;
|
|
13
|
+
}) => void | Promise<void>;
|
|
14
|
+
|
|
15
|
+
function finalSession(session: MessageSessionMeta): MessageSessionMeta {
|
|
16
|
+
return { ...session, final: true };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function publishCapturedResponse(input: {
|
|
20
|
+
publishSessionEvent: SessionPublisher;
|
|
21
|
+
outbox: ReportOutbox;
|
|
22
|
+
provider: string;
|
|
23
|
+
from: string;
|
|
24
|
+
to: string;
|
|
25
|
+
body: string;
|
|
26
|
+
session: MessageSessionMeta;
|
|
27
|
+
replyTo?: number;
|
|
28
|
+
}): Promise<void> {
|
|
29
|
+
await input.publishSessionEvent({
|
|
30
|
+
from: input.from,
|
|
31
|
+
to: input.to,
|
|
32
|
+
body: input.body,
|
|
33
|
+
...(input.replyTo ? { replyTo: input.replyTo } : {}),
|
|
34
|
+
session: finalSession(input.session),
|
|
35
|
+
});
|
|
36
|
+
enqueueCapturedResponseReport(input);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function enqueueCapturedResponseReport(input: {
|
|
40
|
+
outbox: ReportOutbox;
|
|
41
|
+
provider: string;
|
|
42
|
+
from: string;
|
|
43
|
+
to: string;
|
|
44
|
+
body: string;
|
|
45
|
+
session: MessageSessionMeta;
|
|
46
|
+
replyTo?: number;
|
|
47
|
+
}): void {
|
|
48
|
+
if (!input.replyTo || input.to === "user") return;
|
|
49
|
+
const turnId = input.session.turnId ?? "";
|
|
50
|
+
input.outbox.enqueue({
|
|
51
|
+
kind: "session-message",
|
|
52
|
+
idempotencyKey: `response-report:${input.from}:${input.replyTo}:${turnId}`,
|
|
53
|
+
payload: {
|
|
54
|
+
from: input.from,
|
|
55
|
+
to: input.to,
|
|
56
|
+
replyTo: input.replyTo,
|
|
57
|
+
kind: "chat",
|
|
58
|
+
body: input.body,
|
|
59
|
+
replyExpected: false,
|
|
60
|
+
payload: { responseCapture: { provider: input.provider, ...finalSession(input.session) } },
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|