@agentic-kit/metering 0.3.1 → 0.4.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/esm/identity.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Who a metered request belongs to.
2
+ * Who a metered request belongs to, and which task it is a cost of.
3
3
  *
4
- * These are exactly the headers `agentic-server` reads (`X-Database-Id`,
5
- * `X-Entity-Id`, `X-Actor-Id`) — the same identity lane the platform's own
6
- * clients use — so a pi session lands in `inference_log` beside every other
7
- * metered call rather than in a parallel accounting scheme.
4
+ * These are exactly the headers `agentic-server` reads — identity
5
+ * (`X-Database-Id`, `X-Entity-Id`, `X-Actor-Id`) plus task correlation
6
+ * (`X-Invocation-Id`, `X-Job-Id`, `X-Attempt`, `X-Run-Id`) — the same lane the
7
+ * platform's own clients use, so a pi session lands in `inference_log` beside
8
+ * every other metered call rather than in a parallel accounting scheme, and its
9
+ * tokens join the invocation the customer was actually charged for.
8
10
  *
9
11
  * Headers are only trustworthy where the gateway is not reachable by the
10
12
  * untrusted party: in-cluster, or behind an authenticated ingress that pins the
@@ -18,6 +20,14 @@ export interface MeteredIdentity {
18
20
  entityId?: string;
19
21
  /** The actor on whose behalf the run executes. */
20
22
  actorId?: string;
23
+ /** Invocation the run is executing, when the platform dispatched it. */
24
+ invocationId?: string;
25
+ /** Queue job id for that invocation; decimal digits only. */
26
+ jobId?: string;
27
+ /** Attempt number of that job; a non-negative integer. */
28
+ attempt?: number;
29
+ /** The agent run itself. */
30
+ runId?: string;
21
31
  /**
22
32
  * Bearer token for the gateway's ingress — run-scoped, not an account token.
23
33
  * Sent as `Authorization: Bearer <token>`.
@@ -27,6 +37,10 @@ export interface MeteredIdentity {
27
37
  export declare const DATABASE_ID_HEADER = "X-Database-Id";
28
38
  export declare const ENTITY_ID_HEADER = "X-Entity-Id";
29
39
  export declare const ACTOR_ID_HEADER = "X-Actor-Id";
40
+ export declare const INVOCATION_ID_HEADER = "X-Invocation-Id";
41
+ export declare const JOB_ID_HEADER = "X-Job-Id";
42
+ export declare const ATTEMPT_HEADER = "X-Attempt";
43
+ export declare const RUN_ID_HEADER = "X-Run-Id";
30
44
  /**
31
45
  * Build the identity headers for a metered request.
32
46
  *
package/esm/identity.js CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Who a metered request belongs to.
2
+ * Who a metered request belongs to, and which task it is a cost of.
3
3
  *
4
- * These are exactly the headers `agentic-server` reads (`X-Database-Id`,
5
- * `X-Entity-Id`, `X-Actor-Id`) — the same identity lane the platform's own
6
- * clients use — so a pi session lands in `inference_log` beside every other
7
- * metered call rather than in a parallel accounting scheme.
4
+ * These are exactly the headers `agentic-server` reads — identity
5
+ * (`X-Database-Id`, `X-Entity-Id`, `X-Actor-Id`) plus task correlation
6
+ * (`X-Invocation-Id`, `X-Job-Id`, `X-Attempt`, `X-Run-Id`) — the same lane the
7
+ * platform's own clients use, so a pi session lands in `inference_log` beside
8
+ * every other metered call rather than in a parallel accounting scheme, and its
9
+ * tokens join the invocation the customer was actually charged for.
8
10
  *
9
11
  * Headers are only trustworthy where the gateway is not reachable by the
10
12
  * untrusted party: in-cluster, or behind an authenticated ingress that pins the
@@ -14,6 +16,10 @@
14
16
  export const DATABASE_ID_HEADER = 'X-Database-Id';
15
17
  export const ENTITY_ID_HEADER = 'X-Entity-Id';
16
18
  export const ACTOR_ID_HEADER = 'X-Actor-Id';
19
+ export const INVOCATION_ID_HEADER = 'X-Invocation-Id';
20
+ export const JOB_ID_HEADER = 'X-Job-Id';
21
+ export const ATTEMPT_HEADER = 'X-Attempt';
22
+ export const RUN_ID_HEADER = 'X-Run-Id';
17
23
  /**
18
24
  * Build the identity headers for a metered request.
19
25
  *
@@ -32,6 +38,24 @@ export function buildIdentityHeaders(identity) {
32
38
  const actorId = identity.actorId?.trim();
33
39
  if (actorId)
34
40
  headers[ACTOR_ID_HEADER] = actorId;
41
+ const invocationId = identity.invocationId?.trim();
42
+ if (invocationId)
43
+ headers[INVOCATION_ID_HEADER] = invocationId;
44
+ const jobId = identity.jobId?.trim();
45
+ if (jobId) {
46
+ if (!/^\d+$/.test(jobId))
47
+ throw new Error(`metered model: identity.jobId must be decimal digits, got "${jobId}"`);
48
+ headers[JOB_ID_HEADER] = jobId;
49
+ }
50
+ if (identity.attempt !== undefined) {
51
+ if (!Number.isInteger(identity.attempt) || identity.attempt < 0) {
52
+ throw new Error(`metered model: identity.attempt must be a non-negative integer, got ${identity.attempt}`);
53
+ }
54
+ headers[ATTEMPT_HEADER] = String(identity.attempt);
55
+ }
56
+ const runId = identity.runId?.trim();
57
+ if (runId)
58
+ headers[RUN_ID_HEADER] = runId;
35
59
  const runToken = identity.runToken?.trim();
36
60
  if (runToken)
37
61
  headers.Authorization = `Bearer ${runToken}`;
package/esm/index.d.ts CHANGED
@@ -8,6 +8,6 @@
8
8
  * its own harness and feeds `toUsageReport()` from its own message events.
9
9
  */
10
10
  export { completionsBaseUrl, DEFAULT_PROVIDER_NAME, GATEWAY_API, type MeteredGateway, type MeteredGatewayOptions, type MeteredModel, type MeteredModelCost, type MeteredModelSpec, normalizeGatewayUrl, resolveMeteredGateway, resolveMeteredModel } from './gateway';
11
- export { ACTOR_ID_HEADER, buildIdentityHeaders, DATABASE_ID_HEADER, ENTITY_ID_HEADER, type MeteredIdentity } from './identity';
11
+ export { ACTOR_ID_HEADER, ATTEMPT_HEADER, buildIdentityHeaders, DATABASE_ID_HEADER, ENTITY_ID_HEADER, INVOCATION_ID_HEADER, JOB_ID_HEADER, type MeteredIdentity, RUN_ID_HEADER } from './identity';
12
12
  export { httpUsageSink, type HttpUsageSinkOptions, UsageReporter, type UsageReporterOptions, type UsageSink } from './reporter';
13
13
  export { type AssistantUsageMessage, isAssistantMessage, toUsageReport, type ToUsageReportOptions, type UsageReport } from './usage-report';
package/esm/index.js CHANGED
@@ -8,6 +8,6 @@
8
8
  * its own harness and feeds `toUsageReport()` from its own message events.
9
9
  */
10
10
  export { completionsBaseUrl, DEFAULT_PROVIDER_NAME, GATEWAY_API, normalizeGatewayUrl, resolveMeteredGateway, resolveMeteredModel } from './gateway';
11
- export { ACTOR_ID_HEADER, buildIdentityHeaders, DATABASE_ID_HEADER, ENTITY_ID_HEADER } from './identity';
11
+ export { ACTOR_ID_HEADER, ATTEMPT_HEADER, buildIdentityHeaders, DATABASE_ID_HEADER, ENTITY_ID_HEADER, INVOCATION_ID_HEADER, JOB_ID_HEADER, RUN_ID_HEADER } from './identity';
12
12
  export { httpUsageSink, UsageReporter } from './reporter';
13
13
  export { isAssistantMessage, toUsageReport } from './usage-report';
package/identity.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Who a metered request belongs to.
2
+ * Who a metered request belongs to, and which task it is a cost of.
3
3
  *
4
- * These are exactly the headers `agentic-server` reads (`X-Database-Id`,
5
- * `X-Entity-Id`, `X-Actor-Id`) — the same identity lane the platform's own
6
- * clients use — so a pi session lands in `inference_log` beside every other
7
- * metered call rather than in a parallel accounting scheme.
4
+ * These are exactly the headers `agentic-server` reads — identity
5
+ * (`X-Database-Id`, `X-Entity-Id`, `X-Actor-Id`) plus task correlation
6
+ * (`X-Invocation-Id`, `X-Job-Id`, `X-Attempt`, `X-Run-Id`) — the same lane the
7
+ * platform's own clients use, so a pi session lands in `inference_log` beside
8
+ * every other metered call rather than in a parallel accounting scheme, and its
9
+ * tokens join the invocation the customer was actually charged for.
8
10
  *
9
11
  * Headers are only trustworthy where the gateway is not reachable by the
10
12
  * untrusted party: in-cluster, or behind an authenticated ingress that pins the
@@ -18,6 +20,14 @@ export interface MeteredIdentity {
18
20
  entityId?: string;
19
21
  /** The actor on whose behalf the run executes. */
20
22
  actorId?: string;
23
+ /** Invocation the run is executing, when the platform dispatched it. */
24
+ invocationId?: string;
25
+ /** Queue job id for that invocation; decimal digits only. */
26
+ jobId?: string;
27
+ /** Attempt number of that job; a non-negative integer. */
28
+ attempt?: number;
29
+ /** The agent run itself. */
30
+ runId?: string;
21
31
  /**
22
32
  * Bearer token for the gateway's ingress — run-scoped, not an account token.
23
33
  * Sent as `Authorization: Bearer <token>`.
@@ -27,6 +37,10 @@ export interface MeteredIdentity {
27
37
  export declare const DATABASE_ID_HEADER = "X-Database-Id";
28
38
  export declare const ENTITY_ID_HEADER = "X-Entity-Id";
29
39
  export declare const ACTOR_ID_HEADER = "X-Actor-Id";
40
+ export declare const INVOCATION_ID_HEADER = "X-Invocation-Id";
41
+ export declare const JOB_ID_HEADER = "X-Job-Id";
42
+ export declare const ATTEMPT_HEADER = "X-Attempt";
43
+ export declare const RUN_ID_HEADER = "X-Run-Id";
30
44
  /**
31
45
  * Build the identity headers for a metered request.
32
46
  *
package/identity.js CHANGED
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  /**
3
- * Who a metered request belongs to.
3
+ * Who a metered request belongs to, and which task it is a cost of.
4
4
  *
5
- * These are exactly the headers `agentic-server` reads (`X-Database-Id`,
6
- * `X-Entity-Id`, `X-Actor-Id`) — the same identity lane the platform's own
7
- * clients use — so a pi session lands in `inference_log` beside every other
8
- * metered call rather than in a parallel accounting scheme.
5
+ * These are exactly the headers `agentic-server` reads — identity
6
+ * (`X-Database-Id`, `X-Entity-Id`, `X-Actor-Id`) plus task correlation
7
+ * (`X-Invocation-Id`, `X-Job-Id`, `X-Attempt`, `X-Run-Id`) — the same lane the
8
+ * platform's own clients use, so a pi session lands in `inference_log` beside
9
+ * every other metered call rather than in a parallel accounting scheme, and its
10
+ * tokens join the invocation the customer was actually charged for.
9
11
  *
10
12
  * Headers are only trustworthy where the gateway is not reachable by the
11
13
  * untrusted party: in-cluster, or behind an authenticated ingress that pins the
@@ -13,11 +15,15 @@
13
15
  * ingress do the pinning.
14
16
  */
15
17
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.ACTOR_ID_HEADER = exports.ENTITY_ID_HEADER = exports.DATABASE_ID_HEADER = void 0;
18
+ exports.RUN_ID_HEADER = exports.ATTEMPT_HEADER = exports.JOB_ID_HEADER = exports.INVOCATION_ID_HEADER = exports.ACTOR_ID_HEADER = exports.ENTITY_ID_HEADER = exports.DATABASE_ID_HEADER = void 0;
17
19
  exports.buildIdentityHeaders = buildIdentityHeaders;
18
20
  exports.DATABASE_ID_HEADER = 'X-Database-Id';
19
21
  exports.ENTITY_ID_HEADER = 'X-Entity-Id';
20
22
  exports.ACTOR_ID_HEADER = 'X-Actor-Id';
23
+ exports.INVOCATION_ID_HEADER = 'X-Invocation-Id';
24
+ exports.JOB_ID_HEADER = 'X-Job-Id';
25
+ exports.ATTEMPT_HEADER = 'X-Attempt';
26
+ exports.RUN_ID_HEADER = 'X-Run-Id';
21
27
  /**
22
28
  * Build the identity headers for a metered request.
23
29
  *
@@ -36,6 +42,24 @@ function buildIdentityHeaders(identity) {
36
42
  const actorId = identity.actorId?.trim();
37
43
  if (actorId)
38
44
  headers[exports.ACTOR_ID_HEADER] = actorId;
45
+ const invocationId = identity.invocationId?.trim();
46
+ if (invocationId)
47
+ headers[exports.INVOCATION_ID_HEADER] = invocationId;
48
+ const jobId = identity.jobId?.trim();
49
+ if (jobId) {
50
+ if (!/^\d+$/.test(jobId))
51
+ throw new Error(`metered model: identity.jobId must be decimal digits, got "${jobId}"`);
52
+ headers[exports.JOB_ID_HEADER] = jobId;
53
+ }
54
+ if (identity.attempt !== undefined) {
55
+ if (!Number.isInteger(identity.attempt) || identity.attempt < 0) {
56
+ throw new Error(`metered model: identity.attempt must be a non-negative integer, got ${identity.attempt}`);
57
+ }
58
+ headers[exports.ATTEMPT_HEADER] = String(identity.attempt);
59
+ }
60
+ const runId = identity.runId?.trim();
61
+ if (runId)
62
+ headers[exports.RUN_ID_HEADER] = runId;
39
63
  const runToken = identity.runToken?.trim();
40
64
  if (runToken)
41
65
  headers.Authorization = `Bearer ${runToken}`;
package/index.d.ts CHANGED
@@ -8,6 +8,6 @@
8
8
  * its own harness and feeds `toUsageReport()` from its own message events.
9
9
  */
10
10
  export { completionsBaseUrl, DEFAULT_PROVIDER_NAME, GATEWAY_API, type MeteredGateway, type MeteredGatewayOptions, type MeteredModel, type MeteredModelCost, type MeteredModelSpec, normalizeGatewayUrl, resolveMeteredGateway, resolveMeteredModel } from './gateway';
11
- export { ACTOR_ID_HEADER, buildIdentityHeaders, DATABASE_ID_HEADER, ENTITY_ID_HEADER, type MeteredIdentity } from './identity';
11
+ export { ACTOR_ID_HEADER, ATTEMPT_HEADER, buildIdentityHeaders, DATABASE_ID_HEADER, ENTITY_ID_HEADER, INVOCATION_ID_HEADER, JOB_ID_HEADER, type MeteredIdentity, RUN_ID_HEADER } from './identity';
12
12
  export { httpUsageSink, type HttpUsageSinkOptions, UsageReporter, type UsageReporterOptions, type UsageSink } from './reporter';
13
13
  export { type AssistantUsageMessage, isAssistantMessage, toUsageReport, type ToUsageReportOptions, type UsageReport } from './usage-report';
package/index.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * its own harness and feeds `toUsageReport()` from its own message events.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.toUsageReport = exports.isAssistantMessage = exports.UsageReporter = exports.httpUsageSink = exports.ENTITY_ID_HEADER = exports.DATABASE_ID_HEADER = exports.buildIdentityHeaders = exports.ACTOR_ID_HEADER = exports.resolveMeteredModel = exports.resolveMeteredGateway = exports.normalizeGatewayUrl = exports.GATEWAY_API = exports.DEFAULT_PROVIDER_NAME = exports.completionsBaseUrl = void 0;
12
+ exports.toUsageReport = exports.isAssistantMessage = exports.UsageReporter = exports.httpUsageSink = exports.RUN_ID_HEADER = exports.JOB_ID_HEADER = exports.INVOCATION_ID_HEADER = exports.ENTITY_ID_HEADER = exports.DATABASE_ID_HEADER = exports.buildIdentityHeaders = exports.ATTEMPT_HEADER = exports.ACTOR_ID_HEADER = exports.resolveMeteredModel = exports.resolveMeteredGateway = exports.normalizeGatewayUrl = exports.GATEWAY_API = exports.DEFAULT_PROVIDER_NAME = exports.completionsBaseUrl = void 0;
13
13
  var gateway_1 = require("./gateway");
14
14
  Object.defineProperty(exports, "completionsBaseUrl", { enumerable: true, get: function () { return gateway_1.completionsBaseUrl; } });
15
15
  Object.defineProperty(exports, "DEFAULT_PROVIDER_NAME", { enumerable: true, get: function () { return gateway_1.DEFAULT_PROVIDER_NAME; } });
@@ -19,9 +19,13 @@ Object.defineProperty(exports, "resolveMeteredGateway", { enumerable: true, get:
19
19
  Object.defineProperty(exports, "resolveMeteredModel", { enumerable: true, get: function () { return gateway_1.resolveMeteredModel; } });
20
20
  var identity_1 = require("./identity");
21
21
  Object.defineProperty(exports, "ACTOR_ID_HEADER", { enumerable: true, get: function () { return identity_1.ACTOR_ID_HEADER; } });
22
+ Object.defineProperty(exports, "ATTEMPT_HEADER", { enumerable: true, get: function () { return identity_1.ATTEMPT_HEADER; } });
22
23
  Object.defineProperty(exports, "buildIdentityHeaders", { enumerable: true, get: function () { return identity_1.buildIdentityHeaders; } });
23
24
  Object.defineProperty(exports, "DATABASE_ID_HEADER", { enumerable: true, get: function () { return identity_1.DATABASE_ID_HEADER; } });
24
25
  Object.defineProperty(exports, "ENTITY_ID_HEADER", { enumerable: true, get: function () { return identity_1.ENTITY_ID_HEADER; } });
26
+ Object.defineProperty(exports, "INVOCATION_ID_HEADER", { enumerable: true, get: function () { return identity_1.INVOCATION_ID_HEADER; } });
27
+ Object.defineProperty(exports, "JOB_ID_HEADER", { enumerable: true, get: function () { return identity_1.JOB_ID_HEADER; } });
28
+ Object.defineProperty(exports, "RUN_ID_HEADER", { enumerable: true, get: function () { return identity_1.RUN_ID_HEADER; } });
25
29
  var reporter_1 = require("./reporter");
26
30
  Object.defineProperty(exports, "httpUsageSink", { enumerable: true, get: function () { return reporter_1.httpUsageSink; } });
27
31
  Object.defineProperty(exports, "UsageReporter", { enumerable: true, get: function () { return reporter_1.UsageReporter; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentic-kit/metering",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "harness-neutral metering for an agent run — the Constructive gateway as a model endpoint, run identity headers, and usage reporting",
6
6
  "main": "index.js",
@@ -35,5 +35,5 @@
35
35
  "gateway",
36
36
  "constructive"
37
37
  ],
38
- "gitHead": "224b9030a0314a070f3054bc551a986949993b5d"
38
+ "gitHead": "cc30249ddf84bc8c410d9681adb15f98228ab591"
39
39
  }