@openwop/openwop 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +29 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +85 -0
- package/dist/client.js.map +1 -1
- package/dist/event-helpers.d.ts +31 -1
- package/dist/event-helpers.d.ts.map +1 -1
- package/dist/event-helpers.js +71 -0
- package/dist/event-helpers.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/run-helpers.d.ts +6 -6
- package/dist/run-helpers.d.ts.map +1 -1
- package/dist/run-helpers.js +9 -5
- package/dist/run-helpers.js.map +1 -1
- package/dist/types.d.ts +351 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +6 -3
- package/src/client.ts +109 -0
- package/src/event-helpers.ts +116 -0
- package/src/index.ts +33 -0
- package/src/run-helpers.ts +9 -5
- package/src/types.ts +393 -4
package/src/client.ts
CHANGED
|
@@ -12,6 +12,13 @@ import { streamEvents, type EventsStreamOptions } from './sse.js';
|
|
|
12
12
|
import {
|
|
13
13
|
WopError,
|
|
14
14
|
type AuditVerifyResult,
|
|
15
|
+
type CreateTriggerSubscriptionResponse,
|
|
16
|
+
type LocalizedContentLanguageSettings,
|
|
17
|
+
type LocalizedContentPage,
|
|
18
|
+
type LocalizedContentPageResponse,
|
|
19
|
+
type LocalizedContentSection,
|
|
20
|
+
type PutContentSectionRequest,
|
|
21
|
+
type TriggerSubscriptionRegistration,
|
|
15
22
|
type BulkCancelRunsRequest,
|
|
16
23
|
type BulkCancelRunsResponse,
|
|
17
24
|
type Capabilities,
|
|
@@ -837,6 +844,108 @@ export class OpenwopClient {
|
|
|
837
844
|
},
|
|
838
845
|
};
|
|
839
846
|
|
|
847
|
+
// ── RFC 0103 Localized content surface (gated on capabilities.content) ──
|
|
848
|
+
readonly content = {
|
|
849
|
+
/** `GET /v1/content/pages` — list page records. Returns `null` when the
|
|
850
|
+
* host doesn't advertise `capabilities.content` (501). */
|
|
851
|
+
listPages: async (): Promise<readonly LocalizedContentPage[] | null> => {
|
|
852
|
+
try {
|
|
853
|
+
return await this.#request<readonly LocalizedContentPage[]>({
|
|
854
|
+
method: 'GET',
|
|
855
|
+
path: '/v1/content/pages',
|
|
856
|
+
});
|
|
857
|
+
} catch (err) {
|
|
858
|
+
if (err instanceof WopError && err.status === 501) return null;
|
|
859
|
+
throw err;
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
|
|
863
|
+
/** `GET /v1/content/pages/{slug}` — the negotiated locale's resolved page +
|
|
864
|
+
* sections. `acceptLanguage` rides the `Accept-Language` header (the Stable
|
|
865
|
+
* `i18n.md` negotiation; no `?locale=`). Returns `null` on `404`
|
|
866
|
+
* (no such published page) or `501` (uncapable). */
|
|
867
|
+
getPage: async (
|
|
868
|
+
slug: string,
|
|
869
|
+
acceptLanguage?: string,
|
|
870
|
+
): Promise<LocalizedContentPageResponse | null> => {
|
|
871
|
+
try {
|
|
872
|
+
return await this.#request<LocalizedContentPageResponse>({
|
|
873
|
+
method: 'GET',
|
|
874
|
+
path: `/v1/content/pages/${encodeURIComponent(slug)}`,
|
|
875
|
+
...(acceptLanguage
|
|
876
|
+
? { headers: { 'Accept-Language': acceptLanguage } }
|
|
877
|
+
: {}),
|
|
878
|
+
});
|
|
879
|
+
} catch (err) {
|
|
880
|
+
if (err instanceof WopError && (err.status === 404 || err.status === 501))
|
|
881
|
+
return null;
|
|
882
|
+
throw err;
|
|
883
|
+
}
|
|
884
|
+
},
|
|
885
|
+
|
|
886
|
+
/** `POST /v1/content/pages` — create a page record (admin). Throws the
|
|
887
|
+
* typed `WopError` on `400`/`401`/`403`. */
|
|
888
|
+
createPage: (body: LocalizedContentPage): Promise<LocalizedContentPage> =>
|
|
889
|
+
this.#request<LocalizedContentPage>({
|
|
890
|
+
method: 'POST',
|
|
891
|
+
path: '/v1/content/pages',
|
|
892
|
+
body,
|
|
893
|
+
}),
|
|
894
|
+
|
|
895
|
+
/** `PUT /v1/content/pages/{pageId}/sections/{sectionId}` — upsert a
|
|
896
|
+
* section's field overlay for a locale (admin). */
|
|
897
|
+
putSection: (
|
|
898
|
+
pageId: string,
|
|
899
|
+
sectionId: string,
|
|
900
|
+
body: PutContentSectionRequest,
|
|
901
|
+
): Promise<LocalizedContentSection> =>
|
|
902
|
+
this.#request<LocalizedContentSection>({
|
|
903
|
+
method: 'PUT',
|
|
904
|
+
path: `/v1/content/pages/${encodeURIComponent(pageId)}/sections/${encodeURIComponent(sectionId)}`,
|
|
905
|
+
body,
|
|
906
|
+
}),
|
|
907
|
+
|
|
908
|
+
/** `GET /v1/content/settings` — language settings. Returns `null` when the
|
|
909
|
+
* host doesn't advertise `capabilities.content` (501). */
|
|
910
|
+
getSettings: async (): Promise<LocalizedContentLanguageSettings | null> => {
|
|
911
|
+
try {
|
|
912
|
+
return await this.#request<LocalizedContentLanguageSettings>({
|
|
913
|
+
method: 'GET',
|
|
914
|
+
path: '/v1/content/settings',
|
|
915
|
+
});
|
|
916
|
+
} catch (err) {
|
|
917
|
+
if (err instanceof WopError && err.status === 501) return null;
|
|
918
|
+
throw err;
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
|
|
922
|
+
/** `PUT /v1/content/settings` — replace language settings (admin). */
|
|
923
|
+
putSettings: (
|
|
924
|
+
body: LocalizedContentLanguageSettings,
|
|
925
|
+
): Promise<LocalizedContentLanguageSettings> =>
|
|
926
|
+
this.#request<LocalizedContentLanguageSettings>({
|
|
927
|
+
method: 'PUT',
|
|
928
|
+
path: '/v1/content/settings',
|
|
929
|
+
body,
|
|
930
|
+
}),
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
// ── RFC 0099 Trigger subscriptions (gated on capabilities.triggerBridge) ──
|
|
934
|
+
readonly triggerSubscriptions = {
|
|
935
|
+
/** `POST /v1/trigger-subscriptions` — register an external-event trigger.
|
|
936
|
+
* The `binding.secret*` is returned ONCE at creation (SR-1); persist it.
|
|
937
|
+
* Throws the typed `WopError` on `400`/`401`/`403`, or `501` when the host
|
|
938
|
+
* doesn't advertise the trigger-bridge ingestion surface. */
|
|
939
|
+
create: (
|
|
940
|
+
body: TriggerSubscriptionRegistration,
|
|
941
|
+
): Promise<CreateTriggerSubscriptionResponse> =>
|
|
942
|
+
this.#request<CreateTriggerSubscriptionResponse>({
|
|
943
|
+
method: 'POST',
|
|
944
|
+
path: '/v1/trigger-subscriptions',
|
|
945
|
+
body,
|
|
946
|
+
}),
|
|
947
|
+
};
|
|
948
|
+
|
|
840
949
|
// ── Agent workspace files (RFC 0059; gated on capabilities.workspace) ──
|
|
841
950
|
readonly workspace = {
|
|
842
951
|
/**
|
package/src/event-helpers.ts
CHANGED
|
@@ -36,8 +36,17 @@ import type {
|
|
|
36
36
|
AgentToolCalledPayload,
|
|
37
37
|
AgentToolReturnedPayload,
|
|
38
38
|
MemoryWrittenPayload,
|
|
39
|
+
OutputChunkPayload,
|
|
39
40
|
RunEventDoc,
|
|
40
41
|
TypedRunEvent,
|
|
42
|
+
VoiceSpeechStartPayload,
|
|
43
|
+
VoiceTranscriptPayload,
|
|
44
|
+
VoiceEndpointCandidatePayload,
|
|
45
|
+
VoiceTurnCommitPayload,
|
|
46
|
+
VoiceSynthesisChunkPayload,
|
|
47
|
+
VoiceBargeInPayload,
|
|
48
|
+
VoiceCancelledPayload,
|
|
49
|
+
ChannelPresencePayload,
|
|
41
50
|
} from './types.js';
|
|
42
51
|
|
|
43
52
|
// ─── Type guards ────────────────────────────────────────────────────────
|
|
@@ -143,6 +152,113 @@ export function isMemoryWritten(
|
|
|
143
152
|
);
|
|
144
153
|
}
|
|
145
154
|
|
|
155
|
+
/** `output.chunk` / `ai.message.chunk` (RFC 0094 §D). Accepts both
|
|
156
|
+
* discriminators — `output.chunk` is the persisted run-event type;
|
|
157
|
+
* `ai.message.chunk` is the stream-mode `messages` SSE event name
|
|
158
|
+
* carrying the same payload per `stream-modes.md §messages`. Narrows
|
|
159
|
+
* when the payload carries the required `nodeId` + `runId` + `chunk`
|
|
160
|
+
* strings AND the boolean `isLast`. */
|
|
161
|
+
export function isOutputChunk(
|
|
162
|
+
ev: RunEventDoc,
|
|
163
|
+
): ev is TypedRunEvent<OutputChunkPayload> {
|
|
164
|
+
if (ev.type !== 'output.chunk' && ev.type !== 'ai.message.chunk') return false;
|
|
165
|
+
if (!hasStringField(ev.payload, 'nodeId')) return false;
|
|
166
|
+
if (!hasStringField(ev.payload, 'runId')) return false;
|
|
167
|
+
if (!hasStringField(ev.payload, 'chunk')) return false;
|
|
168
|
+
return typeof (ev.payload as Record<string, unknown>).isLast === 'boolean';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function hasNumberField(payload: unknown, field: string): boolean {
|
|
172
|
+
return (
|
|
173
|
+
payload !== null &&
|
|
174
|
+
typeof payload === 'object' &&
|
|
175
|
+
typeof (payload as Record<string, unknown>)[field] === 'number'
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** `voice.speech_start` (RFC 0106). */
|
|
180
|
+
export function isVoiceSpeechStart(
|
|
181
|
+
ev: RunEventDoc,
|
|
182
|
+
): ev is TypedRunEvent<VoiceSpeechStartPayload> {
|
|
183
|
+
return ev.type === 'voice.speech_start' && hasNumberField(ev.payload, 'atMs');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** `voice.transcript` (RFC 0106). Narrows when `type` matches AND payload
|
|
187
|
+
* carries the required `text` + `isFinal` + `atMs` + `contentTrust`. The
|
|
188
|
+
* transcript is untrusted ingress (`voice-transcript-untrusted`). */
|
|
189
|
+
export function isVoiceTranscript(
|
|
190
|
+
ev: RunEventDoc,
|
|
191
|
+
): ev is TypedRunEvent<VoiceTranscriptPayload> {
|
|
192
|
+
return (
|
|
193
|
+
ev.type === 'voice.transcript' &&
|
|
194
|
+
hasStringField(ev.payload, 'text') &&
|
|
195
|
+
typeof (ev.payload as Record<string, unknown>).isFinal === 'boolean' &&
|
|
196
|
+
hasNumberField(ev.payload, 'atMs') &&
|
|
197
|
+
(ev.payload as Record<string, unknown>).contentTrust === 'untrusted'
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** `voice.endpoint_candidate` (RFC 0106). */
|
|
202
|
+
export function isVoiceEndpointCandidate(
|
|
203
|
+
ev: RunEventDoc,
|
|
204
|
+
): ev is TypedRunEvent<VoiceEndpointCandidatePayload> {
|
|
205
|
+
return (
|
|
206
|
+
ev.type === 'voice.endpoint_candidate' && hasNumberField(ev.payload, 'atMs')
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** `voice.turn_commit` (RFC 0106). Narrows when payload carries the required
|
|
211
|
+
* `atMs` + `finalText` (the settled transcript). */
|
|
212
|
+
export function isVoiceTurnCommit(
|
|
213
|
+
ev: RunEventDoc,
|
|
214
|
+
): ev is TypedRunEvent<VoiceTurnCommitPayload> {
|
|
215
|
+
return (
|
|
216
|
+
ev.type === 'voice.turn_commit' &&
|
|
217
|
+
hasNumberField(ev.payload, 'atMs') &&
|
|
218
|
+
hasStringField(ev.payload, 'finalText')
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** `voice.synthesis_chunk` (RFC 0106). Narrows when payload carries the
|
|
223
|
+
* required `seq` (number) + `mimeType` (string). */
|
|
224
|
+
export function isVoiceSynthesisChunk(
|
|
225
|
+
ev: RunEventDoc,
|
|
226
|
+
): ev is TypedRunEvent<VoiceSynthesisChunkPayload> {
|
|
227
|
+
return (
|
|
228
|
+
ev.type === 'voice.synthesis_chunk' &&
|
|
229
|
+
hasNumberField(ev.payload, 'seq') &&
|
|
230
|
+
hasStringField(ev.payload, 'mimeType')
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** `voice.barge_in` (RFC 0106). */
|
|
235
|
+
export function isVoiceBargeIn(
|
|
236
|
+
ev: RunEventDoc,
|
|
237
|
+
): ev is TypedRunEvent<VoiceBargeInPayload> {
|
|
238
|
+
return ev.type === 'voice.barge_in' && hasNumberField(ev.payload, 'atMs');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** `voice.cancelled` (RFC 0106). */
|
|
242
|
+
export function isVoiceCancelled(
|
|
243
|
+
ev: RunEventDoc,
|
|
244
|
+
): ev is TypedRunEvent<VoiceCancelledPayload> {
|
|
245
|
+
return ev.type === 'voice.cancelled' && hasNumberField(ev.payload, 'atMs');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** `channel.presence` (RFC 0110). EPHEMERAL — observable on the LIVE event
|
|
249
|
+
* stream only; ABSENT on replay / `:fork` (the host never persists presence
|
|
250
|
+
* to the replayable log). Narrows when payload carries `conversationId` +
|
|
251
|
+
* a `present` array. */
|
|
252
|
+
export function isChannelPresence(
|
|
253
|
+
ev: RunEventDoc,
|
|
254
|
+
): ev is TypedRunEvent<ChannelPresencePayload> {
|
|
255
|
+
return (
|
|
256
|
+
ev.type === 'channel.presence' &&
|
|
257
|
+
hasStringField(ev.payload, 'conversationId') &&
|
|
258
|
+
Array.isArray((ev.payload as Record<string, unknown>).present)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
146
262
|
// ─── High-level subscription helper ─────────────────────────────────────
|
|
147
263
|
|
|
148
264
|
/** Returned by {@link subscribeToAgentReasoning}. Call to cancel the
|
package/src/index.ts
CHANGED
|
@@ -59,6 +59,18 @@ export type {
|
|
|
59
59
|
AgentHandoffPayload,
|
|
60
60
|
AgentDecidedPayload,
|
|
61
61
|
MemoryWrittenPayload,
|
|
62
|
+
// RFC 0094 §D — streaming output chunk (`output.chunk` / `ai.message.chunk`)
|
|
63
|
+
OutputChunkPayload,
|
|
64
|
+
// RFC 0106 — voice.* run-event payloads
|
|
65
|
+
VoiceSpeechStartPayload,
|
|
66
|
+
VoiceTranscriptPayload,
|
|
67
|
+
VoiceEndpointCandidatePayload,
|
|
68
|
+
VoiceTurnCommitPayload,
|
|
69
|
+
VoiceSynthesisChunkPayload,
|
|
70
|
+
VoiceBargeInPayload,
|
|
71
|
+
VoiceCancelledPayload,
|
|
72
|
+
// RFC 0110 — channel.presence run-event payload
|
|
73
|
+
ChannelPresencePayload,
|
|
62
74
|
// RFC 0027 + RFC 0028 — Prompt library (spec/v1/prompts.md)
|
|
63
75
|
GetPromptRequest,
|
|
64
76
|
ListPromptsRequest,
|
|
@@ -113,6 +125,15 @@ export {
|
|
|
113
125
|
isAgentHandoff,
|
|
114
126
|
isAgentDecided,
|
|
115
127
|
isMemoryWritten,
|
|
128
|
+
isOutputChunk,
|
|
129
|
+
isVoiceSpeechStart,
|
|
130
|
+
isVoiceTranscript,
|
|
131
|
+
isVoiceEndpointCandidate,
|
|
132
|
+
isVoiceTurnCommit,
|
|
133
|
+
isVoiceSynthesisChunk,
|
|
134
|
+
isVoiceBargeIn,
|
|
135
|
+
isVoiceCancelled,
|
|
136
|
+
isChannelPresence,
|
|
116
137
|
subscribeToAgentReasoning,
|
|
117
138
|
} from './event-helpers.js';
|
|
118
139
|
export type {
|
|
@@ -180,6 +201,7 @@ export type {
|
|
|
180
201
|
// AI Envelope types (DRAFT v1.x — spec/v1/ai-envelope.md). Inbound LLM-emission
|
|
181
202
|
// envelope, distinct from RunEventDoc (outbound) and ErrorEnvelope (host HTTP).
|
|
182
203
|
export type {
|
|
204
|
+
A2UISurfacePayload,
|
|
183
205
|
AIEnvelope,
|
|
184
206
|
AIEnvelopeErrorPayload,
|
|
185
207
|
ClarificationRequestPayload,
|
|
@@ -193,6 +215,17 @@ export type {
|
|
|
193
215
|
SchemaRequestPayload,
|
|
194
216
|
SchemaResponsePayload,
|
|
195
217
|
ValidationDetail,
|
|
218
|
+
// RFC 0103 — localized content surface
|
|
219
|
+
LocalizedContentStatus,
|
|
220
|
+
LocalizedContentPage,
|
|
221
|
+
LocalizedContentSection,
|
|
222
|
+
LocalizedContentPageResponse,
|
|
223
|
+
LocalizedContentLanguageSettings,
|
|
224
|
+
PutContentSectionRequest,
|
|
225
|
+
// RFC 0099 — trigger subscription registration
|
|
226
|
+
TriggerSubscriptionRegistration,
|
|
227
|
+
TriggerSubscription,
|
|
228
|
+
CreateTriggerSubscriptionResponse,
|
|
196
229
|
} from './types.js';
|
|
197
230
|
|
|
198
231
|
// RFC 0030 §A `reasoning` field prompt-directive helper. Hosts that
|
package/src/run-helpers.ts
CHANGED
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
* the small known-non-terminal set is treated as terminal. This keeps
|
|
19
19
|
* the helper correct against:
|
|
20
20
|
*
|
|
21
|
-
* - the canonical
|
|
22
|
-
* / `waiting-approval` / `waiting-input` / `
|
|
23
|
-
* `cancelled`)
|
|
24
|
-
* - host extensions like `'planned'`, `'executing'`, `'
|
|
25
|
-
* `'
|
|
21
|
+
* - the canonical 10-member spec union (`pending` / `running` / `paused`
|
|
22
|
+
* / `waiting-approval` / `waiting-input` / `waiting-external` /
|
|
23
|
+
* `completed` / `failed` / `cancelling` / `cancelled`)
|
|
24
|
+
* - host extensions like `'planned'`, `'executing'`, `'timed-out'`,
|
|
25
|
+
* `'interrupted'` which the OpenWOP engine emits
|
|
26
26
|
* - any future spec additions before the SDK ships an updated minor
|
|
27
27
|
*
|
|
28
28
|
* @module @openwop/openwop/run-helpers
|
|
@@ -44,6 +44,10 @@ export const ACTIVE_RUN_STATUSES = [
|
|
|
44
44
|
'paused',
|
|
45
45
|
'waiting-approval',
|
|
46
46
|
'waiting-input',
|
|
47
|
+
'waiting-external',
|
|
48
|
+
// RFC 0094 §B — transitional state during the cancel cascade; the run
|
|
49
|
+
// WILL still transition (to terminal `cancelled`), so it is active.
|
|
50
|
+
'cancelling',
|
|
47
51
|
] as const;
|
|
48
52
|
|
|
49
53
|
/**
|