@voicelayer/sdk 0.4.2 → 0.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/README.md +27 -0
- package/dist/brain/index.d.ts +5 -49
- package/dist/brain/index.js +78 -5
- package/dist/index.d.ts +423 -1003
- package/dist/index.js +1485 -286
- package/dist/runtime/text-session.d.ts +2 -1
- package/dist/runtime/text-session.js +1180 -180
- package/dist/{text-session-CtXihRr6.d.ts → text-session-Bf4Jni7H.d.ts} +1136 -102
- package/dist/types-KqrAfY85.d.ts +47 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -333,6 +333,33 @@ node agent.ts start
|
|
|
333
333
|
|
|
334
334
|
Agent names starting `voicelayer-` (and the names of VoiceLayer's own workers) are reserved; registering one is refused with `422 agent_name_reserved`.
|
|
335
335
|
|
|
336
|
+
### Outbound HTTP from your agent
|
|
337
|
+
|
|
338
|
+
`httpTool`, a flow's tool steps and schema tools, and a process's completion `backendAck` all go through the SDK's
|
|
339
|
+
outbound guard. They use http(s) only, and any private, loopback, link-local or cloud-metadata address is refused, both
|
|
340
|
+
after DNS and on every redirect (at most 5 hops). The connection goes only to the address that was checked, a request
|
|
341
|
+
times out (a `backendAck` waits at most 10 s), and responses are capped at 2 MiB.
|
|
342
|
+
|
|
343
|
+
If your self-hosted worker has to call a service on your own network, opt in per tool or per ACK:
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
httpTool({ name: 'inventory', description: '…', input: { sku: 'string' }, url: 'http://inventory.internal/{sku}', allowPrivateNetwork: true });
|
|
347
|
+
defineProcess({ collect: { … }, backendAck: { url: 'http://localhost:4000/ack', allowPrivateNetwork: true } });
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
`allowPrivateNetwork` only lifts the private-address refusal. The request is still http(s), still pinned to the checked
|
|
351
|
+
address and still never follows a redirect blindly.
|
|
352
|
+
|
|
353
|
+
On `httpTool` you set it in your own code, so it takes effect directly. On a `backendAck`, or on a tool in a stored
|
|
354
|
+
flow or process schema, it takes effect only when the worker's operator also sets **`VL_ALLOW_PRIVATE_NETWORK=1`** in
|
|
355
|
+
the worker's environment, because an author's flag alone shouldn't open your network. VoiceLayer-hosted workers (those
|
|
356
|
+
holding `INTERNAL_SERVICE_TOKEN`) and the VoiceLayer API's text engine never honour it, whatever the environment says.
|
|
357
|
+
Their tool steps run through the platform's server-side guard, which has no such switch.
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
export VL_ALLOW_PRIVATE_NETWORK=1 # self-hosted only: honour authors' allowPrivateNetwork on schema tools / backendAck
|
|
361
|
+
```
|
|
362
|
+
|
|
336
363
|
### Texts
|
|
337
364
|
|
|
338
365
|
`.start()` also registers a second LiveKit name, `<name>::text`, beside the voice one. A text message dispatched to it
|
package/dist/brain/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { O as OnQuery, B as BrainTransport, d as BrainMessage } from '../types-KqrAfY85.js';
|
|
2
|
+
export { a as BrainCallMetadata, b as BrainCapabilities, c as BrainChunk, e as BrainRequest, f as OnQueryContext, g as OnQueryResult } from '../types-KqrAfY85.js';
|
|
1
3
|
import { Redis } from 'ioredis';
|
|
2
4
|
import { z } from 'zod';
|
|
3
5
|
|
|
@@ -79,64 +81,18 @@ declare const ConnectorUpFrame: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
|
|
|
79
81
|
code: z.ZodEnum<["upstream_timeout", "upstream_error", "bad_response", "normalize_failed", "unreachable"]>;
|
|
80
82
|
message: z.ZodString;
|
|
81
83
|
}, "strip", z.ZodTypeAny, {
|
|
82
|
-
kind: "brain.error";
|
|
83
84
|
code: "upstream_timeout" | "upstream_error" | "bad_response" | "normalize_failed" | "unreachable";
|
|
84
85
|
message: string;
|
|
86
|
+
kind: "brain.error";
|
|
85
87
|
streamId: string;
|
|
86
88
|
}, {
|
|
87
|
-
kind: "brain.error";
|
|
88
89
|
code: "upstream_timeout" | "upstream_error" | "bad_response" | "normalize_failed" | "unreachable";
|
|
89
90
|
message: string;
|
|
91
|
+
kind: "brain.error";
|
|
90
92
|
streamId: string;
|
|
91
93
|
}>]>;
|
|
92
94
|
type ConnectorUpFrame = z.infer<typeof ConnectorUpFrame>;
|
|
93
95
|
|
|
94
|
-
interface BrainMessage {
|
|
95
|
-
readonly role: 'system' | 'user' | 'assistant';
|
|
96
|
-
readonly content: string;
|
|
97
|
-
}
|
|
98
|
-
interface BrainCallMetadata {
|
|
99
|
-
readonly channel: 'voice' | 'text';
|
|
100
|
-
readonly callId?: string;
|
|
101
|
-
readonly projectId?: string;
|
|
102
|
-
}
|
|
103
|
-
interface BrainRequest {
|
|
104
|
-
readonly messages: readonly BrainMessage[];
|
|
105
|
-
/** Upstream model id / alias. Omitted → the brain's own default. */
|
|
106
|
-
readonly model?: string;
|
|
107
|
-
readonly temperature?: number;
|
|
108
|
-
readonly metadata: BrainCallMetadata;
|
|
109
|
-
}
|
|
110
|
-
/** One streamed piece of the brain's reply. */
|
|
111
|
-
interface BrainChunk {
|
|
112
|
-
readonly content?: string;
|
|
113
|
-
}
|
|
114
|
-
interface BrainCapabilities {
|
|
115
|
-
readonly reachable: boolean;
|
|
116
|
-
readonly streaming: boolean;
|
|
117
|
-
}
|
|
118
|
-
interface BrainTransport {
|
|
119
|
-
readonly kind: 'callback' | 'http' | 'tunnel';
|
|
120
|
-
/** Stream the reply token-by-token (the voice path: first sentence → TTS ASAP). */
|
|
121
|
-
stream(req: BrainRequest, signal: AbortSignal): AsyncIterable<BrainChunk>;
|
|
122
|
-
/** Non-streaming convenience (the text path). */
|
|
123
|
-
complete(req: BrainRequest, signal: AbortSignal): Promise<string>;
|
|
124
|
-
}
|
|
125
|
-
/** Context handed to a customer's in-process `onQuery` brain. */
|
|
126
|
-
interface OnQueryContext {
|
|
127
|
-
/** Full conversation so far (system + prior turns + latest user message). */
|
|
128
|
-
readonly messages: readonly BrainMessage[];
|
|
129
|
-
/** Aborts when the caller barges in / the turn is cancelled. */
|
|
130
|
-
readonly signal: AbortSignal;
|
|
131
|
-
}
|
|
132
|
-
type OnQueryResult = string | AsyncIterable<string>;
|
|
133
|
-
/**
|
|
134
|
-
* Bring-your-own brain, in-process. Receives the latest user utterance (and the
|
|
135
|
-
* full history via `ctx.messages`) and returns the reply — either a string or an
|
|
136
|
-
* async-iterable of string pieces for token streaming.
|
|
137
|
-
*/
|
|
138
|
-
type OnQuery = (text: string, ctx: OnQueryContext) => OnQueryResult | Promise<OnQueryResult>;
|
|
139
|
-
|
|
140
96
|
declare function callbackTransport(onQuery: OnQuery): BrainTransport;
|
|
141
97
|
|
|
142
98
|
/** Convert a LK ChatContext (or any `{items}` shape) into BrainMessages. */
|
|
@@ -280,4 +236,4 @@ interface IncomingBrainRequest {
|
|
|
280
236
|
/** Run one brain.request and yield the reply frames. Never throws. */
|
|
281
237
|
declare function runBrainRequest(req: IncomingBrainRequest, cfg: BrainEndpointConfig, signal: AbortSignal): AsyncGenerator<ConnectorUpFrame>;
|
|
282
238
|
|
|
283
|
-
export { type AssertUrlOptions,
|
|
239
|
+
export { type AssertUrlOptions, BrainConfigError, type BrainEndpointConfig, BrainMessage, type BrainPubSub, BrainRequestError, BrainTransport, type ConnectorChatChunk, ConnectorChatModel, type ConnectorChatModelOptions, type ConnectorLLMOptions, type HostLookup, type HttpBrainTransportOptions, type IncomingBrainRequest, OnQuery, RedisBrainPubSub, type SseDelta, type TunnelBrainTransportOptions, assertPublicHttpsUrl, buildRedisBrainPubSub, callbackTransport, chatChunkStream, chatContextToMessages, createConnectorLLM, httpBrainTransport, isDisallowedIp, lastUserText, parseChatCompletionSse, runBrainRequest, tunnelBrainTransport };
|
package/dist/brain/index.js
CHANGED
|
@@ -599,7 +599,10 @@ var ProcessFieldDTO = z.object({
|
|
|
599
599
|
min: z.number().optional(),
|
|
600
600
|
max: z.number().optional(),
|
|
601
601
|
enum: z.array(z.string()).max(64).optional(),
|
|
602
|
-
ask: z.string().max(512).optional()
|
|
602
|
+
ask: z.string().max(512).optional(),
|
|
603
|
+
/** false ⇒ written by the agent itself (a tool's output, an assignment), never said by the caller — the runtime
|
|
604
|
+
* doesn't extract it from their words. Absent ⇒ the caller may say it. */
|
|
605
|
+
fromCaller: z.boolean().optional()
|
|
603
606
|
});
|
|
604
607
|
var ProcessTriggerDTO = z.object({
|
|
605
608
|
name: z.string().min(1).max(64),
|
|
@@ -618,7 +621,12 @@ var ProcessToolDTO = z.object({
|
|
|
618
621
|
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
619
622
|
headers: z.record(z.string().max(1024)).optional(),
|
|
620
623
|
auth: z.enum(["none", "connection"]),
|
|
621
|
-
connectionRef: z.string().max(128).optional()
|
|
624
|
+
connectionRef: z.string().max(128).optional(),
|
|
625
|
+
/**
|
|
626
|
+
* Self-hosted workers only: allow a private / loopback address (a localhost service of your own). A platform
|
|
627
|
+
* worker (it holds the internal service token) never honours it.
|
|
628
|
+
*/
|
|
629
|
+
allowPrivateNetwork: z.boolean().optional()
|
|
622
630
|
});
|
|
623
631
|
var ProcessSchemaDTO = z.object({
|
|
624
632
|
id: z.string().min(1).max(64),
|
|
@@ -632,7 +640,9 @@ var ProcessSchemaDTO = z.object({
|
|
|
632
640
|
requiredFields: z.array(z.string()).max(64),
|
|
633
641
|
backendAck: z.object({
|
|
634
642
|
url: z.string().url(),
|
|
635
|
-
timeoutMs: z.number().int().positive()
|
|
643
|
+
timeoutMs: z.number().int().positive(),
|
|
644
|
+
// self-hosted workers only (see ProcessToolDTO.allowPrivateNetwork); a platform worker never honours it
|
|
645
|
+
allowPrivateNetwork: z.boolean().optional()
|
|
636
646
|
}).optional()
|
|
637
647
|
}),
|
|
638
648
|
// Deterministic rails compiled from trigger/handoff/end nodes.
|
|
@@ -650,6 +660,9 @@ var ProcessSchemaDTO = z.object({
|
|
|
650
660
|
}).optional(),
|
|
651
661
|
// Tool capabilities compiled from tool nodes (maps to AgentConfig.tools).
|
|
652
662
|
tools: z.array(ProcessToolDTO).max(32).optional(),
|
|
663
|
+
// The agent's human name, sealed at deploy (G-31): what a caller hears for {{ agent_name }} and what the dashboard
|
|
664
|
+
// shows. Distinct from the agent's dispatch name (a slug). Absent on schemas deployed before it.
|
|
665
|
+
displayName: z.string().min(1).max(128).optional(),
|
|
653
666
|
// Voice turn-taking compiled from the flow's speech capability node (maps to
|
|
654
667
|
// AgentConfig.speech → applySpeechTurnHandling). Absent = platform defaults.
|
|
655
668
|
speech: z.object({
|
|
@@ -1878,6 +1891,43 @@ z.object({
|
|
|
1878
1891
|
perCallMaxCumulativeMs: z.number().int().min(1e3).default(3e5)
|
|
1879
1892
|
})
|
|
1880
1893
|
});
|
|
1894
|
+
|
|
1895
|
+
// ../contracts/src/dispatch-metadata.ts
|
|
1896
|
+
var IDENTITY_DISPATCH_METADATA_KEYS = [
|
|
1897
|
+
"projectId",
|
|
1898
|
+
"agentId",
|
|
1899
|
+
"sessionId",
|
|
1900
|
+
"callId",
|
|
1901
|
+
"phoneNumberId",
|
|
1902
|
+
"bindingId",
|
|
1903
|
+
"apiKeyId",
|
|
1904
|
+
"tenantId",
|
|
1905
|
+
// the SecurityPrimitive's identity for the call
|
|
1906
|
+
"moduleId",
|
|
1907
|
+
"toNumber",
|
|
1908
|
+
// fromNumber / toNumber / callerId: a warm transfer's caller ID (sdk handoff.ts ownDidFor)
|
|
1909
|
+
"fromNumber",
|
|
1910
|
+
"callerId"
|
|
1911
|
+
];
|
|
1912
|
+
var RESERVED_DISPATCH_METADATA_KEYS = [
|
|
1913
|
+
...IDENTITY_DISPATCH_METADATA_KEYS,
|
|
1914
|
+
"route",
|
|
1915
|
+
"direction",
|
|
1916
|
+
"carrier",
|
|
1917
|
+
"source",
|
|
1918
|
+
"mode",
|
|
1919
|
+
// mode + turnId would make a call's job run as a text turn
|
|
1920
|
+
"turnId",
|
|
1921
|
+
// set by the platform from its own inputs (the call's directive, the project's recording notice, AMD) — a caller's
|
|
1922
|
+
// copy in a metadata bag would speak a line, skip a disclosure or change answering-machine handling
|
|
1923
|
+
"initialDirective",
|
|
1924
|
+
"recordingAnnouncement",
|
|
1925
|
+
"amd"
|
|
1926
|
+
];
|
|
1927
|
+
new Set(RESERVED_DISPATCH_METADATA_KEYS);
|
|
1928
|
+
new Set(IDENTITY_DISPATCH_METADATA_KEYS);
|
|
1929
|
+
|
|
1930
|
+
// ../contracts/src/flow-validate.ts
|
|
1881
1931
|
var FlowIssueSeverity = z.enum(["error", "warning"]);
|
|
1882
1932
|
var FlowIssue = z.object({
|
|
1883
1933
|
code: z.string().max(64),
|
|
@@ -1970,6 +2020,25 @@ z.object({
|
|
|
1970
2020
|
amd: OutboundAmdMode.optional()
|
|
1971
2021
|
});
|
|
1972
2022
|
var ConnectionAuthType = z.enum(["oauth2", "api_key", "bearer", "basic", "none"]);
|
|
2023
|
+
var TRANSPORT_OWNED_HEADERS = /* @__PURE__ */ new Set([
|
|
2024
|
+
"host",
|
|
2025
|
+
"content-length",
|
|
2026
|
+
"transfer-encoding",
|
|
2027
|
+
"connection",
|
|
2028
|
+
"keep-alive",
|
|
2029
|
+
"upgrade",
|
|
2030
|
+
"te",
|
|
2031
|
+
"trailer",
|
|
2032
|
+
"expect",
|
|
2033
|
+
// the transport advertises only what it can decode
|
|
2034
|
+
"accept-encoding"
|
|
2035
|
+
]);
|
|
2036
|
+
function isTransportOwnedHeader(name) {
|
|
2037
|
+
const n = name.trim().toLowerCase();
|
|
2038
|
+
return TRANSPORT_OWNED_HEADERS.has(n) || n.startsWith("proxy-");
|
|
2039
|
+
}
|
|
2040
|
+
var PLATFORM_OWNED_HEADERS = { has: (n) => n === "content-type" || isTransportOwnedHeader(n) };
|
|
2041
|
+
z.string().trim().regex(/^[A-Za-z0-9!#$%&'*+.^_`|~-]{1,64}$/, "a header name: letters, digits and - only, up to 64").refine((n) => !PLATFORM_OWNED_HEADERS.has(n.toLowerCase()), "the platform sets this header itself");
|
|
1973
2042
|
var ConnectionStatus = z.enum(["active", "revoked", "error"]);
|
|
1974
2043
|
z.object({
|
|
1975
2044
|
v: z.number().int(),
|
|
@@ -2055,7 +2124,11 @@ z.object({
|
|
|
2055
2124
|
reauthRequired: z.boolean().optional()
|
|
2056
2125
|
});
|
|
2057
2126
|
var E164 = z.string().regex(/^\+[1-9]\d{6,14}$/, "must be E.164 (+15551234567)");
|
|
2058
|
-
var
|
|
2127
|
+
var PLATFORM_ROOM_NAMESPACES = ["text-", "vl-", "call-out-"];
|
|
2128
|
+
var RoomPrefix = z.string().regex(/^[a-z0-9][a-z0-9-]{0,30}[a-z0-9-]?$/, "lowercase letters, digits, dashes; max 32").refine(
|
|
2129
|
+
(v) => !PLATFORM_ROOM_NAMESPACES.some((ns) => v.startsWith(ns)),
|
|
2130
|
+
`must not start with a platform room namespace (${PLATFORM_ROOM_NAMESPACES.join(", ")})`
|
|
2131
|
+
);
|
|
2059
2132
|
var RecordingPrefix = z.string().min(1).max(128).refine((v) => !v.startsWith("/") && !v.includes(".."), "relative key prefix only");
|
|
2060
2133
|
var Cidr = z.string().regex(/^\d{1,3}(\.\d{1,3}){3}\/\d{1,2}$/, "must be IPv4 CIDR (a.b.c.d/nn)");
|
|
2061
2134
|
var TelephonySettings = z.object({
|
|
@@ -2356,7 +2429,7 @@ z.discriminatedUnion("kind", [
|
|
|
2356
2429
|
BrainRequestFrame,
|
|
2357
2430
|
BrainCancelFrame
|
|
2358
2431
|
]);
|
|
2359
|
-
var FLOW_BOOT_FAILURES = ["schema_fetch_failed", "no_process_schema", "missing_agent_id", "no_api_key"];
|
|
2432
|
+
var FLOW_BOOT_FAILURES = ["schema_fetch_failed", "no_process_schema", "missing_agent_id", "no_api_key", "worker_identity_refused"];
|
|
2360
2433
|
z.enum(
|
|
2361
2434
|
FLOW_BOOT_FAILURES.map((cause) => `flow_boot:${cause}`)
|
|
2362
2435
|
);
|