@openwop/openwop 1.3.0 → 1.5.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 +42 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +111 -3
- package/dist/client.js.map +1 -1
- package/dist/event-helpers.d.ts +24 -1
- package/dist/event-helpers.d.ts.map +1 -1
- package/dist/event-helpers.js +54 -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/types.d.ts +364 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +139 -4
- package/src/event-helpers.ts +99 -0
- package/src/index.ts +32 -0
- package/src/types.ts +399 -3
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,
|
|
@@ -57,6 +64,7 @@ import {
|
|
|
57
64
|
type OrgChartResponsibilityView,
|
|
58
65
|
type EvalSummary,
|
|
59
66
|
type ToolDescriptor,
|
|
67
|
+
type CompactToolDescriptor,
|
|
60
68
|
type AgentDeployment,
|
|
61
69
|
type AgentDeploymentTransition,
|
|
62
70
|
type CreateUserAgentRequest,
|
|
@@ -529,15 +537,40 @@ export class OpenwopClient {
|
|
|
529
537
|
}
|
|
530
538
|
},
|
|
531
539
|
|
|
540
|
+
/**
|
|
541
|
+
* RFC 0112 — list the `CompactToolDescriptor`s via `GET /v1/tools?view=compact`
|
|
542
|
+
* when the host advertises `capabilities.toolCatalog.compactView`. Unwraps the
|
|
543
|
+
* `{ tools: CompactToolDescriptor[] }` envelope. Returns `null` when the host
|
|
544
|
+
* doesn't advertise the catalog (the endpoint 404s).
|
|
545
|
+
*/
|
|
546
|
+
listCompact: async (): Promise<readonly CompactToolDescriptor[] | null> => {
|
|
547
|
+
try {
|
|
548
|
+
const res = await this.#request<{ tools?: readonly CompactToolDescriptor[] }>({
|
|
549
|
+
method: 'GET',
|
|
550
|
+
path: '/v1/tools?view=compact',
|
|
551
|
+
});
|
|
552
|
+
return res.tools ?? [];
|
|
553
|
+
} catch (err) {
|
|
554
|
+
if (err instanceof WopError && err.status === 404) return null;
|
|
555
|
+
throw err;
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
|
|
532
559
|
/**
|
|
533
560
|
* RFC 0078 §B — return one `ToolDescriptor` by its stable `toolId`. Returns
|
|
534
|
-
* `null` on 404 (no such tool, or the capability is unadvertised).
|
|
561
|
+
* `null` on 404 (no such tool, or the capability is unadvertised). Pass
|
|
562
|
+
* `{ view: 'compact' }` (RFC 0112) to receive the `CompactToolDescriptor`
|
|
563
|
+
* projection instead.
|
|
535
564
|
*/
|
|
536
|
-
get: async (
|
|
565
|
+
get: async (
|
|
566
|
+
toolId: string,
|
|
567
|
+
opts: { readonly view?: 'standard' | 'compact' } = {},
|
|
568
|
+
): Promise<ToolDescriptor | CompactToolDescriptor | null> => {
|
|
569
|
+
const query = opts.view === 'compact' ? '?view=compact' : '';
|
|
537
570
|
try {
|
|
538
|
-
return await this.#request<ToolDescriptor>({
|
|
571
|
+
return await this.#request<ToolDescriptor | CompactToolDescriptor>({
|
|
539
572
|
method: 'GET',
|
|
540
|
-
path: `/v1/tools/${encodeURIComponent(toolId)}`,
|
|
573
|
+
path: `/v1/tools/${encodeURIComponent(toolId)}${query}`,
|
|
541
574
|
});
|
|
542
575
|
} catch (err) {
|
|
543
576
|
if (err instanceof WopError && err.status === 404) return null;
|
|
@@ -837,6 +870,108 @@ export class OpenwopClient {
|
|
|
837
870
|
},
|
|
838
871
|
};
|
|
839
872
|
|
|
873
|
+
// ── RFC 0103 Localized content surface (gated on capabilities.content) ──
|
|
874
|
+
readonly content = {
|
|
875
|
+
/** `GET /v1/content/pages` — list page records. Returns `null` when the
|
|
876
|
+
* host doesn't advertise `capabilities.content` (501). */
|
|
877
|
+
listPages: async (): Promise<readonly LocalizedContentPage[] | null> => {
|
|
878
|
+
try {
|
|
879
|
+
return await this.#request<readonly LocalizedContentPage[]>({
|
|
880
|
+
method: 'GET',
|
|
881
|
+
path: '/v1/content/pages',
|
|
882
|
+
});
|
|
883
|
+
} catch (err) {
|
|
884
|
+
if (err instanceof WopError && err.status === 501) return null;
|
|
885
|
+
throw err;
|
|
886
|
+
}
|
|
887
|
+
},
|
|
888
|
+
|
|
889
|
+
/** `GET /v1/content/pages/{slug}` — the negotiated locale's resolved page +
|
|
890
|
+
* sections. `acceptLanguage` rides the `Accept-Language` header (the Stable
|
|
891
|
+
* `i18n.md` negotiation; no `?locale=`). Returns `null` on `404`
|
|
892
|
+
* (no such published page) or `501` (uncapable). */
|
|
893
|
+
getPage: async (
|
|
894
|
+
slug: string,
|
|
895
|
+
acceptLanguage?: string,
|
|
896
|
+
): Promise<LocalizedContentPageResponse | null> => {
|
|
897
|
+
try {
|
|
898
|
+
return await this.#request<LocalizedContentPageResponse>({
|
|
899
|
+
method: 'GET',
|
|
900
|
+
path: `/v1/content/pages/${encodeURIComponent(slug)}`,
|
|
901
|
+
...(acceptLanguage
|
|
902
|
+
? { headers: { 'Accept-Language': acceptLanguage } }
|
|
903
|
+
: {}),
|
|
904
|
+
});
|
|
905
|
+
} catch (err) {
|
|
906
|
+
if (err instanceof WopError && (err.status === 404 || err.status === 501))
|
|
907
|
+
return null;
|
|
908
|
+
throw err;
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
|
|
912
|
+
/** `POST /v1/content/pages` — create a page record (admin). Throws the
|
|
913
|
+
* typed `WopError` on `400`/`401`/`403`. */
|
|
914
|
+
createPage: (body: LocalizedContentPage): Promise<LocalizedContentPage> =>
|
|
915
|
+
this.#request<LocalizedContentPage>({
|
|
916
|
+
method: 'POST',
|
|
917
|
+
path: '/v1/content/pages',
|
|
918
|
+
body,
|
|
919
|
+
}),
|
|
920
|
+
|
|
921
|
+
/** `PUT /v1/content/pages/{pageId}/sections/{sectionId}` — upsert a
|
|
922
|
+
* section's field overlay for a locale (admin). */
|
|
923
|
+
putSection: (
|
|
924
|
+
pageId: string,
|
|
925
|
+
sectionId: string,
|
|
926
|
+
body: PutContentSectionRequest,
|
|
927
|
+
): Promise<LocalizedContentSection> =>
|
|
928
|
+
this.#request<LocalizedContentSection>({
|
|
929
|
+
method: 'PUT',
|
|
930
|
+
path: `/v1/content/pages/${encodeURIComponent(pageId)}/sections/${encodeURIComponent(sectionId)}`,
|
|
931
|
+
body,
|
|
932
|
+
}),
|
|
933
|
+
|
|
934
|
+
/** `GET /v1/content/settings` — language settings. Returns `null` when the
|
|
935
|
+
* host doesn't advertise `capabilities.content` (501). */
|
|
936
|
+
getSettings: async (): Promise<LocalizedContentLanguageSettings | null> => {
|
|
937
|
+
try {
|
|
938
|
+
return await this.#request<LocalizedContentLanguageSettings>({
|
|
939
|
+
method: 'GET',
|
|
940
|
+
path: '/v1/content/settings',
|
|
941
|
+
});
|
|
942
|
+
} catch (err) {
|
|
943
|
+
if (err instanceof WopError && err.status === 501) return null;
|
|
944
|
+
throw err;
|
|
945
|
+
}
|
|
946
|
+
},
|
|
947
|
+
|
|
948
|
+
/** `PUT /v1/content/settings` — replace language settings (admin). */
|
|
949
|
+
putSettings: (
|
|
950
|
+
body: LocalizedContentLanguageSettings,
|
|
951
|
+
): Promise<LocalizedContentLanguageSettings> =>
|
|
952
|
+
this.#request<LocalizedContentLanguageSettings>({
|
|
953
|
+
method: 'PUT',
|
|
954
|
+
path: '/v1/content/settings',
|
|
955
|
+
body,
|
|
956
|
+
}),
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
// ── RFC 0099 Trigger subscriptions (gated on capabilities.triggerBridge) ──
|
|
960
|
+
readonly triggerSubscriptions = {
|
|
961
|
+
/** `POST /v1/trigger-subscriptions` — register an external-event trigger.
|
|
962
|
+
* The `binding.secret*` is returned ONCE at creation (SR-1); persist it.
|
|
963
|
+
* Throws the typed `WopError` on `400`/`401`/`403`, or `501` when the host
|
|
964
|
+
* doesn't advertise the trigger-bridge ingestion surface. */
|
|
965
|
+
create: (
|
|
966
|
+
body: TriggerSubscriptionRegistration,
|
|
967
|
+
): Promise<CreateTriggerSubscriptionResponse> =>
|
|
968
|
+
this.#request<CreateTriggerSubscriptionResponse>({
|
|
969
|
+
method: 'POST',
|
|
970
|
+
path: '/v1/trigger-subscriptions',
|
|
971
|
+
body,
|
|
972
|
+
}),
|
|
973
|
+
};
|
|
974
|
+
|
|
840
975
|
// ── Agent workspace files (RFC 0059; gated on capabilities.workspace) ──
|
|
841
976
|
readonly workspace = {
|
|
842
977
|
/**
|
package/src/event-helpers.ts
CHANGED
|
@@ -39,6 +39,14 @@ import type {
|
|
|
39
39
|
OutputChunkPayload,
|
|
40
40
|
RunEventDoc,
|
|
41
41
|
TypedRunEvent,
|
|
42
|
+
VoiceSpeechStartPayload,
|
|
43
|
+
VoiceTranscriptPayload,
|
|
44
|
+
VoiceEndpointCandidatePayload,
|
|
45
|
+
VoiceTurnCommitPayload,
|
|
46
|
+
VoiceSynthesisChunkPayload,
|
|
47
|
+
VoiceBargeInPayload,
|
|
48
|
+
VoiceCancelledPayload,
|
|
49
|
+
ChannelPresencePayload,
|
|
42
50
|
} from './types.js';
|
|
43
51
|
|
|
44
52
|
// ─── Type guards ────────────────────────────────────────────────────────
|
|
@@ -160,6 +168,97 @@ export function isOutputChunk(
|
|
|
160
168
|
return typeof (ev.payload as Record<string, unknown>).isLast === 'boolean';
|
|
161
169
|
}
|
|
162
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
|
+
|
|
163
262
|
// ─── High-level subscription helper ─────────────────────────────────────
|
|
164
263
|
|
|
165
264
|
/** Returned by {@link subscribeToAgentReasoning}. Call to cancel the
|
package/src/index.ts
CHANGED
|
@@ -61,6 +61,16 @@ export type {
|
|
|
61
61
|
MemoryWrittenPayload,
|
|
62
62
|
// RFC 0094 §D — streaming output chunk (`output.chunk` / `ai.message.chunk`)
|
|
63
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,
|
|
64
74
|
// RFC 0027 + RFC 0028 — Prompt library (spec/v1/prompts.md)
|
|
65
75
|
GetPromptRequest,
|
|
66
76
|
ListPromptsRequest,
|
|
@@ -116,6 +126,14 @@ export {
|
|
|
116
126
|
isAgentDecided,
|
|
117
127
|
isMemoryWritten,
|
|
118
128
|
isOutputChunk,
|
|
129
|
+
isVoiceSpeechStart,
|
|
130
|
+
isVoiceTranscript,
|
|
131
|
+
isVoiceEndpointCandidate,
|
|
132
|
+
isVoiceTurnCommit,
|
|
133
|
+
isVoiceSynthesisChunk,
|
|
134
|
+
isVoiceBargeIn,
|
|
135
|
+
isVoiceCancelled,
|
|
136
|
+
isChannelPresence,
|
|
119
137
|
subscribeToAgentReasoning,
|
|
120
138
|
} from './event-helpers.js';
|
|
121
139
|
export type {
|
|
@@ -183,6 +201,9 @@ export type {
|
|
|
183
201
|
// AI Envelope types (DRAFT v1.x — spec/v1/ai-envelope.md). Inbound LLM-emission
|
|
184
202
|
// envelope, distinct from RunEventDoc (outbound) and ErrorEnvelope (host HTTP).
|
|
185
203
|
export type {
|
|
204
|
+
A2UISurfacePayload,
|
|
205
|
+
A2uiSurfaceDeltaFrame,
|
|
206
|
+
A2uiSurfacePatchOp,
|
|
186
207
|
AIEnvelope,
|
|
187
208
|
AIEnvelopeErrorPayload,
|
|
188
209
|
ClarificationRequestPayload,
|
|
@@ -196,6 +217,17 @@ export type {
|
|
|
196
217
|
SchemaRequestPayload,
|
|
197
218
|
SchemaResponsePayload,
|
|
198
219
|
ValidationDetail,
|
|
220
|
+
// RFC 0103 — localized content surface
|
|
221
|
+
LocalizedContentStatus,
|
|
222
|
+
LocalizedContentPage,
|
|
223
|
+
LocalizedContentSection,
|
|
224
|
+
LocalizedContentPageResponse,
|
|
225
|
+
LocalizedContentLanguageSettings,
|
|
226
|
+
PutContentSectionRequest,
|
|
227
|
+
// RFC 0099 — trigger subscription registration
|
|
228
|
+
TriggerSubscriptionRegistration,
|
|
229
|
+
TriggerSubscription,
|
|
230
|
+
CreateTriggerSubscriptionResponse,
|
|
199
231
|
} from './types.js';
|
|
200
232
|
|
|
201
233
|
// RFC 0030 §A `reasoning` field prompt-directive helper. Hosts that
|