managed-deepagents 0.10.0-dev.1 → 0.10.0-dev.11
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 +240 -21
- package/dist/agent-auth.d.ts +13 -0
- package/dist/agent-auth.d.ts.map +1 -1
- package/dist/agent-auth.js +16 -1
- package/dist/agent-auth.js.map +1 -1
- package/dist/channels/github/connections.d.ts.map +1 -1
- package/dist/channels/github/connections.js +2 -2
- package/dist/channels/github/connections.js.map +1 -1
- package/dist/channels/github/index.d.ts +2 -9
- package/dist/channels/github/index.d.ts.map +1 -1
- package/dist/channels/github/index.js +72 -140
- package/dist/channels/github/index.js.map +1 -1
- package/dist/channels/github/schema.d.ts.map +1 -1
- package/dist/channels/github/schema.js +1 -3
- package/dist/channels/github/schema.js.map +1 -1
- package/dist/channels/github/types.d.ts +50 -10
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/http/endpoint.d.ts +63 -0
- package/dist/channels/http/endpoint.d.ts.map +1 -0
- package/dist/channels/http/endpoint.js +132 -0
- package/dist/channels/http/endpoint.js.map +1 -0
- package/dist/channels/http/http.d.ts.map +1 -1
- package/dist/channels/http/http.js +233 -66
- package/dist/channels/http/http.js.map +1 -1
- package/dist/channels/http/index.d.ts +1 -1
- package/dist/channels/http/index.d.ts.map +1 -1
- package/dist/channels/http/index.js.map +1 -1
- package/dist/channels/http/ingress.d.ts +34 -3
- package/dist/channels/http/ingress.d.ts.map +1 -1
- package/dist/channels/http/ingress.js +40 -24
- package/dist/channels/http/ingress.js.map +1 -1
- package/dist/channels/http/provider.d.ts +99 -0
- package/dist/channels/http/provider.d.ts.map +1 -0
- package/dist/channels/http/provider.js +188 -0
- package/dist/channels/http/provider.js.map +1 -0
- package/dist/channels/http/reply.d.ts +20 -0
- package/dist/channels/http/reply.d.ts.map +1 -0
- package/dist/channels/http/reply.js +116 -0
- package/dist/channels/http/reply.js.map +1 -0
- package/dist/channels/http/studio.d.ts +17 -0
- package/dist/channels/http/studio.d.ts.map +1 -0
- package/dist/channels/http/studio.js +82 -0
- package/dist/channels/http/studio.js.map +1 -0
- package/dist/channels/http/types.d.ts +77 -6
- package/dist/channels/http/types.d.ts.map +1 -1
- package/dist/channels/linear/connections.d.ts +11 -0
- package/dist/channels/linear/connections.d.ts.map +1 -0
- package/dist/channels/linear/connections.js +14 -0
- package/dist/channels/linear/connections.js.map +1 -0
- package/dist/channels/linear/graphql.d.ts +57 -0
- package/dist/channels/linear/graphql.d.ts.map +1 -0
- package/dist/channels/linear/graphql.js +167 -0
- package/dist/channels/linear/graphql.js.map +1 -0
- package/dist/channels/linear/index.d.ts +9 -0
- package/dist/channels/linear/index.d.ts.map +1 -0
- package/dist/channels/linear/index.js +477 -0
- package/dist/channels/linear/index.js.map +1 -0
- package/dist/channels/linear/schema.d.ts +1064 -0
- package/dist/channels/linear/schema.d.ts.map +1 -0
- package/dist/channels/linear/schema.js +249 -0
- package/dist/channels/linear/schema.js.map +1 -0
- package/dist/channels/linear/types.d.ts +152 -0
- package/dist/channels/linear/types.d.ts.map +1 -0
- package/dist/channels/linear/types.js +2 -0
- package/dist/channels/linear/types.js.map +1 -0
- package/dist/channels/message-schema.d.ts +2 -0
- package/dist/channels/message-schema.d.ts.map +1 -1
- package/dist/channels/message-schema.js +4 -0
- package/dist/channels/message-schema.js.map +1 -1
- package/dist/channels/reserved-connections.d.ts +2 -2
- package/dist/channels/reserved-connections.d.ts.map +1 -1
- package/dist/channels/reserved-connections.js +26 -9
- package/dist/channels/reserved-connections.js.map +1 -1
- package/dist/channels/run-input.d.ts +17 -1
- package/dist/channels/run-input.d.ts.map +1 -1
- package/dist/channels/run-input.js +39 -5
- package/dist/channels/run-input.js.map +1 -1
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +2 -0
- package/dist/channels/slack/index.js.map +1 -1
- package/dist/channels/slack/message-content.d.ts +25 -0
- package/dist/channels/slack/message-content.d.ts.map +1 -0
- package/dist/channels/slack/message-content.js +237 -0
- package/dist/channels/slack/message-content.js.map +1 -0
- package/dist/channels/source-providers.js +1 -1
- package/dist/channels/source-providers.js.map +1 -1
- package/dist/channels/trigger/client.js +7 -3
- package/dist/channels/trigger/client.js.map +1 -1
- package/dist/channels/trigger/http.d.ts +3 -1
- package/dist/channels/trigger/http.d.ts.map +1 -1
- package/dist/channels/trigger/http.js +7 -4
- package/dist/channels/trigger/http.js.map +1 -1
- package/dist/channels/trigger/tracing-project.d.ts +16 -0
- package/dist/channels/trigger/tracing-project.d.ts.map +1 -0
- package/dist/channels/trigger/tracing-project.js +54 -0
- package/dist/channels/trigger/tracing-project.js.map +1 -0
- package/dist/channels/trigger/types.d.ts +12 -2
- package/dist/channels/trigger/types.d.ts.map +1 -1
- package/dist/channels/trigger/types.js.map +1 -1
- package/dist/connections.d.ts +30 -0
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +80 -7
- package/dist/connections.js.map +1 -1
- package/dist/connectors/mcp/index.d.ts.map +1 -1
- package/dist/connectors/mcp/index.js +52 -2
- package/dist/connectors/mcp/index.js.map +1 -1
- package/dist/connectors/mcp/langsmith-url.js +2 -2
- package/dist/connectors/mcp/langsmith-url.js.map +1 -1
- package/dist/credential-gate.d.ts.map +1 -1
- package/dist/credential-gate.js +24 -3
- package/dist/credential-gate.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ingress/runs.d.ts +7 -0
- package/dist/ingress/runs.d.ts.map +1 -1
- package/dist/ingress/runs.js +34 -1
- package/dist/ingress/runs.js.map +1 -1
- package/dist/namespaces.d.ts +15 -0
- package/dist/namespaces.d.ts.map +1 -1
- package/dist/namespaces.js +2 -0
- package/dist/namespaces.js.map +1 -1
- package/dist/runtime/auth.d.ts +4 -6
- package/dist/runtime/auth.d.ts.map +1 -1
- package/dist/runtime/auth.js +165 -31
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/channel-icon.d.ts +22 -0
- package/dist/runtime/channel-icon.d.ts.map +1 -0
- package/dist/runtime/channel-icon.js +70 -0
- package/dist/runtime/channel-icon.js.map +1 -0
- package/dist/runtime/channel.d.ts +6 -0
- package/dist/runtime/channel.d.ts.map +1 -1
- package/dist/runtime/channel.js.map +1 -1
- package/dist/runtime/identity-http.d.ts +2 -0
- package/dist/runtime/identity-http.d.ts.map +1 -1
- package/dist/runtime/identity-http.js +35 -0
- package/dist/runtime/identity-http.js.map +1 -1
- package/dist/runtime/identity-runtime.d.ts +15 -0
- package/dist/runtime/identity-runtime.d.ts.map +1 -1
- package/dist/runtime/identity-runtime.js +35 -0
- package/dist/runtime/identity-runtime.js.map +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +9 -4
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/sandbox-manager.d.ts +11 -0
- package/dist/runtime/sandbox-manager.d.ts.map +1 -1
- package/dist/runtime/sandbox-manager.js +70 -5
- package/dist/runtime/sandbox-manager.js.map +1 -1
- package/dist/runtime/schedule-auth.d.ts +1 -0
- package/dist/runtime/schedule-auth.d.ts.map +1 -1
- package/dist/runtime/schedule-auth.js +68 -2
- package/dist/runtime/schedule-auth.js.map +1 -1
- package/dist/runtime/types.d.ts +5 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime-schedules.d.ts.map +1 -1
- package/dist/runtime-schedules.js +8 -12
- package/dist/runtime-schedules.js.map +1 -1
- package/package.json +7 -7
|
@@ -38,9 +38,40 @@ export type HttpIngressStart = StartedIngressRun | {
|
|
|
38
38
|
export declare function waitForHttpIngressThread(input: HttpIngressSource & {
|
|
39
39
|
threadId: string;
|
|
40
40
|
}): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Cancel the thread's queued and running runs, keeping their progress.
|
|
43
|
+
* Returns the IDs of the runs it cancelled.
|
|
44
|
+
*/
|
|
45
|
+
export declare function cancelHttpIngressRuns(input: {
|
|
46
|
+
userId: string;
|
|
47
|
+
sourceThreadKey: string;
|
|
48
|
+
sourceProvider: string;
|
|
49
|
+
threadId: string;
|
|
50
|
+
}): Promise<string[]>;
|
|
41
51
|
export declare function startHttpIngressAgent(input: StartHttpIngressInput): Promise<HttpIngressStart>;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
/** How a channel run ended; the run posts its own answer. */
|
|
53
|
+
export type HttpIngressOutcome =
|
|
54
|
+
/** It finished. */
|
|
55
|
+
{
|
|
56
|
+
type: "answered";
|
|
57
|
+
}
|
|
58
|
+
/** It stopped on interrupts, so the thread waits on a decision. */
|
|
59
|
+
| {
|
|
60
|
+
type: "paused";
|
|
61
|
+
assistantId?: string;
|
|
62
|
+
}
|
|
63
|
+
/** It was cancelled, with nothing left to answer. */
|
|
64
|
+
| {
|
|
65
|
+
type: "cancelled";
|
|
66
|
+
}
|
|
67
|
+
/** A newer message's `rollback` deleted it. */
|
|
68
|
+
| {
|
|
69
|
+
type: "replaced";
|
|
70
|
+
}
|
|
71
|
+
/** It failed. */
|
|
72
|
+
| {
|
|
73
|
+
type: "failed";
|
|
74
|
+
};
|
|
75
|
+
export declare function observeHttpIngressAgent(input: HttpIngressSource & StartedIngressRun): Promise<HttpIngressOutcome>;
|
|
45
76
|
export {};
|
|
46
77
|
//# sourceMappingURL=ingress.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingress.d.ts","sourceRoot":"","sources":["../../../src/channels/http/ingress.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"ingress.d.ts","sourceRoot":"","sources":["../../../src/channels/http/ingress.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAIlC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,OAAO,EASL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAS1D,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED,UAAU,qBAAsB,SAAQ,iBAAiB;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAED,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GACxB,iBAAiB,GACjB;IACE,OAAO,EAAE,QAAQ,CAAC;IAClB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IAAE,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;CAAE,CAAC;AAE/D,qEAAqE;AACrE,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CASpB;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CA2E3B;AA8CD,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB;AAC5B,mBAAmB;AACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE;AACtB,mEAAmE;GACjE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AAC1C,qDAAqD;GACnD;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE;AACvB,+CAA+C;GAC7C;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE;AACtB,iBAAiB;GACf;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvB,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,GAC3C,OAAO,CAAC,kBAAkB,CAAC,CA6C7B"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/** HTTP content and reply handling around the shared ingress run lifecycle. */
|
|
2
2
|
import { INTERRUPT } from "@langchain/langgraph";
|
|
3
3
|
import { HumanMessage, } from "@langchain/core/messages";
|
|
4
|
-
import { extractAssistantContent } from "../assistant-text.js";
|
|
5
4
|
import { logger } from "../../runtime/log.js";
|
|
6
5
|
import { buildIngressRunContext } from "../../ingress/index.js";
|
|
7
6
|
import { ChannelError } from "../errors.js";
|
|
8
|
-
import { validateMessage } from "../runtime.js";
|
|
9
7
|
import { createIngressLoopbackClient, hasLoopbackCredential, } from "../../ingress/loopback.js";
|
|
10
|
-
import { DELIVERY_KEY_METADATA, ingressThreadState, lookupStatus, startIngressRun, waitForIdleThread, observeIngressRun, recordThreadDelivery, } from "../../ingress/runs.js";
|
|
8
|
+
import { DELIVERY_KEY_METADATA, cancelIngressRuns, ingressThreadState, lookupStatus, startIngressRun, waitForIdleThread, observeIngressRun, recordThreadDelivery, } from "../../ingress/runs.js";
|
|
11
9
|
/** Wait until the thread's queued and running runs have finished. */
|
|
12
10
|
export async function waitForHttpIngressThread(input) {
|
|
13
11
|
const client = createIngressLoopbackClient({
|
|
@@ -17,6 +15,17 @@ export async function waitForHttpIngressThread(input) {
|
|
|
17
15
|
});
|
|
18
16
|
await waitForIdleThread(client, input.threadId);
|
|
19
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Cancel the thread's queued and running runs, keeping their progress.
|
|
20
|
+
* Returns the IDs of the runs it cancelled.
|
|
21
|
+
*/
|
|
22
|
+
export async function cancelHttpIngressRuns(input) {
|
|
23
|
+
if (!hasLoopbackCredential()) {
|
|
24
|
+
throw new ChannelError("channel_run_failed", "managed loopback authentication is not configured");
|
|
25
|
+
}
|
|
26
|
+
const client = createIngressLoopbackClient(input);
|
|
27
|
+
return cancelIngressRuns(client, input.threadId);
|
|
28
|
+
}
|
|
20
29
|
export async function startHttpIngressAgent(input) {
|
|
21
30
|
if (!hasLoopbackCredential()) {
|
|
22
31
|
throw new ChannelError("channel_run_failed", "managed loopback authentication is not configured");
|
|
@@ -27,9 +36,6 @@ export async function startHttpIngressAgent(input) {
|
|
|
27
36
|
sourceProvider: input.sourceProvider ?? input.binding.provider,
|
|
28
37
|
});
|
|
29
38
|
const { state, assistantId } = await ingressThreadState(client, input.threadId, input.deliveryKey);
|
|
30
|
-
const metadata = input.deliveryKey !== undefined && {
|
|
31
|
-
metadata: { [DELIVERY_KEY_METADATA]: input.deliveryKey },
|
|
32
|
-
};
|
|
33
39
|
// A new turn would abandon the decision the thread waits on.
|
|
34
40
|
if (state === "paused")
|
|
35
41
|
return {
|
|
@@ -48,12 +54,20 @@ export async function startHttpIngressAgent(input) {
|
|
|
48
54
|
: await input.prepare?.();
|
|
49
55
|
if (!prepared)
|
|
50
56
|
return { skipped: "ignored" };
|
|
57
|
+
// The handler's metadata goes under MDA's own.
|
|
58
|
+
const metadata = {
|
|
59
|
+
...prepared.metadata,
|
|
60
|
+
...(input.deliveryKey !== undefined && {
|
|
61
|
+
[DELIVERY_KEY_METADATA]: input.deliveryKey,
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
51
64
|
let started;
|
|
52
65
|
try {
|
|
53
66
|
started = await startIngressRun(client, {
|
|
54
67
|
threadId: input.threadId,
|
|
55
68
|
assistantId: input.assistantId,
|
|
56
|
-
...metadata,
|
|
69
|
+
...(Object.keys(metadata).length && { metadata }),
|
|
70
|
+
...(prepared.webhook !== undefined && { webhook: prepared.webhook }),
|
|
57
71
|
multitaskStrategy: strategy,
|
|
58
72
|
messages: prepared.messages,
|
|
59
73
|
...(Object.keys(prepared.state).length && { state: prepared.state }),
|
|
@@ -134,15 +148,23 @@ export async function observeHttpIngressAgent(input) {
|
|
|
134
148
|
if (lookupStatus(error) !== 404)
|
|
135
149
|
throw error;
|
|
136
150
|
logger.info(`channel run was replaced ${JSON.stringify({ threadId: input.threadId })}`);
|
|
137
|
-
return {
|
|
151
|
+
return { type: "replaced" };
|
|
138
152
|
}
|
|
139
153
|
const { values, status } = observed;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
154
|
+
// A cancelled run ends `interrupted` too; only pending interrupts pause.
|
|
155
|
+
const paused = async () => {
|
|
156
|
+
const { state, assistantId } = await ingressThreadState(client, input.threadId);
|
|
157
|
+
if (state === "paused")
|
|
158
|
+
return {
|
|
159
|
+
type: "paused",
|
|
160
|
+
...(assistantId !== undefined && { assistantId }),
|
|
161
|
+
};
|
|
162
|
+
return { type: status === "interrupted" ? "cancelled" : "answered" };
|
|
163
|
+
};
|
|
164
|
+
if (status === "interrupted")
|
|
165
|
+
return await paused();
|
|
166
|
+
if (status !== "success")
|
|
167
|
+
return { type: "failed" };
|
|
146
168
|
const state = values && typeof values === "object" && !Array.isArray(values)
|
|
147
169
|
? values
|
|
148
170
|
: {};
|
|
@@ -150,15 +172,9 @@ export async function observeHttpIngressAgent(input) {
|
|
|
150
172
|
const interrupted = interrupts &&
|
|
151
173
|
typeof interrupts === "object" &&
|
|
152
174
|
Object.keys(interrupts).length > 0;
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
return
|
|
156
|
-
|
|
157
|
-
validateMessage(reply);
|
|
158
|
-
return {
|
|
159
|
-
replyContent: reply.content,
|
|
160
|
-
threadId: input.threadId,
|
|
161
|
-
runId: input.runId,
|
|
162
|
-
};
|
|
175
|
+
// A run that stops on `interrupt()` can still end `success`.
|
|
176
|
+
if (interrupted)
|
|
177
|
+
return await paused();
|
|
178
|
+
return { type: "answered" };
|
|
163
179
|
}
|
|
164
180
|
//# sourceMappingURL=ingress.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingress.js","sourceRoot":"","sources":["../../../src/channels/http/ingress.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EACL,YAAY,GAGb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ingress.js","sourceRoot":"","sources":["../../../src/channels/http/ingress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { JsonObject } from "../manifest.js";
|
|
2
|
+
import type { JsonValue } from "../types.js";
|
|
3
|
+
import type { ChannelRunResult } from "../run-input.js";
|
|
4
|
+
import type { HttpChannel } from "./index.js";
|
|
5
|
+
import type { HttpChannelAdapter, HttpDeliveryOutcome } from "./types.js";
|
|
6
|
+
import { type EventEndpoint } from "./endpoint.js";
|
|
7
|
+
/** The channel's name in the project, or its provider before it has one. */
|
|
8
|
+
export declare function channelName(channel: HttpChannel): string;
|
|
9
|
+
/**
|
|
10
|
+
* Check a channel's `onEvent` keys. The types limit them, but a JavaScript
|
|
11
|
+
* caller or a cast gets no error, and a key nothing dispatches never runs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkEventKeys(provider: string, handlers: object, supported: ReadonlySet<string>): void;
|
|
14
|
+
/**
|
|
15
|
+
* A channel's `onEvent` with each endpoint, a URL or `Request`, replaced by
|
|
16
|
+
* the handler it stands for, so the channel calls handlers alone. A bad
|
|
17
|
+
* endpoint throws when the channel is declared.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveEndpoints<T extends object>(provider: string, onEvent: T | undefined): {
|
|
20
|
+
[K in keyof T]: Exclude<T[K], EventEndpoint>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A provider channel's `onSettled`: how a delivery of one of its events
|
|
24
|
+
* ended, with the event and its thread; see `channels.http`'s `onSettled`.
|
|
25
|
+
*/
|
|
26
|
+
export type EventSettled<E, T = EventThread> = (event: E, thread: T, outcome: HttpDeliveryOutcome) => void | Promise<void>;
|
|
27
|
+
/** The thread a provider channel's hooks hear about. */
|
|
28
|
+
export interface EventThread {
|
|
29
|
+
id: string;
|
|
30
|
+
channel: {
|
|
31
|
+
name: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The HTTP channel's `onSettled` for a provider channel: the channel's own
|
|
36
|
+
* notice first, such as a link to a pending decision, then the user's hook,
|
|
37
|
+
* for the deliveries whose event the channel parsed. A failing notice is
|
|
38
|
+
* logged and doesn't keep the user's hook from running.
|
|
39
|
+
*/
|
|
40
|
+
export declare function settleEvents<E>(notice: NonNullable<HttpChannelAdapter["onSettled"]>, onSettled: EventSettled<E> | undefined, parse: (rawEvent: JsonValue | undefined) => E | undefined, name: () => string): HttpChannelAdapter["onSettled"];
|
|
41
|
+
/** The events deploy subscribes the provider's webhook to: the handled ones. */
|
|
42
|
+
export declare function handledEventKeys(handlers: object): string[];
|
|
43
|
+
/**
|
|
44
|
+
* The connection `mda deploy` stores for the provider's app, or one of the
|
|
45
|
+
* values stored beside it, such as `webhook-secret`, when `suffix` is given.
|
|
46
|
+
*/
|
|
47
|
+
export declare function appConnectionSlug(provider: string, deploymentId: string, suffix?: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* A frozen copy of a parsed event, kept as the delivery's raw event so a
|
|
50
|
+
* handler that changes its argument can't change what MDA keeps.
|
|
51
|
+
*/
|
|
52
|
+
export declare function eventSnapshot(event: unknown, provider: string): JsonValue;
|
|
53
|
+
/** App options for deploy, without unset fields. */
|
|
54
|
+
export declare function definedFields(fields: Record<string, JsonValue | undefined>): JsonObject;
|
|
55
|
+
/**
|
|
56
|
+
* Whether `signature`, a hex HMAC-SHA256 the caller checked the format of,
|
|
57
|
+
* signs `rawBody` with `secret`. Compared in constant time.
|
|
58
|
+
*/
|
|
59
|
+
export declare function verifyHmacSha256(secret: string, rawBody: Uint8Array, signature: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* A value read at most every `ttlMs(value)` milliseconds. Concurrent callers
|
|
62
|
+
* share the read in flight; a failed read is not kept, so the next call reads
|
|
63
|
+
* again.
|
|
64
|
+
*/
|
|
65
|
+
export declare class CachedRead<T> {
|
|
66
|
+
#private;
|
|
67
|
+
private readonly read;
|
|
68
|
+
private readonly ttlMs;
|
|
69
|
+
constructor(read: () => Promise<T>, ttlMs: (value: T) => number);
|
|
70
|
+
get(): Promise<T>;
|
|
71
|
+
/** Read again on the next call. */
|
|
72
|
+
reset(): void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A value `mda deploy` stored for the deployment, such as a webhook secret:
|
|
76
|
+
* the `env` override when set, otherwise the agent secret Agent Auth keeps at
|
|
77
|
+
* `slug(deploymentId)`. Only a missing connection reads as `undefined`, and is
|
|
78
|
+
* logged as `label`; credential store failures propagate.
|
|
79
|
+
*/
|
|
80
|
+
export declare function readDeploymentSecret(env: string, slug: (deploymentId: string) => string, label: string): Promise<string | undefined>;
|
|
81
|
+
/** Forget values read from Agent Auth; for tests. */
|
|
82
|
+
export declare function resetDeploymentSecrets(): void;
|
|
83
|
+
/** What an event's handler did: returned run input, skipped, or threw. */
|
|
84
|
+
export type EventHandlerOutcome = {
|
|
85
|
+
type: "input";
|
|
86
|
+
input: ChannelRunResult;
|
|
87
|
+
} | {
|
|
88
|
+
type: "skipped";
|
|
89
|
+
} | {
|
|
90
|
+
type: "failed";
|
|
91
|
+
};
|
|
92
|
+
/** What an event handler returns: run input, or nothing to skip. */
|
|
93
|
+
export type EventHandlerResult = ChannelRunResult | null | undefined | void;
|
|
94
|
+
/** Run an event's handler. A throw is logged, not raised. */
|
|
95
|
+
export declare function runEventHandler(provider: string, event: {
|
|
96
|
+
key: string;
|
|
97
|
+
deliveryId: string;
|
|
98
|
+
}, call: () => EventHandlerResult | Promise<EventHandlerResult>): Promise<EventHandlerOutcome>;
|
|
99
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/channels/http/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What webhook channels built on `httpChannel`, such as GitHub and Linear,
|
|
3
|
+
* share: their name, the events they subscribe to, the secrets they read from
|
|
4
|
+
* Agent Auth, signature checks, running an event's handler, and the hooks
|
|
5
|
+
* that hand their typed events to the user.
|
|
6
|
+
*/
|
|
7
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
8
|
+
import { isJsonValue } from "../message-schema.js";
|
|
9
|
+
import { immutableCopy } from "../runtime.js";
|
|
10
|
+
import { logger } from "../../runtime/log.js";
|
|
11
|
+
import { endpointHandler, isEventEndpoint, } from "./endpoint.js";
|
|
12
|
+
import { ConnectionNotFoundError, DEPLOYMENT_ID_ENV, connections, } from "../../connections.js";
|
|
13
|
+
/** The channel's name in the project, or its provider before it has one. */
|
|
14
|
+
export function channelName(channel) {
|
|
15
|
+
return channel.name ?? channel.kind;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check a channel's `onEvent` keys. The types limit them, but a JavaScript
|
|
19
|
+
* caller or a cast gets no error, and a key nothing dispatches never runs.
|
|
20
|
+
*/
|
|
21
|
+
export function checkEventKeys(provider, handlers, supported) {
|
|
22
|
+
const unknown = Object.keys(handlers).filter((key) => !supported.has(key));
|
|
23
|
+
if (unknown.length)
|
|
24
|
+
throw new TypeError(`unsupported ${provider} event key ${unknown.sort().join(", ")}`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A channel's `onEvent` with each endpoint, a URL or `Request`, replaced by
|
|
28
|
+
* the handler it stands for, so the channel calls handlers alone. A bad
|
|
29
|
+
* endpoint throws when the channel is declared.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveEndpoints(provider, onEvent) {
|
|
32
|
+
return Object.fromEntries(Object.entries(onEvent ?? {}).map(([key, value]) => [
|
|
33
|
+
key,
|
|
34
|
+
isEventEndpoint(value)
|
|
35
|
+
? endpointHandler(value, `${provider} onEvent["${key}"]`)
|
|
36
|
+
: value,
|
|
37
|
+
]));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The HTTP channel's `onSettled` for a provider channel: the channel's own
|
|
41
|
+
* notice first, such as a link to a pending decision, then the user's hook,
|
|
42
|
+
* for the deliveries whose event the channel parsed. A failing notice is
|
|
43
|
+
* logged and doesn't keep the user's hook from running.
|
|
44
|
+
*/
|
|
45
|
+
export function settleEvents(notice, onSettled, parse, name) {
|
|
46
|
+
return async (target, delivery) => {
|
|
47
|
+
try {
|
|
48
|
+
await notice(target, delivery);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
logger.error(`channel ${delivery.outcome.type} notice failed (${logger.safeErrorLabel(error)})`);
|
|
52
|
+
}
|
|
53
|
+
const event = onSettled && parse(delivery.rawEvent);
|
|
54
|
+
if (event === undefined)
|
|
55
|
+
return;
|
|
56
|
+
await onSettled?.(event, { id: delivery.threadId, channel: { name: name() } }, delivery.outcome);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** The events deploy subscribes the provider's webhook to: the handled ones. */
|
|
60
|
+
export function handledEventKeys(handlers) {
|
|
61
|
+
return Object.entries(handlers)
|
|
62
|
+
.filter(([, handler]) => handler !== undefined)
|
|
63
|
+
.map(([key]) => key)
|
|
64
|
+
.sort();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The connection `mda deploy` stores for the provider's app, or one of the
|
|
68
|
+
* values stored beside it, such as `webhook-secret`, when `suffix` is given.
|
|
69
|
+
*/
|
|
70
|
+
export function appConnectionSlug(provider, deploymentId, suffix) {
|
|
71
|
+
const slug = `mda/${provider}-app/${deploymentId}`;
|
|
72
|
+
return suffix ? `${slug}/${suffix}` : slug;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A frozen copy of a parsed event, kept as the delivery's raw event so a
|
|
76
|
+
* handler that changes its argument can't change what MDA keeps.
|
|
77
|
+
*/
|
|
78
|
+
export function eventSnapshot(event, provider) {
|
|
79
|
+
if (!isJsonValue(event))
|
|
80
|
+
throw new TypeError(`invalid ${provider} event`);
|
|
81
|
+
return immutableCopy(event);
|
|
82
|
+
}
|
|
83
|
+
/** App options for deploy, without unset fields. */
|
|
84
|
+
export function definedFields(fields) {
|
|
85
|
+
const defined = {};
|
|
86
|
+
for (const [key, value] of Object.entries(fields))
|
|
87
|
+
if (value !== undefined)
|
|
88
|
+
defined[key] = value;
|
|
89
|
+
return defined;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Whether `signature`, a hex HMAC-SHA256 the caller checked the format of,
|
|
93
|
+
* signs `rawBody` with `secret`. Compared in constant time.
|
|
94
|
+
*/
|
|
95
|
+
export function verifyHmacSha256(secret, rawBody, signature) {
|
|
96
|
+
const expected = createHmac("sha256", secret).update(rawBody).digest();
|
|
97
|
+
const given = Buffer.from(signature, "hex");
|
|
98
|
+
return given.length === expected.length && timingSafeEqual(expected, given);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A value read at most every `ttlMs(value)` milliseconds. Concurrent callers
|
|
102
|
+
* share the read in flight; a failed read is not kept, so the next call reads
|
|
103
|
+
* again.
|
|
104
|
+
*/
|
|
105
|
+
export class CachedRead {
|
|
106
|
+
read;
|
|
107
|
+
ttlMs;
|
|
108
|
+
#entry;
|
|
109
|
+
constructor(read, ttlMs) {
|
|
110
|
+
this.read = read;
|
|
111
|
+
this.ttlMs = ttlMs;
|
|
112
|
+
}
|
|
113
|
+
get() {
|
|
114
|
+
if (this.#entry && this.#entry.expiresAt > Date.now())
|
|
115
|
+
return this.#entry.value;
|
|
116
|
+
const entry = {
|
|
117
|
+
value: this.read().then((value) => {
|
|
118
|
+
entry.expiresAt = Date.now() + this.ttlMs(value);
|
|
119
|
+
return value;
|
|
120
|
+
}, (error) => {
|
|
121
|
+
if (this.#entry === entry)
|
|
122
|
+
this.#entry = undefined;
|
|
123
|
+
throw error;
|
|
124
|
+
}),
|
|
125
|
+
expiresAt: Number.POSITIVE_INFINITY,
|
|
126
|
+
};
|
|
127
|
+
this.#entry = entry;
|
|
128
|
+
return entry.value;
|
|
129
|
+
}
|
|
130
|
+
/** Read again on the next call. */
|
|
131
|
+
reset() {
|
|
132
|
+
this.#entry = undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** How long a value read from Agent Auth is reused before it is read again. */
|
|
136
|
+
const SECRET_TTL_MS = 5 * 60_000;
|
|
137
|
+
/** How long a missing value is remembered, so unsigned traffic can't hammer Agent Auth. */
|
|
138
|
+
const MISSING_SECRET_TTL_MS = 60_000;
|
|
139
|
+
const deploymentSecrets = new Map();
|
|
140
|
+
/**
|
|
141
|
+
* A value `mda deploy` stored for the deployment, such as a webhook secret:
|
|
142
|
+
* the `env` override when set, otherwise the agent secret Agent Auth keeps at
|
|
143
|
+
* `slug(deploymentId)`. Only a missing connection reads as `undefined`, and is
|
|
144
|
+
* logged as `label`; credential store failures propagate.
|
|
145
|
+
*/
|
|
146
|
+
export function readDeploymentSecret(env, slug, label) {
|
|
147
|
+
const override = process.env[env]?.trim();
|
|
148
|
+
if (override)
|
|
149
|
+
return Promise.resolve(override);
|
|
150
|
+
const deploymentId = process.env[DEPLOYMENT_ID_ENV]?.trim();
|
|
151
|
+
if (!deploymentId)
|
|
152
|
+
return Promise.resolve(undefined);
|
|
153
|
+
const key = slug(deploymentId);
|
|
154
|
+
let cached = deploymentSecrets.get(key);
|
|
155
|
+
if (!cached) {
|
|
156
|
+
cached = new CachedRead(() => connections.resolveDeploymentSecret(key).catch((error) => {
|
|
157
|
+
if (!(error instanceof ConnectionNotFoundError))
|
|
158
|
+
throw error;
|
|
159
|
+
logger.error(`${label} is not stored in Agent Auth`);
|
|
160
|
+
return undefined;
|
|
161
|
+
}), (value) => (value === undefined ? MISSING_SECRET_TTL_MS : SECRET_TTL_MS));
|
|
162
|
+
deploymentSecrets.set(key, cached);
|
|
163
|
+
}
|
|
164
|
+
return cached.get();
|
|
165
|
+
}
|
|
166
|
+
/** Forget values read from Agent Auth; for tests. */
|
|
167
|
+
export function resetDeploymentSecrets() {
|
|
168
|
+
deploymentSecrets.clear();
|
|
169
|
+
}
|
|
170
|
+
/** Run an event's handler. A throw is logged, not raised. */
|
|
171
|
+
export async function runEventHandler(provider, event, call) {
|
|
172
|
+
const receipt = JSON.stringify({
|
|
173
|
+
event: logger.logIdentifier(event.key),
|
|
174
|
+
deliveryId: logger.logIdentifier(event.deliveryId),
|
|
175
|
+
});
|
|
176
|
+
try {
|
|
177
|
+
const input = await call();
|
|
178
|
+
if (input === undefined || input === null)
|
|
179
|
+
return { type: "skipped" };
|
|
180
|
+
logger.info(`${provider} handler returned run input ${receipt}`);
|
|
181
|
+
return { type: "input", input };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
logger.error(`${provider.toLowerCase()} callback failed ${receipt} (${logger.safeErrorLabel(error)})`);
|
|
185
|
+
return { type: "failed" };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/channels/http/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { JsonValue } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Where the thread's latest channel delivery came from, kept in its state.
|
|
5
|
+
* Private (the leading `_`), so it's never part of a run's input or output.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CHANNEL_REPLY_STATE_KEY = "_mda_channel_reply";
|
|
8
|
+
/**
|
|
9
|
+
* Remember a channel delivery's target in the thread's state, and post the
|
|
10
|
+
* answer to it when the agent finishes. A run that stops on `interrupt()` or
|
|
11
|
+
* is cancelled doesn't finish, so it posts nothing; the run that resumes it
|
|
12
|
+
* carries no delivery, so it answers the remembered target.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createChannelReplyMiddleware(): import("langchain").AgentMiddleware<z.ZodObject<{
|
|
15
|
+
_mda_channel_reply: z.ZodOptional<z.ZodObject<{
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
target: z.ZodCustom<JsonValue, JsonValue>;
|
|
18
|
+
}, z.core.$strip>>;
|
|
19
|
+
}, z.core.$strip>, undefined, unknown, readonly (import("@langchain/core/tools").ServerTool | import("@langchain/core/tools").ClientTool)[], readonly []>;
|
|
20
|
+
//# sourceMappingURL=reply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply.d.ts","sourceRoot":"","sources":["../../../src/channels/http/reply.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAqD5D;;;;;GAKG;AACH,wBAAgB,4BAA4B;;;;;0JAyC3C"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An HTTP channel run posts its own answer.
|
|
3
|
+
*
|
|
4
|
+
* The run does it, not the process that received the delivery, so a restart
|
|
5
|
+
* of that process doesn't lose the answer, and a run LangSmith Studio resumes
|
|
6
|
+
* after a decision answers the conversation the paused run came from.
|
|
7
|
+
*/
|
|
8
|
+
import { getConfig } from "@langchain/langgraph";
|
|
9
|
+
import { createMiddleware } from "langchain";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { extractAssistantContent } from "../assistant-text.js";
|
|
12
|
+
import { resolveChannelBinding } from "../binding.js";
|
|
13
|
+
import { isJsonValue } from "../message-schema.js";
|
|
14
|
+
import { messagingTransportForName } from "../messaging-registry.js";
|
|
15
|
+
import { isTrustedScheduleDeliveryRun } from "../schedule-delivery.js";
|
|
16
|
+
import { CHANNEL_THREAD_METADATA, configurableFromRuntime, resolveAmbientConfigurable, } from "../../runtime/identity-runtime.js";
|
|
17
|
+
import { logger } from "../../runtime/log.js";
|
|
18
|
+
/**
|
|
19
|
+
* Where the thread's latest channel delivery came from, kept in its state.
|
|
20
|
+
* Private (the leading `_`), so it's never part of a run's input or output.
|
|
21
|
+
*/
|
|
22
|
+
export const CHANNEL_REPLY_STATE_KEY = "_mda_channel_reply";
|
|
23
|
+
const replyTargetSchema = z.object({
|
|
24
|
+
name: z.string().min(1),
|
|
25
|
+
target: z.custom((value) => isJsonValue(value)),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* The run's verified HTTP channel delivery: one the channel's ingress started
|
|
29
|
+
* for that conversation (the binding matches the run's authenticated source),
|
|
30
|
+
* never one a caller put in the run's context.
|
|
31
|
+
*/
|
|
32
|
+
function deliveredTarget(runtime) {
|
|
33
|
+
const configurable = configurableFromRuntime(runtime) ??
|
|
34
|
+
resolveAmbientConfigurable();
|
|
35
|
+
const binding = resolveChannelBinding(undefined, configurable);
|
|
36
|
+
// Only HTTP channels deliver directly; others answer on their own.
|
|
37
|
+
if (!binding || binding.transport !== "direct")
|
|
38
|
+
return undefined;
|
|
39
|
+
return { name: binding.name, target: binding.target };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether the run is on a channel's thread. Only managed ingress marks one;
|
|
43
|
+
* the runtime's auth strips the marker from every other thread and run, so a
|
|
44
|
+
* caller can't point its own thread's stored target at someone else's
|
|
45
|
+
* conversation. Channel threads take runs only from their channel and resumes
|
|
46
|
+
* from LangSmith Studio.
|
|
47
|
+
*/
|
|
48
|
+
function onChannelThread() {
|
|
49
|
+
try {
|
|
50
|
+
const metadata = getConfig().metadata;
|
|
51
|
+
return metadata?.[CHANNEL_THREAD_METADATA] === "true";
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Outside a runnable context.
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function storedTarget(state) {
|
|
59
|
+
if (!onChannelThread())
|
|
60
|
+
return undefined;
|
|
61
|
+
const value = state && typeof state === "object" && !Array.isArray(state)
|
|
62
|
+
? state[CHANNEL_REPLY_STATE_KEY]
|
|
63
|
+
: undefined;
|
|
64
|
+
const parsed = replyTargetSchema.safeParse(value);
|
|
65
|
+
return parsed.success ? parsed.data : undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Remember a channel delivery's target in the thread's state, and post the
|
|
69
|
+
* answer to it when the agent finishes. A run that stops on `interrupt()` or
|
|
70
|
+
* is cancelled doesn't finish, so it posts nothing; the run that resumes it
|
|
71
|
+
* carries no delivery, so it answers the remembered target.
|
|
72
|
+
*/
|
|
73
|
+
export function createChannelReplyMiddleware() {
|
|
74
|
+
return createMiddleware({
|
|
75
|
+
name: "mda-channel-reply",
|
|
76
|
+
stateSchema: z.object({
|
|
77
|
+
[CHANNEL_REPLY_STATE_KEY]: replyTargetSchema.optional(),
|
|
78
|
+
}),
|
|
79
|
+
beforeAgent(_state, runtime) {
|
|
80
|
+
const delivered = deliveredTarget(runtime);
|
|
81
|
+
return delivered ? { [CHANNEL_REPLY_STATE_KEY]: delivered } : undefined;
|
|
82
|
+
},
|
|
83
|
+
async afterAgent(state, runtime) {
|
|
84
|
+
const configurable = configurableFromRuntime(runtime) ??
|
|
85
|
+
resolveAmbientConfigurable();
|
|
86
|
+
// Scheduled runs post through schedule delivery.
|
|
87
|
+
if (isTrustedScheduleDeliveryRun(configurable))
|
|
88
|
+
return undefined;
|
|
89
|
+
const reply = deliveredTarget(runtime) ?? storedTarget(state);
|
|
90
|
+
if (!reply)
|
|
91
|
+
return undefined;
|
|
92
|
+
const content = extractAssistantContent({
|
|
93
|
+
messages: state.messages,
|
|
94
|
+
});
|
|
95
|
+
if (content === null)
|
|
96
|
+
return undefined;
|
|
97
|
+
const transport = messagingTransportForName(reply.name);
|
|
98
|
+
if (!transport) {
|
|
99
|
+
logger.warn(`channel reply skipped: no channel ${JSON.stringify(logger.logIdentifier(reply.name))}`);
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await transport.post({
|
|
104
|
+
message: { type: "content", content },
|
|
105
|
+
target: reply.target,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// The answer stays in the thread; the run itself succeeded.
|
|
110
|
+
logger.error(`channel reply failed (${logger.safeErrorLabel(error)})`);
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=reply.js.map
|