managed-deepagents 0.10.0-dev.3 → 0.10.0-dev.4
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 +100 -6
- package/dist/channels/github/index.d.ts +3 -8
- package/dist/channels/github/index.d.ts.map +1 -1
- package/dist/channels/github/index.js +5 -50
- package/dist/channels/github/index.js.map +1 -1
- package/dist/channels/http/http.d.ts.map +1 -1
- package/dist/channels/http/http.js +125 -9
- package/dist/channels/http/http.js.map +1 -1
- package/dist/channels/http/ingress.d.ts +24 -0
- package/dist/channels/http/ingress.d.ts.map +1 -1
- package/dist/channels/http/ingress.js +78 -5
- package/dist/channels/http/ingress.js.map +1 -1
- package/dist/channels/http/studio.d.ts +13 -0
- package/dist/channels/http/studio.d.ts.map +1 -0
- package/dist/channels/http/studio.js +80 -0
- package/dist/channels/http/studio.js.map +1 -0
- package/dist/channels/http/types.d.ts +32 -2
- 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 +69 -0
- package/dist/channels/linear/graphql.d.ts.map +1 -0
- package/dist/channels/linear/graphql.js +169 -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 +467 -0
- package/dist/channels/linear/index.js.map +1 -0
- package/dist/channels/linear/schema.d.ts +1035 -0
- package/dist/channels/linear/schema.d.ts.map +1 -0
- package/dist/channels/linear/schema.js +216 -0
- package/dist/channels/linear/schema.js.map +1 -0
- package/dist/channels/linear/types.d.ts +114 -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/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/source-providers.js +1 -1
- package/dist/channels/source-providers.js.map +1 -1
- package/dist/connections.d.ts +14 -3
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +32 -9
- package/dist/connections.js.map +1 -1
- package/dist/credential-gate.d.ts.map +1 -1
- package/dist/credential-gate.js +8 -6
- package/dist/credential-gate.js.map +1 -1
- package/dist/index.d.ts +2 -0
- 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 +11 -0
- package/dist/ingress/runs.d.ts.map +1 -1
- package/dist/ingress/runs.js +54 -0
- 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 +2 -0
- package/dist/runtime/auth.d.ts.map +1 -1
- package/dist/runtime/auth.js +118 -21
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/channel-icon.d.ts +21 -0
- package/dist/runtime/channel-icon.d.ts.map +1 -0
- package/dist/runtime/channel-icon.js +69 -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/schedule-auth.d.ts.map +1 -1
- package/dist/runtime/schedule-auth.js +19 -2
- package/dist/runtime/schedule-auth.js.map +1 -1
- package/package.json +7 -7
|
@@ -7,7 +7,55 @@ import { buildIngressRunContext } from "../../ingress/index.js";
|
|
|
7
7
|
import { ChannelError } from "../errors.js";
|
|
8
8
|
import { validateMessage } from "../runtime.js";
|
|
9
9
|
import { createIngressLoopbackClient, hasLoopbackCredential, } from "../../ingress/loopback.js";
|
|
10
|
-
import { DELIVERY_KEY_METADATA, ingressThreadState, lookupStatus, startIngressRun, waitForIdleThread, observeIngressRun, recordThreadDelivery, } from "../../ingress/runs.js";
|
|
10
|
+
import { DELIVERY_KEY_METADATA, cancelIngressRuns, ingressRunAfter, ingressThreadState, lookupStatus, startIngressRun, waitForIdleThread, observeIngressRun, recordThreadDelivery, } from "../../ingress/runs.js";
|
|
11
|
+
/** How long a paused delivery waits for its thread to go on. */
|
|
12
|
+
const RESUME_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
13
|
+
/** How often it looks, backing off from the first to the last. */
|
|
14
|
+
const RESUME_POLL_MS = { first: 5_000, max: 60_000 };
|
|
15
|
+
function sleep(ms) {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
// A delivery waiting on a decision never keeps the process alive.
|
|
18
|
+
setTimeout(resolve, ms).unref();
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The run that goes on with a thread a delivery's run paused: the decision is
|
|
23
|
+
* made outside the channel (in LangSmith Studio), which resumes the thread in
|
|
24
|
+
* a new run, the only kind the MDA runtime lets Studio start on a channel's
|
|
25
|
+
* thread. Undefined when none comes within a day, or the thread is gone.
|
|
26
|
+
*/
|
|
27
|
+
export async function nextHttpIngressRun(input, options = {}) {
|
|
28
|
+
const client = createIngressLoopbackClient({
|
|
29
|
+
userId: input.userId,
|
|
30
|
+
sourceThreadKey: input.sourceThreadKey,
|
|
31
|
+
sourceProvider: input.sourceProvider ?? input.binding.provider,
|
|
32
|
+
});
|
|
33
|
+
const wait = options.wait ?? sleep;
|
|
34
|
+
const deadline = Date.now() + (options.windowMs ?? RESUME_WINDOW_MS);
|
|
35
|
+
let delay = RESUME_POLL_MS.first;
|
|
36
|
+
while (Date.now() < deadline) {
|
|
37
|
+
await wait(delay);
|
|
38
|
+
delay = Math.min(delay * 2, RESUME_POLL_MS.max);
|
|
39
|
+
let next;
|
|
40
|
+
try {
|
|
41
|
+
next = await ingressRunAfter(client, input);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// The next look may get through.
|
|
45
|
+
logger.warn(`channel thread check failed ${JSON.stringify({
|
|
46
|
+
threadId: input.threadId,
|
|
47
|
+
status: lookupStatus(error),
|
|
48
|
+
})}`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (next === "gone")
|
|
52
|
+
return undefined;
|
|
53
|
+
if (next)
|
|
54
|
+
return next;
|
|
55
|
+
}
|
|
56
|
+
logger.info(`channel thread was not resumed in time ${JSON.stringify({ threadId: input.threadId })}`);
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
11
59
|
/** Wait until the thread's queued and running runs have finished. */
|
|
12
60
|
export async function waitForHttpIngressThread(input) {
|
|
13
61
|
const client = createIngressLoopbackClient({
|
|
@@ -17,6 +65,17 @@ export async function waitForHttpIngressThread(input) {
|
|
|
17
65
|
});
|
|
18
66
|
await waitForIdleThread(client, input.threadId);
|
|
19
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Cancel the thread's queued and running runs, keeping their progress.
|
|
70
|
+
* Returns how many it cancelled.
|
|
71
|
+
*/
|
|
72
|
+
export async function cancelHttpIngressRuns(input) {
|
|
73
|
+
if (!hasLoopbackCredential()) {
|
|
74
|
+
throw new ChannelError("channel_run_failed", "managed loopback authentication is not configured");
|
|
75
|
+
}
|
|
76
|
+
const client = createIngressLoopbackClient(input);
|
|
77
|
+
return cancelIngressRuns(client, input.threadId);
|
|
78
|
+
}
|
|
20
79
|
export async function startHttpIngressAgent(input) {
|
|
21
80
|
if (!hasLoopbackCredential()) {
|
|
22
81
|
throw new ChannelError("channel_run_failed", "managed loopback authentication is not configured");
|
|
@@ -137,9 +196,20 @@ export async function observeHttpIngressAgent(input) {
|
|
|
137
196
|
return { replyContent: null, threadId: input.threadId, runId: input.runId };
|
|
138
197
|
}
|
|
139
198
|
const { values, status } = observed;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
199
|
+
// A cancelled run ends `interrupted` too; only pending interrupts pause.
|
|
200
|
+
const paused = async () => {
|
|
201
|
+
const { state, assistantId } = await ingressThreadState(client, input.threadId);
|
|
202
|
+
return {
|
|
203
|
+
replyContent: null,
|
|
204
|
+
threadId: input.threadId,
|
|
205
|
+
runId: input.runId,
|
|
206
|
+
...(state === "paused" && {
|
|
207
|
+
paused: assistantId === undefined ? {} : { assistantId },
|
|
208
|
+
}),
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
if (status === "interrupted")
|
|
212
|
+
return await paused();
|
|
143
213
|
if (status !== "success") {
|
|
144
214
|
throw new ChannelError("channel_run_failed", "channel run did not complete successfully");
|
|
145
215
|
}
|
|
@@ -150,7 +220,10 @@ export async function observeHttpIngressAgent(input) {
|
|
|
150
220
|
const interrupted = interrupts &&
|
|
151
221
|
typeof interrupts === "object" &&
|
|
152
222
|
Object.keys(interrupts).length > 0;
|
|
153
|
-
|
|
223
|
+
// A run that stops on `interrupt()` can still end `success`.
|
|
224
|
+
if (interrupted)
|
|
225
|
+
return await paused();
|
|
226
|
+
const content = extractAssistantContent(state);
|
|
154
227
|
if (content === null)
|
|
155
228
|
return { replyContent: null, threadId: input.threadId, runId: input.runId };
|
|
156
229
|
const reply = { type: "content", content };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingress.js","sourceRoot":"","sources":["../../../src/channels/http/ingress.ts"],"names":[],"mappings":"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
|
|
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,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,uBAAuB,CAAC;AA6C/B,gEAAgE;AAChE,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC7C,kEAAkE;AAClE,MAAM,cAAc,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AAErD,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,kEAAkE;QAClE,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAA4C,EAC5C,OAAO,GAAgE,EAAE;IAEzE,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ;KAC/D,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,gBAAgB,CAAC,CAAC;IACrE,IAAI,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC;IACjC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,IAAiD,CAAC;QACtD,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,iCAAiC;YACjC,MAAM,CAAC,IAAI,CACT,+BAA+B,IAAI,CAAC,SAAS,CAAC;gBAC5C,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC;aAC5B,CAAC,EAAE,CACL,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QACtC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,MAAM,CAAC,IAAI,CACT,0CAA0C,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,CACzF,CAAC;IACF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAA+C;IAE/C,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ;KAC/D,CAAC,CAAC;IACH,MAAM,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAK3C;IACC,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,YAAY,CACpB,oBAAoB,EACpB,mDAAmD,CACpD,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,2BAA2B,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAA4B;IAE5B,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,YAAY,CACpB,oBAAoB,EACpB,mDAAmD,CACpD,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ;KAC/D,CAAC,CAAC;IACH,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,kBAAkB,CACrD,MAAM,EACN,KAAK,CAAC,QAAQ,EACd,KAAK,CAAC,WAAW,CAClB,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI;QAClD,QAAQ,EAAE,EAAE,CAAC,qBAAqB,CAAC,EAAE,KAAK,CAAC,WAAW,EAAE;KACzD,CAAC;IACF,6DAA6D;IAC7D,IAAI,KAAK,KAAK,QAAQ;QACpB,OAAO;YACL,OAAO,EAAE,QAAQ;YACjB,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;SAClD,CAAC;IACJ,MAAM,QAAQ,GAAG,KAAK,CAAC,iBAAiB,IAAI,SAAS,CAAC;IACtD,kEAAkE;IAClE,MAAM,gBAAgB,GAAG,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,UAAU,CAAC;IAC7E,IAAI,KAAK,KAAK,MAAM,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAC9E,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,gBAAgB,CAAC;QAC9D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,MAAM,QAAQ,GACZ,KAAK,CAAC,KAAK,KAAK,SAAS;QACvB,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;QAC9B,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IAC9B,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAC7C,IAAI,OAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE;YACtC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,GAAG,QAAQ;YACX,iBAAiB,EAAE,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;YACpE,GAAG,sBAAsB,CAAC;gBACxB,gEAAgE;gBAChE,eAAe;gBACf,OAAO,EACL,KAAK,CAAC,KAAK,KAAK,SAAS;oBACvB,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC;wBACE,GAAG,KAAK,CAAC,OAAO;wBAChB,KAAK,EAAE;4BACL,IAAI,EAAE,SAAS;4BACf,QAAQ,EAAE,QAAQ,CAAC,QAAuB;yBAC3C;qBACF;gBACP,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO;aAC3C,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6DAA6D;QAC7D,IAAI,QAAQ,KAAK,QAAQ,IAAI,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG;YACtD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;QACjC,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,sBAAsB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,sBAAsB,CACnC,MAAsD,EACtD,KAA4B;IAE5B,IAAI,KAAK,CAAC,iBAAiB,KAAK,UAAU,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAC3E,OAAO;IACT,IAAI,CAAC;QACH,MAAM,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,MAAM,CAAC,IAAI,CACT,mDAAmD,IAAI,CAAC,SAAS,CAAC;YAChE,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC;SAC5B,CAAC,EAAE,CACL,CAAC;IACJ,CAAC;AACH,CAAC;AAED,wCAAwC;AACxC,SAAS,eAAe,CAAC,OAAuB;IAC9C,MAAM,OAAO,GACX,OAAO,OAAO,KAAK,QAAQ;QACzB,CAAC,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC;QAC3B,CAAC,CAAC,IAAI,YAAY,CAAC;YACf,aAAa,EAAE,OAAkC;SAClD,CAAC,CAAC;IACT,OAAO;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,OAAO,CAAC,OAAoB;gBACrC,iBAAiB,EAAE,OAAO,CAAC,iBAA8B;aAC1D;SACF;QACD,KAAK,EAAE,EAAE;KACV,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAA4C;IAQ5C,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,cAAc,EAAE,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ;KAC/D,CAAC,CAAC;IACH,IAAI,QAAuD,CAAC;IAC5D,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wEAAwE;QACxE,IAAI,YAAY,CAAC,KAAK,CAAC,KAAK,GAAG;YAAE,MAAM,KAAK,CAAC;QAC7C,MAAM,CAAC,IAAI,CACT,4BAA4B,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,CAC3E,CAAC;QACF,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAC9E,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IACpC,yEAAyE;IACzE,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,kBAAkB,CACrD,MAAM,EACN,KAAK,CAAC,QAAQ,CACf,CAAC;QACF,OAAO;YACL,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI;gBACxB,MAAM,EAAE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE;aACzD,CAAC;SACH,CAAC;IACJ,CAAC,CAAC;IACF,IAAI,MAAM,KAAK,aAAa;QAAE,OAAO,MAAM,MAAM,EAAE,CAAC;IACpD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,YAAY,CACpB,oBAAoB,EACpB,2CAA2C,CAC5C,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GACT,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,WAAW,GACf,UAAU;QACV,OAAO,UAAU,KAAK,QAAQ;QAC9B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACrC,6DAA6D;IAC7D,IAAI,WAAW;QAAE,OAAO,MAAM,MAAM,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,OAAO,KAAK,IAAI;QAClB,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAC9E,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,CAAC;IACpD,eAAe,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,OAAO;QAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HttpChannelRunInfo } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The thread in the deployment's Studio, or the deployment's page when the
|
|
4
|
+
* deployment's name or the thread's assistant is unknown. The LangSmith UI is
|
|
5
|
+
* the one `mda deploy` recorded for the deployment's environment
|
|
6
|
+
* (`MDA_LANGSMITH_URL`); without it there is nothing to link to.
|
|
7
|
+
*
|
|
8
|
+
* A platform that serves its own Studio for the deployment, such as the local
|
|
9
|
+
* stack, names it in `MDA_STUDIO_URL`; the link then opens that Studio on the
|
|
10
|
+
* thread.
|
|
11
|
+
*/
|
|
12
|
+
export declare function studioUrl(run: HttpChannelRunInfo | undefined, env?: NodeJS.ProcessEnv): string | undefined;
|
|
13
|
+
//# sourceMappingURL=studio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio.d.ts","sourceRoot":"","sources":["../../../src/channels/http/studio.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AASrD;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,GAAG,oBAAc,GAChB,MAAM,GAAG,SAAS,CA8BpB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** Links from channel notices into the deployment's LangSmith Studio. */
|
|
2
|
+
import { v5 as uuidv5 } from "uuid";
|
|
3
|
+
import { DEPLOYMENT_ID_ENV } from "../../connections.js";
|
|
4
|
+
import { managedDeploymentName } from "../../runtime/sandbox-manager.js";
|
|
5
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
6
|
+
const DEPLOYMENT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
7
|
+
const GRAPH_ID_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/;
|
|
8
|
+
/** The namespace the Agent Server derives a graph's default assistant from. */
|
|
9
|
+
const GRAPH_NAMESPACE = "6ba7b821-9dad-11d1-80b4-00c04fd430c8";
|
|
10
|
+
/**
|
|
11
|
+
* The thread in the deployment's Studio, or the deployment's page when the
|
|
12
|
+
* deployment's name or the thread's assistant is unknown. The LangSmith UI is
|
|
13
|
+
* the one `mda deploy` recorded for the deployment's environment
|
|
14
|
+
* (`MDA_LANGSMITH_URL`); without it there is nothing to link to.
|
|
15
|
+
*
|
|
16
|
+
* A platform that serves its own Studio for the deployment, such as the local
|
|
17
|
+
* stack, names it in `MDA_STUDIO_URL`; the link then opens that Studio on the
|
|
18
|
+
* thread.
|
|
19
|
+
*/
|
|
20
|
+
export function studioUrl(run, env = process.env) {
|
|
21
|
+
const threadId = run?.threadId;
|
|
22
|
+
const thread = threadId && UUID_PATTERN.test(threadId) ? threadId : undefined;
|
|
23
|
+
const standalone = parseHttpUrl(env.MDA_STUDIO_URL);
|
|
24
|
+
if (standalone) {
|
|
25
|
+
if (thread) {
|
|
26
|
+
standalone.searchParams.set("threadId", thread);
|
|
27
|
+
standalone.searchParams.set("mode", "chat");
|
|
28
|
+
}
|
|
29
|
+
return standalone.href;
|
|
30
|
+
}
|
|
31
|
+
const workspace = env.LANGSMITH_TENANT_ID?.trim() ?? "";
|
|
32
|
+
const deployment = env[DEPLOYMENT_ID_ENV]?.trim() ?? "";
|
|
33
|
+
if (!UUID_PATTERN.test(workspace) || !UUID_PATTERN.test(deployment))
|
|
34
|
+
return undefined;
|
|
35
|
+
const origin = parseHttpUrl(env.MDA_LANGSMITH_URL)?.origin;
|
|
36
|
+
if (!origin)
|
|
37
|
+
return undefined;
|
|
38
|
+
const name = managedDeploymentName(env);
|
|
39
|
+
const assistantId = assistantUuid(run?.assistantId);
|
|
40
|
+
if (!name || !DEPLOYMENT_NAME_PATTERN.test(name) || !thread || !assistantId)
|
|
41
|
+
return `${origin}/o/${workspace}/host/deployments/${deployment}`;
|
|
42
|
+
const query = new URLSearchParams({
|
|
43
|
+
organizationId: workspace,
|
|
44
|
+
render: "interact",
|
|
45
|
+
hostProjectId: deployment,
|
|
46
|
+
assistantId,
|
|
47
|
+
mode: "chat",
|
|
48
|
+
threadId: thread,
|
|
49
|
+
});
|
|
50
|
+
return `${origin}/o/${workspace}/a/${encodeURIComponent(name)}/studio/thread?${query}`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Studio opens an assistant by its ID. Channels start runs by graph ID, whose
|
|
54
|
+
* default assistant the Agent Server derives from it.
|
|
55
|
+
*/
|
|
56
|
+
function assistantUuid(assistant) {
|
|
57
|
+
if (!assistant)
|
|
58
|
+
return undefined;
|
|
59
|
+
if (UUID_PATTERN.test(assistant))
|
|
60
|
+
return assistant;
|
|
61
|
+
return GRAPH_ID_PATTERN.test(assistant)
|
|
62
|
+
? uuidv5(assistant, GRAPH_NAMESPACE)
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
function parseHttpUrl(value) {
|
|
66
|
+
if (!value?.trim())
|
|
67
|
+
return undefined;
|
|
68
|
+
try {
|
|
69
|
+
const url = new URL(value.trim());
|
|
70
|
+
return (url.protocol === "https:" || url.protocol === "http:") &&
|
|
71
|
+
!url.username &&
|
|
72
|
+
!url.password
|
|
73
|
+
? url
|
|
74
|
+
: undefined;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=studio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio.js","sourceRoot":"","sources":["../../../src/channels/http/studio.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,6 +28,16 @@ export type HttpChannelParseResult = {
|
|
|
28
28
|
} | {
|
|
29
29
|
type: "ignore";
|
|
30
30
|
response?: Response;
|
|
31
|
+
} | {
|
|
32
|
+
/**
|
|
33
|
+
* Stop the work on the message's thread: MDA cancels its queued and
|
|
34
|
+
* running runs, keeping their progress, then calls `onCancelled`. The
|
|
35
|
+
* message needs no `content`.
|
|
36
|
+
*/
|
|
37
|
+
type: "cancel";
|
|
38
|
+
message: HttpChannelInboundMessage;
|
|
39
|
+
rawEvent?: JsonValue;
|
|
40
|
+
response?: Response;
|
|
31
41
|
};
|
|
32
42
|
/** MDA adds the verified reply target to the validated message. */
|
|
33
43
|
export type HttpChannelPostInput = ChannelMessage & {
|
|
@@ -63,10 +73,25 @@ export interface HttpChannelAdapter {
|
|
|
63
73
|
*/
|
|
64
74
|
input?(message: HttpChannelInboundMessage, rawEvent: JsonValue | undefined): ChannelRunResult | null | undefined | Promise<ChannelRunResult | null | undefined>;
|
|
65
75
|
/**
|
|
66
|
-
* The
|
|
67
|
-
*
|
|
76
|
+
* The thread waits on a decision: its run just stopped on interrupts, or a
|
|
77
|
+
* message arrived while it waits, so MDA started no run. Tell the sender
|
|
78
|
+
* where to make it (Studio resumes interrupts). Failures are logged.
|
|
68
79
|
*/
|
|
69
80
|
onPaused?(target: JsonValue, run: HttpChannelRunInfo): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* A verified message reached its thread, before MDA starts or queues
|
|
83
|
+
* anything for it, and whatever it then does. For providers that
|
|
84
|
+
* expect a prompt acknowledgement. Runs in the background; failures are
|
|
85
|
+
* logged.
|
|
86
|
+
*/
|
|
87
|
+
onDelivered?(target: JsonValue, run: HttpChannelRunInfo): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* MDA cancelled the thread's runs for a `cancel` result; `cancelled` says
|
|
90
|
+
* how many were active. Runs in the background; failures are logged.
|
|
91
|
+
*/
|
|
92
|
+
onCancelled?(target: JsonValue, run: HttpChannelRunInfo & {
|
|
93
|
+
cancelled: number;
|
|
94
|
+
}): Promise<void>;
|
|
70
95
|
}
|
|
71
96
|
/** The thread a notice is about, for links into LangSmith Studio. */
|
|
72
97
|
export interface HttpChannelRunInfo {
|
|
@@ -75,6 +100,11 @@ export interface HttpChannelRunInfo {
|
|
|
75
100
|
assistantId?: string;
|
|
76
101
|
/** The provider event of the delivery the notice is about, when parsed. */
|
|
77
102
|
rawEvent?: JsonValue;
|
|
103
|
+
/**
|
|
104
|
+
* For `onPaused`: the delivery's own run just stopped on interrupts, rather
|
|
105
|
+
* than the message arriving while the thread already waited.
|
|
106
|
+
*/
|
|
107
|
+
stopped?: true;
|
|
78
108
|
}
|
|
79
109
|
export interface HttpChannelRequest {
|
|
80
110
|
request: Request;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/channels/http/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,MAAM,EAAE,SAAS,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,sBAAsB,GAC9B;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,yBAAyB,CAAC;IACnC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,GACD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/channels/http/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved agent connection for the deployment's Linear app: reading it
|
|
3
|
+
* returns the app's access token, which Agent Auth renews.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LINEAR_TOKEN_SLUG = "mda/linear-token";
|
|
6
|
+
/**
|
|
7
|
+
* The deployment's Linear app connection, or one of the app values stored
|
|
8
|
+
* beside it (`webhook-secret`) when `suffix` is given.
|
|
9
|
+
*/
|
|
10
|
+
export declare function linearAppConnectionSlug(deploymentId: string, suffix?: string): string;
|
|
11
|
+
//# sourceMappingURL=connections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../../src/channels/linear/connections.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAGR"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved agent connection for the deployment's Linear app: reading it
|
|
3
|
+
* returns the app's access token, which Agent Auth renews.
|
|
4
|
+
*/
|
|
5
|
+
export const LINEAR_TOKEN_SLUG = "mda/linear-token";
|
|
6
|
+
/**
|
|
7
|
+
* The deployment's Linear app connection, or one of the app values stored
|
|
8
|
+
* beside it (`webhook-secret`) when `suffix` is given.
|
|
9
|
+
*/
|
|
10
|
+
export function linearAppConnectionSlug(deploymentId, suffix) {
|
|
11
|
+
const slug = `mda/linear-app/${deploymentId}`;
|
|
12
|
+
return suffix ? `${slug}/${suffix}` : slug;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=connections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connections.js","sourceRoot":"","sources":["../../../src/channels/linear/connections.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,YAAoB,EACpB,MAAe;IAEf,MAAM,IAAI,GAAG,kBAAkB,YAAY,EAAE,CAAC;IAC9C,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Linear refused a request for exceeding its rate limit. */
|
|
2
|
+
export declare class LinearRateLimitError extends Error {
|
|
3
|
+
constructor();
|
|
4
|
+
}
|
|
5
|
+
/** Forget the cached app token; for tests. */
|
|
6
|
+
export declare function resetLinearToken(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Run a GraphQL operation as the app. `query` is a constant; everything that
|
|
9
|
+
* varies goes in `variables`. A rejected token is read again once. Returns
|
|
10
|
+
* the response's `data`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function linearRequest<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
13
|
+
/** The Linear user the app acts as. */
|
|
14
|
+
export type LinearAppUser = {
|
|
15
|
+
id: string;
|
|
16
|
+
displayName: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The Linear user the app acts as, read once per process: its own comments
|
|
20
|
+
* and changes are ignored, and a comment mentioning its `displayName` starts
|
|
21
|
+
* an agent session.
|
|
22
|
+
*/
|
|
23
|
+
export declare function linearAppUser(): Promise<LinearAppUser>;
|
|
24
|
+
/** Forget the cached app user; for tests. */
|
|
25
|
+
export declare function resetLinearAppUser(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Comment on an issue as the app, threaded under `parentId` when given.
|
|
28
|
+
* Returns the comment's id and URL.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createLinearComment(input: {
|
|
31
|
+
issueId: string;
|
|
32
|
+
body: string;
|
|
33
|
+
parentId?: string;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
id: string;
|
|
36
|
+
url?: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Whether a comment belongs to an agent session's thread. */
|
|
39
|
+
export declare function commentInAgentSession(commentId: string): Promise<boolean>;
|
|
40
|
+
/** What the app says in an agent session. */
|
|
41
|
+
export type LinearActivityContent = {
|
|
42
|
+
type: "thought" | "response" | "error" | "elicitation";
|
|
43
|
+
body: string;
|
|
44
|
+
} | {
|
|
45
|
+
type: "action";
|
|
46
|
+
action: string;
|
|
47
|
+
parameter: string;
|
|
48
|
+
result?: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Post an activity to an agent session as the app. `ephemeral` thoughts and
|
|
52
|
+
* actions are replaced by the next activity; a `select` signal offers
|
|
53
|
+
* options to choose from.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createLinearActivity(input: {
|
|
56
|
+
agentSessionId: string;
|
|
57
|
+
content: LinearActivityContent;
|
|
58
|
+
ephemeral?: boolean;
|
|
59
|
+
signal?: "select" | "auth";
|
|
60
|
+
signalMetadata?: Record<string, unknown>;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
id: string;
|
|
63
|
+
}>;
|
|
64
|
+
/** Link an agent session to a page about it, such as its Studio thread. */
|
|
65
|
+
export declare function addLinearSessionUrl(agentSessionId: string, link: {
|
|
66
|
+
label: string;
|
|
67
|
+
url: string;
|
|
68
|
+
}): Promise<void>;
|
|
69
|
+
//# sourceMappingURL=graphql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../../src/channels/linear/graphql.ts"],"names":[],"mappings":"AA0BA,6DAA6D;AAC7D,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,cAGC;CACF;AAgBD,8CAA8C;AAC9C,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAWD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACtC,OAAO,CAAC,CAAC,CAAC,CA0BZ;AAiBD,uCAAuC;AACvC,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAGhE;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,CAgBtD;AAED,6CAA6C;AAC7C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAQxC;AAMD,8DAA8D;AAC9D,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED,6CAA6C;AAC7C,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAM3E;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ1B;AAMD,2EAA2E;AAC3E,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { connections } from "../../connections.js";
|
|
2
|
+
import { LINEAR_TOKEN_SLUG } from "./connections.js";
|
|
3
|
+
const LINEAR_GRAPHQL_URL = "https://api.linear.app/graphql";
|
|
4
|
+
const LINEAR_API_TIMEOUT_MS = 10_000;
|
|
5
|
+
/** The largest Linear response body read. */
|
|
6
|
+
const LINEAR_RESPONSE_MAX_CHARS = 1_000_000;
|
|
7
|
+
/** How long the app token read from Agent Auth is reused. */
|
|
8
|
+
const TOKEN_TTL_MS = 5 * 60_000;
|
|
9
|
+
let appToken;
|
|
10
|
+
/**
|
|
11
|
+
* Where GraphQL requests go: Linear's API, or under `mda dev`
|
|
12
|
+
* (`MDA_LOCAL_DEV=1`) the stand-in `MDA_LINEAR_API_URL` names, so local
|
|
13
|
+
* tests never reach Linear. A deployment always uses Linear's API.
|
|
14
|
+
*/
|
|
15
|
+
function graphqlUrl(env = process.env) {
|
|
16
|
+
const override = env.MDA_LINEAR_API_URL?.trim();
|
|
17
|
+
if (env.MDA_LOCAL_DEV !== "1" || !override)
|
|
18
|
+
return LINEAR_GRAPHQL_URL;
|
|
19
|
+
const url = new URL(override);
|
|
20
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
21
|
+
throw new TypeError("MDA_LINEAR_API_URL must be an http(s) URL");
|
|
22
|
+
return url.toString();
|
|
23
|
+
}
|
|
24
|
+
/** Linear refused a request for exceeding its rate limit. */
|
|
25
|
+
export class LinearRateLimitError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super("Linear rate limit exceeded");
|
|
28
|
+
this.name = "LinearRateLimitError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** The app's access token, read from Agent Auth at most every few minutes. */
|
|
32
|
+
function linearToken() {
|
|
33
|
+
if (appToken && appToken.expiresAt > Date.now())
|
|
34
|
+
return appToken.value;
|
|
35
|
+
const entry = {
|
|
36
|
+
value: connections.resolveDeploymentSecret(LINEAR_TOKEN_SLUG),
|
|
37
|
+
expiresAt: Date.now() + TOKEN_TTL_MS,
|
|
38
|
+
};
|
|
39
|
+
entry.value.catch(() => {
|
|
40
|
+
if (appToken === entry)
|
|
41
|
+
appToken = undefined;
|
|
42
|
+
});
|
|
43
|
+
appToken = entry;
|
|
44
|
+
return entry.value;
|
|
45
|
+
}
|
|
46
|
+
/** Forget the cached app token; for tests. */
|
|
47
|
+
export function resetLinearToken() {
|
|
48
|
+
appToken = undefined;
|
|
49
|
+
}
|
|
50
|
+
function errorCodes(body) {
|
|
51
|
+
return (body.errors ?? []).flatMap((error) => typeof error.extensions?.code === "string" ? [error.extensions.code] : []);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Run a GraphQL operation as the app. `query` is a constant; everything that
|
|
55
|
+
* varies goes in `variables`. A rejected token is read again once. Returns
|
|
56
|
+
* the response's `data`.
|
|
57
|
+
*/
|
|
58
|
+
export async function linearRequest(query, variables = {}) {
|
|
59
|
+
const send = async () => fetch(graphqlUrl(), {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: {
|
|
62
|
+
Authorization: `Bearer ${await linearToken()}`,
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({ query, variables }),
|
|
66
|
+
signal: AbortSignal.timeout(LINEAR_API_TIMEOUT_MS),
|
|
67
|
+
});
|
|
68
|
+
let response = await send();
|
|
69
|
+
let body = await readBody(response);
|
|
70
|
+
if (response.status === 401 ||
|
|
71
|
+
errorCodes(body).includes("AUTHENTICATION_ERROR")) {
|
|
72
|
+
appToken = undefined;
|
|
73
|
+
response = await send();
|
|
74
|
+
body = await readBody(response);
|
|
75
|
+
}
|
|
76
|
+
if (errorCodes(body).includes("RATELIMITED"))
|
|
77
|
+
throw new LinearRateLimitError();
|
|
78
|
+
if (!response.ok || body.errors?.length || body.data === undefined)
|
|
79
|
+
throw new Error(`Linear refused the request (HTTP ${response.status})`);
|
|
80
|
+
return body.data;
|
|
81
|
+
}
|
|
82
|
+
async function readBody(response) {
|
|
83
|
+
const text = await response.text();
|
|
84
|
+
if (text.length > LINEAR_RESPONSE_MAX_CHARS)
|
|
85
|
+
return {};
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(text);
|
|
88
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
89
|
+
? parsed
|
|
90
|
+
: {};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const VIEWER_QUERY = "query MdaLinearViewer { viewer { id displayName } }";
|
|
97
|
+
let appUser;
|
|
98
|
+
/**
|
|
99
|
+
* The Linear user the app acts as, read once per process: its own comments
|
|
100
|
+
* and changes are ignored, and a comment mentioning its `displayName` starts
|
|
101
|
+
* an agent session.
|
|
102
|
+
*/
|
|
103
|
+
export function linearAppUser() {
|
|
104
|
+
appUser ??= linearRequest(VIEWER_QUERY).then(({ viewer }) => {
|
|
105
|
+
if (typeof viewer?.id !== "string" ||
|
|
106
|
+
!viewer.id ||
|
|
107
|
+
typeof viewer.displayName !== "string")
|
|
108
|
+
throw new Error("Linear did not report the app's user");
|
|
109
|
+
return { id: viewer.id, displayName: viewer.displayName };
|
|
110
|
+
});
|
|
111
|
+
appUser.catch(() => {
|
|
112
|
+
appUser = undefined;
|
|
113
|
+
});
|
|
114
|
+
return appUser;
|
|
115
|
+
}
|
|
116
|
+
/** Forget the cached app user; for tests. */
|
|
117
|
+
export function resetLinearAppUser() {
|
|
118
|
+
appUser = undefined;
|
|
119
|
+
}
|
|
120
|
+
const COMMENT_CREATE_MUTATION = `mutation MdaLinearCommentCreate($input: CommentCreateInput!) {
|
|
121
|
+
commentCreate(input: $input) { success comment { id url } }
|
|
122
|
+
}`;
|
|
123
|
+
/**
|
|
124
|
+
* Comment on an issue as the app, threaded under `parentId` when given.
|
|
125
|
+
* Returns the comment's id and URL.
|
|
126
|
+
*/
|
|
127
|
+
export async function createLinearComment(input) {
|
|
128
|
+
const data = await linearRequest(COMMENT_CREATE_MUTATION, { input });
|
|
129
|
+
const comment = data.commentCreate?.comment;
|
|
130
|
+
if (!data.commentCreate?.success || !comment?.id)
|
|
131
|
+
throw new Error("Linear did not create the comment");
|
|
132
|
+
return { id: comment.id, ...(comment.url && { url: comment.url }) };
|
|
133
|
+
}
|
|
134
|
+
const COMMENT_SESSION_QUERY = `query MdaLinearCommentSession($id: String!) {
|
|
135
|
+
comment(id: $id) { agentSession { id } }
|
|
136
|
+
}`;
|
|
137
|
+
/** Whether a comment belongs to an agent session's thread. */
|
|
138
|
+
export async function commentInAgentSession(commentId) {
|
|
139
|
+
const data = await linearRequest(COMMENT_SESSION_QUERY, { id: commentId });
|
|
140
|
+
return Boolean(data.comment?.agentSession?.id);
|
|
141
|
+
}
|
|
142
|
+
const ACTIVITY_CREATE_MUTATION = `mutation MdaLinearActivityCreate($input: AgentActivityCreateInput!) {
|
|
143
|
+
agentActivityCreate(input: $input) { success agentActivity { id } }
|
|
144
|
+
}`;
|
|
145
|
+
/**
|
|
146
|
+
* Post an activity to an agent session as the app. `ephemeral` thoughts and
|
|
147
|
+
* actions are replaced by the next activity; a `select` signal offers
|
|
148
|
+
* options to choose from.
|
|
149
|
+
*/
|
|
150
|
+
export async function createLinearActivity(input) {
|
|
151
|
+
const data = await linearRequest(ACTIVITY_CREATE_MUTATION, { input });
|
|
152
|
+
const activity = data.agentActivityCreate?.agentActivity;
|
|
153
|
+
if (!data.agentActivityCreate?.success || !activity?.id)
|
|
154
|
+
throw new Error("Linear did not create the activity");
|
|
155
|
+
return { id: activity.id };
|
|
156
|
+
}
|
|
157
|
+
const SESSION_UPDATE_MUTATION = `mutation MdaLinearSessionUpdate($id: String!, $input: AgentSessionUpdateInput!) {
|
|
158
|
+
agentSessionUpdate(id: $id, input: $input) { success }
|
|
159
|
+
}`;
|
|
160
|
+
/** Link an agent session to a page about it, such as its Studio thread. */
|
|
161
|
+
export async function addLinearSessionUrl(agentSessionId, link) {
|
|
162
|
+
const data = await linearRequest(SESSION_UPDATE_MUTATION, {
|
|
163
|
+
id: agentSessionId,
|
|
164
|
+
input: { addedExternalUrls: [link] },
|
|
165
|
+
});
|
|
166
|
+
if (!data.agentSessionUpdate?.success)
|
|
167
|
+
throw new Error("Linear did not update the session");
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=graphql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../src/channels/linear/graphql.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type HttpChannel } from "../http/index.js";
|
|
2
|
+
import type { LinearChannelOptions } from "./types.js";
|
|
3
|
+
export type { LinearAppOptions, LinearChannelOptions, LinearChannelRuntime, LinearEvent, LinearEventCallback, LinearEventKey, LinearEventResult, LinearPayloadFor, } from "./types.js";
|
|
4
|
+
export { LinearRateLimitError } from "./graphql.js";
|
|
5
|
+
/** Adapt verified Linear webhooks into HTTP channel messages or skips. */
|
|
6
|
+
export declare function linearChannel(options?: LinearChannelOptions): HttpChannel;
|
|
7
|
+
/** Forget the cached webhook secret; for tests. */
|
|
8
|
+
export declare function resetLinearWebhookSecret(): void;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/linear/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAMjB,MAAM,kBAAkB,CAAC;AA2B1B,OAAO,KAAK,EAEV,oBAAoB,EAIrB,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAiBpD,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,WAAW,CAiD7E;AA8GD,mDAAmD;AACnD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|