@heddleagent/execution-host-client 6.7.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -35
- package/dist/agentcore/agentcore-execution-host.d.ts +1 -1
- package/dist/agentcore/agentcore-execution-host.d.ts.map +1 -1
- package/dist/agentcore/agentcore-execution-host.js +6 -3
- package/dist/agentcore/agentcore-execution-host.js.map +1 -1
- package/dist/cli/hostctl.d.ts +11 -0
- package/dist/cli/hostctl.d.ts.map +1 -0
- package/dist/cli/hostctl.js +49 -0
- package/dist/cli/hostctl.js.map +1 -0
- package/dist/contracts/index.d.ts +18 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +28 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/conversation/hosted-conversation-turn-service.js +2 -2
- package/dist/conversation/hosted-conversation-turn-service.js.map +1 -1
- package/dist/conversation/types.d.ts +2 -2
- package/dist/conversation/types.d.ts.map +1 -1
- package/dist/conversation/types.js.map +1 -1
- package/dist/coordinator/contracts.d.ts +148 -5
- package/dist/coordinator/contracts.d.ts.map +1 -1
- package/dist/coordinator/contracts.js +74 -3
- package/dist/coordinator/contracts.js.map +1 -1
- package/dist/coordinator/hosted-heartbeat-execution-client.d.ts +30 -0
- package/dist/coordinator/hosted-heartbeat-execution-client.d.ts.map +1 -0
- package/dist/coordinator/hosted-heartbeat-execution-client.js +240 -0
- package/dist/coordinator/hosted-heartbeat-execution-client.js.map +1 -0
- package/dist/coordinator/hosted-heartbeat-execution-service.d.ts +14 -0
- package/dist/coordinator/hosted-heartbeat-execution-service.d.ts.map +1 -0
- package/dist/coordinator/hosted-heartbeat-execution-service.js +100 -0
- package/dist/coordinator/hosted-heartbeat-execution-service.js.map +1 -0
- package/dist/coordinator/index.d.ts +5 -5
- package/dist/coordinator/index.d.ts.map +1 -1
- package/dist/coordinator/index.js +3 -3
- package/dist/coordinator/index.js.map +1 -1
- package/dist/coordinator/node/execution-http-service.d.ts +11 -0
- package/dist/coordinator/node/execution-http-service.d.ts.map +1 -0
- package/dist/coordinator/node/{delegation-http-service.js → execution-http-service.js} +52 -39
- package/dist/coordinator/node/execution-http-service.js.map +1 -0
- package/dist/coordinator/node/index.d.ts +2 -2
- package/dist/coordinator/node/index.d.ts.map +1 -1
- package/dist/coordinator/node/index.js +1 -1
- package/dist/coordinator/node/index.js.map +1 -1
- package/dist/coordinator/node/types.d.ts +10 -9
- package/dist/coordinator/node/types.d.ts.map +1 -1
- package/dist/coordinator/node/types.js.map +1 -1
- package/dist/coordinator/types.d.ts +51 -13
- package/dist/coordinator/types.d.ts.map +1 -1
- package/dist/coordinator/types.js.map +1 -1
- package/dist/heartbeat/hosted-heartbeat-task-service.js +2 -2
- package/dist/heartbeat/hosted-heartbeat-task-service.js.map +1 -1
- package/dist/host/jwt-execution-host-mcp-capability-verifier.d.ts.map +1 -1
- package/dist/host/jwt-execution-host-mcp-capability-verifier.js +4 -2
- package/dist/host/jwt-execution-host-mcp-capability-verifier.js.map +1 -1
- package/dist/host/jwt-execution-identity-verifier.d.ts.map +1 -1
- package/dist/host/jwt-execution-identity-verifier.js +4 -2
- package/dist/host/jwt-execution-identity-verifier.js.map +1 -1
- package/dist/host/runtime-session/service.d.ts +2 -2
- package/dist/host/runtime-session/service.d.ts.map +1 -1
- package/dist/host/runtime-session/service.js +1 -1
- package/dist/host/runtime-session/service.js.map +1 -1
- package/dist/host/runtime-session/types.d.ts +2 -2
- package/dist/host/runtime-session/types.d.ts.map +1 -1
- package/dist/host/runtime-session/types.js.map +1 -1
- package/dist/host/schemas.d.ts +6 -0
- package/dist/host/schemas.d.ts.map +1 -1
- package/dist/host/schemas.js +18 -1
- package/dist/host/schemas.js.map +1 -1
- package/dist/host/types.d.ts +2 -0
- package/dist/host/types.d.ts.map +1 -1
- package/dist/host/types.js.map +1 -1
- package/dist/http-sse/direct-http-execution-host.d.ts.map +1 -1
- package/dist/http-sse/direct-http-execution-host.js +8 -7
- package/dist/http-sse/direct-http-execution-host.js.map +1 -1
- package/dist/http-sse/types.d.ts +5 -3
- package/dist/http-sse/types.d.ts.map +1 -1
- package/dist/http-sse/types.js.map +1 -1
- package/dist/node/authority-key.d.ts.map +1 -1
- package/dist/node/authority-key.js +24 -49
- package/dist/node/authority-key.js.map +1 -1
- package/dist/node/direct-credentials.d.ts +3 -7
- package/dist/node/direct-credentials.d.ts.map +1 -1
- package/dist/node/direct-credentials.js +3 -15
- package/dist/node/direct-credentials.js.map +1 -1
- package/dist/node/environment-value.d.ts +17 -0
- package/dist/node/environment-value.d.ts.map +1 -0
- package/dist/node/environment-value.js +78 -0
- package/dist/node/environment-value.js.map +1 -0
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2 -0
- package/dist/node/index.js.map +1 -1
- package/dist/node/local-credential-bundle.d.ts +33 -0
- package/dist/node/local-credential-bundle.d.ts.map +1 -0
- package/dist/node/local-credential-bundle.js +196 -0
- package/dist/node/local-credential-bundle.js.map +1 -0
- package/dist/node/owner-only-file.d.ts +17 -0
- package/dist/node/owner-only-file.d.ts.map +1 -0
- package/dist/node/owner-only-file.js +59 -0
- package/dist/node/owner-only-file.js.map +1 -0
- package/dist/testing/request.d.ts.map +1 -1
- package/dist/testing/request.js +14 -4
- package/dist/testing/request.js.map +1 -1
- package/package.json +5 -1
- package/spec/v1/openapi.json +62 -4
- package/spec/v1/schema-bundle.json +58 -0
- package/dist/coordinator/hosted-heartbeat-delegation-client.d.ts +0 -21
- package/dist/coordinator/hosted-heartbeat-delegation-client.d.ts.map +0 -1
- package/dist/coordinator/hosted-heartbeat-delegation-client.js +0 -117
- package/dist/coordinator/hosted-heartbeat-delegation-client.js.map +0 -1
- package/dist/coordinator/hosted-heartbeat-delegation-service.d.ts +0 -15
- package/dist/coordinator/hosted-heartbeat-delegation-service.d.ts.map +0 -1
- package/dist/coordinator/hosted-heartbeat-delegation-service.js +0 -81
- package/dist/coordinator/hosted-heartbeat-delegation-service.js.map +0 -1
- package/dist/coordinator/node/delegation-http-service.d.ts +0 -11
- package/dist/coordinator/node/delegation-http-service.d.ts.map +0 -1
- package/dist/coordinator/node/delegation-http-service.js.map +0 -1
|
@@ -1,35 +1,60 @@
|
|
|
1
1
|
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
2
2
|
import { z, ZodError } from 'zod';
|
|
3
|
-
import {
|
|
4
|
-
import { HostedHeartbeatDelegationRejectedError, } from '../hosted-heartbeat-delegation-service.js';
|
|
3
|
+
import { HOSTED_HEARTBEAT_EXECUTION_PATHS, HostedHeartbeatExecutionPreparationRequestSchema, HostedHeartbeatExecutionSettlementRequestSchema, } from '../contracts.js';
|
|
5
4
|
import { HostedHeartbeatServiceTokenSchema } from '../service-token.js';
|
|
6
5
|
import { NodeHttpPathSchema, NodeHttpRequestError, errorType, readJsonBody, readPathname, takeAuthorization, writeJson, writeJsonError, } from '../../node/http-utils.js';
|
|
7
6
|
const DEFAULT_MAX_BODY_BYTES = 16 * 1_024;
|
|
8
|
-
/** Standard authenticated Node HTTP edge for product-owned
|
|
9
|
-
export class
|
|
10
|
-
#
|
|
7
|
+
/** Standard authenticated Node HTTP edge for product-owned work lifecycle. */
|
|
8
|
+
export class NodeHostedHeartbeatExecutionHttpService {
|
|
9
|
+
#executions;
|
|
11
10
|
#tokenDigest;
|
|
12
|
-
#
|
|
11
|
+
#paths;
|
|
13
12
|
#maxBodyBytes;
|
|
14
13
|
#reportFailure;
|
|
15
14
|
#active = new Set();
|
|
16
15
|
#closed = false;
|
|
17
16
|
#closePromise;
|
|
18
17
|
constructor(config) {
|
|
19
|
-
this.#
|
|
18
|
+
this.#executions = config.executions;
|
|
20
19
|
this.#tokenDigest = digest(HostedHeartbeatServiceTokenSchema.parse(config.apiToken));
|
|
21
|
-
this.#
|
|
20
|
+
this.#paths = {
|
|
21
|
+
prepare: NodeHttpPathSchema.parse(config.preparePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.prepare),
|
|
22
|
+
settle: NodeHttpPathSchema.parse(config.settlePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.settle),
|
|
23
|
+
};
|
|
22
24
|
this.#maxBodyBytes = z.number().int().min(1).max(1_048_576).parse(config.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES);
|
|
23
25
|
this.#reportFailure = config.reportFailure;
|
|
24
26
|
}
|
|
25
27
|
handle(request, response) {
|
|
26
|
-
|
|
28
|
+
const operation = this.#operation(readPathname(request.url));
|
|
29
|
+
if (!operation) {
|
|
27
30
|
return false;
|
|
28
31
|
}
|
|
29
|
-
this
|
|
32
|
+
this.#start(operation, request, response);
|
|
30
33
|
return true;
|
|
31
34
|
}
|
|
32
|
-
|
|
35
|
+
handleExecution(request, response) {
|
|
36
|
+
const operation = this.#operation(readPathname(request.url));
|
|
37
|
+
if (!operation) {
|
|
38
|
+
request.resume();
|
|
39
|
+
writeJsonError(response, 404, 'Heartbeat execution route not found.');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.#start(operation, request, response);
|
|
43
|
+
}
|
|
44
|
+
close() {
|
|
45
|
+
if (!this.#closePromise) {
|
|
46
|
+
this.#closed = true;
|
|
47
|
+
const active = [...this.#active];
|
|
48
|
+
active.forEach(({ abortController, request, response }) => {
|
|
49
|
+
abortController.abort(new Error('The heartbeat execution service is stopping.'));
|
|
50
|
+
request.destroy();
|
|
51
|
+
response.destroy();
|
|
52
|
+
});
|
|
53
|
+
this.#closePromise = Promise.allSettled(active.map(({ pending }) => pending)).then(() => undefined);
|
|
54
|
+
}
|
|
55
|
+
return this.#closePromise;
|
|
56
|
+
}
|
|
57
|
+
#start(operation, request, response) {
|
|
33
58
|
if (this.#closed) {
|
|
34
59
|
request.resume();
|
|
35
60
|
writeJsonError(response, 503, 'Hosted execution is unavailable.');
|
|
@@ -48,7 +73,7 @@ export class NodeHostedHeartbeatDelegationHttpService {
|
|
|
48
73
|
}
|
|
49
74
|
catch (error) {
|
|
50
75
|
request.resume();
|
|
51
|
-
writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat
|
|
76
|
+
writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat execution request.');
|
|
52
77
|
return;
|
|
53
78
|
}
|
|
54
79
|
if (!this.#authenticates(authorization)) {
|
|
@@ -59,7 +84,7 @@ export class NodeHostedHeartbeatDelegationHttpService {
|
|
|
59
84
|
return;
|
|
60
85
|
}
|
|
61
86
|
const abortController = new AbortController();
|
|
62
|
-
const abort = () => abortController.abort(new Error('The heartbeat
|
|
87
|
+
const abort = () => abortController.abort(new Error('The heartbeat execution request closed.'));
|
|
63
88
|
request.once('aborted', abort);
|
|
64
89
|
response.once('close', abort);
|
|
65
90
|
const active = {
|
|
@@ -68,48 +93,36 @@ export class NodeHostedHeartbeatDelegationHttpService {
|
|
|
68
93
|
response,
|
|
69
94
|
pending: Promise.resolve(),
|
|
70
95
|
};
|
|
71
|
-
active.pending = this.#serve(request, response, abortController.signal).finally(() => {
|
|
96
|
+
active.pending = this.#serve(operation, request, response, abortController.signal).finally(() => {
|
|
72
97
|
request.removeListener('aborted', abort);
|
|
73
98
|
response.removeListener('close', abort);
|
|
74
99
|
this.#active.delete(active);
|
|
75
100
|
});
|
|
76
101
|
this.#active.add(active);
|
|
77
102
|
}
|
|
78
|
-
|
|
79
|
-
if (!this.#closePromise) {
|
|
80
|
-
this.#closed = true;
|
|
81
|
-
const active = [...this.#active];
|
|
82
|
-
active.forEach(({ abortController, request, response }) => {
|
|
83
|
-
abortController.abort(new Error('The heartbeat delegation service is stopping.'));
|
|
84
|
-
request.destroy();
|
|
85
|
-
response.destroy();
|
|
86
|
-
});
|
|
87
|
-
this.#closePromise = Promise.allSettled(active.map(({ pending }) => pending)).then(() => undefined);
|
|
88
|
-
}
|
|
89
|
-
return this.#closePromise;
|
|
90
|
-
}
|
|
91
|
-
async #serve(request, response, signal) {
|
|
103
|
+
async #serve(operation, request, response, signal) {
|
|
92
104
|
try {
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
105
|
+
const body = await readJsonBody(request, this.#maxBodyBytes, signal);
|
|
106
|
+
const result = operation === 'prepare'
|
|
107
|
+
? await this.#executions.prepare(HostedHeartbeatExecutionPreparationRequestSchema.parse(body), signal)
|
|
108
|
+
: await this.#executions.settle(HostedHeartbeatExecutionSettlementRequestSchema.parse(body), signal);
|
|
109
|
+
writeJson(response, 200, result);
|
|
96
110
|
}
|
|
97
111
|
catch (error) {
|
|
98
112
|
if (signal.aborted) {
|
|
99
113
|
return;
|
|
100
114
|
}
|
|
101
|
-
if (error instanceof HostedHeartbeatDelegationRejectedError) {
|
|
102
|
-
writeJsonError(response, 403, error.message);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
115
|
if (error instanceof NodeHttpRequestError || error instanceof ZodError) {
|
|
106
|
-
writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat
|
|
116
|
+
writeJsonError(response, error instanceof NodeHttpRequestError ? error.statusCode : 400, 'Invalid heartbeat execution request.');
|
|
107
117
|
return;
|
|
108
118
|
}
|
|
109
|
-
this.#report({ phase:
|
|
110
|
-
writeJsonError(response, 500,
|
|
119
|
+
this.#report({ phase: operation, errorType: errorType(error) });
|
|
120
|
+
writeJsonError(response, 500, `Heartbeat execution ${operation} failed.`);
|
|
111
121
|
}
|
|
112
122
|
}
|
|
123
|
+
#operation(pathname) {
|
|
124
|
+
return Object.entries(this.#paths).find(([, path]) => path === pathname)?.[0];
|
|
125
|
+
}
|
|
113
126
|
#authenticates(authorization) {
|
|
114
127
|
const token = /^Bearer ([^\s]+)$/i.exec(authorization?.trim() ?? '')?.[1];
|
|
115
128
|
return token
|
|
@@ -128,4 +141,4 @@ export class NodeHostedHeartbeatDelegationHttpService {
|
|
|
128
141
|
function digest(value) {
|
|
129
142
|
return createHash('sha256').update(value, 'utf8').digest();
|
|
130
143
|
}
|
|
131
|
-
//# sourceMappingURL=
|
|
144
|
+
//# sourceMappingURL=execution-http-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-http-service.js","sourceRoot":"","sources":["../../../src/coordinator/node/execution-http-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAClC,OAAO,EACL,gCAAgC,EAChC,gDAAgD,EAChD,+CAA+C,GAChD,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iCAAiC,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,cAAc,GACf,MAAM,0BAA0B,CAAC;AAOlC,MAAM,sBAAsB,GAAG,EAAE,GAAG,KAAK,CAAC;AAU1C,8EAA8E;AAC9E,MAAM,OAAO,uCAAuC;IAEzC,WAAW,CAElB;IACO,YAAY,CAAS;IACrB,MAAM,CAAqC;IAC3C,aAAa,CAAS;IACtB,cAAc,CAErB;IACO,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IAC5C,OAAO,GAAG,KAAK,CAAC;IAChB,aAAa,CAA4B;IAEzC,YAAY,MAAqD;QAC/D,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,MAAM,CACxB,iCAAiC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CACzD,CAAC;QACF,IAAI,CAAC,MAAM,GAAG;YACZ,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAC/B,MAAM,CAAC,WAAW,IAAI,gCAAgC,CAAC,OAAO,CAC/D;YACD,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAC9B,MAAM,CAAC,UAAU,IAAI,gCAAgC,CAAC,MAAM,CAC7D;SACF,CAAC;QACF,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAC/D,MAAM,CAAC,YAAY,IAAI,sBAAsB,CAC9C,CAAC;QACF,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC;IAC7C,CAAC;IAED,MAAM,CAAC,OAAwB,EAAE,QAAwB;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,eAAe,CACb,OAAwB,EACxB,QAAwB;QAExB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,sCAAsC,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;YACjC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;gBACxD,eAAe,CAAC,KAAK,CACnB,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAC1D,CAAC;gBACF,OAAO,CAAC,OAAO,EAAE,CAAC;gBAClB,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,UAAU,CACrC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,CACrC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,MAAM,CACJ,SAA6B,EAC7B,OAAwB,EACxB,QAAwB;QAExB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,kCAAkC,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QAED,IAAI,aAAiC,CAAC;QACtC,IAAI,CAAC;YACH,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,qBAAqB,EAAE;oBACnD,KAAK,EAAE,MAAM;iBACd,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,cAAc,CACZ,QAAQ,EACR,KAAK,YAAY,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAC9D,sCAAsC,CACvC,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,6BAA6B,EAAE;gBAC3D,kBAAkB,EAAE,QAAQ;aAC7B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CACvC,IAAI,KAAK,CAAC,yCAAyC,CAAC,CACrD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC/B,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAkB;YAC5B,eAAe;YACf,OAAO;YACP,QAAQ;YACR,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;SAC3B,CAAC;QACF,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAC1B,SAAS,EACT,OAAO,EACP,QAAQ,EACR,eAAe,CAAC,MAAM,CACvB,CAAC,OAAO,CAAC,GAAG,EAAE;YACb,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACzC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,MAAM,CACV,SAA6B,EAC7B,OAAwB,EACxB,QAAwB,EACxB,MAAmB;QAEnB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YACrE,MAAM,MAAM,GAAG,SAAS,KAAK,SAAS;gBACpC,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAC5B,gDAAgD,CAAC,KAAK,CAAC,IAAI,CAAC,EAC5D,MAAM,CACP;gBACH,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAC3B,+CAA+C,CAAC,KAAK,CAAC,IAAI,CAAC,EAC3D,MAAM,CACP,CAAC;YACN,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO;YACT,CAAC;YACD,IAAI,KAAK,YAAY,oBAAoB,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;gBACvE,cAAc,CACZ,QAAQ,EACR,KAAK,YAAY,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAC9D,sCAAsC,CACvC,CAAC;gBACF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChE,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE,uBAAuB,SAAS,UAAU,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,UAAU,CAAC,QAA4B;QACrC,OAAQ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAG/B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,cAAc,CAAC,aAAiC;QAC9C,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CACrC,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,CAC5B,EAAE,CAAC,CAAC,CAAC,CAAC;QACP,OAAO,KAAK;YACV,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC;YACnD,CAAC,CAAC,KAAK,CAAC;IACZ,CAAC;IAED,OAAO,CAAC,OAA4C;QAClD,IAAI,CAAC;YACH,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;IACH,CAAC;CACF;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;AAC7D,CAAC","sourcesContent":["import { createHash, timingSafeEqual } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { z, ZodError } from 'zod';\nimport {\n HOSTED_HEARTBEAT_EXECUTION_PATHS,\n HostedHeartbeatExecutionPreparationRequestSchema,\n HostedHeartbeatExecutionSettlementRequestSchema,\n} from '../contracts.js';\nimport { HostedHeartbeatServiceTokenSchema } from '../service-token.js';\nimport {\n NodeHttpPathSchema,\n NodeHttpRequestError,\n errorType,\n readJsonBody,\n readPathname,\n takeAuthorization,\n writeJson,\n writeJsonError,\n} from '../../node/http-utils.js';\nimport type {\n NodeHostedHeartbeatExecutionFailure,\n NodeHostedHeartbeatExecutionHttpHandler,\n NodeHostedHeartbeatExecutionHttpServiceConfig,\n} from './types.js';\n\nconst DEFAULT_MAX_BODY_BYTES = 16 * 1_024;\n\ntype ExecutionOperation = 'prepare' | 'settle';\ntype ActiveRequest = {\n abortController: AbortController;\n request: IncomingMessage;\n response: ServerResponse;\n pending: Promise<void>;\n};\n\n/** Standard authenticated Node HTTP edge for product-owned work lifecycle. */\nexport class NodeHostedHeartbeatExecutionHttpService\nimplements NodeHostedHeartbeatExecutionHttpHandler {\n readonly #executions: NodeHostedHeartbeatExecutionHttpServiceConfig[\n 'executions'\n ];\n readonly #tokenDigest: Buffer;\n readonly #paths: Record<ExecutionOperation, string>;\n readonly #maxBodyBytes: number;\n readonly #reportFailure: NodeHostedHeartbeatExecutionHttpServiceConfig[\n 'reportFailure'\n ];\n readonly #active = new Set<ActiveRequest>();\n #closed = false;\n #closePromise: Promise<void> | undefined;\n\n constructor(config: NodeHostedHeartbeatExecutionHttpServiceConfig) {\n this.#executions = config.executions;\n this.#tokenDigest = digest(\n HostedHeartbeatServiceTokenSchema.parse(config.apiToken),\n );\n this.#paths = {\n prepare: NodeHttpPathSchema.parse(\n config.preparePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.prepare,\n ),\n settle: NodeHttpPathSchema.parse(\n config.settlePath ?? HOSTED_HEARTBEAT_EXECUTION_PATHS.settle,\n ),\n };\n this.#maxBodyBytes = z.number().int().min(1).max(1_048_576).parse(\n config.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,\n );\n this.#reportFailure = config.reportFailure;\n }\n\n handle(request: IncomingMessage, response: ServerResponse): boolean {\n const operation = this.#operation(readPathname(request.url));\n if (!operation) {\n return false;\n }\n this.#start(operation, request, response);\n return true;\n }\n\n handleExecution(\n request: IncomingMessage,\n response: ServerResponse,\n ): void {\n const operation = this.#operation(readPathname(request.url));\n if (!operation) {\n request.resume();\n writeJsonError(response, 404, 'Heartbeat execution route not found.');\n return;\n }\n this.#start(operation, request, response);\n }\n\n close(): Promise<void> {\n if (!this.#closePromise) {\n this.#closed = true;\n const active = [...this.#active];\n active.forEach(({ abortController, request, response }) => {\n abortController.abort(\n new Error('The heartbeat execution service is stopping.'),\n );\n request.destroy();\n response.destroy();\n });\n this.#closePromise = Promise.allSettled(\n active.map(({ pending }) => pending),\n ).then(() => undefined);\n }\n return this.#closePromise;\n }\n\n #start(\n operation: ExecutionOperation,\n request: IncomingMessage,\n response: ServerResponse,\n ): void {\n if (this.#closed) {\n request.resume();\n writeJsonError(response, 503, 'Hosted execution is unavailable.');\n return;\n }\n\n let authorization: string | undefined;\n try {\n authorization = takeAuthorization(request);\n if (request.method !== 'POST') {\n request.resume();\n writeJsonError(response, 405, 'Method not allowed.', {\n Allow: 'POST',\n });\n return;\n }\n } catch (error) {\n request.resume();\n writeJsonError(\n response,\n error instanceof NodeHttpRequestError ? error.statusCode : 400,\n 'Invalid heartbeat execution request.',\n );\n return;\n }\n if (!this.#authenticates(authorization)) {\n request.resume();\n writeJsonError(response, 401, 'Authentication is required.', {\n 'WWW-Authenticate': 'Bearer',\n });\n return;\n }\n\n const abortController = new AbortController();\n const abort = () => abortController.abort(\n new Error('The heartbeat execution request closed.'),\n );\n request.once('aborted', abort);\n response.once('close', abort);\n const active: ActiveRequest = {\n abortController,\n request,\n response,\n pending: Promise.resolve(),\n };\n active.pending = this.#serve(\n operation,\n request,\n response,\n abortController.signal,\n ).finally(() => {\n request.removeListener('aborted', abort);\n response.removeListener('close', abort);\n this.#active.delete(active);\n });\n this.#active.add(active);\n }\n\n async #serve(\n operation: ExecutionOperation,\n request: IncomingMessage,\n response: ServerResponse,\n signal: AbortSignal,\n ): Promise<void> {\n try {\n const body = await readJsonBody(request, this.#maxBodyBytes, signal);\n const result = operation === 'prepare'\n ? await this.#executions.prepare(\n HostedHeartbeatExecutionPreparationRequestSchema.parse(body),\n signal,\n )\n : await this.#executions.settle(\n HostedHeartbeatExecutionSettlementRequestSchema.parse(body),\n signal,\n );\n writeJson(response, 200, result);\n } catch (error) {\n if (signal.aborted) {\n return;\n }\n if (error instanceof NodeHttpRequestError || error instanceof ZodError) {\n writeJsonError(\n response,\n error instanceof NodeHttpRequestError ? error.statusCode : 400,\n 'Invalid heartbeat execution request.',\n );\n return;\n }\n this.#report({ phase: operation, errorType: errorType(error) });\n writeJsonError(response, 500, `Heartbeat execution ${operation} failed.`);\n }\n }\n\n #operation(pathname: string | undefined): ExecutionOperation | undefined {\n return (Object.entries(this.#paths) as Array<[\n ExecutionOperation,\n string,\n ]>).find(([, path]) => path === pathname)?.[0];\n }\n\n #authenticates(authorization: string | undefined): boolean {\n const token = /^Bearer ([^\\s]+)$/i.exec(\n authorization?.trim() ?? '',\n )?.[1];\n return token\n ? timingSafeEqual(digest(token), this.#tokenDigest)\n : false;\n }\n\n #report(failure: NodeHostedHeartbeatExecutionFailure): void {\n try {\n this.#reportFailure?.(Object.freeze({ ...failure }));\n } catch {\n // Observability must not change request settlement.\n }\n }\n}\n\nfunction digest(value: string): Buffer {\n return createHash('sha256').update(value, 'utf8').digest();\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { NodeHostedHeartbeatExecutionHttpService } from './execution-http-service.js';
|
|
2
2
|
export { takeHostedHeartbeatServiceToken } from './environment.js';
|
|
3
|
-
export type {
|
|
3
|
+
export type { NodeHostedHeartbeatExecutionFailure, NodeHostedHeartbeatExecutionHttpHandler, NodeHostedHeartbeatExecutionHttpServiceConfig, } from './types.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EACV,mCAAmC,EACnC,uCAAuC,EACvC,6CAA6C,GAC9C,MAAM,YAAY,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { NodeHostedHeartbeatExecutionHttpService } from './execution-http-service.js';
|
|
2
2
|
export { takeHostedHeartbeatServiceToken } from './environment.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coordinator/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uCAAuC,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["export { NodeHostedHeartbeatExecutionHttpService } from './execution-http-service.js';\nexport { takeHostedHeartbeatServiceToken } from './environment.js';\nexport type {\n NodeHostedHeartbeatExecutionFailure,\n NodeHostedHeartbeatExecutionHttpHandler,\n NodeHostedHeartbeatExecutionHttpServiceConfig,\n} from './types.js';\n"]}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import type {
|
|
3
|
-
export type
|
|
4
|
-
phase: '
|
|
2
|
+
import type { HostedHeartbeatExecutionApi } from '../types.js';
|
|
3
|
+
export type NodeHostedHeartbeatExecutionFailure = {
|
|
4
|
+
phase: 'prepare' | 'settle';
|
|
5
5
|
errorType: string;
|
|
6
6
|
};
|
|
7
|
-
export type
|
|
8
|
-
|
|
7
|
+
export type NodeHostedHeartbeatExecutionHttpServiceConfig = {
|
|
8
|
+
executions: HostedHeartbeatExecutionApi;
|
|
9
9
|
apiToken: string;
|
|
10
|
-
|
|
10
|
+
preparePath?: string;
|
|
11
|
+
settlePath?: string;
|
|
11
12
|
maxBodyBytes?: number;
|
|
12
13
|
/** Receives credential-free operational metadata, never the raw error. */
|
|
13
|
-
reportFailure?: (failure:
|
|
14
|
+
reportFailure?: (failure: NodeHostedHeartbeatExecutionFailure) => void;
|
|
14
15
|
};
|
|
15
|
-
export interface
|
|
16
|
+
export interface NodeHostedHeartbeatExecutionHttpHandler {
|
|
16
17
|
handle(request: IncomingMessage, response: ServerResponse): boolean;
|
|
17
|
-
|
|
18
|
+
handleExecution(request: IncomingMessage, response: ServerResponse): void;
|
|
18
19
|
close(): Promise<void>;
|
|
19
20
|
}
|
|
20
21
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,MAAM,mCAAmC,GAAG;IAChD,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,6CAA6C,GAAG;IAC1D,UAAU,EAAE,2BAA2B,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,IAAI,CAAC;CACxE,CAAC;AAEF,MAAM,WAAW,uCAAuC;IACtD,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC;IACpE,eAAe,CACb,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAAC;IACR,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type {
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/coordinator/node/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { HostedHeartbeatExecutionApi } from '../types.js';\n\nexport type NodeHostedHeartbeatExecutionFailure = {\n phase: 'prepare' | 'settle';\n errorType: string;\n};\n\nexport type NodeHostedHeartbeatExecutionHttpServiceConfig = {\n executions: HostedHeartbeatExecutionApi;\n apiToken: string;\n preparePath?: string;\n settlePath?: string;\n maxBodyBytes?: number;\n /** Receives credential-free operational metadata, never the raw error. */\n reportFailure?: (failure: NodeHostedHeartbeatExecutionFailure) => void;\n};\n\nexport interface NodeHostedHeartbeatExecutionHttpHandler {\n handle(request: IncomingMessage, response: ServerResponse): boolean;\n handleExecution(\n request: IncomingMessage,\n response: ServerResponse,\n ): void;\n close(): Promise<void>;\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import type { ExecutionAuthorityIssuer } from '../authority/index.js';
|
|
|
2
2
|
import type { HostedModelCredentialProvider } from '../conversation/index.js';
|
|
3
3
|
import type { HostedHeartbeatAgentExecutionTransportInput } from '../heartbeat/index.js';
|
|
4
4
|
import type { HeartbeatExecutionHost } from '../http-sse/index.js';
|
|
5
|
-
import type { HostedHeartbeatCoordinatorTaskInput, HostedHeartbeatCoordinatorState, HostedHeartbeatCoordinatorTaskDetail, HostedHeartbeatCoordinatorTaskView,
|
|
5
|
+
import type { HostedHeartbeatCoordinatorTaskInput, HostedHeartbeatCoordinatorState, HostedHeartbeatCoordinatorTaskDetail, HostedHeartbeatCoordinatorTaskView, HostedHeartbeatExecutionPreparation, HostedHeartbeatExecutionPreparationDecision, HostedHeartbeatExecutionPreparationRequest, HostedHeartbeatExecutionSettlement, HostedHeartbeatExecutionSettlementRequest, HostedHeartbeatDesiredTask } from './contracts.js';
|
|
6
6
|
export type HostedHeartbeatCoordinatorClientConfig = {
|
|
7
7
|
baseUrl: URL;
|
|
8
8
|
apiToken: string;
|
|
@@ -32,36 +32,74 @@ export type HostedHeartbeatTaskReconciliation = {
|
|
|
32
32
|
export type HostedHeartbeatTaskReconcilerConfig = {
|
|
33
33
|
coordinator: Pick<HostedHeartbeatCoordinatorTaskApi, 'listTasks' | 'upsertTask' | 'deleteTask' | 'pause' | 'resume'>;
|
|
34
34
|
};
|
|
35
|
-
export type
|
|
35
|
+
export type HostedHeartbeatExecutionPreparationInput = {
|
|
36
36
|
taskId: string;
|
|
37
37
|
executionId: string;
|
|
38
|
+
interruptedExecutionId?: string;
|
|
38
39
|
signal: AbortSignal;
|
|
39
40
|
};
|
|
40
|
-
export
|
|
41
|
-
|
|
41
|
+
export type HostedHeartbeatExecutionSettlementInput = HostedHeartbeatExecutionSettlementRequest & {
|
|
42
|
+
signal: AbortSignal;
|
|
43
|
+
};
|
|
44
|
+
/** Product-owned lifecycle around one Coordinator-owned execution attempt. */
|
|
45
|
+
export interface HostedHeartbeatProductExecutionLifecycle {
|
|
46
|
+
prepare(input: HostedHeartbeatExecutionPreparationInput): HostedHeartbeatExecutionPreparationDecision | Promise<HostedHeartbeatExecutionPreparationDecision>;
|
|
47
|
+
settle(input: HostedHeartbeatExecutionSettlementInput): HostedHeartbeatExecutionSettlement['disposition'] | Promise<HostedHeartbeatExecutionSettlement['disposition']>;
|
|
42
48
|
}
|
|
43
|
-
export type
|
|
49
|
+
export type HostedHeartbeatExecutionServiceConfig = {
|
|
44
50
|
authority: ExecutionAuthorityIssuer;
|
|
45
|
-
|
|
51
|
+
lifecycle: HostedHeartbeatProductExecutionLifecycle;
|
|
46
52
|
runtimeSessionNamespace: string;
|
|
47
53
|
maxExecutionMs: number;
|
|
48
54
|
now?: () => Date;
|
|
49
55
|
};
|
|
50
|
-
export interface
|
|
51
|
-
|
|
56
|
+
export interface HostedHeartbeatExecutionApi {
|
|
57
|
+
prepare(input: HostedHeartbeatExecutionPreparationRequest, signal?: AbortSignal): Promise<HostedHeartbeatExecutionPreparation>;
|
|
58
|
+
settle(input: HostedHeartbeatExecutionSettlementRequest, signal?: AbortSignal): Promise<HostedHeartbeatExecutionSettlement>;
|
|
52
59
|
}
|
|
53
|
-
export type
|
|
60
|
+
export type HostedHeartbeatExecutionClientConfig = {
|
|
54
61
|
baseUrl: URL;
|
|
55
62
|
apiToken: string;
|
|
63
|
+
/** Allows only Docker's explicit local-host alias over HTTP. */
|
|
64
|
+
allowDockerLocalHost?: boolean;
|
|
56
65
|
fetch?: typeof globalThis.fetch;
|
|
57
|
-
|
|
66
|
+
preparePath?: string;
|
|
67
|
+
settlePath?: string;
|
|
68
|
+
requestTimeoutMs?: number;
|
|
58
69
|
};
|
|
59
|
-
export type
|
|
60
|
-
|
|
70
|
+
export type HostedHeartbeatDelegatedExecutionConfig = {
|
|
71
|
+
executions: HostedHeartbeatExecutionApi;
|
|
61
72
|
executionHost: HeartbeatExecutionHost;
|
|
62
73
|
modelCredentials: HostedModelCredentialProvider;
|
|
63
74
|
};
|
|
64
|
-
export interface
|
|
75
|
+
export interface HostedHeartbeatExecutionTransportPort {
|
|
65
76
|
execute(input: HostedHeartbeatAgentExecutionTransportInput): Promise<unknown>;
|
|
66
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Structural subset of Heddle's heartbeat handler context. Keeping this port
|
|
80
|
+
* local avoids making the adopter client depend on the full Runtime package.
|
|
81
|
+
*/
|
|
82
|
+
export type HostedHeartbeatCoordinatorExecutionContext<TResult = unknown, TOutcome = unknown> = {
|
|
83
|
+
task: {
|
|
84
|
+
id: string;
|
|
85
|
+
state?: {
|
|
86
|
+
recovery?: {
|
|
87
|
+
interruptedExecutionId: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
executionId: string;
|
|
92
|
+
signal: AbortSignal;
|
|
93
|
+
runAgent(): Promise<TResult>;
|
|
94
|
+
skip(input: {
|
|
95
|
+
summary: string;
|
|
96
|
+
}): TOutcome;
|
|
97
|
+
retry(input: {
|
|
98
|
+
summary: string;
|
|
99
|
+
delayMs?: number;
|
|
100
|
+
}): TOutcome;
|
|
101
|
+
block(input: {
|
|
102
|
+
summary: string;
|
|
103
|
+
}): TOutcome;
|
|
104
|
+
};
|
|
67
105
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACV,6BAA6B,EAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,2CAA2C,EAC5C,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,KAAK,EACV,mCAAmC,EACnC,+BAA+B,EAC/B,oCAAoC,EACpC,kCAAkC,EAClC,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ExecutionAuthorityIssuer,\n} from '../authority/index.js';\nimport type {\n HostedModelCredentialProvider,\n} from '../conversation/index.js';\nimport type {\n HostedHeartbeatAgentExecutionTransportInput,\n} from '../heartbeat/index.js';\nimport type { HeartbeatExecutionHost } from '../http-sse/index.js';\nimport type {\n HostedHeartbeatCoordinatorTaskInput,\n HostedHeartbeatCoordinatorState,\n HostedHeartbeatCoordinatorTaskDetail,\n HostedHeartbeatCoordinatorTaskView,\n
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/coordinator/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ExecutionAuthorityIssuer,\n} from '../authority/index.js';\nimport type {\n HostedModelCredentialProvider,\n} from '../conversation/index.js';\nimport type {\n HostedHeartbeatAgentExecutionTransportInput,\n} from '../heartbeat/index.js';\nimport type { HeartbeatExecutionHost } from '../http-sse/index.js';\nimport type {\n HostedHeartbeatCoordinatorTaskInput,\n HostedHeartbeatCoordinatorState,\n HostedHeartbeatCoordinatorTaskDetail,\n HostedHeartbeatCoordinatorTaskView,\n HostedHeartbeatExecutionPreparation,\n HostedHeartbeatExecutionPreparationDecision,\n HostedHeartbeatExecutionPreparationRequest,\n HostedHeartbeatExecutionSettlement,\n HostedHeartbeatExecutionSettlementRequest,\n HostedHeartbeatDesiredTask,\n} from './contracts.js';\n\nexport type HostedHeartbeatCoordinatorClientConfig = {\n baseUrl: URL;\n apiToken: string;\n fetch?: typeof globalThis.fetch;\n};\n\nexport interface HostedHeartbeatCoordinatorTaskApi {\n readState(signal?: AbortSignal): Promise<HostedHeartbeatCoordinatorState>;\n listTasks(\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskView[]>;\n readTask(\n taskId: string,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskDetail>;\n upsertTask(\n taskId: string,\n task: HostedHeartbeatCoordinatorTaskInput,\n signal?: AbortSignal,\n ): Promise<void>;\n triggerTask(\n taskId: string,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatCoordinatorTaskView>;\n deleteTask(taskId: string, signal?: AbortSignal): Promise<void>;\n pause(signal?: AbortSignal): Promise<void>;\n resume(signal?: AbortSignal): Promise<void>;\n drain(signal?: AbortSignal): Promise<void>;\n}\n\nexport type HostedHeartbeatTaskReconciliationInput = {\n desiredTasks: readonly HostedHeartbeatDesiredTask[];\n resume: boolean;\n signal?: AbortSignal;\n};\n\nexport type HostedHeartbeatTaskReconciliation = {\n deleted: number;\n upserted: number;\n resumed: boolean;\n};\n\nexport type HostedHeartbeatTaskReconcilerConfig = {\n coordinator: Pick<\n HostedHeartbeatCoordinatorTaskApi,\n 'listTasks' | 'upsertTask' | 'deleteTask' | 'pause' | 'resume'\n >;\n};\n\nexport type HostedHeartbeatExecutionPreparationInput = {\n taskId: string;\n executionId: string;\n interruptedExecutionId?: string;\n signal: AbortSignal;\n};\n\nexport type HostedHeartbeatExecutionSettlementInput =\n HostedHeartbeatExecutionSettlementRequest & {\n signal: AbortSignal;\n };\n\n/** Product-owned lifecycle around one Coordinator-owned execution attempt. */\nexport interface HostedHeartbeatProductExecutionLifecycle {\n prepare(\n input: HostedHeartbeatExecutionPreparationInput,\n ): HostedHeartbeatExecutionPreparationDecision\n | Promise<HostedHeartbeatExecutionPreparationDecision>;\n settle(\n input: HostedHeartbeatExecutionSettlementInput,\n ): HostedHeartbeatExecutionSettlement['disposition']\n | Promise<HostedHeartbeatExecutionSettlement['disposition']>;\n}\n\nexport type HostedHeartbeatExecutionServiceConfig = {\n authority: ExecutionAuthorityIssuer;\n lifecycle: HostedHeartbeatProductExecutionLifecycle;\n runtimeSessionNamespace: string;\n maxExecutionMs: number;\n now?: () => Date;\n};\n\nexport interface HostedHeartbeatExecutionApi {\n prepare(\n input: HostedHeartbeatExecutionPreparationRequest,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatExecutionPreparation>;\n settle(\n input: HostedHeartbeatExecutionSettlementRequest,\n signal?: AbortSignal,\n ): Promise<HostedHeartbeatExecutionSettlement>;\n}\n\nexport type HostedHeartbeatExecutionClientConfig = {\n baseUrl: URL;\n apiToken: string;\n /** Allows only Docker's explicit local-host alias over HTTP. */\n allowDockerLocalHost?: boolean;\n fetch?: typeof globalThis.fetch;\n preparePath?: string;\n settlePath?: string;\n requestTimeoutMs?: number;\n};\n\nexport type HostedHeartbeatDelegatedExecutionConfig = {\n executions: HostedHeartbeatExecutionApi;\n executionHost: HeartbeatExecutionHost;\n modelCredentials: HostedModelCredentialProvider;\n};\n\nexport interface HostedHeartbeatExecutionTransportPort {\n execute(\n input: HostedHeartbeatAgentExecutionTransportInput,\n ): Promise<unknown>;\n}\n\n/**\n * Structural subset of Heddle's heartbeat handler context. Keeping this port\n * local avoids making the adopter client depend on the full Runtime package.\n */\nexport type HostedHeartbeatCoordinatorExecutionContext<\n TResult = unknown,\n TOutcome = unknown,\n> = {\n task: {\n id: string;\n state?: {\n recovery?: { interruptedExecutionId: string };\n };\n };\n executionId: string;\n signal: AbortSignal;\n runAgent(): Promise<TResult>;\n skip(input: { summary: string }): TOutcome;\n retry(input: { summary: string; delayMs?: number }): TOutcome;\n block(input: { summary: string }): TOutcome;\n};\n"]}
|
|
@@ -48,7 +48,7 @@ export class HostedHeartbeatTaskService {
|
|
|
48
48
|
if (this.#allowedTools && !mcpCapability) {
|
|
49
49
|
throw new HostedHeartbeatConfigurationError('Hosted heartbeat tool policy requires an MCP-capable execution authority.');
|
|
50
50
|
}
|
|
51
|
-
const
|
|
51
|
+
const modelCredential = await this.#modelCredentials.resolveModelCredential({
|
|
52
52
|
scope: input.scope,
|
|
53
53
|
invocationId: input.invocationId,
|
|
54
54
|
signal: input.signal,
|
|
@@ -74,7 +74,7 @@ export class HostedHeartbeatTaskService {
|
|
|
74
74
|
...(input.signal ? { signal: input.signal } : {}),
|
|
75
75
|
executionAssertion: issued.executionAssertion(),
|
|
76
76
|
...(mcpCapability ? { mcpCapability } : {}),
|
|
77
|
-
|
|
77
|
+
modelCredential,
|
|
78
78
|
})) {
|
|
79
79
|
if (event.kind === 'activity') {
|
|
80
80
|
input.publishActivity?.(event.activity);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hosted-heartbeat-task-service.js","sourceRoot":"","sources":["../../src/heartbeat/hosted-heartbeat-task-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qCAAqC,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,8BAA8B,GAI/B,MAAM,YAAY,CAAC;AAEpB,MAAM,OAAO,iCAAkC,SAAQ,KAAK;IACjD,IAAI,GAAG,mCAAmC,CAAC;CACrD;AAED,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAGjC;IAFZ,IAAI,GAAG,+BAA+B,CAAC;IAEhD,YAAqB,IAAY;QAC/B,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAD5B,SAAI,GAAJ,IAAI,CAAQ;IAEjC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,0BAA0B;IAE5B,UAAU,CAAgD;IAC1D,cAAc,CAAoD;IAClE,iBAAiB,CAExB;IACO,aAAa,CAAgC;IAEtD,YAAY,MAAwC;QAClD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACjD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,GAAG;YAC7B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YACrE,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CACX,QAAkC;QAElC,MAAM,KAAK,GAAG,8BAA8B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7D,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YACzC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,QAAQ,EAAE,uBAAuB;YACjC,GAAG,CAAC,IAAI,CAAC,aAAa;gBACpB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE;gBAC/C,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,EAAE,CAAC;YACzC,MAAM,IAAI,iCAAiC,CACzC,2EAA2E,CAC5E,CAAC;QACJ,CAAC;QACD,MAAM,
|
|
1
|
+
{"version":3,"file":"hosted-heartbeat-task-service.js","sourceRoot":"","sources":["../../src/heartbeat/hosted-heartbeat-task-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,qCAAqC,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,8BAA8B,GAI/B,MAAM,YAAY,CAAC;AAEpB,MAAM,OAAO,iCAAkC,SAAQ,KAAK;IACjD,IAAI,GAAG,mCAAmC,CAAC;CACrD;AAED,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAGjC;IAFZ,IAAI,GAAG,+BAA+B,CAAC;IAEhD,YAAqB,IAAY;QAC/B,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAD5B,SAAI,GAAJ,IAAI,CAAQ;IAEjC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,0BAA0B;IAE5B,UAAU,CAAgD;IAC1D,cAAc,CAAoD;IAClE,iBAAiB,CAExB;IACO,aAAa,CAAgC;IAEtD,YAAY,MAAwC;QAClD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC;QAC3C,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACjD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,GAAG;YAC7B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YACrE,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CACX,QAAkC;QAElC,MAAM,KAAK,GAAG,8BAA8B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7D,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YACzC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,QAAQ,EAAE,uBAAuB;YACjC,GAAG,CAAC,IAAI,CAAC,aAAa;gBACpB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE;gBAC/C,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,EAAE,CAAC;YACzC,MAAM,IAAI,iCAAiC,CACzC,2EAA2E,CAC5E,CAAC;QACJ,CAAC;QACD,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,sBAAsB,CAAC;YAC1E,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QAE/B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC;YAChE,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,GAAG,CAAC,KAAK,CAAC,eAAe;gBACvB,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE;gBAC5C,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,GAAG,CAAC,KAAK,CAAC,gBAAgB;gBACxB,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE;gBAC9C,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,EAAE;YAC/C,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,eAAe;SAChB,CAAC,EAAE,CAAC;YACH,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,KAAK,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACxC,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC5B,OAAO,KAAK,CAAC,MAAM,CAAC;YACtB,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC/B,MAAM,IAAI,qCAAqC,EAAE,CAAC;YACpD,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC3B,MAAM,IAAI,6BAA6B,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QACD,MAAM,IAAI,6BAA6B,CAAC,yBAAyB,CAAC,CAAC;IACrE,CAAC;CACF","sourcesContent":["import {\n HEARTBEAT_TASK_WORKFLOW,\n McpAllowedToolsSchema,\n} from '../contracts/index.js';\nimport { ExecutionHostInvocationCancelledError } from '../http-sse/index.js';\nimport {\n HostedHeartbeatTaskInputSchema,\n type HostedHeartbeatTaskInput,\n type HostedHeartbeatTaskRunner,\n type HostedHeartbeatTaskServiceConfig,\n} from './types.js';\n\nexport class HostedHeartbeatConfigurationError extends Error {\n readonly name = 'HostedHeartbeatConfigurationError';\n}\n\nexport class HostedHeartbeatExecutionError extends Error {\n readonly name = 'HostedHeartbeatExecutionError';\n\n constructor(readonly code: string) {\n super('Execution Host heartbeat task failed.');\n }\n}\n\n/**\n * Provider-neutral application service for one remotely executed heartbeat.\n *\n * It owns authority issuance, optional product-tool policy, model credentials,\n * ordered stream consumption, cancellation, and terminal classification. The\n * caller owns product scope/session mapping and the durable heartbeat store.\n */\nexport class HostedHeartbeatTaskService\nimplements HostedHeartbeatTaskRunner {\n readonly #authority: HostedHeartbeatTaskServiceConfig['authority'];\n readonly #executionHost: HostedHeartbeatTaskServiceConfig['executionHost'];\n readonly #modelCredentials: HostedHeartbeatTaskServiceConfig[\n 'modelCredentials'\n ];\n readonly #allowedTools: readonly string[] | undefined;\n\n constructor(config: HostedHeartbeatTaskServiceConfig) {\n this.#authority = config.authority;\n this.#executionHost = config.executionHost;\n this.#modelCredentials = config.modelCredentials;\n this.#allowedTools = config.mcp\n ? Object.freeze(McpAllowedToolsSchema.parse(config.mcp.allowedTools))\n : undefined;\n }\n\n async execute(\n rawInput: HostedHeartbeatTaskInput,\n ): Promise<unknown> {\n const input = HostedHeartbeatTaskInputSchema.parse(rawInput);\n input.signal?.throwIfAborted();\n const issued = await this.#authority.issue({\n scope: input.scope,\n runtimeSessionId: input.runtimeSessionId,\n invocationId: input.invocationId,\n workflow: HEARTBEAT_TASK_WORKFLOW,\n ...(this.#allowedTools\n ? { mcp: { allowedTools: this.#allowedTools } }\n : {}),\n });\n const mcpCapability = issued.mcpCapability();\n if (this.#allowedTools && !mcpCapability) {\n throw new HostedHeartbeatConfigurationError(\n 'Hosted heartbeat tool policy requires an MCP-capable execution authority.',\n );\n }\n const modelCredential = await this.#modelCredentials.resolveModelCredential({\n scope: input.scope,\n invocationId: input.invocationId,\n signal: input.signal,\n });\n input.signal?.throwIfAborted();\n\n for await (const event of this.#executionHost.streamHeartbeatTask({\n invocationId: input.invocationId,\n runtimeSessionId: input.runtimeSessionId,\n taskId: input.taskId,\n task: input.task,\n ...(input.checkpoint ? { checkpoint: input.checkpoint } : {}),\n runContext: input.runContext,\n ...(input.model ? { model: input.model } : {}),\n ...(input.reasoningEffort\n ? { reasoningEffort: input.reasoningEffort }\n : {}),\n ...(input.maxSteps !== undefined ? { maxSteps: input.maxSteps } : {}),\n ...(input.searchIgnoreDirs\n ? { searchIgnoreDirs: input.searchIgnoreDirs }\n : {}),\n ...(input.systemContext ? { systemContext: input.systemContext } : {}),\n ...(input.deadlineAt ? { deadlineAt: input.deadlineAt } : {}),\n ...(input.signal ? { signal: input.signal } : {}),\n executionAssertion: issued.executionAssertion(),\n ...(mcpCapability ? { mcpCapability } : {}),\n modelCredential,\n })) {\n if (event.kind === 'activity') {\n input.publishActivity?.(event.activity);\n continue;\n }\n if (event.kind === 'result') {\n return event.result;\n }\n if (event.kind === 'cancelled') {\n throw new ExecutionHostInvocationCancelledError();\n }\n if (event.kind === 'error') {\n throw new HostedHeartbeatExecutionError(event.error.code);\n }\n }\n throw new HostedHeartbeatExecutionError('missing_terminal_result');\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-execution-host-mcp-capability-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jwt-execution-host-mcp-capability-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,+BAA+B,EAC/B,6CAA6C,EAC7C,kCAAkC,EAClC,2CAA2C,EAC3C,kCAAkC,EACnC,MAAM,YAAY,CAAC;AAOpB,gFAAgF;AAChF,qBAAa,qCACb,YAAW,kCAAkC;;gBAMzC,MAAM,EAAE,2CAA2C,EACnD,OAAO,GAAE,+BAAoC;IAczC,MAAM,CACV,UAAU,EAAE,6CAA6C,GACxD,OAAO,CAAC,kCAAkC,CAAC;CAkF/C"}
|
|
@@ -3,7 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { MCP_CAPABILITY_TYPE, McpCapabilityClaimsSchema, } from '../contracts/index.js';
|
|
4
4
|
import { createJwtKeyResolver, resolveJwtVerificationUnavailableCategory, } from '../internal/jwt-verification.js';
|
|
5
5
|
import { ExecutionHostMcpCapabilityUnavailableError, ExecutionHostMcpCapabilityVerificationError, } from './errors.js';
|
|
6
|
-
import {
|
|
6
|
+
import { parseJwtExecutionHostMcpCapabilityVerifierConfig, } from './schemas.js';
|
|
7
7
|
const AssertionSchema = z.string().trim().min(32).max(4_096);
|
|
8
8
|
/** Verifies MCP authority against an independently verified host invocation. */
|
|
9
9
|
export class JwtExecutionHostMcpCapabilityVerifier {
|
|
@@ -11,7 +11,9 @@ export class JwtExecutionHostMcpCapabilityVerifier {
|
|
|
11
11
|
#keyResolver;
|
|
12
12
|
#now;
|
|
13
13
|
constructor(config, options = {}) {
|
|
14
|
-
const parsed =
|
|
14
|
+
const parsed = parseJwtExecutionHostMcpCapabilityVerifierConfig(config, {
|
|
15
|
+
allowDockerLocalHost: options.allowDockerLocalHost === true,
|
|
16
|
+
});
|
|
15
17
|
this.#config = Object.freeze({
|
|
16
18
|
...parsed,
|
|
17
19
|
jwksUrl: new URL(parsed.jwksUrl),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-execution-host-mcp-capability-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,yCAAyC,GAC1C,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,0CAA0C,EAC1C,2CAA2C,GAC5C,MAAM,aAAa,CAAC;AACrB,OAAO,
|
|
1
|
+
{"version":3,"file":"jwt-execution-host-mcp-capability-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-host-mcp-capability-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtVerify } from 'jose';\nimport { z } from 'zod';\nimport {\n MCP_CAPABILITY_TYPE,\n McpCapabilityClaimsSchema,\n} from '../contracts/index.js';\nimport {\n createJwtKeyResolver,\n resolveJwtVerificationUnavailableCategory,\n} from '../internal/jwt-verification.js';\nimport {\n ExecutionHostMcpCapabilityUnavailableError,\n ExecutionHostMcpCapabilityVerificationError,\n} from './errors.js';\nimport {\n JwtExecutionHostMcpCapabilityVerifierConfigSchema,\n parseJwtExecutionHostMcpCapabilityVerifierConfig,\n} from './schemas.js';\nimport type {\n ExecutionHostJwtVerifierOptions,\n ExecutionHostMcpCapabilityVerificationRequest,\n ExecutionHostMcpCapabilityVerifier,\n JwtExecutionHostMcpCapabilityVerifierConfig,\n VerifiedExecutionHostMcpCapability,\n} from './types.js';\n\nconst AssertionSchema = z.string().trim().min(32).max(4_096);\ntype ParsedConfig = z.infer<\n typeof JwtExecutionHostMcpCapabilityVerifierConfigSchema\n>;\n\n/** Verifies MCP authority against an independently verified host invocation. */\nexport class JwtExecutionHostMcpCapabilityVerifier\nimplements ExecutionHostMcpCapabilityVerifier {\n readonly #config: Readonly<ParsedConfig>;\n readonly #keyResolver: NonNullable<ExecutionHostJwtVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtExecutionHostMcpCapabilityVerifierConfig,\n options: ExecutionHostJwtVerifierOptions = {},\n ) {\n const parsed = parseJwtExecutionHostMcpCapabilityVerifierConfig(config, {\n allowDockerLocalHost: options.allowDockerLocalHost === true,\n });\n this.#config = Object.freeze({\n ...parsed,\n jwksUrl: new URL(parsed.jwksUrl),\n });\n this.#keyResolver = options.keyResolver\n ?? createJwtKeyResolver(this.#config.jwksUrl);\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(\n rawRequest: ExecutionHostMcpCapabilityVerificationRequest,\n ): Promise<VerifiedExecutionHostMcpCapability> {\n try {\n const request = Object.freeze({\n ...rawRequest,\n assertion: AssertionSchema.parse(rawRequest.assertion),\n });\n const { payload } = await jwtVerify(\n request.assertion,\n this.#keyResolver,\n {\n algorithms: [...this.#config.jwtAlgorithms],\n audience: this.#config.audience,\n clockTolerance: this.#config.clockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.issuer,\n maxTokenAge: this.#config.maxCapabilityAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: MCP_CAPABILITY_TYPE,\n },\n );\n const claims = McpCapabilityClaimsSchema.parse(payload);\n this.#assertInvocationBinding(claims, request);\n this.#assertBoundedLifetime(claims);\n\n return Object.freeze({\n assertion: request.assertion,\n capabilityId: claims.jti,\n serverId: claims.serverId,\n allowedTools: Object.freeze([...claims.allowedTools]),\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof ExecutionHostMcpCapabilityVerificationError\n || error instanceof ExecutionHostMcpCapabilityUnavailableError\n ) {\n throw error;\n }\n const category = resolveJwtVerificationUnavailableCategory(error);\n if (category) {\n throw new ExecutionHostMcpCapabilityUnavailableError(\n category,\n { cause: error },\n );\n }\n throw new ExecutionHostMcpCapabilityVerificationError({ cause: error });\n }\n }\n\n #assertInvocationBinding(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n request: ExecutionHostMcpCapabilityVerificationRequest,\n ): void {\n const { identity } = request;\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.adopterId !== identity.scope.adopterId\n || claims.tenantId !== identity.scope.tenantId\n || claims.sub !== identity.scope.subjectId\n || claims.productSessionId !== identity.scope.productSessionId\n || claims.runtimeSessionId !== identity.runtimeSessionId\n || claims.invocationId !== identity.invocationId\n || claims.workflow !== identity.workflow\n || claims.serverId !== this.#config.serverId\n || claims.jti === identity.invocationId\n ) {\n throw new ExecutionHostMcpCapabilityVerificationError();\n }\n }\n\n #assertBoundedLifetime(\n claims: z.infer<typeof McpCapabilityClaimsSchema>,\n ): void {\n const lifetimeSeconds = claims.exp - claims.iat;\n if (\n lifetimeSeconds <= 0\n || lifetimeSeconds > this.#config.maxCapabilityAgeSeconds\n ) {\n throw new ExecutionHostMcpCapabilityVerificationError();\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-execution-identity-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jwt-execution-identity-verifier.d.ts","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,oCAAoC,EACpC,yBAAyB,EACzB,+BAA+B,EAC/B,kCAAkC,EAClC,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAKpB,4EAA4E;AAC5E,qBAAa,4BAA6B,YAAW,yBAAyB;;gBAM1E,MAAM,EAAE,kCAAkC,EAC1C,OAAO,GAAE,+BAAoC;IAczC,MAAM,CACV,UAAU,EAAE,oCAAoC,GAC/C,OAAO,CAAC,yBAAyB,CAAC;CAgEtC"}
|
|
@@ -3,7 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { EXECUTION_ASSERTION_TYPE, ExecutionAssertionClaimsSchema, } from '../contracts/index.js';
|
|
4
4
|
import { createJwtKeyResolver, resolveJwtVerificationUnavailableCategory, } from '../internal/jwt-verification.js';
|
|
5
5
|
import { ExecutionIdentityUnavailableError, ExecutionIdentityVerificationError, } from './errors.js';
|
|
6
|
-
import {
|
|
6
|
+
import { parseJwtExecutionIdentityVerifierConfig, } from './schemas.js';
|
|
7
7
|
const AssertionSchema = z.string().trim().min(32).max(4_096);
|
|
8
8
|
/** Verifies adopter authority and binds it to one exact host invocation. */
|
|
9
9
|
export class JwtExecutionIdentityVerifier {
|
|
@@ -11,7 +11,9 @@ export class JwtExecutionIdentityVerifier {
|
|
|
11
11
|
#keyResolver;
|
|
12
12
|
#now;
|
|
13
13
|
constructor(config, options = {}) {
|
|
14
|
-
const parsed =
|
|
14
|
+
const parsed = parseJwtExecutionIdentityVerifierConfig(config, {
|
|
15
|
+
allowDockerLocalHost: options.allowDockerLocalHost === true,
|
|
16
|
+
});
|
|
15
17
|
this.#config = Object.freeze({
|
|
16
18
|
...parsed,
|
|
17
19
|
executionJwksUrl: new URL(parsed.executionJwksUrl),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-execution-identity-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,yCAAyC,GAC1C,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,iCAAiC,EACjC,kCAAkC,GACnC,MAAM,aAAa,CAAC;AACrB,OAAO,
|
|
1
|
+
{"version":3,"file":"jwt-execution-identity-verifier.js","sourceRoot":"","sources":["../../src/host/jwt-execution-identity-verifier.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtVerify } from 'jose';\nimport { z } from 'zod';\nimport {\n EXECUTION_ASSERTION_TYPE,\n ExecutionAssertionClaimsSchema,\n} from '../contracts/index.js';\nimport {\n createJwtKeyResolver,\n resolveJwtVerificationUnavailableCategory,\n} from '../internal/jwt-verification.js';\nimport {\n ExecutionIdentityUnavailableError,\n ExecutionIdentityVerificationError,\n} from './errors.js';\nimport {\n JwtExecutionIdentityVerifierConfigSchema,\n parseJwtExecutionIdentityVerifierConfig,\n} from './schemas.js';\nimport type {\n ExecutionIdentityVerificationRequest,\n ExecutionIdentityVerifier,\n ExecutionHostJwtVerifierOptions,\n JwtExecutionIdentityVerifierConfig,\n VerifiedExecutionIdentity,\n} from './types.js';\n\nconst AssertionSchema = z.string().trim().min(32).max(4_096);\ntype ParsedConfig = z.infer<typeof JwtExecutionIdentityVerifierConfigSchema>;\n\n/** Verifies adopter authority and binds it to one exact host invocation. */\nexport class JwtExecutionIdentityVerifier implements ExecutionIdentityVerifier {\n readonly #config: Readonly<ParsedConfig>;\n readonly #keyResolver: NonNullable<ExecutionHostJwtVerifierOptions['keyResolver']>;\n readonly #now: () => Date;\n\n constructor(\n config: JwtExecutionIdentityVerifierConfig,\n options: ExecutionHostJwtVerifierOptions = {},\n ) {\n const parsed = parseJwtExecutionIdentityVerifierConfig(config, {\n allowDockerLocalHost: options.allowDockerLocalHost === true,\n });\n this.#config = Object.freeze({\n ...parsed,\n executionJwksUrl: new URL(parsed.executionJwksUrl),\n });\n this.#keyResolver = options.keyResolver\n ?? createJwtKeyResolver(this.#config.executionJwksUrl);\n this.#now = options.now ?? (() => new Date());\n }\n\n async verify(\n rawRequest: ExecutionIdentityVerificationRequest,\n ): Promise<VerifiedExecutionIdentity> {\n try {\n const request = Object.freeze({\n ...rawRequest,\n assertion: AssertionSchema.parse(rawRequest.assertion),\n });\n const { payload } = await jwtVerify(\n request.assertion,\n this.#keyResolver,\n {\n algorithms: [...this.#config.executionJwtAlgorithms],\n audience: this.#config.executionAudience,\n clockTolerance: this.#config.assertionClockToleranceSeconds,\n currentDate: this.#now(),\n issuer: this.#config.executionIssuer,\n maxTokenAge: this.#config.maxAssertionAgeSeconds,\n requiredClaims: ['exp', 'iat', 'jti', 'sub'],\n typ: EXECUTION_ASSERTION_TYPE,\n },\n );\n const claims = ExecutionAssertionClaimsSchema.parse(payload);\n this.#assertRequestBinding(claims, request);\n\n return Object.freeze({\n scope: Object.freeze({\n adopterId: claims.adopterId,\n tenantId: claims.tenantId,\n subjectId: claims.sub,\n productSessionId: claims.productSessionId,\n }),\n runtimeSessionId: claims.runtimeSessionId,\n invocationId: claims.jti,\n workflow: claims.workflow,\n issuedAt: new Date(claims.iat * 1_000).toISOString(),\n expiresAt: new Date(claims.exp * 1_000).toISOString(),\n });\n } catch (error) {\n if (\n error instanceof ExecutionIdentityVerificationError\n || error instanceof ExecutionIdentityUnavailableError\n ) {\n throw error;\n }\n const category = resolveJwtVerificationUnavailableCategory(error);\n if (category) {\n throw new ExecutionIdentityUnavailableError(category, { cause: error });\n }\n throw new ExecutionIdentityVerificationError({ cause: error });\n }\n }\n\n #assertRequestBinding(\n claims: z.infer<typeof ExecutionAssertionClaimsSchema>,\n request: ExecutionIdentityVerificationRequest,\n ): void {\n if (\n claims.adopterId !== this.#config.trustedAdopterId\n || claims.runtimeSessionId !== request.runtimeSessionId\n || claims.jti !== request.invocationId\n || claims.workflow !== request.workflow\n ) {\n throw new ExecutionIdentityVerificationError();\n }\n }\n}\n"]}
|