> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes. # Helper Functions & Utilities > Top-level convenience functions for creating contexts, server-side API tools, expression tools, environment variable expansion, security, and type inference. [context]: /docs/server-sdks/reference/typescript/agents/context-builder/context [contextbuilder]: /docs/server-sdks/reference/typescript/agents/context-builder [datamap]: /docs/server-sdks/reference/typescript/agents/data-map [ref-functionresult]: /docs/server-sdks/reference/typescript/agents/function-result [ref-pombuilder]: /docs/server-sdks/reference/typescript/agents/pom-builder [ref-skillregistry]: /docs/server-sdks/reference/typescript/agents/skill-registry [ref-skillbase-gettools]: /docs/server-sdks/reference/typescript/agents/skill-base/get-tools [ref-definetypedtool]: /docs/server-sdks/reference/typescript/agents/agent-base/define-typed-tool The SignalWire Server SDK exports helper functions and utilities at the top level for common tasks like creating standalone contexts, building server-side API tools, managing environment variable expansion, security, and type inference. All are imported directly from `@signalwire/sdk`. ```typescript {2-12} import { createSimpleContext, createSimpleApiTool, createExpressionTool, defineSkillTool, setAllowedEnvPrefixes, getAllowedEnvPrefixes, safeAssign, filterSensitiveHeaders, redactUrl, isServerlessMode, inferSchema, registerBuiltinSkills, } from '@signalwire/sdk'; ``` --- ## **createSimpleContext** ```typescript {1} createSimpleContext(name?: string): Context ``` Create a standalone [`Context`][context] object without needing a full [`ContextBuilder`][contextbuilder]. Useful for quick single-context agents. #### Parameters **`name`** `string` — default: default Context name. For single-context agents this is typically `"default"`. --- #### Returns [`Context`][context] -- A new Context object ready for adding steps. #### Example ```typescript {3} import { createSimpleContext } from '@signalwire/sdk'; const ctx = createSimpleContext(); ctx.addStep('greet', { task: 'Say hello to the caller.' }); ctx.addStep('help', { task: 'Ask how you can help today.' }); ``` --- ## **createSimpleApiTool** ```typescript {1} createSimpleApiTool(opts: { name: string; url: string; responseTemplate: string; parameters?: Record; method?: string; headers?: Record; body?: Record; errorKeys?: string[]; }): DataMap ``` Create a server-side API tool with minimal configuration. Returns a configured [`DataMap`][datamap] that executes an HTTP request on the SignalWire server without requiring a webhook endpoint. #### Parameters **`opts.name`** `string` — required The name for the SWAIG tool. --- **`opts.url`** `string` — required API endpoint URL. Supports `${args.paramName}` substitution for injecting parameter values (e.g., `"https://api.example.com/search?q=${args.query}"`). --- **`opts.responseTemplate`** `string` — required Template string for formatting the API response. Uses `${response.field}` syntax to reference fields from the API response JSON. --- **`opts.parameters`** `Record` Parameter definitions. Each key is a parameter name, and each value is an object with `type` (default `"string"`), `description`, and optionally `required`. --- **`opts.method`** `string` — default: GET HTTP method for the API call. --- **`opts.headers`** `Record` HTTP headers to include in the request. --- **`opts.body`** `Record` Request body for POST/PUT requests. --- **`opts.errorKeys`** `string[]` JSON keys whose presence in the response indicates an error. --- #### Returns [`DataMap`][datamap] -- A configured DataMap ready to be registered with an agent. #### Example ```typescript {3} import { AgentBase, createSimpleApiTool } from '@signalwire/sdk'; const weatherTool = createSimpleApiTool({ name: 'get_weather', url: 'https://api.weather.com/v1/current?key=API_KEY&q=${args.location}', responseTemplate: 'Weather in ${args.location}: ${response.current.condition.text}, ${response.current.temp_f}F', parameters: { location: { type: 'string', description: 'City name', required: true, }, }, }); const agent = new AgentBase({ name: 'weather-agent' }); weatherTool.registerWithAgent(agent); ``` > **Tip** > > For more complex API integrations with multiple webhooks, fallback outputs, or > array processing, use the [`DataMap`][datamap] > builder directly. --- ## **createExpressionTool** ```typescript {1} createExpressionTool(opts: { name: string; patterns: Record; parameters?: Record; }): DataMap ``` Create a pattern-matching tool that evaluates expressions locally on the SignalWire server without making any HTTP requests. Useful for command routing and conditional responses. #### Parameters **`opts.name`** `string` — required The name for the SWAIG tool. --- **`opts.patterns`** `Record` — required A record mapping test values to `[pattern, FunctionResult]` tuples. The key is a template string (e.g., `"${args.command}"`), and the pattern is a regex string matched against it. --- **`opts.parameters`** `Record` Parameter definitions, same format as `createSimpleApiTool`. --- #### Returns [`DataMap`][datamap] -- A configured DataMap with expression-based routing. #### Example ```typescript {3} import { AgentBase, FunctionResult, createExpressionTool } from '@signalwire/sdk'; const routingTool = createExpressionTool({ name: 'route_command', patterns: { '${args.command}': [ 'play.*', new FunctionResult('Starting playback.'), ], }, parameters: { command: { type: 'string', description: 'The command to route', required: true }, filename: { type: 'string', description: 'File to play' }, }, }); const agent = new AgentBase({ name: 'router' }); routingTool.registerWithAgent(agent); ``` > **Note** > > Since object keys must be unique, you cannot map multiple patterns against the same > test value using `createExpressionTool`. For that case, use the [`DataMap`][datamap] > builder and call `.expression()` multiple times. --- ## **defineSkillTool** ```typescript {1} defineSkillTool(toolDef: SkillToolDefinition): SkillToolDefinition ``` Build a tool entry for a skill's [`getTools()`][ref-skillbase-gettools] array with typed handler arguments. The `parameters` schema and `required` list are captured at compile time, so a required `string` property arrives in the handler as `args.query: string`, an `enum` narrows to its literal union, and optional properties are marked `?`. The skill-side counterpart to [`defineTypedTool()`][ref-definetypedtool]. The typing is an authoring convenience only. At runtime `args` is whatever the model extracted, so keep defensive checks on values that matter. The returned definition is an ordinary `SkillToolDefinition`, and the generated SWAIG output is identical to a hand-written entry. #### Parameters **`toolDef`** `SkillToolDefinition` — required The tool definition: `name`, `description`, `parameters`, optional `required`, and a `handler` whose `args` type is inferred from the schema. --- #### Returns `SkillToolDefinition` -- The same definition, ready to return from `getTools()`. #### Example ```typescript {9-23} import { SkillBase, defineSkillTool, FunctionResult, type SkillToolDefinition } from '@signalwire/sdk'; class FareSkill extends SkillBase { static override SKILL_NAME = 'fare'; static override SKILL_DESCRIPTION = 'Quote taxi fares.'; override getTools(): SkillToolDefinition[] { return [ defineSkillTool({ name: 'quote_fare', description: 'Quote a fare between two addresses', parameters: { pickup: { type: 'string', description: 'Pickup address' }, dropoff: { type: 'string', description: 'Drop-off address' }, }, required: ['pickup', 'dropoff'], handler: async (args) => { if (!args.pickup.trim() || !args.dropoff.trim()) { return new FunctionResult('Provide both addresses.'); } return new FunctionResult(`Estimated fare from ${args.pickup} to ${args.dropoff}: $32.`); }, }), ]; } } ``` --- ## **setAllowedEnvPrefixes** ```typescript {1} setAllowedEnvPrefixes(prefixes: string[]): void ``` Set the global allowed environment variable prefixes for `${ENV.*}` expansion in DataMap URLs, bodies, and outputs. Only environment variables whose names start with one of these prefixes will be expanded. The default prefixes are `['SIGNALWIRE_', 'SWML_', 'SW_']`. #### Parameters **`prefixes`** `string[]` — required Array of prefix strings to allow. Pass an empty array to allow all environment variables (escape hatch -- use with caution). --- #### Example ```typescript {4} import { setAllowedEnvPrefixes } from '@signalwire/sdk'; // Allow custom prefixes in addition to defaults setAllowedEnvPrefixes(['SIGNALWIRE_', 'SWML_', 'SW_', 'MY_APP_']); ``` --- ## **getAllowedEnvPrefixes** ```typescript {1} getAllowedEnvPrefixes(): string[] ``` Get a copy of the current global allowed environment variable prefixes. #### Returns `string[]` -- A copy of the current prefix list. #### Example ```typescript {3} import { getAllowedEnvPrefixes } from '@signalwire/sdk'; const prefixes = getAllowedEnvPrefixes(); console.log(prefixes); // ['SIGNALWIRE_', 'SWML_', 'SW_'] ``` --- ## **safeAssign** Copy properties from `source` to `target`, filtering out prototype-pollution keys (`__proto__`, `constructor`, `prototype`). Drop-in replacement for `Object.assign()` where `source` is untrusted. ## **Parameters** **`target`** `Record` — required The object to assign into. --- **`source`** `Record` — required The object to copy properties from. --- ## **Returns** The `target` object. ## **Example** ```typescript {4} import { safeAssign } from '@signalwire/sdk'; const target = { a: 1 }; safeAssign(target, { b: 2, __proto__: 'blocked' }); console.log(target); // { a: 1, b: 2 } ``` --- ## **filterSensitiveHeaders** Return a copy of `headers` with sensitive entries removed (`authorization`, `cookie`, `x-api-key`, `proxy-authorization`, `set-cookie`). ## **Parameters** **`headers`** `Record` — required Original header record. --- ## **Returns** `Record` -- A new record with sensitive headers removed. ## **Example** ```typescript {4} import { filterSensitiveHeaders } from '@signalwire/sdk'; const raw = { 'content-type': 'application/json', authorization: 'Bearer secret' }; const safe = filterSensitiveHeaders(raw); console.log(safe); // { 'content-type': 'application/json' } ``` --- ## **redactUrl** Redact credentials embedded in a URL. Replaces the password portion with `****`. ## **Parameters** **`url`** `string` — required The URL string to redact. --- ## **Returns** `string` -- The URL with the password replaced by `****`. ## **Example** ```typescript {3} import { redactUrl } from '@signalwire/sdk'; console.log(redactUrl('https://admin:secret@example.com/api')); // "https://admin:****@example.com/api" ``` --- ## **validateUrl** Validate that a URL is safe to fetch — rejects URLs whose hostname resolves to a private or reserved IP range (loopback, RFC1918, link-local, IPv6 private). Never throws; returns `false` on failure. ## **Parameters** **`url`** `string` — required The URL to validate. --- **`allowPrivate`** `boolean` — default: false When `true`, skip the private-IP check. --- ## **Returns** `Promise` -- `true` if the URL is safe to fetch, `false` otherwise. ## **Example** ```typescript {3} import { validateUrl } from '@signalwire/sdk'; const ok = await validateUrl('https://api.example.com/endpoint'); console.log(ok); // true const bad = await validateUrl('http://127.0.0.1:8080/admin'); console.log(bad); // false ``` --- ## **isServerlessMode** Return whether the SDK is running in a serverless environment — that is, when the detected execution mode is something other than `"server"` (e.g. a cloud function or edge runtime). ## **Returns** `boolean` -- `true` when running in a serverless environment, `false` otherwise. ## **Example** ```typescript {3} import { isServerlessMode } from '@signalwire/sdk'; if (isServerlessMode()) { console.log('Running in a serverless environment.'); } ``` --- ## **MAX\_SKILL\_INPUT\_LENGTH** Maximum allowed input length for skill handler arguments (characters). Value: `1000`. ## **Example** ```typescript {3} import { MAX_SKILL_INPUT_LENGTH } from '@signalwire/sdk'; console.log(MAX_SKILL_INPUT_LENGTH); // 1000 ``` --- ## **inferSchema** Infer a JSON Schema from a function's source code by parsing parameter names and default values. Used internally by `defineTypedTool()`. ## **Parameters** **`fn`** `Function` — required The function to analyze. --- ## **Returns** `InferredSchema | null` -- The inferred schema with `parameters`, `required`, `paramNames`, and `hasRawData` fields, or `null` if inference fails. ## **Example** ```typescript {3} import { inferSchema } from '@signalwire/sdk'; const schema = inferSchema((city: string, units = 'metric') => {}); console.log(schema?.parameters); // { city: { type: 'string' }, units: { type: 'string' } } console.log(schema?.required); // ['city'] ``` --- ## **parseFunctionParams** Parse function parameter names and default values from source code text. ## **Parameters** **`source`** `string` — required The function source code string (via `fn.toString()`). --- ## **Returns** `ParsedParam[]` -- Array of `{ name: string; defaultValue?: string }` objects. --- ## **createTypedHandlerWrapper** Create a wrapper function that unpacks a `Record` args dict into named positional parameters for a typed handler. ## **Parameters** **`fn`** `Function` — required The original typed handler function. --- **`paramNames`** `string[]` — required Ordered parameter names to extract from args. --- **`hasRawData`** `boolean` — required Whether the handler accepts a rawData parameter. --- ## **Returns** `SwaigHandler` -- A wrapped handler with the standard `(args, rawData)` signature. --- ## **PomSection** A single section in a Prompt Object Model, with a title, body, bullets, and nested subsections. Returned by [`PomBuilder.getSection()`][ref-pombuilder] and [`PomBuilder.findSection()`][ref-pombuilder]. ## **Properties** **`title`** `string | null` Section heading text, or `null` if untitled. --- **`body`** `string` Section body paragraph text. --- **`bullets`** `string[]` List of bullet point strings. --- **`subsections`** `PomSection[]` Nested child sections. --- **`numbered`** `boolean | null` Whether this section is numbered when rendered. --- **`numberedBullets`** `boolean` Whether bullet points are rendered as a numbered list. --- --- ## **registerBuiltinSkills** Register all 19 built-in skills with the global [`SkillRegistry`][ref-skillregistry]. Call this once at startup if you want to use `SkillRegistry.create('datetime')` style registration. ## **Parameters** None. ## **Returns** `void` ## **Example** ```typescript {3} import { registerBuiltinSkills, SkillRegistry } from '@signalwire/sdk'; registerBuiltinSkills(); const registry = SkillRegistry.getInstance(); console.log(registry.listRegistered()); // ['datetime', 'math', 'joke', ...] ``` > Top-level convenience functions for creating contexts, server-side API tools, expression tools, environment variable expansion, security, and type inference.