@obversa/api 0.1.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/accepted-result-support.d.ts +1 -0
- package/dist/accepted-result-support.js +5 -0
- package/dist/accepted-result-support.js.map +1 -0
- package/dist/action-decision.d.ts +15 -0
- package/dist/approval-support.d.ts +1 -0
- package/dist/approval-support.js +5 -0
- package/dist/approval-support.js.map +1 -0
- package/dist/artifacts/conformance.d.ts +20 -0
- package/dist/artifacts/store.d.ts +30 -0
- package/dist/budget.d.ts +36 -0
- package/dist/callback/approval.d.ts +80 -0
- package/dist/callback/client-contract.d.ts +81 -0
- package/dist/callback/gate.d.ts +49 -0
- package/dist/callback/stored-client.d.ts +22 -0
- package/dist/chunk-6NA4RDQ4.js +81 -0
- package/dist/chunk-6NA4RDQ4.js.map +1 -0
- package/dist/chunk-6NAMCSPJ.js +331 -0
- package/dist/chunk-6NAMCSPJ.js.map +1 -0
- package/dist/chunk-6ZP73HZN.js +293 -0
- package/dist/chunk-6ZP73HZN.js.map +1 -0
- package/dist/chunk-AJ353QD5.js +157 -0
- package/dist/chunk-AJ353QD5.js.map +1 -0
- package/dist/chunk-VWZKI7AG.js +552 -0
- package/dist/chunk-VWZKI7AG.js.map +1 -0
- package/dist/chunk-WGLWWKF3.js +135 -0
- package/dist/chunk-WGLWWKF3.js.map +1 -0
- package/dist/contracts.d.ts +122 -0
- package/dist/engine-conformance.d.ts +80 -0
- package/dist/environment.d.ts +53 -0
- package/dist/error.d.ts +36 -0
- package/dist/events/conformance.d.ts +20 -0
- package/dist/events/envelope.d.ts +26 -0
- package/dist/events/store.d.ts +15 -0
- package/dist/graph-commands.d.ts +23 -0
- package/dist/graph-contract.d.ts +48 -0
- package/dist/graph-executor.d.ts +61 -0
- package/dist/graph-kernel.d.ts +2 -0
- package/dist/graph-plan.d.ts +140 -0
- package/dist/graph-type.d.ts +45 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +806 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +14 -0
- package/dist/memory-conformance.d.ts +17 -0
- package/dist/memory-types.d.ts +127 -0
- package/dist/model-identity.d.ts +28 -0
- package/dist/node-data-context.d.ts +11 -0
- package/dist/preflight-result.d.ts +17 -0
- package/dist/proof/acceptance.d.ts +60 -0
- package/dist/proof/artifact.d.ts +2 -0
- package/dist/proof/cache.d.ts +46 -0
- package/dist/reasoning-record-contract.d.ts +52 -0
- package/dist/result-contract.d.ts +16 -0
- package/dist/result.d.ts +30 -0
- package/dist/run-definition-support.d.ts +1 -0
- package/dist/run-definition-support.js +5 -0
- package/dist/run-definition-support.js.map +1 -0
- package/dist/run-definition.d.ts +73 -0
- package/dist/storage/error.d.ts +7 -0
- package/dist/storage/id.d.ts +2 -0
- package/dist/testing.d.ts +5 -0
- package/dist/testing.js +1745 -0
- package/dist/testing.js.map +1 -0
- package/dist/workspace/conformance.d.ts +30 -0
- package/dist/workspace/policy.d.ts +6 -0
- package/dist/workspace/provider.d.ts +132 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonny Neill
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @obversa/api
|
|
2
|
+
|
|
3
|
+
`@obversa/api` defines the shared contracts and validation used by Obversa
|
|
4
|
+
runtimes and plugins. It includes the engine, memory, and workspace ports
|
|
5
|
+
and their conformance kits. The runtime still runs graphs and writes records.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 22.12 or later
|
|
10
|
+
|
|
11
|
+
## Build from the workspace
|
|
12
|
+
|
|
13
|
+
From the workspace root, run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
corepack enable
|
|
17
|
+
pnpm install --frozen-lockfile
|
|
18
|
+
pnpm --filter @obversa/api build
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Contract
|
|
22
|
+
|
|
23
|
+
An engine runs one fresh agent attempt:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import type { Engine } from '@obversa/api';
|
|
27
|
+
|
|
28
|
+
declare const engine: Engine;
|
|
29
|
+
|
|
30
|
+
const result = await engine.run(
|
|
31
|
+
{ prompt: 'Review this change.' },
|
|
32
|
+
() => {},
|
|
33
|
+
new AbortController().signal,
|
|
34
|
+
);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Adapter conformance
|
|
38
|
+
|
|
39
|
+
Import the framework-free conformance runner from `@obversa/api/testing`
|
|
40
|
+
and the offline mock from `@obversa/core/testing`.
|
|
41
|
+
|
|
42
|
+
## Command adapters
|
|
43
|
+
|
|
44
|
+
Import owned-process execution and inspection from `@obversa/core/command`.
|
|
45
|
+
The command runner bounds time, retained output, and process-tree memory.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { acceptedResultSupport } from './proof/acceptance.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"accepted-result-support.js"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type JsonObject, type JsonValue } from './json.js';
|
|
2
|
+
export interface AllowActionDecision extends JsonObject {
|
|
3
|
+
readonly kind: 'allow';
|
|
4
|
+
}
|
|
5
|
+
export interface WaitActionDecision extends JsonObject {
|
|
6
|
+
readonly kind: 'wait';
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
readonly request: JsonValue;
|
|
9
|
+
}
|
|
10
|
+
export interface DenyActionDecision extends JsonObject {
|
|
11
|
+
readonly kind: 'deny';
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
}
|
|
14
|
+
export type ActionDecision = AllowActionDecision | WaitActionDecision | DenyActionDecision;
|
|
15
|
+
export declare function validateActionDecision(value: ActionDecision): ActionDecision;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { bindingFromSubject, hasExactFields, isObject } from './callback/approval.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"approval-support.js"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ArtifactStore } from './store.js';
|
|
2
|
+
export interface ArtifactStoreConformanceOptions {
|
|
3
|
+
readonly maxArtifactBytes: number;
|
|
4
|
+
readonly maxTotalArtifactBytesPerRun: number;
|
|
5
|
+
readonly knownSecrets: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export type ArtifactStoreConformanceFactory = (options: ArtifactStoreConformanceOptions) => ArtifactStore | Promise<ArtifactStore>;
|
|
8
|
+
export interface ArtifactStoreConformanceFailure {
|
|
9
|
+
readonly case: string;
|
|
10
|
+
readonly message: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ArtifactStoreConformanceReport {
|
|
13
|
+
readonly ok: boolean;
|
|
14
|
+
readonly cases: number;
|
|
15
|
+
readonly failures: readonly ArtifactStoreConformanceFailure[];
|
|
16
|
+
}
|
|
17
|
+
/** Run the framework-free behavioral checks for an ArtifactStore provider. */
|
|
18
|
+
export declare function runArtifactStoreConformance(factory: ArtifactStoreConformanceFactory): Promise<ArtifactStoreConformanceReport>;
|
|
19
|
+
/** Throw one readable error when an ArtifactStore provider breaks the contract. */
|
|
20
|
+
export declare function assertArtifactStoreConformance(factory: ArtifactStoreConformanceFactory): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { JsonObject, Sha256Digest } from '../json.js';
|
|
2
|
+
export type ArtifactContentMode = 'exact' | 'state' | 'free-text';
|
|
3
|
+
export interface ArtifactScope {
|
|
4
|
+
readonly namespace: string;
|
|
5
|
+
readonly runId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface NewArtifact {
|
|
8
|
+
readonly bytes: Uint8Array;
|
|
9
|
+
readonly mediaType: string;
|
|
10
|
+
readonly purpose: string;
|
|
11
|
+
readonly contentMode: ArtifactContentMode;
|
|
12
|
+
readonly sensitive?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export type ArtifactBatch = readonly [NewArtifact, ...NewArtifact[]];
|
|
15
|
+
export interface ArtifactReference<Purpose extends string = string> extends JsonObject {
|
|
16
|
+
readonly schemaVersion: 1;
|
|
17
|
+
readonly digest: Sha256Digest;
|
|
18
|
+
readonly byteLength: number;
|
|
19
|
+
readonly mediaType: string;
|
|
20
|
+
readonly purpose: Purpose;
|
|
21
|
+
}
|
|
22
|
+
export interface ArtifactStore {
|
|
23
|
+
preflightWrite(scope: ArtifactScope, artifacts: ArtifactBatch): Promise<readonly ArtifactReference[]>;
|
|
24
|
+
write(scope: ArtifactScope, artifact: NewArtifact): Promise<ArtifactReference>;
|
|
25
|
+
read(scope: ArtifactScope, reference: ArtifactReference): Promise<Uint8Array>;
|
|
26
|
+
deleteRun(scope: ArtifactScope): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare function validateArtifactScope(value: unknown): ArtifactScope;
|
|
29
|
+
export declare function validateNewArtifact(value: unknown): NewArtifact;
|
|
30
|
+
export declare function validateArtifactReference(value: unknown): ArtifactReference;
|
package/dist/budget.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { UsageReceipt } from './contracts.js';
|
|
2
|
+
import type { JsonObject, Sha256Digest } from './json.js';
|
|
3
|
+
export type TokenLimitMode = 'hard' | 'observed';
|
|
4
|
+
export interface TokenAllowance extends JsonObject {
|
|
5
|
+
readonly mode: TokenLimitMode;
|
|
6
|
+
readonly tokens: number;
|
|
7
|
+
}
|
|
8
|
+
export interface AttemptBudgetPolicy extends JsonObject {
|
|
9
|
+
readonly inputBytes: number;
|
|
10
|
+
readonly outputBytes: number;
|
|
11
|
+
readonly timeoutMs: number;
|
|
12
|
+
readonly teardownGraceMs: number;
|
|
13
|
+
readonly memoryBytes: number;
|
|
14
|
+
readonly filesChanged: number;
|
|
15
|
+
readonly linesChanged: number;
|
|
16
|
+
readonly callTokens: TokenAllowance | null;
|
|
17
|
+
}
|
|
18
|
+
export interface TokenBudgetSnapshot {
|
|
19
|
+
readonly limit: number;
|
|
20
|
+
readonly spent: number;
|
|
21
|
+
readonly reserved: number;
|
|
22
|
+
readonly unknownUsageCalls: number;
|
|
23
|
+
}
|
|
24
|
+
export interface BudgetReservation {
|
|
25
|
+
readonly reservationId: Sha256Digest;
|
|
26
|
+
readonly amount: number;
|
|
27
|
+
commit(usage: UsageReceipt): void;
|
|
28
|
+
release(): void;
|
|
29
|
+
}
|
|
30
|
+
export interface TokenBudget {
|
|
31
|
+
child(limit: number): TokenBudget;
|
|
32
|
+
reserve(allowance: TokenAllowance, capabilities: {
|
|
33
|
+
readonly hardLimitEnforceable: boolean;
|
|
34
|
+
}): BudgetReservation;
|
|
35
|
+
snapshot(): TokenBudgetSnapshot;
|
|
36
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { NewDomainEvent } from '../events/envelope.js';
|
|
2
|
+
import type { PermissionDescriptor } from '../graph-plan.js';
|
|
3
|
+
import { type JsonObject, type Sha256Digest } from '../json.js';
|
|
4
|
+
import { type ActionDecision } from '../action-decision.js';
|
|
5
|
+
import type { WorkspaceAnchor } from '../workspace/provider.js';
|
|
6
|
+
import type { AcceptedResultGraph } from '../proof/acceptance.js';
|
|
7
|
+
import type { ProofArtifactReference } from '../proof/artifact.js';
|
|
8
|
+
import type { CallbackEvent } from './client-contract.js';
|
|
9
|
+
import { type CallbackGateDefinition, type CallbackRequest } from './gate.js';
|
|
10
|
+
export type ApprovalSubmission = Extract<CallbackEvent, {
|
|
11
|
+
readonly kind: 'callback-submitted';
|
|
12
|
+
}>;
|
|
13
|
+
export interface ApprovalSubjectInput {
|
|
14
|
+
readonly workspaceAnchor: WorkspaceAnchor | null;
|
|
15
|
+
readonly inputArtifactHashes: Readonly<Record<string, Sha256Digest>>;
|
|
16
|
+
readonly proofScope: JsonObject;
|
|
17
|
+
readonly proofArtifact: ProofArtifactReference;
|
|
18
|
+
readonly proposedOutput: Uint8Array;
|
|
19
|
+
readonly effectivePermissions: readonly PermissionDescriptor[];
|
|
20
|
+
}
|
|
21
|
+
export interface ApprovalResolutionInput extends ApprovalSubjectInput {
|
|
22
|
+
readonly request: CallbackRequest;
|
|
23
|
+
}
|
|
24
|
+
export interface ApprovalSubject extends JsonObject {
|
|
25
|
+
readonly workspaceAnchor: WorkspaceAnchor | null;
|
|
26
|
+
readonly inputArtifactHashes: Readonly<Record<string, Sha256Digest>>;
|
|
27
|
+
readonly proofScope: JsonObject;
|
|
28
|
+
readonly proofArtifact: ProofArtifactReference;
|
|
29
|
+
readonly proposedOutputDigest: Sha256Digest;
|
|
30
|
+
readonly effectivePermissions: readonly JsonObject[];
|
|
31
|
+
}
|
|
32
|
+
export interface ApprovalBinding extends JsonObject {
|
|
33
|
+
readonly requestId: string;
|
|
34
|
+
readonly requestDigest: string;
|
|
35
|
+
readonly planDigest: Sha256Digest;
|
|
36
|
+
readonly graph: AcceptedResultGraph;
|
|
37
|
+
readonly workspaceAnchor: WorkspaceAnchor | null;
|
|
38
|
+
readonly inputArtifactHashes: Readonly<Record<string, Sha256Digest>>;
|
|
39
|
+
readonly proofScope: JsonObject;
|
|
40
|
+
readonly proofArtifact: ProofArtifactReference;
|
|
41
|
+
readonly proposedOutputDigest: Sha256Digest;
|
|
42
|
+
readonly actor: JsonObject;
|
|
43
|
+
readonly responsePath: string;
|
|
44
|
+
readonly decision: ActionDecision;
|
|
45
|
+
readonly effectivePermissions: readonly JsonObject[];
|
|
46
|
+
}
|
|
47
|
+
export interface ApprovalRecord extends JsonObject {
|
|
48
|
+
readonly schemaVersion: 1;
|
|
49
|
+
readonly binding: ApprovalBinding;
|
|
50
|
+
readonly bindingDigest: Sha256Digest;
|
|
51
|
+
}
|
|
52
|
+
export interface ApprovalEventPayload extends JsonObject {
|
|
53
|
+
readonly requestId: string;
|
|
54
|
+
readonly record: ApprovalRecord;
|
|
55
|
+
}
|
|
56
|
+
export type NewApprovalEvent = NewDomainEvent<'callback:approval-recorded', 1, ApprovalEventPayload>;
|
|
57
|
+
export declare class ApprovalSubjectError extends Error {
|
|
58
|
+
readonly code: 'SUBJECT_MISMATCH';
|
|
59
|
+
constructor(message: string);
|
|
60
|
+
}
|
|
61
|
+
export declare function isObject(value: unknown): value is JsonObject;
|
|
62
|
+
export declare function hasExactFields(value: JsonObject, fields: readonly string[]): boolean;
|
|
63
|
+
export declare function snapshotApprovalSubject(input: ApprovalSubjectInput): ApprovalSubject;
|
|
64
|
+
export declare function approvalSubjectDigest(input: ApprovalSubjectInput): Sha256Digest;
|
|
65
|
+
export declare function createApprovalCallbackGate(definition: CallbackGateDefinition, subject: ApprovalSubjectInput): CallbackRequest;
|
|
66
|
+
export declare function validateApprovalSubject(value: unknown): ApprovalSubject;
|
|
67
|
+
export declare function assertApprovalPermissionsAdmitted(subject: ApprovalSubject, admitted: readonly PermissionDescriptor[]): void;
|
|
68
|
+
export interface StoredApprovalBindingInput {
|
|
69
|
+
readonly request: CallbackRequest;
|
|
70
|
+
readonly planDigest: Sha256Digest;
|
|
71
|
+
readonly graph: AcceptedResultGraph;
|
|
72
|
+
readonly subject: ApprovalSubject;
|
|
73
|
+
readonly actor: JsonObject;
|
|
74
|
+
readonly responsePath: string;
|
|
75
|
+
}
|
|
76
|
+
export declare function bindingFromSubject(input: StoredApprovalBindingInput, decision: ActionDecision): ApprovalBinding;
|
|
77
|
+
export declare function validateApprovalRecord(value: unknown): ApprovalRecord;
|
|
78
|
+
export interface PrepareApprovalRecordInput extends StoredApprovalBindingInput {
|
|
79
|
+
readonly submission: ApprovalSubmission;
|
|
80
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type CallbackRequest } from './gate.js';
|
|
2
|
+
import { type JsonObject, type JsonValue } from '../json.js';
|
|
3
|
+
export type CallbackEvent = {
|
|
4
|
+
readonly kind: 'callback-requested';
|
|
5
|
+
readonly request: CallbackRequest;
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'callback-claimed';
|
|
8
|
+
readonly requestId: string;
|
|
9
|
+
readonly routerId: string;
|
|
10
|
+
readonly claimToken: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'callback-released';
|
|
13
|
+
readonly requestId: string;
|
|
14
|
+
readonly routerId: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'callback-submitted';
|
|
17
|
+
readonly requestId: string;
|
|
18
|
+
readonly requestDigest: string;
|
|
19
|
+
readonly routerId: string;
|
|
20
|
+
readonly response: JsonValue;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: 'callback-rejected';
|
|
23
|
+
readonly requestId: string;
|
|
24
|
+
readonly routerId: string;
|
|
25
|
+
readonly reason: string;
|
|
26
|
+
} | {
|
|
27
|
+
readonly kind: 'callback-superseded';
|
|
28
|
+
readonly requestId: string;
|
|
29
|
+
readonly supersededBy: string;
|
|
30
|
+
};
|
|
31
|
+
/** Validate one callback event before it can affect replayed state. */
|
|
32
|
+
export declare function validateCallbackEvent(value: unknown): CallbackEvent;
|
|
33
|
+
export interface ClaimOk {
|
|
34
|
+
readonly ok: true;
|
|
35
|
+
readonly claimToken: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ClaimRefused {
|
|
38
|
+
readonly ok: false;
|
|
39
|
+
readonly kind: 'missing' | 'claimed' | 'answered' | 'superseded';
|
|
40
|
+
readonly routerId: string | null;
|
|
41
|
+
}
|
|
42
|
+
export type ClaimResult = ClaimOk | ClaimRefused;
|
|
43
|
+
export interface SubmitOk {
|
|
44
|
+
readonly ok: true;
|
|
45
|
+
readonly response: JsonValue;
|
|
46
|
+
}
|
|
47
|
+
export interface SubmitRefused {
|
|
48
|
+
readonly ok: false;
|
|
49
|
+
readonly kind: 'missing' | 'not-claimed' | 'not-owner' | 'stale' | 'invalid';
|
|
50
|
+
readonly reason: string;
|
|
51
|
+
}
|
|
52
|
+
export type SubmitResult = SubmitOk | SubmitRefused;
|
|
53
|
+
export interface ReleaseOk {
|
|
54
|
+
readonly ok: true;
|
|
55
|
+
}
|
|
56
|
+
export interface ReleaseRefused {
|
|
57
|
+
readonly ok: false;
|
|
58
|
+
readonly kind: 'missing' | 'not-owner';
|
|
59
|
+
}
|
|
60
|
+
export type ReleaseResult = ReleaseOk | ReleaseRefused;
|
|
61
|
+
export interface CallbackClient {
|
|
62
|
+
/** Record a gate's request and make it pending. Observation only. */
|
|
63
|
+
post(request: CallbackRequest): void;
|
|
64
|
+
/** The pending requests, without starting any effect. */
|
|
65
|
+
listPending(): readonly CallbackRequest[];
|
|
66
|
+
/** Atomically assign a request to one router. */
|
|
67
|
+
claim(requestId: string, routerId: string): ClaimResult;
|
|
68
|
+
/**
|
|
69
|
+
* Validate and record a structured response. The assignment binds the
|
|
70
|
+
* response schema and the request digest: a submit whose digest does
|
|
71
|
+
* not match the posted request is stale.
|
|
72
|
+
*/
|
|
73
|
+
submit(requestId: string, claimToken: string, routerId: string, requestDigest: string, response: JsonValue): SubmitResult;
|
|
74
|
+
/** Give a claimed request back so another router can take it. */
|
|
75
|
+
release(requestId: string, claimToken: string): ReleaseResult;
|
|
76
|
+
/** Mark a request superseded by a newer one from the same gate. */
|
|
77
|
+
supersede(requestId: string, supersededBy: string): void;
|
|
78
|
+
/** The full history, optionally for one request. */
|
|
79
|
+
history(requestId?: string): readonly CallbackEvent[];
|
|
80
|
+
}
|
|
81
|
+
export type Responder = (request: CallbackRequest) => Promise<JsonObject> | JsonObject;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Callback Gate (roadmap D7): a question the run asks and waits for,
|
|
3
|
+
* answered through a replaceable router. The runtime stores the durable
|
|
4
|
+
* request and its assignment; an external router claims the request,
|
|
5
|
+
* submits a structured response, and the runtime validates and records it.
|
|
6
|
+
*
|
|
7
|
+
* The request digest covers the gate version, the decision text, the
|
|
8
|
+
* response schema, and the referenced input bytes. Display-only data —
|
|
9
|
+
* placement, layout, theme, and other presentation or routing hints — is
|
|
10
|
+
* stored in the request payload but excluded from the digest, so
|
|
11
|
+
* restyling a question never invalidates a pending answer, and changing
|
|
12
|
+
* what is asked always does.
|
|
13
|
+
*/
|
|
14
|
+
import { type JsonObject, type JsonValue } from '../json.js';
|
|
15
|
+
export interface CallbackGateDefinition {
|
|
16
|
+
readonly gateId: string;
|
|
17
|
+
readonly gateVersion: number;
|
|
18
|
+
/** The question the run is asking, in plain text. */
|
|
19
|
+
readonly decisionText: string;
|
|
20
|
+
/** The shape a valid answer takes. */
|
|
21
|
+
readonly responseSchema: JsonObject;
|
|
22
|
+
/** The input bytes the decision refers to. */
|
|
23
|
+
readonly input: JsonValue;
|
|
24
|
+
/** Presentation and routing hints: stored, never digested. */
|
|
25
|
+
readonly presentation?: JsonObject;
|
|
26
|
+
}
|
|
27
|
+
export interface CallbackRequest extends JsonObject {
|
|
28
|
+
readonly requestId: string;
|
|
29
|
+
readonly gateId: string;
|
|
30
|
+
readonly gateVersion: number;
|
|
31
|
+
readonly digest: string;
|
|
32
|
+
readonly decisionText: string;
|
|
33
|
+
readonly responseSchema: JsonObject;
|
|
34
|
+
readonly input: JsonValue;
|
|
35
|
+
readonly presentation: JsonObject;
|
|
36
|
+
}
|
|
37
|
+
/** Create the gate's request. Same definition bytes, same digest. */
|
|
38
|
+
export declare function createCallbackGate(definition: CallbackGateDefinition): CallbackRequest;
|
|
39
|
+
/** The digest a gate definition produces, without creating a request. */
|
|
40
|
+
export declare function callbackRequestDigest(definition: Omit<CallbackGateDefinition, 'presentation'>): string;
|
|
41
|
+
/** Validate stored request bytes and their content-derived identity. */
|
|
42
|
+
export declare function validateCallbackRequest(value: unknown): CallbackRequest;
|
|
43
|
+
/** Validate a response object against a response schema's plain shape. */
|
|
44
|
+
export declare function validateCallbackResponse(response: JsonValue, schema: JsonObject): {
|
|
45
|
+
ok: true;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
reason: string;
|
|
49
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { NewDomainEvent } from '../events/envelope.js';
|
|
2
|
+
import type { JsonObject, JsonValue } from '../json.js';
|
|
3
|
+
import type { ApprovalSubject, ApprovalSubjectInput } from './approval.js';
|
|
4
|
+
import type { CallbackEvent, ClaimResult, ReleaseResult, SubmitResult } from './client-contract.js';
|
|
5
|
+
import type { CallbackRequest } from './gate.js';
|
|
6
|
+
type CallbackHistoryPayload = Readonly<{
|
|
7
|
+
readonly event: JsonObject;
|
|
8
|
+
}> | Readonly<{
|
|
9
|
+
readonly event: JsonObject;
|
|
10
|
+
readonly approvalSubject: ApprovalSubject;
|
|
11
|
+
}>;
|
|
12
|
+
export type NewCallbackHistoryEvent = NewDomainEvent<'callback:history-recorded', 1, CallbackHistoryPayload>;
|
|
13
|
+
export interface StoredCallbackClient {
|
|
14
|
+
post(request: CallbackRequest, approvalSubject?: ApprovalSubjectInput): Promise<void>;
|
|
15
|
+
listPending(): Promise<readonly CallbackRequest[]>;
|
|
16
|
+
claim(requestId: string, routerId: string): Promise<ClaimResult>;
|
|
17
|
+
submit(requestId: string, claimToken: string, routerId: string, requestDigest: string, response: JsonValue, actor?: JsonObject): Promise<SubmitResult>;
|
|
18
|
+
release(requestId: string, claimToken: string): Promise<ReleaseResult>;
|
|
19
|
+
supersede(requestId: string, supersededBy: string): Promise<void>;
|
|
20
|
+
history(requestId?: string): Promise<readonly CallbackEvent[]>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { validateArtifactReference } from './chunk-WGLWWKF3.js';
|
|
2
|
+
import { cloneFrozenJson, digestJson } from './chunk-AJ353QD5.js';
|
|
3
|
+
|
|
4
|
+
// src/proof/acceptance.ts
|
|
5
|
+
var SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/u;
|
|
6
|
+
function isObject(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function hasExactFields(value, fields) {
|
|
10
|
+
const actual = Object.keys(value).sort();
|
|
11
|
+
const expected = [...fields].sort();
|
|
12
|
+
return actual.length === expected.length && actual.every((field, index) => field === expected[index]);
|
|
13
|
+
}
|
|
14
|
+
function isDigest(value) {
|
|
15
|
+
return typeof value === "string" && SHA256_DIGEST.test(value);
|
|
16
|
+
}
|
|
17
|
+
function bindingFrom(input) {
|
|
18
|
+
const reviewerIdentity = cloneFrozenJson(input.reviewerIdentity);
|
|
19
|
+
return cloneFrozenJson({
|
|
20
|
+
inputHashes: input.inputHashes,
|
|
21
|
+
proofScope: input.proofScope,
|
|
22
|
+
proofArtifact: input.proofArtifact,
|
|
23
|
+
graph: input.graph,
|
|
24
|
+
workspaceAnchor: input.workspaceAnchor,
|
|
25
|
+
reviewerIdentity,
|
|
26
|
+
reviewerFingerprint: digestJson(reviewerIdentity)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function validateAcceptedResultRecord(value) {
|
|
30
|
+
const record = cloneFrozenJson(value);
|
|
31
|
+
if (!isObject(record)) {
|
|
32
|
+
throw new TypeError("invalid accepted-result record");
|
|
33
|
+
}
|
|
34
|
+
const { binding } = record;
|
|
35
|
+
if (!hasExactFields(record, [
|
|
36
|
+
"schemaVersion",
|
|
37
|
+
"result",
|
|
38
|
+
"resultDigest",
|
|
39
|
+
"binding",
|
|
40
|
+
"bindingDigest"
|
|
41
|
+
]) || record.schemaVersion !== 1 || record.result === void 0 || !isDigest(record.resultDigest) || record.resultDigest !== digestJson(record.result) || !isObject(binding) || !isDigest(record.bindingDigest)) {
|
|
42
|
+
throw new TypeError("invalid accepted-result record");
|
|
43
|
+
}
|
|
44
|
+
if (!hasExactFields(binding, [
|
|
45
|
+
"inputHashes",
|
|
46
|
+
"proofScope",
|
|
47
|
+
"proofArtifact",
|
|
48
|
+
"graph",
|
|
49
|
+
"workspaceAnchor",
|
|
50
|
+
"reviewerIdentity",
|
|
51
|
+
"reviewerFingerprint"
|
|
52
|
+
]) || !isObject(binding.inputHashes) || Object.values(binding.inputHashes).some((hash) => !isDigest(hash)) || !isObject(binding.proofScope) || !isObject(binding.proofArtifact) || !isObject(binding.graph) || !hasExactFields(binding.graph, ["definitionDigest", "typeVersion"]) || !isDigest(binding.graph.definitionDigest) || typeof binding.graph.typeVersion !== "number" || !Number.isSafeInteger(binding.graph.typeVersion) || binding.graph.typeVersion < 1 || !isObject(binding.workspaceAnchor) || !isObject(binding.reviewerIdentity) || !isDigest(binding.reviewerFingerprint) || binding.reviewerFingerprint !== digestJson(binding.reviewerIdentity) || record.bindingDigest !== digestJson(binding)) {
|
|
53
|
+
throw new TypeError("invalid accepted-result binding");
|
|
54
|
+
}
|
|
55
|
+
const proofArtifact = validateArtifactReference(binding.proofArtifact);
|
|
56
|
+
if (proofArtifact.purpose !== "proof-packet") {
|
|
57
|
+
throw new TypeError("accepted result needs a proof-packet artifact");
|
|
58
|
+
}
|
|
59
|
+
return record;
|
|
60
|
+
}
|
|
61
|
+
function acceptedResultMatches(record, current) {
|
|
62
|
+
return acceptedResultMatchesBinding(record, bindingFrom(current));
|
|
63
|
+
}
|
|
64
|
+
function acceptedResultMatchesBinding(record, current) {
|
|
65
|
+
try {
|
|
66
|
+
const stored = validateAcceptedResultRecord(record);
|
|
67
|
+
return stored.bindingDigest === digestJson(current);
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
var acceptedResultSupport = Object.freeze({
|
|
73
|
+
isObject,
|
|
74
|
+
hasExactFields,
|
|
75
|
+
bindingFrom,
|
|
76
|
+
acceptedResultMatchesBinding
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export { acceptedResultMatches, acceptedResultSupport, validateAcceptedResultRecord };
|
|
80
|
+
//# sourceMappingURL=chunk-6NA4RDQ4.js.map
|
|
81
|
+
//# sourceMappingURL=chunk-6NA4RDQ4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/proof/acceptance.ts"],"names":[],"mappings":"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","file":"chunk-6NA4RDQ4.js","sourcesContent":["import { validateArtifactReference } from '../artifacts/store.js';\nimport type { NewDomainEvent } from '../events/envelope.js';\nimport { cloneFrozenJson, digestJson, type JsonObject, type JsonValue, type Sha256Digest } from '../json.js';\nimport type { WorkspaceAnchor } from '../workspace/provider.js';\nimport type { ProofArtifactReference } from './artifact.js';\n\nexport interface AcceptedResultGraph extends JsonObject {\n readonly definitionDigest: Sha256Digest;\n readonly typeVersion: number;\n}\n\nexport interface AcceptedResultBindingInput {\n readonly inputHashes: Readonly<Record<string, Sha256Digest>>;\n readonly proofScope: JsonObject;\n readonly proofArtifact: ProofArtifactReference;\n readonly graph: AcceptedResultGraph;\n readonly workspaceAnchor: WorkspaceAnchor;\n readonly reviewerIdentity: JsonObject;\n}\n\nexport interface AcceptedResultBinding extends JsonObject {\n readonly inputHashes: Readonly<Record<string, Sha256Digest>>;\n readonly proofScope: JsonObject;\n readonly proofArtifact: ProofArtifactReference;\n readonly graph: AcceptedResultGraph;\n readonly workspaceAnchor: WorkspaceAnchor;\n readonly reviewerIdentity: JsonObject;\n readonly reviewerFingerprint: Sha256Digest;\n}\n\nexport interface AcceptedResultRecord extends JsonObject {\n readonly schemaVersion: 1;\n readonly result: JsonValue;\n readonly resultDigest: Sha256Digest;\n readonly binding: AcceptedResultBinding;\n readonly bindingDigest: Sha256Digest;\n}\n\nexport interface AcceptedResultEventPayload extends JsonObject {\n readonly position: string;\n readonly record: AcceptedResultRecord;\n}\n\nexport type NewAcceptedResultEvent = NewDomainEvent<\n 'proof:result-accepted',\n 1,\n AcceptedResultEventPayload\n>;\n\nexport interface CreateAcceptedResultRecordInput extends AcceptedResultBindingInput {\n readonly result: JsonValue;\n}\n\nexport type AcceptedResultResolution =\n | Readonly<{ readonly kind: 'accepted'; readonly record: AcceptedResultRecord }>\n | Readonly<{ readonly kind: 'wait'; readonly reason: string }>;\n\nconst SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/u;\n\nfunction isObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactFields(value: JsonObject, fields: readonly string[]): boolean {\n const actual = Object.keys(value).sort();\n const expected = [...fields].sort();\n return actual.length === expected.length\n && actual.every((field, index) => field === expected[index]);\n}\n\nfunction isDigest(value: JsonValue | undefined): value is Sha256Digest {\n return typeof value === 'string' && SHA256_DIGEST.test(value);\n}\n\nfunction bindingFrom(input: AcceptedResultBindingInput): AcceptedResultBinding {\n const reviewerIdentity = cloneFrozenJson(input.reviewerIdentity) as JsonObject;\n return cloneFrozenJson({\n inputHashes: input.inputHashes,\n proofScope: input.proofScope,\n proofArtifact: input.proofArtifact,\n graph: input.graph,\n workspaceAnchor: input.workspaceAnchor,\n reviewerIdentity,\n reviewerFingerprint: digestJson(reviewerIdentity),\n }) as AcceptedResultBinding;\n}\n\nexport function validateAcceptedResultRecord(value: unknown): AcceptedResultRecord {\n const record = cloneFrozenJson(value as JsonValue);\n if (!isObject(record)) {\n throw new TypeError('invalid accepted-result record');\n }\n const { binding } = record;\n if (!hasExactFields(record, [\n 'schemaVersion',\n 'result',\n 'resultDigest',\n 'binding',\n 'bindingDigest',\n ])\n || record.schemaVersion !== 1\n || record.result === undefined\n || !isDigest(record.resultDigest)\n || record.resultDigest !== digestJson(record.result)\n || !isObject(binding)\n || !isDigest(record.bindingDigest)) {\n throw new TypeError('invalid accepted-result record');\n }\n\n if (!hasExactFields(binding, [\n 'inputHashes',\n 'proofScope',\n 'proofArtifact',\n 'graph',\n 'workspaceAnchor',\n 'reviewerIdentity',\n 'reviewerFingerprint',\n ])\n || !isObject(binding.inputHashes)\n || Object.values(binding.inputHashes).some((hash) => !isDigest(hash))\n || !isObject(binding.proofScope)\n || !isObject(binding.proofArtifact)\n || !isObject(binding.graph)\n || !hasExactFields(binding.graph, ['definitionDigest', 'typeVersion'])\n || !isDigest(binding.graph.definitionDigest)\n || typeof binding.graph.typeVersion !== 'number'\n || !Number.isSafeInteger(binding.graph.typeVersion)\n || binding.graph.typeVersion < 1\n || !isObject(binding.workspaceAnchor)\n || !isObject(binding.reviewerIdentity)\n || !isDigest(binding.reviewerFingerprint)\n || binding.reviewerFingerprint !== digestJson(binding.reviewerIdentity)\n || record.bindingDigest !== digestJson(binding)) {\n throw new TypeError('invalid accepted-result binding');\n }\n const proofArtifact = validateArtifactReference(binding.proofArtifact);\n if (proofArtifact.purpose !== 'proof-packet') {\n throw new TypeError('accepted result needs a proof-packet artifact');\n }\n\n return record as AcceptedResultRecord;\n}\n\nexport function acceptedResultMatches(\n record: AcceptedResultRecord,\n current: AcceptedResultBindingInput,\n): boolean {\n return acceptedResultMatchesBinding(record, bindingFrom(current));\n}\n\nfunction acceptedResultMatchesBinding(\n record: AcceptedResultRecord,\n current: AcceptedResultBinding,\n): boolean {\n try {\n const stored = validateAcceptedResultRecord(record);\n return stored.bindingDigest === digestJson(current);\n } catch {\n return false;\n }\n}\n\nexport const acceptedResultSupport = Object.freeze({\n isObject,\n hasExactFields,\n bindingFrom,\n acceptedResultMatchesBinding,\n});\n"]}
|