@openwop/openwop 1.1.1 → 1.1.2
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 +4 -0
- package/dist/client.d.ts +80 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +186 -0
- package/dist/client.js.map +1 -1
- package/dist/cost-attribution.d.ts +49 -0
- package/dist/cost-attribution.d.ts.map +1 -0
- package/dist/cost-attribution.js +65 -0
- package/dist/cost-attribution.js.map +1 -0
- package/dist/event-helpers.d.ts +95 -0
- package/dist/event-helpers.d.ts.map +1 -0
- package/dist/event-helpers.js +160 -0
- package/dist/event-helpers.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/registry-helpers.d.ts +118 -0
- package/dist/registry-helpers.d.ts.map +1 -0
- package/dist/registry-helpers.js +82 -0
- package/dist/registry-helpers.js.map +1 -0
- package/dist/types.d.ts +376 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/webhook-helpers.d.ts +73 -0
- package/dist/webhook-helpers.d.ts.map +1 -0
- package/dist/webhook-helpers.js +97 -0
- package/dist/webhook-helpers.js.map +1 -0
- package/package.json +1 -1
- package/src/client.ts +218 -0
- package/src/cost-attribution.ts +72 -0
- package/src/event-helpers.ts +238 -0
- package/src/index.ts +96 -0
- package/src/registry-helpers.ts +173 -0
- package/src/types.ts +424 -0
- package/src/webhook-helpers.ts +131 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public-registry read helpers per
|
|
3
|
+
* `spec/v1/registry-operations.md`.
|
|
4
|
+
*
|
|
5
|
+
* The OpenWOP host SDK targets the host wire surface
|
|
6
|
+
* (`/.well-known/openwop` + `/v1/runs/*` + `/v1/interrupts/*` etc).
|
|
7
|
+
* The **public node-pack registry** at `packs.openwop.dev` is a
|
|
8
|
+
* separate wire surface with its own discovery payload and pack-
|
|
9
|
+
* versioned read endpoints. This module exposes a thin typed client
|
|
10
|
+
* for that surface so adopters fetching pack manifests, indices, or
|
|
11
|
+
* signature material don't roll their own HTTP plumbing.
|
|
12
|
+
*
|
|
13
|
+
* Read-only by design — the public registry uses pull-request-driven
|
|
14
|
+
* publishing per `spec/v1/registry-operations.md` §"Submission flow"
|
|
15
|
+
* + the `registry-publish.yml` GitHub workflow. There is no write API.
|
|
16
|
+
*
|
|
17
|
+
* No auth required for public reads.
|
|
18
|
+
*
|
|
19
|
+
* @module @openwop/openwop/registry-helpers
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** Public registry discovery payload per `registry-operations.md` §"Discovery". */
|
|
23
|
+
export interface RegistryDiscovery {
|
|
24
|
+
registryVersion: string;
|
|
25
|
+
protocolVersion: string;
|
|
26
|
+
name?: string;
|
|
27
|
+
operator?: string;
|
|
28
|
+
url?: string;
|
|
29
|
+
supportedNamespaces: readonly string[];
|
|
30
|
+
supportedSigningMethods: readonly string[];
|
|
31
|
+
supportedTrustModes?: readonly string[];
|
|
32
|
+
endpoints: {
|
|
33
|
+
registryIndex: string;
|
|
34
|
+
packMetadata: string;
|
|
35
|
+
versionManifest: string;
|
|
36
|
+
versionTarball: string;
|
|
37
|
+
versionSignature: string;
|
|
38
|
+
publicKey: string;
|
|
39
|
+
};
|
|
40
|
+
signingKeys?: ReadonlyArray<{
|
|
41
|
+
keyId: string;
|
|
42
|
+
algorithm: string;
|
|
43
|
+
publicKeyUrl?: string;
|
|
44
|
+
permittedNamespaces?: readonly string[];
|
|
45
|
+
operator?: string;
|
|
46
|
+
status?: string;
|
|
47
|
+
}>;
|
|
48
|
+
[key: string]: unknown;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Registry-wide index entry per `/v1/index.json` rows. */
|
|
52
|
+
export interface RegistryIndexEntry {
|
|
53
|
+
name: string;
|
|
54
|
+
latestVersion: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
scope?: string;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface RegistryIndex {
|
|
61
|
+
packs: ReadonlyArray<RegistryIndexEntry>;
|
|
62
|
+
generated?: string;
|
|
63
|
+
packCount?: number;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Per-pack metadata document at `/v1/packs/{name}/index.json`. */
|
|
68
|
+
export interface RegistryPackMetadata {
|
|
69
|
+
name: string;
|
|
70
|
+
description?: string;
|
|
71
|
+
versions: ReadonlyArray<string>;
|
|
72
|
+
latestVersion?: string;
|
|
73
|
+
[key: string]: unknown;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Version manifest at `/v1/packs/{name}/-/{version}.json`. */
|
|
77
|
+
export interface RegistryVersionManifest {
|
|
78
|
+
name: string;
|
|
79
|
+
version: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
/** SRI hash: `sha256-<43-char-b64>=`. */
|
|
82
|
+
integrity?: string;
|
|
83
|
+
signing?: {
|
|
84
|
+
method: 'ed25519' | 'manual' | string;
|
|
85
|
+
keyId: string;
|
|
86
|
+
publicKeyUrl?: string;
|
|
87
|
+
};
|
|
88
|
+
[key: string]: unknown;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RegistryClientOptions {
|
|
92
|
+
/** Base URL for the registry. Defaults to `https://packs.openwop.dev`. */
|
|
93
|
+
baseUrl?: string;
|
|
94
|
+
/** Custom fetch implementation; defaults to `globalThis.fetch`. */
|
|
95
|
+
fetch?: typeof fetch;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Typed client for the public OpenWOP node-pack registry. Read-only;
|
|
100
|
+
* no auth required for the canonical public read surface.
|
|
101
|
+
*
|
|
102
|
+
* For host-side install-time verification (SRI + Ed25519 + lockfile),
|
|
103
|
+
* see `examples/hosts/postgres/src/pack-consumer.ts` — the registry
|
|
104
|
+
* client is the fetch surface; the consumer is the security surface.
|
|
105
|
+
*/
|
|
106
|
+
export class RegistryClient {
|
|
107
|
+
readonly baseUrl: string;
|
|
108
|
+
readonly #fetch: typeof fetch;
|
|
109
|
+
|
|
110
|
+
constructor(options: RegistryClientOptions = {}) {
|
|
111
|
+
this.baseUrl = (options.baseUrl ?? 'https://packs.openwop.dev').replace(/\/$/, '');
|
|
112
|
+
this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** `GET /.well-known/openwop-registry` — discovery + endpoint catalog. */
|
|
116
|
+
async discovery(): Promise<RegistryDiscovery> {
|
|
117
|
+
return this.#getJson<RegistryDiscovery>('/.well-known/openwop-registry');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** `GET /v1/index.json` — registry-wide pack index. */
|
|
121
|
+
async index(): Promise<RegistryIndex> {
|
|
122
|
+
return this.#getJson<RegistryIndex>('/v1/index.json');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** `GET /v1/packs/{name}/index.json` — per-pack metadata. */
|
|
126
|
+
async pack(name: string): Promise<RegistryPackMetadata> {
|
|
127
|
+
return this.#getJson<RegistryPackMetadata>(
|
|
128
|
+
`/v1/packs/${encodeURIComponent(name)}/index.json`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** `GET /v1/packs/{name}/-/{version}.json` — version manifest. */
|
|
133
|
+
async version(name: string, version: string): Promise<RegistryVersionManifest> {
|
|
134
|
+
return this.#getJson<RegistryVersionManifest>(
|
|
135
|
+
`/v1/packs/${encodeURIComponent(name)}/-/${encodeURIComponent(version)}.json`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Fetch raw tarball bytes. Caller MUST verify SRI + signature before trust. */
|
|
140
|
+
async tarball(name: string, version: string): Promise<Buffer> {
|
|
141
|
+
return this.#getBinary(
|
|
142
|
+
`/v1/packs/${encodeURIComponent(name)}/-/${encodeURIComponent(version)}.tgz`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Fetch raw 64-byte Ed25519 signature bytes. */
|
|
147
|
+
async signature(name: string, version: string): Promise<Buffer> {
|
|
148
|
+
return this.#getBinary(
|
|
149
|
+
`/v1/packs/${encodeURIComponent(name)}/-/${encodeURIComponent(version)}.sig`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Fetch a publisher's public key as PEM text. */
|
|
154
|
+
async publicKey(keyId: string): Promise<string> {
|
|
155
|
+
const res = await this.#fetch(`${this.baseUrl}/keys/${encodeURIComponent(keyId)}.pub`);
|
|
156
|
+
if (!res.ok) throw new Error(`registry: GET /keys/${keyId}.pub returned ${res.status}`);
|
|
157
|
+
return res.text();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async #getJson<T>(path: string): Promise<T> {
|
|
161
|
+
const res = await this.#fetch(`${this.baseUrl}${path}`, {
|
|
162
|
+
headers: { Accept: 'application/json' },
|
|
163
|
+
});
|
|
164
|
+
if (!res.ok) throw new Error(`registry: GET ${path} returned ${res.status}`);
|
|
165
|
+
return (await res.json()) as T;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async #getBinary(path: string): Promise<Buffer> {
|
|
169
|
+
const res = await this.#fetch(`${this.baseUrl}${path}`);
|
|
170
|
+
if (!res.ok) throw new Error(`registry: GET ${path} returned ${res.status}`);
|
|
171
|
+
return Buffer.from(await res.arrayBuffer());
|
|
172
|
+
}
|
|
173
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type RunStatus =
|
|
|
18
18
|
| 'paused'
|
|
19
19
|
| 'waiting-approval'
|
|
20
20
|
| 'waiting-input'
|
|
21
|
+
| 'waiting-external'
|
|
21
22
|
| 'completed'
|
|
22
23
|
| 'failed'
|
|
23
24
|
| 'cancelled';
|
|
@@ -54,6 +55,24 @@ export interface RunSnapshot {
|
|
|
54
55
|
variables?: Record<string, unknown>;
|
|
55
56
|
channels?: Record<string, unknown>;
|
|
56
57
|
error?: { code?: string; message?: string };
|
|
58
|
+
/** Linkage back to the parent run when this run was spawned via
|
|
59
|
+
* `core.subWorkflow`. Per `interrupt-profiles.md §openwop-interrupt-
|
|
60
|
+
* cascade-cancel`: child runs preserve `parentRunId` + `parentNodeId`
|
|
61
|
+
* so cancellation can cascade. Absent for top-level runs. */
|
|
62
|
+
parentRunId?: string;
|
|
63
|
+
parentNodeId?: string;
|
|
64
|
+
/** Surfaced for `waiting-*` runs per `interrupt.md §"Signed-token
|
|
65
|
+
* callback"`. Carries the open interrupt's metadata so clients can
|
|
66
|
+
* resolve via `POST /v1/interrupts/{token}` without consulting a
|
|
67
|
+
* separate endpoint. Hosts MAY omit `data` to keep payloads small;
|
|
68
|
+
* the token + callbackUrl are the load-bearing fields. */
|
|
69
|
+
interrupt?: {
|
|
70
|
+
kind: string;
|
|
71
|
+
nodeId: string;
|
|
72
|
+
interruptToken?: string;
|
|
73
|
+
callbackUrl?: string;
|
|
74
|
+
data?: unknown;
|
|
75
|
+
};
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
/**
|
|
@@ -103,6 +122,80 @@ export interface CancelRunResponse {
|
|
|
103
122
|
status: 'cancelled' | 'cancelling';
|
|
104
123
|
}
|
|
105
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Portable JSON diagnostic export for a single run per
|
|
127
|
+
* `spec/v1/debug-bundle.md` + `schemas/debug-bundle.schema.json`.
|
|
128
|
+
*
|
|
129
|
+
* Hosts MAY omit non-required fields. Consumers MUST treat masked /
|
|
130
|
+
* omitted / hashed values as the spec-canonical content per the host's
|
|
131
|
+
* advertised `redactionMode` — they are NOT placeholders for missing
|
|
132
|
+
* data.
|
|
133
|
+
*/
|
|
134
|
+
export interface DebugBundle {
|
|
135
|
+
bundleVersion: string;
|
|
136
|
+
generatedAt: string;
|
|
137
|
+
host: { name?: string; version?: string; vendor?: string };
|
|
138
|
+
run: Record<string, unknown>;
|
|
139
|
+
events: ReadonlyArray<Record<string, unknown>>;
|
|
140
|
+
redactionApplied: boolean;
|
|
141
|
+
/** Reflects the host's `capabilities.compliance.defaultMode`. */
|
|
142
|
+
redactionMode: 'mask' | 'omit' | 'hash' | 'passthrough';
|
|
143
|
+
/** True when the bundle hit the host's size cap; pair with `truncatedReason`. */
|
|
144
|
+
truncated?: boolean;
|
|
145
|
+
truncatedReason?: string;
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface DebugBundleOptions {
|
|
150
|
+
/** Optional host-extension query parameter to lower the size cap for testing. Spec-canonical hosts SHOULD prefer `host.<vendor>.<query>` namespacing; this is the SQLite-reference convention. */
|
|
151
|
+
maxEvents?: number;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface RegisterWebhookRequest {
|
|
155
|
+
/** Receiver URL the host will POST signed deliveries to. */
|
|
156
|
+
url: string;
|
|
157
|
+
/** Event types to subscribe to (subset of the `RunEventType` enum). */
|
|
158
|
+
events: readonly string[];
|
|
159
|
+
/** Optional pre-shared secret; if omitted the host generates one and returns it in the response. */
|
|
160
|
+
secret?: string;
|
|
161
|
+
/** Optional tag filter — only events from runs carrying these tags are delivered. */
|
|
162
|
+
tags?: readonly string[];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface RegisterWebhookResponse {
|
|
166
|
+
/** Server-issued opaque subscription id; pass to `webhooks.unregister`. */
|
|
167
|
+
subscriptionId: string;
|
|
168
|
+
url: string;
|
|
169
|
+
/**
|
|
170
|
+
* The signing secret. **Returned ONCE on registration** — the host
|
|
171
|
+
* cannot recover it later. Store it server-side for HMAC verification.
|
|
172
|
+
*/
|
|
173
|
+
secret: string;
|
|
174
|
+
eventTypes: readonly string[];
|
|
175
|
+
createdAt: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface PauseRunRequest {
|
|
179
|
+
reason?: string;
|
|
180
|
+
drainPolicy?: 'immediate' | 'drain-current-node';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface PauseRunResponse {
|
|
184
|
+
runId: string;
|
|
185
|
+
status: 'paused';
|
|
186
|
+
pausedAt?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface ResumeRunRequest {
|
|
190
|
+
reason?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface ResumeRunResponse {
|
|
194
|
+
runId: string;
|
|
195
|
+
status: 'running';
|
|
196
|
+
resumedAt?: string;
|
|
197
|
+
}
|
|
198
|
+
|
|
106
199
|
// rest-endpoints.md §"POST /v1/runs:bulk-cancel" (closes R1).
|
|
107
200
|
export interface BulkCancelRunsRequest {
|
|
108
201
|
runIds: readonly string[];
|
|
@@ -388,9 +481,100 @@ export interface AgentsCapability {
|
|
|
388
481
|
reasoning?: {
|
|
389
482
|
verbosity: ReasoningVerbosity;
|
|
390
483
|
tokenLimit?: number;
|
|
484
|
+
/** RFC 0024. When `true`, host MAY emit `agent.reasoning.delta`
|
|
485
|
+
* events incrementally while a reasoning block is still open,
|
|
486
|
+
* in addition to the final `agent.reasoned`. Consumers that
|
|
487
|
+
* only read `agent.reasoned` remain correct (the closing event
|
|
488
|
+
* is authoritative). */
|
|
489
|
+
streaming?: boolean;
|
|
391
490
|
};
|
|
392
491
|
}
|
|
393
492
|
|
|
493
|
+
// ─── agent.* event payloads (RFC 0002 §B + RFC 0024) ────────────────────
|
|
494
|
+
//
|
|
495
|
+
// Mirror of `schemas/run-event-payloads.schema.json#$defs.agent*`. Field
|
|
496
|
+
// names + types match the canonical wire contract verbatim; the `[key:
|
|
497
|
+
// string]: unknown` index signature reflects the deliberate
|
|
498
|
+
// `additionalProperties: true` carve-out on the agent.* payloads (Phase
|
|
499
|
+
// 1 of the multi-agent shift). When the canonical schema changes, these
|
|
500
|
+
// interfaces MUST be updated in lock-step — see the assertion in
|
|
501
|
+
// `__tests__/event-helpers.test.ts` that exercises every required field.
|
|
502
|
+
|
|
503
|
+
/** `agent.reasoned` payload (RFC 0002 §B). Fired once per closed
|
|
504
|
+
* reasoning block. The `reasoning` field is authoritative — when a
|
|
505
|
+
* streaming host also emitted `agent.reasoning.delta` events, this
|
|
506
|
+
* event still carries the complete trace (possibly after host-side
|
|
507
|
+
* truncation under `verbosity: 'summary'`). */
|
|
508
|
+
export interface AgentReasonedPayload {
|
|
509
|
+
agentId: string;
|
|
510
|
+
reasoning: string;
|
|
511
|
+
verbosity?: ReasoningVerbosity;
|
|
512
|
+
[key: string]: unknown;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** `agent.reasoning.delta` payload (RFC 0024). Incremental reasoning
|
|
516
|
+
* chunk emitted while a reasoning block is still open. Consumers
|
|
517
|
+
* concatenate `delta` strings in `sequence` order to reconstruct
|
|
518
|
+
* the in-progress trace; the closing `agent.reasoned` event carries
|
|
519
|
+
* the authoritative final content. */
|
|
520
|
+
export interface AgentReasoningDeltaPayload {
|
|
521
|
+
agentId: string;
|
|
522
|
+
delta: string;
|
|
523
|
+
sequence: number;
|
|
524
|
+
verbosity?: ReasoningVerbosity;
|
|
525
|
+
[key: string]: unknown;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/** `agent.toolCalled` payload (RFC 0002 §B). Pairs with `agent.toolReturned`
|
|
529
|
+
* via shared `callId`; the toolReturned event's `causationId` equals
|
|
530
|
+
* the toolCalled event's `eventId`. */
|
|
531
|
+
export interface AgentToolCalledPayload {
|
|
532
|
+
agentId: string;
|
|
533
|
+
toolName: string;
|
|
534
|
+
callId: string;
|
|
535
|
+
inputs?: unknown;
|
|
536
|
+
[key: string]: unknown;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/** `agent.toolReturned` payload (RFC 0002 §B). `outcome` and `error`
|
|
540
|
+
* are mutually exclusive: success returns set `outcome`; failures set
|
|
541
|
+
* `error`. Hosts that need stricter validation layer it host-side. */
|
|
542
|
+
export interface AgentToolReturnedPayload {
|
|
543
|
+
agentId: string;
|
|
544
|
+
toolName: string;
|
|
545
|
+
callId: string;
|
|
546
|
+
outcome?: unknown;
|
|
547
|
+
error?: ErrorEnvelope;
|
|
548
|
+
[key: string]: unknown;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** `agent.handoff` payload (RFC 0002 §B). Note the distinct field
|
|
552
|
+
* names — `fromAgentId` / `toAgentId`, NOT a single `agentId` like
|
|
553
|
+
* the other agent.* events. */
|
|
554
|
+
export interface AgentHandoffPayload {
|
|
555
|
+
fromAgentId: string;
|
|
556
|
+
toAgentId: string;
|
|
557
|
+
reason?: string;
|
|
558
|
+
[key: string]: unknown;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** `agent.decided` payload (RFC 0002 §B). `confidence` in `[0, 1]`
|
|
562
|
+
* drives the low-confidence escalation contract (`node.suspended
|
|
563
|
+
* { reason: 'low-confidence' }`) when below the resolved threshold. */
|
|
564
|
+
export interface AgentDecidedPayload {
|
|
565
|
+
agentId: string;
|
|
566
|
+
decision: unknown;
|
|
567
|
+
confidence?: number;
|
|
568
|
+
[key: string]: unknown;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/** A `RunEventDoc` narrowed to a specific event-type discriminator +
|
|
572
|
+
* payload shape. Returned by the `isAgent*` type guards in
|
|
573
|
+
* `event-helpers.ts`. */
|
|
574
|
+
export interface TypedRunEvent<T> extends RunEventDoc {
|
|
575
|
+
payload: T;
|
|
576
|
+
}
|
|
577
|
+
|
|
394
578
|
// ─── Auth profile claims (Phase I.5 + I.6) ──────────────────────────────
|
|
395
579
|
|
|
396
580
|
/** Profile identifiers per auth-profiles.md. */
|
|
@@ -419,6 +603,246 @@ export interface DiscoveryAuthScopedCapability {
|
|
|
419
603
|
mode: 'same-endpoint';
|
|
420
604
|
}
|
|
421
605
|
|
|
606
|
+
// ---------------------------------------------------------------------------
|
|
607
|
+
// AI Envelope (DRAFT v1.x — `spec/v1/ai-envelope.md`)
|
|
608
|
+
//
|
|
609
|
+
// Inbound LLM-emission envelope. Distinct from `RunEventDoc` (outbound event
|
|
610
|
+
// log) and `ErrorEnvelope` (host HTTP error response). Top-level shape is
|
|
611
|
+
// closed; payload shape is selected by `type` and validated against a
|
|
612
|
+
// per-kind JSON Schema advertised via `Capabilities.supportedEnvelopes` +
|
|
613
|
+
// `Capabilities.schemaVersions`. See spec doc for full normative prose.
|
|
614
|
+
// ---------------------------------------------------------------------------
|
|
615
|
+
|
|
616
|
+
/** Wire metadata on every AI Envelope. */
|
|
617
|
+
export interface EnvelopeMeta {
|
|
618
|
+
/** Provenance of this emission. */
|
|
619
|
+
source: 'ai-generation' | 'user' | 'system';
|
|
620
|
+
/** Mirrors `RunEventDoc.contentTrust`. Hosts MUST set 'untrusted' for MCP / A2A origin. */
|
|
621
|
+
contentTrust?: 'trusted' | 'untrusted';
|
|
622
|
+
/** ISO 8601 UTC timestamp. */
|
|
623
|
+
ts: string;
|
|
624
|
+
/** Optional W3C trace-context for distributed tracing. */
|
|
625
|
+
traceparent?: string;
|
|
626
|
+
/** Optional human-readable label for ops dashboards. */
|
|
627
|
+
label?: string;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/** Chunking info for streamed emissions. (in-flight) */
|
|
631
|
+
export interface PartialInfo {
|
|
632
|
+
isPartial: boolean;
|
|
633
|
+
index: number;
|
|
634
|
+
/** -1 when total is unknown (streaming without precount). */
|
|
635
|
+
total: number;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/** Canonical inbound LLM-emission wire shape per `spec/v1/ai-envelope.md`. */
|
|
639
|
+
export interface AIEnvelope<TPayload = unknown> {
|
|
640
|
+
/** Discriminator for payload shape, kind routing, and Envelope Contract gate. */
|
|
641
|
+
type: string;
|
|
642
|
+
/** Per-kind schema version. Absent → treat as 0. */
|
|
643
|
+
schemaVersion?: number;
|
|
644
|
+
/** Globally unique envelope id. Engine-assigned if absent on receipt. */
|
|
645
|
+
envelopeId: string;
|
|
646
|
+
/** Caller-stable id for dedup, replay short-circuit, and causal chaining. */
|
|
647
|
+
correlationId: string;
|
|
648
|
+
/** Set when the emitting node is identifiable. */
|
|
649
|
+
nodeId?: string;
|
|
650
|
+
/** Discriminated payload. Shape selected by `type`. */
|
|
651
|
+
payload: TPayload;
|
|
652
|
+
/** Wire metadata. */
|
|
653
|
+
meta: EnvelopeMeta;
|
|
654
|
+
/** Present when this is one fragment of a streamed emission. */
|
|
655
|
+
partial?: PartialInfo;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** Per-typeId envelope-kind permission set per `ai-envelope.md` §"Envelope Contract". */
|
|
659
|
+
export interface EnvelopeContract {
|
|
660
|
+
/** Kinds the engine will accept from this node. */
|
|
661
|
+
accepts: string[];
|
|
662
|
+
/** Refusal behavior for non-`accepts`, non-universal kinds. */
|
|
663
|
+
refusalMode: 'fail-node' | 'discard-and-warn';
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/** Returned by the engine's `acceptEnvelope` path. */
|
|
667
|
+
export type EnvelopeOutcome =
|
|
668
|
+
| { status: 'accepted'; recordedEventIds: string[] }
|
|
669
|
+
| { status: 'gated'; reason: string; gate: EnvelopeContractRefusal }
|
|
670
|
+
| { status: 'invalid'; reason: string; details: ValidationDetail[] }
|
|
671
|
+
| { status: 'breached'; reason: string; capKind: 'envelopes' | 'schema' | 'clarification' };
|
|
672
|
+
|
|
673
|
+
export interface EnvelopeContractRefusal {
|
|
674
|
+
refusedType: string;
|
|
675
|
+
acceptedTypes: string[];
|
|
676
|
+
refusalMode: 'fail-node' | 'discard-and-warn';
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
export interface ValidationDetail {
|
|
680
|
+
path: string;
|
|
681
|
+
message: string;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/** Optional capability advertisement. Default when absent: 'warn'. */
|
|
685
|
+
export type EnvelopeStrictness = 'warn' | 'strict';
|
|
686
|
+
|
|
687
|
+
/** Optional capability advertisement per `ai-envelope.md` §"Capability handshake integration". */
|
|
688
|
+
export interface EnvelopeContractsCapability {
|
|
689
|
+
advertised: boolean;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Universal-kind payloads. Per-kind schemas at `schemas/envelopes/<kind>.schema.json`.
|
|
693
|
+
|
|
694
|
+
/** Payload of the universal `clarification.request` envelope kind. */
|
|
695
|
+
export interface ClarificationRequestPayload {
|
|
696
|
+
questions: Array<{
|
|
697
|
+
id: string;
|
|
698
|
+
question: string;
|
|
699
|
+
schema?: Record<string, unknown>;
|
|
700
|
+
}>;
|
|
701
|
+
contextType?: string;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/** Payload of the universal `schema.request` envelope kind. */
|
|
705
|
+
export interface SchemaRequestPayload {
|
|
706
|
+
envelopeType: string;
|
|
707
|
+
reason?: string;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** Payload of the universal `schema.response` envelope kind (LLM ack). */
|
|
711
|
+
export interface SchemaResponsePayload {
|
|
712
|
+
envelopeType: string;
|
|
713
|
+
ack: true;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Payload of the universal `error` envelope kind (the LLM's deliberate error
|
|
718
|
+
* report). Distinct from `ErrorEnvelope` (the host's HTTP error response).
|
|
719
|
+
*/
|
|
720
|
+
export interface AIEnvelopeErrorPayload {
|
|
721
|
+
code: string;
|
|
722
|
+
message: string;
|
|
723
|
+
details?: Record<string, unknown>;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// ── RFC 0027 + RFC 0028 — Prompt library (spec/v1/prompts.md) ──
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Role a PromptTemplate plays when composed into an LLM call. Shared enum
|
|
730
|
+
* `$ref`-ed by every schema that names a prompt kind. Per
|
|
731
|
+
* `schemas/prompt-kind.schema.json`.
|
|
732
|
+
*/
|
|
733
|
+
export type PromptKind = 'system' | 'user' | 'few-shot' | 'schema-hint';
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Typed interpolation slot in a PromptTemplate. Bindings are validated
|
|
737
|
+
* against this declaration before composition. Per
|
|
738
|
+
* `schemas/prompt-template.schema.json#/$defs/PromptVariable`.
|
|
739
|
+
*/
|
|
740
|
+
export interface PromptVariable {
|
|
741
|
+
name: string;
|
|
742
|
+
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
743
|
+
required: boolean;
|
|
744
|
+
source?: 'input' | 'variable' | 'secret' | 'context';
|
|
745
|
+
extractPath?: string;
|
|
746
|
+
defaultValue?: unknown;
|
|
747
|
+
description?: string;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Named, versioned, variable-bound prompt body. Per
|
|
752
|
+
* `schemas/prompt-template.schema.json` + spec/v1/prompts.md §PromptTemplate.
|
|
753
|
+
*
|
|
754
|
+
* `meta.packName` + `meta.packVersion` are required when `meta.source: "pack"`
|
|
755
|
+
* (RFC 0028 §C); a JSON-Schema `if/then` conditional enforces this at the
|
|
756
|
+
* wire layer.
|
|
757
|
+
*/
|
|
758
|
+
export interface PromptTemplate {
|
|
759
|
+
templateId: string;
|
|
760
|
+
version: string;
|
|
761
|
+
kind: PromptKind;
|
|
762
|
+
text: string;
|
|
763
|
+
name?: string;
|
|
764
|
+
description?: string;
|
|
765
|
+
variables?: PromptVariable[];
|
|
766
|
+
modelHints?: {
|
|
767
|
+
modelClass?: string;
|
|
768
|
+
temperature?: number;
|
|
769
|
+
maxTokens?: number;
|
|
770
|
+
envelopeType?: string;
|
|
771
|
+
};
|
|
772
|
+
tags?: string[];
|
|
773
|
+
meta?: {
|
|
774
|
+
author?: string;
|
|
775
|
+
createdAt?: string;
|
|
776
|
+
updatedAt?: string;
|
|
777
|
+
source?: 'host' | 'pack' | 'user';
|
|
778
|
+
packName?: string;
|
|
779
|
+
packVersion?: string;
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Reference to a PromptTemplate. Two equivalent forms — the stringy URI
|
|
785
|
+
* `prompt:<templateId>[@<version>]` and the structured object — per
|
|
786
|
+
* `schemas/prompt-ref.schema.json`. The stringy form is canonical for
|
|
787
|
+
* inline use; the object form is canonical when `libraryId` disambiguation
|
|
788
|
+
* or per-reference `variableOverrides` are needed.
|
|
789
|
+
*/
|
|
790
|
+
export type PromptRef =
|
|
791
|
+
| string
|
|
792
|
+
| {
|
|
793
|
+
libraryId?: string;
|
|
794
|
+
templateId: string;
|
|
795
|
+
version?: string;
|
|
796
|
+
variableOverrides?: Record<string, unknown>;
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
/** Filter set for `client.prompts.list(...)` per RFC 0028 §A. */
|
|
800
|
+
export interface ListPromptsRequest {
|
|
801
|
+
kind?: PromptKind;
|
|
802
|
+
tag?: string;
|
|
803
|
+
modelClass?: string;
|
|
804
|
+
source?: 'host' | 'pack' | 'user';
|
|
805
|
+
cursor?: string;
|
|
806
|
+
limit?: number;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export interface ListPromptsResponse {
|
|
810
|
+
items: PromptTemplate[];
|
|
811
|
+
nextCursor?: string;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/** Identifier set for `client.prompts.get(...)` per RFC 0028 §A. */
|
|
815
|
+
export interface GetPromptRequest {
|
|
816
|
+
templateId: string;
|
|
817
|
+
/** Pin to a SemVer version. When omitted, returns the latest. */
|
|
818
|
+
version?: string;
|
|
819
|
+
/** Disambiguate when multiple installed packs ship the same templateId. */
|
|
820
|
+
libraryId?: string;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/** Request shape for `client.prompts.render(...)` per RFC 0028 §A. */
|
|
824
|
+
export interface RenderPromptRequest {
|
|
825
|
+
ref: PromptRef;
|
|
826
|
+
variables: Record<string, unknown>;
|
|
827
|
+
/**
|
|
828
|
+
* Aggregate trust marker for the supplied bindings; propagated through
|
|
829
|
+
* composition per RFC 0027 §E. Defaults to `trusted` when omitted.
|
|
830
|
+
*/
|
|
831
|
+
contentTrust?: 'trusted' | 'untrusted';
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/** Response shape for `client.prompts.render(...)`. The `hash` and
|
|
835
|
+
* `variableHashes` are always present; `composed` populates only under
|
|
836
|
+
* `capabilities.prompts.observability: "full"`. Same deterministic-hash
|
|
837
|
+
* invariant as `prompt.composed` events (RFC 0027 §F). */
|
|
838
|
+
export interface RenderPromptResponse {
|
|
839
|
+
hash: string;
|
|
840
|
+
refs: string[];
|
|
841
|
+
variableHashes: Record<string, string>;
|
|
842
|
+
composed?: string;
|
|
843
|
+
contentTrust?: 'trusted' | 'untrusted';
|
|
844
|
+
}
|
|
845
|
+
|
|
422
846
|
/**
|
|
423
847
|
* Thrown when the server returns a non-2xx response. Carries the original
|
|
424
848
|
* status, parsed error envelope (if available), the raw response text,
|