@kindgi/api 0.1.2 → 0.1.3

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.
Files changed (88) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +2 -1
  3. package/dist/app.js.map +1 -1
  4. package/dist/cost-binding.d.ts +81 -5
  5. package/dist/cost-binding.d.ts.map +1 -1
  6. package/dist/cost-binding.js +6 -0
  7. package/dist/cost-binding.js.map +1 -1
  8. package/dist/hitl-binding.d.ts +20 -5
  9. package/dist/hitl-binding.d.ts.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/middleware/auth.d.ts +3 -2
  14. package/dist/middleware/auth.d.ts.map +1 -1
  15. package/dist/middleware/auth.js.map +1 -1
  16. package/dist/middleware/idempotency.d.ts +5 -1
  17. package/dist/middleware/idempotency.d.ts.map +1 -1
  18. package/dist/middleware/idempotency.js +8 -1
  19. package/dist/middleware/idempotency.js.map +1 -1
  20. package/dist/openapi/operations.d.ts.map +1 -1
  21. package/dist/openapi/operations.js +83 -18
  22. package/dist/openapi/operations.js.map +1 -1
  23. package/dist/openapi/schemas.d.ts +18 -0
  24. package/dist/openapi/schemas.d.ts.map +1 -1
  25. package/dist/openapi/schemas.js +202 -7
  26. package/dist/openapi/schemas.js.map +1 -1
  27. package/dist/provenance-binding.d.ts +27 -1
  28. package/dist/provenance-binding.d.ts.map +1 -1
  29. package/dist/provenance-binding.js.map +1 -1
  30. package/dist/reviewer-binding.d.ts +10 -2
  31. package/dist/reviewer-binding.d.ts.map +1 -1
  32. package/dist/reviewer-role.d.ts +13 -0
  33. package/dist/reviewer-role.d.ts.map +1 -0
  34. package/dist/reviewer-role.js +27 -0
  35. package/dist/reviewer-role.js.map +1 -0
  36. package/dist/routes/approvals.d.ts +5 -4
  37. package/dist/routes/approvals.d.ts.map +1 -1
  38. package/dist/routes/approvals.js +52 -16
  39. package/dist/routes/approvals.js.map +1 -1
  40. package/dist/routes/conversations.d.ts +7 -1
  41. package/dist/routes/conversations.d.ts.map +1 -1
  42. package/dist/routes/conversations.js +41 -1
  43. package/dist/routes/conversations.js.map +1 -1
  44. package/dist/routes/cost.d.ts.map +1 -1
  45. package/dist/routes/cost.js +95 -9
  46. package/dist/routes/cost.js.map +1 -1
  47. package/dist/routes/identity.d.ts +7 -0
  48. package/dist/routes/identity.d.ts.map +1 -1
  49. package/dist/routes/identity.js +3 -2
  50. package/dist/routes/identity.js.map +1 -1
  51. package/dist/routes/provenance.d.ts.map +1 -1
  52. package/dist/routes/provenance.js +32 -1
  53. package/dist/routes/provenance.js.map +1 -1
  54. package/dist/routes/runs.d.ts +0 -7
  55. package/dist/routes/runs.d.ts.map +1 -1
  56. package/dist/routes/runs.js +44 -20
  57. package/dist/routes/runs.js.map +1 -1
  58. package/dist/routes/scope-params.d.ts +16 -1
  59. package/dist/routes/scope-params.d.ts.map +1 -1
  60. package/dist/routes/scope-params.js +28 -0
  61. package/dist/routes/scope-params.js.map +1 -1
  62. package/dist/types.d.ts +4 -3
  63. package/dist/types.d.ts.map +1 -1
  64. package/dist/webhook-endpoint-binding.d.ts +11 -0
  65. package/dist/webhook-endpoint-binding.d.ts.map +1 -1
  66. package/dist/webhook-endpoint-binding.js.map +1 -1
  67. package/openapi.json +599 -24
  68. package/package.json +21 -21
  69. package/src/app.ts +5 -1
  70. package/src/cost-binding.ts +96 -5
  71. package/src/hitl-binding.ts +20 -4
  72. package/src/index.ts +3 -0
  73. package/src/middleware/auth.ts +3 -2
  74. package/src/middleware/idempotency.ts +7 -1
  75. package/src/openapi/operations.ts +93 -18
  76. package/src/openapi/schemas.ts +221 -7
  77. package/src/provenance-binding.ts +42 -1
  78. package/src/reviewer-binding.ts +10 -2
  79. package/src/reviewer-role.ts +35 -0
  80. package/src/routes/approvals.ts +70 -19
  81. package/src/routes/conversations.ts +57 -1
  82. package/src/routes/cost.ts +104 -20
  83. package/src/routes/identity.ts +10 -2
  84. package/src/routes/provenance.ts +48 -1
  85. package/src/routes/runs.ts +54 -22
  86. package/src/routes/scope-params.ts +35 -1
  87. package/src/types.ts +4 -3
  88. package/src/webhook-endpoint-binding.ts +11 -0
@@ -128,6 +128,23 @@ export const RunStatusSchema: JsonSchema = {
128
128
  enum: ['pending', 'running', 'suspended', 'completed', 'failed', 'cancelled'],
129
129
  };
130
130
 
131
+ /**
132
+ * The agent a run is a turn of. A component of its own, so generated
133
+ * clients name it `RunAgent` (not after the `agent` property).
134
+ */
135
+ export const RunAgentSchema: JsonSchema = {
136
+ type: 'object',
137
+ additionalProperties: false,
138
+ required: ['id', 'version', 'conversationId'],
139
+ description:
140
+ "Set on an agent's turn (an agent run, or the turn a flow's agent step started): the agent, the version that ran and the conversation. Absent on other runs, and on turns that ran before Kindgi 0.1.3.",
141
+ properties: {
142
+ id: { type: 'string', description: 'The agent id.' },
143
+ version: { type: 'string', description: 'The agent version that ran (semver).' },
144
+ conversationId: { type: 'string', format: 'uuid' },
145
+ },
146
+ };
147
+
131
148
  export const RunSchema: JsonSchema = {
132
149
  type: 'object',
133
150
  additionalProperties: false,
@@ -167,6 +184,7 @@ export const RunSchema: JsonSchema = {
167
184
  type: 'string',
168
185
  description: 'Set on a child run: the node in the parent run that started it.',
169
186
  },
187
+ agent: { $ref: '#/components/schemas/RunAgent' },
170
188
  publicAccessToken: {
171
189
  type: 'string',
172
190
  description:
@@ -557,6 +575,29 @@ export const ApprovalSchema: JsonSchema = {
557
575
  updatedAt: { type: 'string', format: 'date-time' },
558
576
  decidedAt: { type: 'string', format: 'date-time' },
559
577
  expiresAt: { type: 'string', format: 'date-time' },
578
+ decision: {
579
+ description:
580
+ "The reviewer's decision, once one is recorded. Absent while the approval is open, and when it ended without one (it expired, or a timeout escalated it).",
581
+ $ref: '#/components/schemas/ApprovalDecisionRecord',
582
+ },
583
+ },
584
+ };
585
+
586
+ export const ApprovalDecisionRecordSchema: JsonSchema = {
587
+ type: 'object',
588
+ additionalProperties: false,
589
+ required: ['decision', 'reviewerId', 'reviewerRoleAtDecision', 'decidedAt'],
590
+ properties: {
591
+ decision: ReviewDecisionKindSchema,
592
+ decidedBy: {
593
+ type: 'string',
594
+ description:
595
+ "Who decided, as an actor: `user:<userId>`, the reviewer's user. The run's journal and provenance name the decider the same way. The Kindgi runtime always records it; a deployment whose HITL binding doesn't leaves it out.",
596
+ },
597
+ reviewerId: { type: 'string', format: 'uuid' },
598
+ reviewerRoleAtDecision: ReviewerRoleSchema,
599
+ decidedAt: { type: 'string', format: 'date-time' },
600
+ rationale: { type: 'string' },
560
601
  },
561
602
  };
562
603
 
@@ -599,7 +640,7 @@ export const CompleteApprovalBodySchema: JsonSchema = {
599
640
  rationale: { type: 'string' },
600
641
  value: {
601
642
  description:
602
- 'Payload passed to the run waitpoint (`RunBinding.completeToken`) when the approval is linked to a suspended run and the decision is `approve` or `reject`.',
643
+ "Payload passed to the run waitpoint (`RunBinding.completeToken`) when the approval is linked to a suspended run and the decision is `approve` or `reject`. Refused (400 `bad-input`) for an agent's tool-call or session gate (`tool-call:pending`, `agent-turn:session-hitl-gate`): those resume on the decision alone.",
603
644
  },
604
645
  },
605
646
  };
@@ -1652,6 +1693,12 @@ export const ConversationSchema: JsonSchema = {
1652
1693
  agentVersion: { type: 'string', description: 'Semver.' },
1653
1694
  title: { type: 'string' },
1654
1695
  participantId: { type: 'string' },
1696
+ projectId: {
1697
+ type: 'string',
1698
+ format: 'uuid',
1699
+ description:
1700
+ "The project the conversation is in: the project of the run that opened it, or `projectId` on open (the tenant's Default project when omitted). Absent on conversations from before Kindgi 0.1.3; those are listed only without a scope.",
1701
+ },
1655
1702
  scope: {
1656
1703
  type: 'object',
1657
1704
  additionalProperties: true,
@@ -1706,6 +1753,12 @@ export const OpenConversationBodySchema: JsonSchema = {
1706
1753
  type: 'string',
1707
1754
  description: 'Optional. Defaults to `"Untitled conversation"` when omitted.',
1708
1755
  },
1756
+ projectId: {
1757
+ type: 'string',
1758
+ format: 'uuid',
1759
+ description:
1760
+ "The project the conversation is in; `GET /v1/conversations?scopeKind=project&scopeId=…` lists it. A project of the caller's tenant, else `400 bad-input`. Omitted: the tenant's Default project, as for a run.",
1761
+ },
1709
1762
  scope: {
1710
1763
  type: 'object',
1711
1764
  additionalProperties: true,
@@ -2483,6 +2536,12 @@ export const ProvenanceRecordMetadataSchema: JsonSchema = {
2483
2536
  'True when the emission-time signature is present. Independent of whether the export route can produce a signed bundle.',
2484
2537
  },
2485
2538
  createdAt: { type: 'string', format: 'date-time' },
2539
+ projectId: {
2540
+ type: 'string',
2541
+ format: 'uuid',
2542
+ description:
2543
+ "The project of the record's run. Absent on records from before Kindgi 0.1.3; those are listed only without a scope.",
2544
+ },
2486
2545
  },
2487
2546
  };
2488
2547
 
@@ -2508,6 +2567,22 @@ export const ProvenanceRecordSchema: JsonSchema = {
2508
2567
  },
2509
2568
  signature: ProvenanceSignatureSchema,
2510
2569
  createdAt: { type: 'string', format: 'date-time' },
2570
+ callUsage: {
2571
+ type: 'object',
2572
+ description:
2573
+ "Each model call's usage from the cost ledger, by the `callId` in its `model-call` node's attributes. Joined when read: not part of the signed DAG. A signed export includes it, as it stood when signed.",
2574
+ additionalProperties: {
2575
+ type: 'object',
2576
+ additionalProperties: false,
2577
+ required: ['usage'],
2578
+ properties: {
2579
+ usage: { $ref: '#/components/schemas/ModelCallTokens' },
2580
+ costUsd: { type: 'number', minimum: 0 },
2581
+ durationMs: { type: 'integer', minimum: 0 },
2582
+ servedModel: { type: 'string' },
2583
+ },
2584
+ },
2585
+ },
2511
2586
  },
2512
2587
  };
2513
2588
 
@@ -2544,7 +2619,7 @@ export const ExportProvenanceBodySchema: JsonSchema = {
2544
2619
 
2545
2620
  export const ExportProvenanceResultSchema: JsonSchema = {
2546
2621
  description:
2547
- 'Signed exportable bundle. `bundle` is base64 of the exact bytes that were signed (sorted-key canonical JSON, no whitespace); verifiers can pass those bytes directly to `verifyEd25519`. The bundle body itself includes `bundleSchemaVersion`, `runId`, `tenantId`, `dag: { nodes, edges }`, `messages?` (if requested), etc. See `canonicalization` for the deterministic serialization algorithm.',
2622
+ 'Signed exportable bundle. `bundle` is base64 of the exact bytes that were signed (sorted-key canonical JSON, no whitespace); verifiers can pass those bytes directly to `verifyEd25519`. The bundle body itself includes `bundleSchemaVersion`, `runId`, `tenantId`, `dag: { nodes, edges }`, `messages?` (if requested), `callUsage?` (the usage of the model calls, from the cost ledger), etc. See `canonicalization` for the deterministic serialization algorithm.',
2548
2623
  type: 'object',
2549
2624
  additionalProperties: false,
2550
2625
  required: [
@@ -2566,7 +2641,8 @@ export const ExportProvenanceResultSchema: JsonSchema = {
2566
2641
  },
2567
2642
  bundleSchemaVersion: {
2568
2643
  type: 'string',
2569
- description: 'Semver for the shape of the bundle body. Currently `1.0.0`.',
2644
+ description:
2645
+ "Semver for the shape of the bundle body. Currently `1.1.0`, which adds `callUsage`: each model call's usage from the cost ledger, by call id, as it stood when signed.",
2570
2646
  },
2571
2647
  algorithm: { type: 'string', const: 'ed25519' },
2572
2648
  signingKeyId: { type: 'string' },
@@ -3243,7 +3319,65 @@ export const GetMCPPromptResultSchema: JsonSchema = {
3243
3319
  */
3244
3320
  export const CostGroupDimensionSchema: JsonSchema = {
3245
3321
  type: 'string',
3246
- enum: ['agentId', 'runId', 'category', 'providerId', 'day', 'month', 'tenant', 'conversationId'],
3322
+ enum: [
3323
+ 'agentId',
3324
+ 'runId',
3325
+ 'category',
3326
+ 'providerId',
3327
+ 'day',
3328
+ 'month',
3329
+ 'tenant',
3330
+ 'conversationId',
3331
+ 'model',
3332
+ 'servedModel',
3333
+ 'projectId',
3334
+ 'orgId',
3335
+ 'rootRunId',
3336
+ 'flowId',
3337
+ ],
3338
+ };
3339
+
3340
+ /** Why a model call failed, as its cost record carries it. */
3341
+ export const ModelCallErrorSchema: JsonSchema = {
3342
+ type: 'object',
3343
+ additionalProperties: false,
3344
+ required: ['message'],
3345
+ description: 'Why a model call failed (`status: failed`).',
3346
+ properties: { message: { type: 'string' } },
3347
+ };
3348
+
3349
+ /** A model call's tokens, as a cost record and a provenance record carry them. */
3350
+ export const ModelCallTokensSchema: JsonSchema = {
3351
+ type: 'object',
3352
+ additionalProperties: false,
3353
+ required: ['promptTokens', 'completionTokens'],
3354
+ description:
3355
+ "The call's tokens. `promptTokens` / `completionTokens` are the totals; `cacheReadTokens` / `cacheWriteTokens` are parts of `promptTokens`, `reasoningTokens` of `completionTokens`, present when the provider reports them.",
3356
+ properties: {
3357
+ promptTokens: { type: 'integer', minimum: 0 },
3358
+ completionTokens: { type: 'integer', minimum: 0 },
3359
+ cacheReadTokens: { type: 'integer', minimum: 0 },
3360
+ cacheWriteTokens: { type: 'integer', minimum: 0 },
3361
+ reasoningTokens: { type: 'integer', minimum: 0 },
3362
+ },
3363
+ };
3364
+
3365
+ /**
3366
+ * Token sums of an aggregate. `prompt` / `completion` are the totals;
3367
+ * `cacheRead` / `cacheWrite` are parts of `prompt`, `reasoning` of
3368
+ * `completion` (`0` where providers didn't report them).
3369
+ */
3370
+ export const CostTokenTotalsSchema: JsonSchema = {
3371
+ type: 'object',
3372
+ additionalProperties: false,
3373
+ required: ['prompt', 'completion', 'cacheRead', 'cacheWrite', 'reasoning'],
3374
+ properties: {
3375
+ prompt: { type: 'integer', minimum: 0 },
3376
+ completion: { type: 'integer', minimum: 0 },
3377
+ cacheRead: { type: 'integer', minimum: 0 },
3378
+ cacheWrite: { type: 'integer', minimum: 0 },
3379
+ reasoning: { type: 'integer', minimum: 0 },
3380
+ },
3247
3381
  };
3248
3382
 
3249
3383
  /**
@@ -3283,6 +3417,63 @@ export const CostRecordSchema: JsonSchema = {
3283
3417
  additionalProperties: true,
3284
3418
  description: 'Free-form filter/display tags — never counters.',
3285
3419
  },
3420
+ callId: {
3421
+ type: 'string',
3422
+ description:
3423
+ "A model call's id (`category` `llm.inference`); its provenance `model-call` node carries it too.",
3424
+ },
3425
+ projectId: { type: 'string', format: 'uuid' },
3426
+ rootRunId: {
3427
+ type: 'string',
3428
+ format: 'uuid',
3429
+ description: "The root of the record's run tree (a flow run, for its agent turns).",
3430
+ },
3431
+ parentRunId: { type: 'string', format: 'uuid' },
3432
+ agentVersion: { type: 'string' },
3433
+ flowId: { type: 'string', description: "The flow of the run tree's root." },
3434
+ nodeId: { type: 'string', description: 'The step that made the call.' },
3435
+ step: { type: 'integer', minimum: 1, description: "The turn's step number." },
3436
+ purpose: {
3437
+ type: 'string',
3438
+ description:
3439
+ "What the call was for, beyond the turn's own model step: `guardrail-judge:<guardrail id>`.",
3440
+ },
3441
+ model: { type: 'string', description: 'The model actually called.' },
3442
+ servedModel: {
3443
+ type: 'string',
3444
+ description: 'The exact model version the vendor reported (vendors alias).',
3445
+ },
3446
+ fallback: {
3447
+ type: 'boolean',
3448
+ description: 'The router picked a fallback provider for the turn.',
3449
+ },
3450
+ status: {
3451
+ type: 'string',
3452
+ enum: ['ok', 'failed'],
3453
+ description: '`ok`: the provider answered. `failed`: the call threw.',
3454
+ },
3455
+ usage: { $ref: '#/components/schemas/ModelCallTokens' },
3456
+ durationMs: { type: 'integer', minimum: 0 },
3457
+ finishReason: { type: 'string' },
3458
+ providerRequestId: { type: 'string', description: "The vendor's id for the request." },
3459
+ attempts: {
3460
+ type: 'integer',
3461
+ minimum: 1,
3462
+ description: "HTTP attempts the call took, the client's retries included.",
3463
+ },
3464
+ error: { $ref: '#/components/schemas/ModelCallError' },
3465
+ rawUsage: {
3466
+ type: 'object',
3467
+ additionalProperties: false,
3468
+ required: ['provider', 'model', 'usage'],
3469
+ description:
3470
+ "The vendor's own usage object, exactly as it reported it. Only with `include=rawUsage`.",
3471
+ properties: {
3472
+ provider: { type: 'string' },
3473
+ model: { type: 'string' },
3474
+ usage: { type: 'object', additionalProperties: true },
3475
+ },
3476
+ },
3286
3477
  },
3287
3478
  };
3288
3479
 
@@ -3303,7 +3494,7 @@ export const CostRecordCollectionPageSchema: JsonSchema = {
3303
3494
  export const CostAggregateGroupSchema: JsonSchema = {
3304
3495
  type: 'object',
3305
3496
  additionalProperties: false,
3306
- required: ['key', 'count', 'totalUsd'],
3497
+ required: ['key', 'count', 'totalUsd', 'tokens'],
3307
3498
  properties: {
3308
3499
  key: {
3309
3500
  type: 'object',
@@ -3313,13 +3504,14 @@ export const CostAggregateGroupSchema: JsonSchema = {
3313
3504
  },
3314
3505
  count: { type: 'integer', minimum: 0 },
3315
3506
  totalUsd: { type: 'number', minimum: 0 },
3507
+ tokens: { $ref: '#/components/schemas/CostTokenTotals' },
3316
3508
  },
3317
3509
  };
3318
3510
 
3319
3511
  export const CostAggregateResultSchema: JsonSchema = {
3320
3512
  type: 'object',
3321
3513
  additionalProperties: false,
3322
- required: ['groups', 'totalUsd', 'totalRecords', 'timeRange', 'groupBy'],
3514
+ required: ['groups', 'totalUsd', 'totalRecords', 'tokens', 'timeRange', 'groupBy'],
3323
3515
  properties: {
3324
3516
  groups: {
3325
3517
  type: 'array',
@@ -3327,6 +3519,7 @@ export const CostAggregateResultSchema: JsonSchema = {
3327
3519
  },
3328
3520
  totalUsd: { type: 'number', minimum: 0 },
3329
3521
  totalRecords: { type: 'integer', minimum: 0 },
3522
+ tokens: { $ref: '#/components/schemas/CostTokenTotals' },
3330
3523
  timeRange: {
3331
3524
  type: 'object',
3332
3525
  additionalProperties: false,
@@ -3980,7 +4173,7 @@ export const LogoutResultSchema: JsonSchema = {
3980
4173
 
3981
4174
  export const WhoamiResultSchema: JsonSchema = {
3982
4175
  description:
3983
- "Introspection of the caller's current authentication context. Always carries `tenantId` and `scopes` (empty for static bearer tokens), plus `userId` when the token carries one; session-token callers additionally see `sessionId`, `providerId`, and `expiresAt`. `user` is the caller's directory record, present when the deployment wires an identity directory and it knows the `userId`. `reviewerRole` is set when the token carries a reviewer role — clients can use it to gate reviewer-only UI (the approvals surface) without a second round trip.",
4176
+ "Introspection of the caller's current authentication context. Always carries `tenantId` and `scopes` (empty for static bearer tokens), plus `userId` when the token carries one; session-token callers additionally see `sessionId`, `providerId`, and `expiresAt`. `user` is the caller's directory record, present when the deployment wires an identity directory and it knows the `userId`. `reviewerRole` is set when the caller is a reviewer — its token carries a reviewer role, or its user is a registered reviewer — so clients can gate reviewer-only UI (the approvals surface) without a second round trip.",
3984
4177
  type: 'object',
3985
4178
  additionalProperties: false,
3986
4179
  required: ['tenantId', 'scopes'],
@@ -5844,6 +6037,20 @@ export const WebhookEndpointUnregisterResultSchema: JsonSchema = {
5844
6037
  },
5845
6038
  };
5846
6039
 
6040
+ /** A run tree's model calls, as `run.finished` carries them. */
6041
+ export const RunTreeUsageSchema: JsonSchema = {
6042
+ type: 'object',
6043
+ additionalProperties: false,
6044
+ required: ['calls', 'costUsd', 'tokens'],
6045
+ description:
6046
+ "The model calls of the run tree (this run and every run it started) that the cost ledger had recorded when this run finished: a child run still running then isn't in it. `calls` counts failed calls too. Absent when the runtime records no usage.",
6047
+ properties: {
6048
+ calls: { type: 'integer', minimum: 0 },
6049
+ costUsd: { type: 'number', minimum: 0 },
6050
+ tokens: { $ref: '#/components/schemas/CostTokenTotals' },
6051
+ },
6052
+ };
6053
+
5847
6054
  export const FinishedRunSchema: JsonSchema = {
5848
6055
  type: 'object',
5849
6056
  additionalProperties: false,
@@ -5873,6 +6080,7 @@ export const FinishedRunSchema: JsonSchema = {
5873
6080
  },
5874
6081
  createdAt: { type: 'string', format: 'date-time' },
5875
6082
  completedAt: { type: 'string', format: 'date-time' },
6083
+ usage: { $ref: '#/components/schemas/RunTreeUsage' },
5876
6084
  },
5877
6085
  };
5878
6086
 
@@ -6020,6 +6228,7 @@ export const COMPONENT_SCHEMAS: ReadonlyArray<readonly [string, JsonSchema]> = [
6020
6228
  ['WireError', WireErrorSchema],
6021
6229
  ['HealthResult', HealthResultSchema],
6022
6230
  ['RunStatus', RunStatusSchema],
6231
+ ['RunAgent', RunAgentSchema],
6023
6232
  ['Run', RunSchema],
6024
6233
  ['StartRunOptions', StartRunOptionsSchema],
6025
6234
  ['StartRunBody', StartRunBodySchema],
@@ -6047,6 +6256,7 @@ export const COMPONENT_SCHEMAS: ReadonlyArray<readonly [string, JsonSchema]> = [
6047
6256
  ['ApprovalStatus', ApprovalStatusSchema],
6048
6257
  ['ReviewDecisionKind', ReviewDecisionKindSchema],
6049
6258
  ['Approval', ApprovalSchema],
6259
+ ['ApprovalDecisionRecord', ApprovalDecisionRecordSchema],
6050
6260
  ['ReviewDecision', ReviewDecisionSchema],
6051
6261
  ['ApprovalCollectionPage', ApprovalCollectionPageSchema],
6052
6262
  ['CompleteApprovalBody', CompleteApprovalBodySchema],
@@ -6190,6 +6400,9 @@ export const COMPONENT_SCHEMAS: ReadonlyArray<readonly [string, JsonSchema]> = [
6190
6400
  ['GetMCPPromptResult', GetMCPPromptResultSchema],
6191
6401
  ['CostGroupDimension', CostGroupDimensionSchema],
6192
6402
  ['CostRecord', CostRecordSchema],
6403
+ ['ModelCallTokens', ModelCallTokensSchema],
6404
+ ['ModelCallError', ModelCallErrorSchema],
6405
+ ['CostTokenTotals', CostTokenTotalsSchema],
6193
6406
  ['CostRecordCollectionPage', CostRecordCollectionPageSchema],
6194
6407
  ['CostAggregateGroup', CostAggregateGroupSchema],
6195
6408
  ['CostAggregateResult', CostAggregateResultSchema],
@@ -6348,6 +6561,7 @@ export const COMPONENT_SCHEMAS: ReadonlyArray<readonly [string, JsonSchema]> = [
6348
6561
  ['CreateWebhookEndpointBody', CreateWebhookEndpointBodySchema],
6349
6562
  ['PatchWebhookEndpointBody', PatchWebhookEndpointBodySchema],
6350
6563
  ['WebhookEndpointUnregisterResult', WebhookEndpointUnregisterResultSchema],
6564
+ ['RunTreeUsage', RunTreeUsageSchema],
6351
6565
  ['FinishedRun', FinishedRunSchema],
6352
6566
  ['RunFinishedEvent', RunFinishedEventSchema],
6353
6567
  ['WebhookTestEvent', WebhookTestEventSchema],
@@ -8,7 +8,16 @@
8
8
  // touches provenance storage directly.
9
9
  //
10
10
 
11
- import type { FlowId, ProvenanceId, Result, RunId, TenantId, Timestamp } from '@kindgi/types';
11
+ import type {
12
+ FlowId,
13
+ ListScope,
14
+ ProjectId,
15
+ ProvenanceId,
16
+ Result,
17
+ RunId,
18
+ TenantId,
19
+ Timestamp,
20
+ } from '@kindgi/types';
12
21
 
13
22
  // ---------- domain type surface ----------
14
23
 
@@ -98,6 +107,8 @@ export interface ProvenanceListCursor {
98
107
  export interface ListProvenanceRecordsInput {
99
108
  readonly tenantId: TenantId;
100
109
  readonly limit: number;
110
+ /** Only one project's records, or every project's in an org. Absent: the tenant's. */
111
+ readonly scope?: ListScope;
101
112
  readonly runId?: RunId;
102
113
  readonly agentId?: string;
103
114
  readonly createdAfter?: Date;
@@ -117,6 +128,8 @@ export interface ProvenanceRecordSummary {
117
128
  readonly createdAt: Timestamp;
118
129
  readonly flowRef?: { readonly id: FlowId; readonly version: string };
119
130
  readonly signed: boolean;
131
+ /** The project of the record's run; absent on records from before it was stored. */
132
+ readonly projectId?: ProjectId;
120
133
  }
121
134
 
122
135
  export interface ListProvenanceRecordsResult {
@@ -166,4 +179,32 @@ export interface ProvenanceBinding {
166
179
  * tenant/run pair.
167
180
  */
168
181
  getByRunId(tenantId: TenantId, runId: RunId): Promise<Result<Provenance, ProvenanceBindingError>>;
182
+
183
+ /**
184
+ * The cost ledger's usage of each model call in the run's provenance,
185
+ * by the `callId` in its `model-call` node's attributes. Optional: a
186
+ * deployment without a cost ledger omits it. The routes add it to a
187
+ * read as `callUsage`, outside the signed DAG; a signed export
188
+ * includes it as it stood when signed.
189
+ */
190
+ getCallUsage?(
191
+ tenantId: TenantId,
192
+ runId: RunId,
193
+ ): Promise<Result<CallUsageByCallId, ProvenanceBindingError>>;
169
194
  }
195
+
196
+ /** One model call's usage, as the cost ledger has it. */
197
+ export interface CallUsage {
198
+ readonly usage: {
199
+ readonly promptTokens: number;
200
+ readonly completionTokens: number;
201
+ readonly cacheReadTokens?: number;
202
+ readonly cacheWriteTokens?: number;
203
+ readonly reasoningTokens?: number;
204
+ };
205
+ readonly costUsd?: number;
206
+ readonly durationMs?: number;
207
+ readonly servedModel?: string;
208
+ }
209
+
210
+ export type CallUsageByCallId = Readonly<Record<string, CallUsage>>;
@@ -6,16 +6,24 @@ import type { Cursor, ReviewerId, TenantId, Timestamp, UserId } from '@kindgi/ty
6
6
 
7
7
  /**
8
8
  * Translates the bearer-token identity (`UserId`) into the `ReviewerId`
9
- * that `HitlBinding.submitReview` needs. The API package intentionally does
9
+ * that `HitlBinding.submitReview` needs, and the reviewer role the
10
+ * approvals surface is scoped by. The API package intentionally does
10
11
  * NOT own the `user ↔ reviewer` mapping — deployments plug that in via
11
12
  * this binding, same pattern as `TokenResolver` (for auth read) and
12
13
  * `TokenAdmin` (for mint/revoke).
13
14
  *
14
- * Return `null` when the user has no registered reviewer row for the
15
+ * Both return `null` when the user has no active reviewer row for the
15
16
  * tenant (leads to `403 permission-denied` from the approvals route).
16
17
  */
17
18
  export interface ReviewerBinding {
18
19
  resolveReviewer(input: ReviewerLookupInput): Promise<ReviewerId | null>;
20
+ /**
21
+ * The user's reviewer role in the tenant. Consulted for a token that
22
+ * carries no `reviewerRole` of its own (a session or API key of a
23
+ * registered reviewer), so the roster, not the token, says who reviews.
24
+ * A binding without it: only a token that carries its role reviews.
25
+ */
26
+ resolveReviewerRole?(input: ReviewerLookupInput): Promise<ReviewerRole | null>;
19
27
  }
20
28
 
21
29
  export interface ReviewerLookupInput {
@@ -0,0 +1,35 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import type { ReviewerRole } from '@kindgi/authz';
5
+ import type { TenantId, UserId } from '@kindgi/types';
6
+ import type { Context } from 'hono';
7
+
8
+ import type { ReviewerBinding } from './reviewer-binding.js';
9
+ import type { AppEnv } from './types.js';
10
+
11
+ /**
12
+ * The caller's reviewer role: the one its token carries, else the one the
13
+ * roster gives its user (`ReviewerBinding.resolveReviewerRole`, when the
14
+ * binding has it), kept on the request. `undefined` for a caller that
15
+ * isn't a reviewer: a token with neither a role nor a user, or a user the
16
+ * roster doesn't know.
17
+ */
18
+ export async function callerReviewerRole(
19
+ c: Context<AppEnv>,
20
+ reviewerBinding: ReviewerBinding | undefined,
21
+ ): Promise<ReviewerRole | undefined> {
22
+ const carried = c.get('reviewerRole');
23
+ if (carried !== undefined) return carried;
24
+ const userId = c.get('userId') as UserId | undefined;
25
+ if (userId === undefined || reviewerBinding?.resolveReviewerRole === undefined) {
26
+ return undefined;
27
+ }
28
+ const role = await reviewerBinding.resolveReviewerRole({
29
+ tenantId: c.get('tenantId') as TenantId,
30
+ userId,
31
+ });
32
+ if (role === null) return undefined;
33
+ c.set('reviewerRole', role);
34
+ return role;
35
+ }