@openclaw/voice-call 2026.9.3 → 2026.9.5
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/assets/activity.svg +3 -0
- package/assets/icon.png +0 -0
- package/dist/{cli-D7qQRwUE.js → .setup/cli-z1onSLj4.mjs} +7 -7
- package/dist/{config-DQwvsxeV.js → .setup/config-72FnMWHb.mjs} +3 -3
- package/dist/{guarded-json-api-Z9SuGiD_.js → .setup/guarded-json-api-CuLkeTrl.mjs} +17 -39
- package/dist/{mock-C57qj18W.js → .setup/mock-CcYEAUhV.mjs} +1 -1
- package/dist/{plivo-qSdVTUcE.js → .setup/plivo-DWYNkAQ3.mjs} +2 -2
- package/dist/{realtime-handler-BSW48gqM.js → .setup/realtime-handler-CaoetLrM.mjs} +411 -144
- package/dist/{response-generator-IX26g0hi.js → .setup/response-generator-DB1nElLO.mjs} +2 -2
- package/dist/{runtime-entry-B8SNb2qD.js → .setup/runtime-entry-YWSSnAsH.mjs} +472 -302
- package/dist/{store-path-M0GXxUfv.js → .setup/store-path-B1j1up4_.mjs} +91 -55
- package/dist/{telnyx-B8shXuBM.js → .setup/telnyx-BY3ef4Cc.mjs} +1 -1
- package/dist/{twilio-DhsTO8-E.js → .setup/twilio-DWZ4HVmF.mjs} +9 -23
- package/dist/doctor-contract-api.js +15 -33
- package/dist/index.js +3 -3
- package/dist/runtime-entry.js +1 -1
- package/node_modules/typebox/build/compile/validator.d.mts +1 -1
- package/node_modules/typebox/build/compile/validator.mjs +1 -1
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +7 -5
- package/node_modules/typebox/build/format/iri.mjs +5 -1
- package/node_modules/typebox/build/guard/emit.mjs +2 -4
- package/node_modules/typebox/build/guard/guard.mjs +6 -18
- package/node_modules/typebox/build/guard/string.mjs +16 -24
- package/node_modules/typebox/build/schema/build.mjs +2 -2
- package/node_modules/typebox/build/schema/check.mjs +1 -1
- package/node_modules/typebox/build/schema/compile.d.mts +3 -2
- package/node_modules/typebox/build/schema/compile.mjs +8 -8
- package/node_modules/typebox/build/schema/engine/_context.d.mts +6 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +23 -15
- package/node_modules/typebox/build/schema/engine/_functions.d.mts +2 -2
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/_reducer.d.mts +3 -3
- package/node_modules/typebox/build/schema/engine/_refine.d.mts +5 -5
- package/node_modules/typebox/build/schema/engine/_refine.mjs +4 -7
- package/node_modules/typebox/build/schema/engine/_stack.d.mts +34 -16
- package/node_modules/typebox/build/schema/engine/_stack.mjs +148 -104
- package/node_modules/typebox/build/schema/engine/additionalItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +8 -8
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +26 -18
- package/node_modules/typebox/build/schema/engine/allOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/allOf.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/anyOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/anyOf.mjs +5 -10
- package/node_modules/typebox/build/schema/engine/boolean.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/boolean.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/const.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/const.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/contains.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/contains.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/dependencies.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +3 -6
- package/node_modules/typebox/build/schema/engine/dependentRequired.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dependentRequired.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/dependentSchemas.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +11 -7
- package/node_modules/typebox/build/schema/engine/enum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/enum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/exclusiveMaximum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/exclusiveMaximum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/exclusiveMinimum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/exclusiveMinimum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/format.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/format.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/if.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/if.mjs +7 -15
- package/node_modules/typebox/build/schema/engine/items.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/items.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/maxContains.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maxItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxItems.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maxLength.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxLength.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maxProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maxProperties.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/maximum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/maximum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minContains.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minContains.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minItems.d.mts +5 -5
- package/node_modules/typebox/build/schema/engine/minItems.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minLength.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minLength.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minProperties.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/minimum.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/minimum.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/multipleOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/multipleOf.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/not.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -8
- package/node_modules/typebox/build/schema/engine/oneOf.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +6 -11
- package/node_modules/typebox/build/schema/engine/pattern.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -7
- package/node_modules/typebox/build/schema/engine/patternProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/prefixItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/prefixItems.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/properties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/properties.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/propertyNames.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +4 -10
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +11 -7
- package/node_modules/typebox/build/schema/engine/ref.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/ref.mjs +19 -15
- package/node_modules/typebox/build/schema/engine/required.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/required.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/schema.d.mts +7 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +137 -133
- package/node_modules/typebox/build/schema/engine/type.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +2 -6
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +5 -9
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +5 -9
- package/node_modules/typebox/build/schema/engine/uniqueItems.d.mts +4 -4
- package/node_modules/typebox/build/schema/engine/uniqueItems.mjs +2 -6
- package/node_modules/typebox/build/schema/errors.d.mts +2 -2
- package/node_modules/typebox/build/schema/errors.mjs +8 -14
- package/node_modules/typebox/build/schema/intern/index.d.mts +1 -0
- package/node_modules/typebox/build/schema/intern/index.mjs +1 -0
- package/node_modules/typebox/build/schema/intern/intern.d.mts +11 -0
- package/node_modules/typebox/build/schema/intern/intern.mjs +293 -0
- package/node_modules/typebox/build/schema/meta/draft_2019_09.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_2019_09.mjs +288 -0
- package/node_modules/typebox/build/schema/meta/draft_2020_12.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_2020_12.mjs +300 -0
- package/node_modules/typebox/build/schema/meta/draft_3.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_3.mjs +143 -0
- package/node_modules/typebox/build/schema/meta/draft_4.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_4.mjs +149 -0
- package/node_modules/typebox/build/schema/meta/draft_6.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_6.mjs +155 -0
- package/node_modules/typebox/build/schema/meta/draft_7.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/draft_7.mjs +172 -0
- package/node_modules/typebox/build/schema/meta/index.d.mts +2 -0
- package/node_modules/typebox/build/schema/meta/index.mjs +2 -0
- package/node_modules/typebox/build/schema/meta/meta.d.mts +9 -0
- package/node_modules/typebox/build/schema/meta/meta.mjs +15 -0
- package/node_modules/typebox/build/schema/meta/schema.d.mts +6 -0
- package/node_modules/typebox/build/schema/meta/schema.mjs +1 -0
- package/node_modules/typebox/build/schema/parse.d.mts +1 -0
- package/node_modules/typebox/build/schema/parse.mjs +10 -5
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +8 -3
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +268 -139
- package/node_modules/typebox/build/schema/schema.d.mts +2 -0
- package/node_modules/typebox/build/schema/schema.mjs +2 -0
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -12
- package/node_modules/typebox/build/value/errors/errors.mjs +2 -7
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +59 -89
- package/node_modules/zod/README.md +27 -0
- package/node_modules/zod/compile.cjs +77 -0
- package/node_modules/zod/compile.d.cts +1 -0
- package/node_modules/zod/compile.d.ts +1 -0
- package/node_modules/zod/compile.js +52 -0
- package/node_modules/zod/index.cjs +2 -2
- package/node_modules/zod/index.d.cts +1 -2
- package/node_modules/zod/index.d.ts +1 -2
- package/node_modules/zod/index.js +5 -2
- package/node_modules/zod/package.json +13 -2
- package/node_modules/zod/src/compile.ts +56 -0
- package/node_modules/zod/src/index.ts +5 -2
- package/node_modules/zod/src/v3/ZodError.ts +22 -12
- package/node_modules/zod/src/v3/tests/error.test.ts +35 -0
- package/node_modules/zod/src/v3/tests/intersection.test.ts +18 -0
- package/node_modules/zod/src/v3/tests/language-server.test.ts +1 -2
- package/node_modules/zod/src/v3/tests/object.test.ts +3 -6
- package/node_modules/zod/src/v3/tests/readonly.test.ts +0 -80
- package/node_modules/zod/src/v3/tests/string.test.ts +6 -0
- package/node_modules/zod/src/v3/types.ts +5 -5
- package/node_modules/zod/src/v4/classic/checks.ts +1 -0
- package/node_modules/zod/src/v4/classic/compat.ts +26 -18
- package/node_modules/zod/src/v4/classic/deep-partial.ts +76 -0
- package/node_modules/zod/src/v4/classic/errors.ts +59 -44
- package/node_modules/zod/src/v4/classic/external.ts +12 -9
- package/node_modules/zod/src/v4/classic/from-json-schema.ts +140 -78
- package/node_modules/zod/src/v4/classic/in-out.ts +45 -0
- package/node_modules/zod/src/v4/classic/index.ts +2 -2
- package/node_modules/zod/src/v4/classic/iso.ts +2 -72
- package/node_modules/zod/src/v4/classic/parse.ts +10 -4
- package/node_modules/zod/src/v4/classic/schemas.ts +452 -262
- package/node_modules/zod/src/v4/classic/tests/apply.test.ts +27 -0
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +2 -2
- package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +135 -0
- package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +30 -1
- package/node_modules/zod/src/v4/classic/tests/catch.test.ts +278 -0
- package/node_modules/zod/src/v4/classic/tests/codec-examples.test.ts +1 -2
- package/node_modules/zod/src/v4/classic/tests/codec.test.ts +2 -1
- package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +2 -2
- package/node_modules/zod/src/v4/classic/tests/credit-card.test.ts +76 -0
- package/node_modules/zod/src/v4/classic/tests/cyclic-data.test.ts +720 -0
- package/node_modules/zod/src/v4/classic/tests/date.test.ts +30 -0
- package/node_modules/zod/src/v4/classic/tests/datetime.test.ts +32 -18
- package/node_modules/zod/src/v4/classic/tests/deep-partial.test.ts +380 -0
- package/node_modules/zod/src/v4/classic/tests/default-locale.test.ts +32 -0
- package/node_modules/zod/src/v4/classic/tests/default.test.ts +46 -0
- package/node_modules/zod/src/v4/classic/tests/detached-methods.test.ts +31 -7
- package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +155 -13
- package/node_modules/zod/src/v4/classic/tests/enum.test.ts +11 -0
- package/node_modules/zod/src/v4/classic/tests/error-utils.test.ts +112 -2
- package/node_modules/zod/src/v4/classic/tests/error.test.ts +274 -6
- package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +425 -10
- package/node_modules/zod/src/v4/classic/tests/function.test.ts +31 -0
- package/node_modules/zod/src/v4/classic/tests/global-config.test.ts +2 -9
- package/node_modules/zod/src/v4/classic/tests/hash.test.ts +1 -2
- package/node_modules/zod/src/v4/classic/tests/in-out.test.ts +159 -0
- package/node_modules/zod/src/v4/classic/tests/index.test.ts +21 -2
- package/node_modules/zod/src/v4/classic/tests/instance-footprint.test.ts +281 -0
- package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +47 -0
- package/node_modules/zod/src/v4/classic/tests/intersection.test.ts +136 -0
- package/node_modules/zod/src/v4/classic/tests/issue-schema.test.ts +183 -0
- package/node_modules/zod/src/v4/classic/tests/jitless-allows-eval.test.ts +3 -10
- package/node_modules/zod/src/v4/classic/tests/lazy.test.ts +36 -1
- package/node_modules/zod/src/v4/classic/tests/literal.test.ts +12 -1
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +12 -0
- package/node_modules/zod/src/v4/classic/tests/number.test.ts +46 -9
- package/node_modules/zod/src/v4/classic/tests/object.test.ts +245 -12
- package/node_modules/zod/src/v4/classic/tests/optin-ladder.test.ts +234 -0
- package/node_modules/zod/src/v4/classic/tests/optional.test.ts +49 -16
- package/node_modules/zod/src/v4/classic/tests/partial.test.ts +51 -4
- package/node_modules/zod/src/v4/classic/tests/preprocess-types.test.ts +20 -2
- package/node_modules/zod/src/v4/classic/tests/readonly.test.ts +0 -68
- package/node_modules/zod/src/v4/classic/tests/record.test.ts +186 -18
- package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +33 -2
- package/node_modules/zod/src/v4/classic/tests/redos.test.ts +68 -0
- package/node_modules/zod/src/v4/classic/tests/refine.test.ts +60 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +9 -0
- package/node_modules/zod/src/v4/classic/tests/string.test.ts +127 -5
- package/node_modules/zod/src/v4/classic/tests/stringbool.test.ts +18 -0
- package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +11 -2
- package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +1585 -173
- package/node_modules/zod/src/v4/classic/tests/tuple.test.ts +45 -30
- package/node_modules/zod/src/v4/classic/tests/union.test.ts +39 -2
- package/node_modules/zod/src/v4/classic/tests/validate.test.ts +76 -0
- package/node_modules/zod/src/v4/classic/tests/validations.test.ts +2 -2
- package/node_modules/zod/src/v4/core/api.ts +48 -12
- package/node_modules/zod/src/v4/core/checks.ts +57 -44
- package/node_modules/zod/src/v4/core/compile.ts +2188 -0
- package/node_modules/zod/src/v4/core/core.ts +98 -19
- package/node_modules/zod/src/v4/core/doc.ts +11 -7
- package/node_modules/zod/src/v4/core/errors.ts +115 -24
- package/node_modules/zod/src/v4/core/index.ts +3 -0
- package/node_modules/zod/src/v4/core/json-schema-generator.ts +6 -1
- package/node_modules/zod/src/v4/core/json-schema-processors.ts +257 -93
- package/node_modules/zod/src/v4/core/json-schema.ts +2 -1
- package/node_modules/zod/src/v4/core/memoizer.ts +284 -0
- package/node_modules/zod/src/v4/core/parse.ts +131 -38
- package/node_modules/zod/src/v4/core/regexes.ts +30 -13
- package/node_modules/zod/src/v4/core/registries.ts +2 -2
- package/node_modules/zod/src/v4/core/schemas.ts +759 -461
- package/node_modules/zod/src/v4/core/tests/compile-differential.test.ts +969 -0
- package/node_modules/zod/src/v4/core/tests/compile-global.test.ts +89 -0
- package/node_modules/zod/src/v4/core/tests/compile-off-by-default.test.ts +26 -0
- package/node_modules/zod/src/v4/core/tests/compile-stats.test.ts +34 -0
- package/node_modules/zod/src/v4/core/tests/compile.test.ts +1639 -0
- package/node_modules/zod/src/v4/core/tests/locales/el.test.ts +1 -2
- package/node_modules/zod/src/v4/core/tests/locales/es.test.ts +1 -2
- package/node_modules/zod/src/v4/core/tests/locales/fr.test.ts +3 -3
- package/node_modules/zod/src/v4/core/tests/locales/parity.test.ts +42 -0
- package/node_modules/zod/src/v4/core/tests/locales/tk.test.ts +69 -0
- package/node_modules/zod/src/v4/core/tests/treeshake.test.ts +51 -0
- package/node_modules/zod/src/v4/core/tests/url-no-canparse.test.ts +31 -0
- package/node_modules/zod/src/v4/core/to-json-schema.ts +275 -42
- package/node_modules/zod/src/v4/core/util.ts +268 -42
- package/node_modules/zod/src/v4/core/versions.ts +2 -2
- package/node_modules/zod/src/v4/core/visit.ts +193 -0
- package/node_modules/zod/src/v4/index.ts +3 -3
- package/node_modules/zod/src/v4/locales/ar.ts +3 -0
- package/node_modules/zod/src/v4/locales/az.ts +3 -0
- package/node_modules/zod/src/v4/locales/be.ts +10 -0
- package/node_modules/zod/src/v4/locales/bg.ts +3 -0
- package/node_modules/zod/src/v4/locales/bn.ts +121 -0
- package/node_modules/zod/src/v4/locales/ca.ts +3 -0
- package/node_modules/zod/src/v4/locales/ckb.ts +138 -0
- package/node_modules/zod/src/v4/locales/cs.ts +3 -0
- package/node_modules/zod/src/v4/locales/da.ts +5 -2
- package/node_modules/zod/src/v4/locales/de.ts +3 -0
- package/node_modules/zod/src/v4/locales/el.ts +1 -0
- package/node_modules/zod/src/v4/locales/en.ts +15 -4
- package/node_modules/zod/src/v4/locales/eo.ts +3 -0
- package/node_modules/zod/src/v4/locales/es.ts +2 -0
- package/node_modules/zod/src/v4/locales/fa.ts +3 -0
- package/node_modules/zod/src/v4/locales/fi.ts +3 -0
- package/node_modules/zod/src/v4/locales/fr-CA.ts +3 -0
- package/node_modules/zod/src/v4/locales/fr.ts +19 -14
- package/node_modules/zod/src/v4/locales/gu.ts +121 -0
- package/node_modules/zod/src/v4/locales/he.ts +6 -1
- package/node_modules/zod/src/v4/locales/hi.ts +124 -0
- package/node_modules/zod/src/v4/locales/hr.ts +2 -0
- package/node_modules/zod/src/v4/locales/hu.ts +3 -0
- package/node_modules/zod/src/v4/locales/hy.ts +9 -0
- package/node_modules/zod/src/v4/locales/id.ts +3 -0
- package/node_modules/zod/src/v4/locales/index.ts +10 -0
- package/node_modules/zod/src/v4/locales/is.ts +3 -0
- package/node_modules/zod/src/v4/locales/it.ts +3 -0
- package/node_modules/zod/src/v4/locales/ja.ts +3 -0
- package/node_modules/zod/src/v4/locales/ka.ts +3 -0
- package/node_modules/zod/src/v4/locales/km.ts +3 -0
- package/node_modules/zod/src/v4/locales/kn.ts +124 -0
- package/node_modules/zod/src/v4/locales/ko.ts +3 -0
- package/node_modules/zod/src/v4/locales/lt.ts +2 -0
- package/node_modules/zod/src/v4/locales/mk.ts +3 -0
- package/node_modules/zod/src/v4/locales/ms.ts +3 -0
- package/node_modules/zod/src/v4/locales/ne.ts +126 -0
- package/node_modules/zod/src/v4/locales/nl.ts +3 -0
- package/node_modules/zod/src/v4/locales/nn.ts +119 -0
- package/node_modules/zod/src/v4/locales/no.ts +5 -2
- package/node_modules/zod/src/v4/locales/ota.ts +3 -0
- package/node_modules/zod/src/v4/locales/pl.ts +3 -0
- package/node_modules/zod/src/v4/locales/ps.ts +3 -0
- package/node_modules/zod/src/v4/locales/pt-BR.ts +159 -0
- package/node_modules/zod/src/v4/locales/pt.ts +99 -58
- package/node_modules/zod/src/v4/locales/ro.ts +1 -0
- package/node_modules/zod/src/v4/locales/ru.ts +10 -0
- package/node_modules/zod/src/v4/locales/sk.ts +121 -0
- package/node_modules/zod/src/v4/locales/sl.ts +3 -0
- package/node_modules/zod/src/v4/locales/sv.ts +5 -2
- package/node_modules/zod/src/v4/locales/ta.ts +3 -0
- package/node_modules/zod/src/v4/locales/th.ts +3 -0
- package/node_modules/zod/src/v4/locales/tk.ts +111 -0
- package/node_modules/zod/src/v4/locales/tr.ts +3 -0
- package/node_modules/zod/src/v4/locales/uk.ts +3 -0
- package/node_modules/zod/src/v4/locales/ur.ts +3 -0
- package/node_modules/zod/src/v4/locales/uz.ts +1 -0
- package/node_modules/zod/src/v4/locales/vi.ts +3 -0
- package/node_modules/zod/src/v4/locales/yo.ts +3 -0
- package/node_modules/zod/src/v4/locales/zh-CN.ts +3 -0
- package/node_modules/zod/src/v4/locales/zh-TW.ts +3 -0
- package/node_modules/zod/src/v4/mini/checks.ts +1 -0
- package/node_modules/zod/src/v4/mini/deep-partial.ts +73 -0
- package/node_modules/zod/src/v4/mini/external.ts +10 -1
- package/node_modules/zod/src/v4/mini/in-out.ts +45 -0
- package/node_modules/zod/src/v4/mini/parse.ts +2 -0
- package/node_modules/zod/src/v4/mini/schemas.ts +135 -56
- package/node_modules/zod/src/v4/mini/tests/apply.test.ts +33 -0
- package/node_modules/zod/src/v4/mini/tests/assignability.test.ts +62 -1
- package/node_modules/zod/src/v4/mini/tests/checks.test.ts +14 -0
- package/node_modules/zod/src/v4/mini/tests/codec.test.ts +35 -1
- package/node_modules/zod/src/v4/mini/tests/cyclic-data.test.ts +84 -0
- package/node_modules/zod/src/v4/mini/tests/deep-partial.test.ts +54 -0
- package/node_modules/zod/src/v4/mini/tests/error.test.ts +23 -4
- package/node_modules/zod/src/v4/mini/tests/functions.test.ts +9 -0
- package/node_modules/zod/src/v4/mini/tests/index.test.ts +72 -5
- package/node_modules/zod/src/v4/mini/tests/number.test.ts +14 -0
- package/node_modules/zod/src/v4/mini/tests/object.test.ts +65 -0
- package/node_modules/zod/src/v4/mini/tests/string.test.ts +21 -0
- package/node_modules/zod/v3/ZodError.cjs +22 -12
- package/node_modules/zod/v3/ZodError.d.cts +1 -1
- package/node_modules/zod/v3/ZodError.d.ts +1 -1
- package/node_modules/zod/v3/ZodError.js +22 -12
- package/node_modules/zod/v3/types.cjs +7 -5
- package/node_modules/zod/v3/types.js +7 -5
- package/node_modules/zod/v4/classic/checks.cjs +2 -1
- package/node_modules/zod/v4/classic/checks.d.cts +1 -1
- package/node_modules/zod/v4/classic/checks.d.ts +1 -1
- package/node_modules/zod/v4/classic/checks.js +1 -1
- package/node_modules/zod/v4/classic/compat.d.cts +9 -11
- package/node_modules/zod/v4/classic/compat.d.ts +9 -11
- package/node_modules/zod/v4/classic/deep-partial.cjs +39 -0
- package/node_modules/zod/v4/classic/deep-partial.d.cts +14 -0
- package/node_modules/zod/v4/classic/deep-partial.d.ts +14 -0
- package/node_modules/zod/v4/classic/deep-partial.js +13 -0
- package/node_modules/zod/v4/classic/errors.cjs +43 -34
- package/node_modules/zod/v4/classic/errors.d.cts +3 -4
- package/node_modules/zod/v4/classic/errors.d.ts +3 -4
- package/node_modules/zod/v4/classic/errors.js +43 -34
- package/node_modules/zod/v4/classic/external.cjs +30 -27
- package/node_modules/zod/v4/classic/external.d.cts +5 -2
- package/node_modules/zod/v4/classic/external.d.ts +5 -2
- package/node_modules/zod/v4/classic/external.js +5 -8
- package/node_modules/zod/v4/classic/from-json-schema.cjs +136 -75
- package/node_modules/zod/v4/classic/from-json-schema.js +136 -75
- package/node_modules/zod/v4/classic/in-out.cjs +63 -0
- package/node_modules/zod/v4/classic/in-out.d.cts +8 -0
- package/node_modules/zod/v4/classic/in-out.d.ts +8 -0
- package/node_modules/zod/v4/classic/in-out.js +36 -0
- package/node_modules/zod/v4/classic/index.cjs +2 -2
- package/node_modules/zod/v4/classic/index.d.cts +1 -2
- package/node_modules/zod/v4/classic/index.d.ts +1 -2
- package/node_modules/zod/v4/classic/index.js +2 -2
- package/node_modules/zod/v4/classic/iso.cjs +11 -22
- package/node_modules/zod/v4/classic/iso.d.cts +2 -17
- package/node_modules/zod/v4/classic/iso.d.ts +2 -17
- package/node_modules/zod/v4/classic/iso.js +2 -17
- package/node_modules/zod/v4/classic/parse.cjs +4 -1
- package/node_modules/zod/v4/classic/parse.d.cts +17 -4
- package/node_modules/zod/v4/classic/parse.d.ts +17 -4
- package/node_modules/zod/v4/classic/parse.js +1 -0
- package/node_modules/zod/v4/classic/schemas.cjs +498 -398
- package/node_modules/zod/v4/classic/schemas.d.cts +53 -18
- package/node_modules/zod/v4/classic/schemas.d.ts +53 -18
- package/node_modules/zod/v4/classic/schemas.js +492 -396
- package/node_modules/zod/v4/core/api.cjs +23 -4
- package/node_modules/zod/v4/core/api.d.cts +13 -9
- package/node_modules/zod/v4/core/api.d.ts +13 -9
- package/node_modules/zod/v4/core/api.js +21 -4
- package/node_modules/zod/v4/core/checks.cjs +37 -31
- package/node_modules/zod/v4/core/checks.d.cts +13 -13
- package/node_modules/zod/v4/core/checks.d.ts +13 -13
- package/node_modules/zod/v4/core/checks.js +37 -31
- package/node_modules/zod/v4/core/compile.cjs +1813 -0
- package/node_modules/zod/v4/core/compile.d.cts +51 -0
- package/node_modules/zod/v4/core/compile.d.ts +51 -0
- package/node_modules/zod/v4/core/compile.js +1783 -0
- package/node_modules/zod/v4/core/core.cjs +81 -18
- package/node_modules/zod/v4/core/core.d.cts +16 -4
- package/node_modules/zod/v4/core/core.d.ts +16 -4
- package/node_modules/zod/v4/core/core.js +82 -19
- package/node_modules/zod/v4/core/doc.cjs +5 -7
- package/node_modules/zod/v4/core/doc.d.cts +3 -1
- package/node_modules/zod/v4/core/doc.d.ts +3 -1
- package/node_modules/zod/v4/core/doc.js +5 -7
- package/node_modules/zod/v4/core/errors.cjs +110 -25
- package/node_modules/zod/v4/core/errors.d.cts +4 -0
- package/node_modules/zod/v4/core/errors.d.ts +4 -0
- package/node_modules/zod/v4/core/errors.js +110 -25
- package/node_modules/zod/v4/core/index.cjs +5 -1
- package/node_modules/zod/v4/core/index.d.cts +3 -0
- package/node_modules/zod/v4/core/index.d.ts +3 -0
- package/node_modules/zod/v4/core/index.js +3 -0
- package/node_modules/zod/v4/core/json-schema-generator.cjs +4 -0
- package/node_modules/zod/v4/core/json-schema-generator.d.cts +2 -2
- package/node_modules/zod/v4/core/json-schema-generator.d.ts +2 -2
- package/node_modules/zod/v4/core/json-schema-generator.js +4 -0
- package/node_modules/zod/v4/core/json-schema-processors.cjs +264 -95
- package/node_modules/zod/v4/core/json-schema-processors.js +243 -97
- package/node_modules/zod/v4/core/json-schema.d.cts +2 -1
- package/node_modules/zod/v4/core/json-schema.d.ts +2 -1
- package/node_modules/zod/v4/core/memoizer.cjs +272 -0
- package/node_modules/zod/v4/core/memoizer.d.cts +15 -0
- package/node_modules/zod/v4/core/memoizer.d.ts +15 -0
- package/node_modules/zod/v4/core/memoizer.js +265 -0
- package/node_modules/zod/v4/core/parse.cjs +96 -34
- package/node_modules/zod/v4/core/parse.d.cts +14 -11
- package/node_modules/zod/v4/core/parse.d.ts +14 -11
- package/node_modules/zod/v4/core/parse.js +94 -33
- package/node_modules/zod/v4/core/regexes.cjs +27 -15
- package/node_modules/zod/v4/core/regexes.d.cts +2 -0
- package/node_modules/zod/v4/core/regexes.d.ts +2 -0
- package/node_modules/zod/v4/core/regexes.js +24 -13
- package/node_modules/zod/v4/core/registries.js +2 -2
- package/node_modules/zod/v4/core/schemas.cjs +537 -326
- package/node_modules/zod/v4/core/schemas.d.cts +100 -31
- package/node_modules/zod/v4/core/schemas.d.ts +100 -31
- package/node_modules/zod/v4/core/schemas.js +526 -325
- package/node_modules/zod/v4/core/to-json-schema.cjs +242 -39
- package/node_modules/zod/v4/core/to-json-schema.d.cts +42 -3
- package/node_modules/zod/v4/core/to-json-schema.d.ts +42 -3
- package/node_modules/zod/v4/core/to-json-schema.js +241 -39
- package/node_modules/zod/v4/core/util.cjs +212 -31
- package/node_modules/zod/v4/core/util.d.cts +58 -1
- package/node_modules/zod/v4/core/util.d.ts +58 -1
- package/node_modules/zod/v4/core/util.js +202 -30
- package/node_modules/zod/v4/core/versions.cjs +2 -2
- package/node_modules/zod/v4/core/versions.d.cts +1 -1
- package/node_modules/zod/v4/core/versions.d.ts +1 -1
- package/node_modules/zod/v4/core/versions.js +2 -2
- package/node_modules/zod/v4/core/visit.cjs +195 -0
- package/node_modules/zod/v4/core/visit.d.cts +30 -0
- package/node_modules/zod/v4/core/visit.d.ts +30 -0
- package/node_modules/zod/v4/core/visit.js +169 -0
- package/node_modules/zod/v4/index.cjs +15 -5
- package/node_modules/zod/v4/index.d.cts +2 -2
- package/node_modules/zod/v4/index.d.ts +2 -2
- package/node_modules/zod/v4/index.js +3 -2
- package/node_modules/zod/v4/locales/ar.cjs +3 -0
- package/node_modules/zod/v4/locales/ar.js +3 -0
- package/node_modules/zod/v4/locales/az.cjs +3 -0
- package/node_modules/zod/v4/locales/az.js +3 -0
- package/node_modules/zod/v4/locales/be.cjs +10 -0
- package/node_modules/zod/v4/locales/be.js +10 -0
- package/node_modules/zod/v4/locales/bg.cjs +3 -0
- package/node_modules/zod/v4/locales/bg.js +3 -0
- package/node_modules/zod/v4/locales/bn.cjs +138 -0
- package/node_modules/zod/v4/locales/bn.d.cts +5 -0
- package/node_modules/zod/v4/locales/bn.d.ts +4 -0
- package/node_modules/zod/v4/locales/bn.js +111 -0
- package/node_modules/zod/v4/locales/ca.cjs +3 -0
- package/node_modules/zod/v4/locales/ca.js +3 -0
- package/node_modules/zod/v4/locales/ckb.cjs +158 -0
- package/node_modules/zod/v4/locales/ckb.d.cts +5 -0
- package/node_modules/zod/v4/locales/ckb.d.ts +4 -0
- package/node_modules/zod/v4/locales/ckb.js +131 -0
- package/node_modules/zod/v4/locales/cs.cjs +3 -0
- package/node_modules/zod/v4/locales/cs.js +3 -0
- package/node_modules/zod/v4/locales/da.cjs +5 -2
- package/node_modules/zod/v4/locales/da.js +5 -2
- package/node_modules/zod/v4/locales/de.cjs +3 -0
- package/node_modules/zod/v4/locales/de.js +3 -0
- package/node_modules/zod/v4/locales/el.cjs +1 -0
- package/node_modules/zod/v4/locales/el.js +1 -0
- package/node_modules/zod/v4/locales/en.cjs +14 -4
- package/node_modules/zod/v4/locales/en.js +14 -4
- package/node_modules/zod/v4/locales/eo.cjs +3 -0
- package/node_modules/zod/v4/locales/eo.js +3 -0
- package/node_modules/zod/v4/locales/es.cjs +2 -0
- package/node_modules/zod/v4/locales/es.js +2 -0
- package/node_modules/zod/v4/locales/fa.cjs +3 -0
- package/node_modules/zod/v4/locales/fa.js +3 -0
- package/node_modules/zod/v4/locales/fi.cjs +3 -0
- package/node_modules/zod/v4/locales/fi.js +3 -0
- package/node_modules/zod/v4/locales/fr-CA.cjs +3 -0
- package/node_modules/zod/v4/locales/fr-CA.js +3 -0
- package/node_modules/zod/v4/locales/fr.cjs +16 -14
- package/node_modules/zod/v4/locales/fr.js +16 -14
- package/node_modules/zod/v4/locales/gu.cjs +138 -0
- package/node_modules/zod/v4/locales/gu.d.cts +5 -0
- package/node_modules/zod/v4/locales/gu.d.ts +4 -0
- package/node_modules/zod/v4/locales/gu.js +111 -0
- package/node_modules/zod/v4/locales/he.cjs +5 -0
- package/node_modules/zod/v4/locales/he.js +5 -0
- package/node_modules/zod/v4/locales/hi.cjs +136 -0
- package/node_modules/zod/v4/locales/hi.d.cts +5 -0
- package/node_modules/zod/v4/locales/hi.d.ts +4 -0
- package/node_modules/zod/v4/locales/hi.js +109 -0
- package/node_modules/zod/v4/locales/hr.cjs +2 -0
- package/node_modules/zod/v4/locales/hr.js +2 -0
- package/node_modules/zod/v4/locales/hu.cjs +3 -0
- package/node_modules/zod/v4/locales/hu.js +3 -0
- package/node_modules/zod/v4/locales/hy.cjs +9 -0
- package/node_modules/zod/v4/locales/hy.js +9 -0
- package/node_modules/zod/v4/locales/id.cjs +3 -0
- package/node_modules/zod/v4/locales/id.js +3 -0
- package/node_modules/zod/v4/locales/index.cjs +22 -2
- package/node_modules/zod/v4/locales/index.d.cts +10 -0
- package/node_modules/zod/v4/locales/index.d.ts +10 -0
- package/node_modules/zod/v4/locales/index.js +10 -0
- package/node_modules/zod/v4/locales/is.cjs +3 -0
- package/node_modules/zod/v4/locales/is.js +3 -0
- package/node_modules/zod/v4/locales/it.cjs +3 -0
- package/node_modules/zod/v4/locales/it.js +3 -0
- package/node_modules/zod/v4/locales/ja.cjs +3 -0
- package/node_modules/zod/v4/locales/ja.js +3 -0
- package/node_modules/zod/v4/locales/ka.cjs +3 -0
- package/node_modules/zod/v4/locales/ka.js +3 -0
- package/node_modules/zod/v4/locales/km.cjs +3 -0
- package/node_modules/zod/v4/locales/km.js +3 -0
- package/node_modules/zod/v4/locales/kn.cjs +141 -0
- package/node_modules/zod/v4/locales/kn.d.cts +5 -0
- package/node_modules/zod/v4/locales/kn.d.ts +4 -0
- package/node_modules/zod/v4/locales/kn.js +114 -0
- package/node_modules/zod/v4/locales/ko.cjs +3 -0
- package/node_modules/zod/v4/locales/ko.js +3 -0
- package/node_modules/zod/v4/locales/lt.cjs +2 -0
- package/node_modules/zod/v4/locales/lt.js +2 -0
- package/node_modules/zod/v4/locales/mk.cjs +3 -0
- package/node_modules/zod/v4/locales/mk.js +3 -0
- package/node_modules/zod/v4/locales/ms.cjs +3 -0
- package/node_modules/zod/v4/locales/ms.js +3 -0
- package/node_modules/zod/v4/locales/ne.cjs +136 -0
- package/node_modules/zod/v4/locales/ne.d.cts +5 -0
- package/node_modules/zod/v4/locales/ne.d.ts +4 -0
- package/node_modules/zod/v4/locales/ne.js +109 -0
- package/node_modules/zod/v4/locales/nl.cjs +3 -0
- package/node_modules/zod/v4/locales/nl.js +3 -0
- package/node_modules/zod/v4/locales/nn.cjs +138 -0
- package/node_modules/zod/v4/locales/nn.d.cts +5 -0
- package/node_modules/zod/v4/locales/nn.d.ts +4 -0
- package/node_modules/zod/v4/locales/nn.js +111 -0
- package/node_modules/zod/v4/locales/no.cjs +5 -2
- package/node_modules/zod/v4/locales/no.js +5 -2
- package/node_modules/zod/v4/locales/ota.cjs +3 -0
- package/node_modules/zod/v4/locales/ota.js +3 -0
- package/node_modules/zod/v4/locales/pl.cjs +3 -0
- package/node_modules/zod/v4/locales/pl.js +3 -0
- package/node_modules/zod/v4/locales/ps.cjs +3 -0
- package/node_modules/zod/v4/locales/ps.js +3 -0
- package/node_modules/zod/v4/locales/pt-BR.cjs +168 -0
- package/node_modules/zod/v4/locales/pt-BR.d.cts +5 -0
- package/node_modules/zod/v4/locales/pt-BR.d.ts +4 -0
- package/node_modules/zod/v4/locales/pt-BR.js +141 -0
- package/node_modules/zod/v4/locales/pt.cjs +87 -55
- package/node_modules/zod/v4/locales/pt.js +87 -55
- package/node_modules/zod/v4/locales/ro.cjs +1 -0
- package/node_modules/zod/v4/locales/ro.js +1 -0
- package/node_modules/zod/v4/locales/ru.cjs +10 -0
- package/node_modules/zod/v4/locales/ru.js +10 -0
- package/node_modules/zod/v4/locales/sk.cjs +141 -0
- package/node_modules/zod/v4/locales/sk.d.cts +5 -0
- package/node_modules/zod/v4/locales/sk.d.ts +4 -0
- package/node_modules/zod/v4/locales/sk.js +114 -0
- package/node_modules/zod/v4/locales/sl.cjs +3 -0
- package/node_modules/zod/v4/locales/sl.js +3 -0
- package/node_modules/zod/v4/locales/sv.cjs +5 -2
- package/node_modules/zod/v4/locales/sv.js +5 -2
- package/node_modules/zod/v4/locales/ta.cjs +3 -0
- package/node_modules/zod/v4/locales/ta.js +3 -0
- package/node_modules/zod/v4/locales/th.cjs +3 -0
- package/node_modules/zod/v4/locales/th.js +3 -0
- package/node_modules/zod/v4/locales/tk.cjs +132 -0
- package/node_modules/zod/v4/locales/tk.d.cts +5 -0
- package/node_modules/zod/v4/locales/tk.d.ts +4 -0
- package/node_modules/zod/v4/locales/tk.js +105 -0
- package/node_modules/zod/v4/locales/tr.cjs +3 -0
- package/node_modules/zod/v4/locales/tr.js +3 -0
- package/node_modules/zod/v4/locales/uk.cjs +3 -0
- package/node_modules/zod/v4/locales/uk.js +3 -0
- package/node_modules/zod/v4/locales/ur.cjs +3 -0
- package/node_modules/zod/v4/locales/ur.js +3 -0
- package/node_modules/zod/v4/locales/uz.cjs +1 -0
- package/node_modules/zod/v4/locales/uz.js +1 -0
- package/node_modules/zod/v4/locales/vi.cjs +3 -0
- package/node_modules/zod/v4/locales/vi.js +3 -0
- package/node_modules/zod/v4/locales/yo.cjs +3 -0
- package/node_modules/zod/v4/locales/yo.js +3 -0
- package/node_modules/zod/v4/locales/zh-CN.cjs +3 -0
- package/node_modules/zod/v4/locales/zh-CN.js +3 -0
- package/node_modules/zod/v4/locales/zh-TW.cjs +3 -0
- package/node_modules/zod/v4/locales/zh-TW.js +3 -0
- package/node_modules/zod/v4/mini/checks.cjs +2 -1
- package/node_modules/zod/v4/mini/checks.d.cts +1 -1
- package/node_modules/zod/v4/mini/checks.d.ts +1 -1
- package/node_modules/zod/v4/mini/checks.js +1 -1
- package/node_modules/zod/v4/mini/deep-partial.cjs +39 -0
- package/node_modules/zod/v4/mini/deep-partial.d.cts +14 -0
- package/node_modules/zod/v4/mini/deep-partial.d.ts +14 -0
- package/node_modules/zod/v4/mini/deep-partial.js +13 -0
- package/node_modules/zod/v4/mini/external.cjs +12 -1
- package/node_modules/zod/v4/mini/external.d.cts +5 -2
- package/node_modules/zod/v4/mini/external.d.ts +5 -2
- package/node_modules/zod/v4/mini/external.js +3 -1
- package/node_modules/zod/v4/mini/in-out.cjs +63 -0
- package/node_modules/zod/v4/mini/in-out.d.cts +8 -0
- package/node_modules/zod/v4/mini/in-out.d.ts +8 -0
- package/node_modules/zod/v4/mini/in-out.js +36 -0
- package/node_modules/zod/v4/mini/parse.cjs +3 -1
- package/node_modules/zod/v4/mini/parse.d.cts +1 -1
- package/node_modules/zod/v4/mini/parse.d.ts +1 -1
- package/node_modules/zod/v4/mini/parse.js +1 -1
- package/node_modules/zod/v4/mini/schemas.cjs +75 -47
- package/node_modules/zod/v4/mini/schemas.d.cts +43 -13
- package/node_modules/zod/v4/mini/schemas.d.ts +43 -13
- package/node_modules/zod/v4/mini/schemas.js +71 -45
- package/openclaw.plugin.json +70 -0
- package/package.json +9 -6
- package/node_modules/zod/src/v4/core/config.ts +0 -15
- /package/dist/{realtime-transcription.runtime-CbJAs5t_.js → .setup/realtime-transcription.runtime-CbJAs5t_.mjs} +0 -0
- /package/dist/{realtime-voice.runtime-vtdCOWg-.js → .setup/realtime-voice.runtime-vtdCOWg-.mjs} +0 -0
- /package/dist/{twilio-region-4fkgz3UG.js → .setup/twilio-region-4fkgz3UG.mjs} +0 -0
- /package/dist/{webhook-replay-CCQSoBNF.js → .setup/webhook-replay-CCQSoBNF.mjs} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, sendHttpRequestRejection } from "
|
|
2
|
-
import "
|
|
3
|
-
import { a as resolveVoiceCallEffectiveConfig, c as resolveVoiceCallSessionKey, f as resolveVoiceCallRealtimeTools, i as resolveVoiceCallConfig, l as resolveVoiceCallStreamExposurePaths, n as normalizeVoiceCallConfig, o as resolveVoiceCallNumberRouteKeyForCall, r as resolveTwilioAuthToken, u as validateProviderConfig } from "./config-
|
|
4
|
-
import { _ as releaseRejectedProviderCall, b as setVoiceCallStateRuntime, d as
|
|
1
|
+
import { isBlockedHostnameOrIp, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, sendHttpRequestRejection } from "../runtime-api.js";
|
|
2
|
+
import "../api.js";
|
|
3
|
+
import { a as resolveVoiceCallEffectiveConfig, c as resolveVoiceCallSessionKey, f as resolveVoiceCallRealtimeTools, i as resolveVoiceCallConfig, l as resolveVoiceCallStreamExposurePaths, n as normalizeVoiceCallConfig, o as resolveVoiceCallNumberRouteKeyForCall, r as resolveTwilioAuthToken, u as validateProviderConfig } from "./config-72FnMWHb.mjs";
|
|
4
|
+
import { _ as releaseRejectedProviderCall, b as setVoiceCallStateRuntime, d as getCallHistoryFromStore, f as loadActiveCallsFromStore, g as appendCallReplayKey, m as persistCallRecord, t as resolveDefaultVoiceCallStoreDir, u as findCallInStore, v as rememberManagerReplayKey, x as TerminalStates, y as reserveRejectedProviderCall } from "./store-path-B1j1up4_.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
7
7
|
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
|
@@ -14,6 +14,7 @@ import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, assertRealtimeVoiceAgentConsult
|
|
|
14
14
|
import { WEBHOOK_BODY_READ_DEFAULTS, createWebhookInFlightLimiter, normalizeWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
|
|
15
15
|
import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
16
16
|
import fs from "node:fs";
|
|
17
|
+
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
17
18
|
import crypto from "node:crypto";
|
|
18
19
|
import { redactIdentifier } from "openclaw/plugin-sdk/logging-core";
|
|
19
20
|
import path from "node:path";
|
|
@@ -25,6 +26,7 @@ import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
|
|
|
25
26
|
import http from "node:http";
|
|
26
27
|
import { URL as URL$1 } from "node:url";
|
|
27
28
|
import { resolveConfiguredCapabilityProvider } from "openclaw/plugin-sdk/provider-selection-runtime";
|
|
29
|
+
import { rejectWebSocketUpgrade } from "openclaw/plugin-sdk/websocket-runtime";
|
|
28
30
|
import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
|
|
29
31
|
//#region extensions/voice-call/src/allowlist.ts
|
|
30
32
|
/** Normalize a phone number to digits only. */
|
|
@@ -73,6 +75,15 @@ function addTranscriptEntry(call, speaker, text) {
|
|
|
73
75
|
};
|
|
74
76
|
call.transcript.push(entry);
|
|
75
77
|
}
|
|
78
|
+
/** Stage persisted changes without exposing uncommitted state through active-call getters. */
|
|
79
|
+
function copyCallRecord(call) {
|
|
80
|
+
return {
|
|
81
|
+
...call,
|
|
82
|
+
transcript: [...call.transcript],
|
|
83
|
+
processedEventIds: [...call.processedEventIds],
|
|
84
|
+
...call.metadata ? { metadata: { ...call.metadata } } : {}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
76
87
|
//#endregion
|
|
77
88
|
//#region extensions/voice-call/src/manager/timer-delays.ts
|
|
78
89
|
/** Convert seconds to a safe timeout delay in milliseconds. */
|
|
@@ -101,10 +112,10 @@ function startMaxDurationTimer(params) {
|
|
|
101
112
|
const maxDurationMs = params.timeoutMs === void 0 ? resolveVoiceCallSecondsTimerDelayMs(params.ctx.config.maxDurationSeconds) : resolveVoiceCallTimerDelayMs(params.timeoutMs);
|
|
102
113
|
console.log(`[voice-call] Starting max duration timer (${Math.ceil(maxDurationMs / 1e3)}s) for call ${params.callId}`);
|
|
103
114
|
const timer = setTimeout(() => {
|
|
104
|
-
(async () => {
|
|
115
|
+
const work = (async () => {
|
|
105
116
|
params.ctx.maxDurationTimers.delete(params.callId);
|
|
106
117
|
const call = params.ctx.activeCalls.get(params.callId);
|
|
107
|
-
if (call && !TerminalStates.has(call.state)) {
|
|
118
|
+
if (!params.ctx.isStopping() && call && !TerminalStates.has(call.state)) {
|
|
108
119
|
console.log(`[voice-call] Max duration reached (${Math.ceil(maxDurationMs / 1e3)}s), ending call ${params.callId}`);
|
|
109
120
|
try {
|
|
110
121
|
const result = await params.onTimeout(params.callId);
|
|
@@ -114,19 +125,10 @@ function startMaxDurationTimer(params) {
|
|
|
114
125
|
}
|
|
115
126
|
}
|
|
116
127
|
})();
|
|
128
|
+
params.ctx.trackCallWork(work);
|
|
117
129
|
}, maxDurationMs);
|
|
118
130
|
params.ctx.maxDurationTimers.set(params.callId, timer);
|
|
119
131
|
}
|
|
120
|
-
/** Backfill max-duration enforcement from the first live conversation signal. */
|
|
121
|
-
function ensureMaxDurationTimerForLiveCall(params) {
|
|
122
|
-
if (params.call.answeredAt) return;
|
|
123
|
-
params.call.answeredAt = params.liveAt;
|
|
124
|
-
startMaxDurationTimer({
|
|
125
|
-
ctx: params.ctx,
|
|
126
|
-
callId: params.call.callId,
|
|
127
|
-
onTimeout: params.onTimeout
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
132
|
/** Clear and forget a pending final-transcript waiter. */
|
|
131
133
|
function clearTranscriptWaiter(ctx, callId) {
|
|
132
134
|
const waiter = ctx.transcriptWaiters.get(callId);
|
|
@@ -175,18 +177,26 @@ function removeProviderCallMapping(providerCallIdMap, call) {
|
|
|
175
177
|
if (!call.providerCallId) return;
|
|
176
178
|
if (providerCallIdMap.get(call.providerCallId) === call.callId) providerCallIdMap.delete(call.providerCallId);
|
|
177
179
|
}
|
|
178
|
-
/**
|
|
179
|
-
function finalizeCall(params) {
|
|
180
|
+
/** Finalize under the manager mutation queue, publishing cleanup only after persistence. */
|
|
181
|
+
async function finalizeCall(params) {
|
|
180
182
|
const { ctx, call, endReason } = params;
|
|
183
|
+
if (ctx.activeCalls.get(call.callId) !== call) return;
|
|
181
184
|
const previousState = call.state;
|
|
182
185
|
if (!TerminalStates.has(previousState)) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
186
|
+
const next = copyCallRecord(params.preparedCall ?? call);
|
|
187
|
+
next.endedAt = params.endedAt ?? Date.now();
|
|
188
|
+
next.endReason = endReason;
|
|
189
|
+
transitionState(next, endReason);
|
|
190
|
+
await persistCallRecord(ctx.storePath, next, ctx.stateRuntime);
|
|
191
|
+
Object.assign(call, next);
|
|
187
192
|
log$1.info(`[voice-call] Call finalized callId=${call.callId} providerCallId=${call.providerCallId ?? "unknown"} endReason=${endReason}`);
|
|
188
193
|
}
|
|
189
194
|
if (ctx.maxDurationTimers) clearMaxDurationTimer({ maxDurationTimers: ctx.maxDurationTimers }, call.callId);
|
|
195
|
+
const notifyTimer = ctx.notifyHangupTimers?.get(call.callId);
|
|
196
|
+
if (notifyTimer) {
|
|
197
|
+
clearTimeout(notifyTimer);
|
|
198
|
+
ctx.notifyHangupTimers?.delete(call.callId);
|
|
199
|
+
}
|
|
190
200
|
if (ctx.transcriptWaiters) rejectTranscriptWaiter({ transcriptWaiters: ctx.transcriptWaiters }, call.callId, params.transcriptRejectReason ?? `Call ended: ${endReason}`);
|
|
191
201
|
ctx.activeCalls.delete(call.callId);
|
|
192
202
|
removeProviderCallMapping(ctx.providerCallIdMap, call);
|
|
@@ -234,14 +244,14 @@ function escapeXml(text) {
|
|
|
234
244
|
/**
|
|
235
245
|
* Map of OpenAI voice names to similar Twilio Polly voices.
|
|
236
246
|
*/
|
|
237
|
-
const OPENAI_TO_POLLY_MAP =
|
|
238
|
-
alloy
|
|
239
|
-
echo
|
|
240
|
-
fable
|
|
241
|
-
onyx
|
|
242
|
-
nova
|
|
243
|
-
shimmer
|
|
244
|
-
|
|
247
|
+
const OPENAI_TO_POLLY_MAP = /* @__PURE__ */ new Map([
|
|
248
|
+
["alloy", "Polly.Joanna"],
|
|
249
|
+
["echo", "Polly.Matthew"],
|
|
250
|
+
["fable", "Polly.Amy"],
|
|
251
|
+
["onyx", "Polly.Brian"],
|
|
252
|
+
["nova", "Polly.Salli"],
|
|
253
|
+
["shimmer", "Polly.Kimberly"]
|
|
254
|
+
]);
|
|
245
255
|
/**
|
|
246
256
|
* Default Polly voice when no mapping is found.
|
|
247
257
|
*/
|
|
@@ -256,7 +266,20 @@ const DEFAULT_POLLY_VOICE = "Polly.Joanna";
|
|
|
256
266
|
function mapVoiceToPolly(voice) {
|
|
257
267
|
if (!voice) return DEFAULT_POLLY_VOICE;
|
|
258
268
|
if (voice.startsWith("Polly.") || voice.startsWith("Google.")) return voice;
|
|
259
|
-
return OPENAI_TO_POLLY_MAP
|
|
269
|
+
return OPENAI_TO_POLLY_MAP.get(normalizeLowercaseStringOrEmpty(voice)) ?? DEFAULT_POLLY_VOICE;
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region extensions/voice-call/src/manager/mutations.ts
|
|
273
|
+
/** Commit one live call update while preserving the call identity held by its callbacks. */
|
|
274
|
+
function updateCall(ctx, call, update, isCurrent) {
|
|
275
|
+
return ctx.mutationQueue.enqueue("state", async () => {
|
|
276
|
+
if (ctx.activeCalls.get(call.callId) !== call || TerminalStates.has(call.state) || isCurrent && !isCurrent()) return false;
|
|
277
|
+
const next = copyCallRecord(call);
|
|
278
|
+
update(next);
|
|
279
|
+
await persistCallRecord(ctx.storePath, next, ctx.stateRuntime);
|
|
280
|
+
Object.assign(call, next);
|
|
281
|
+
return true;
|
|
282
|
+
});
|
|
260
283
|
}
|
|
261
284
|
//#endregion
|
|
262
285
|
//#region extensions/voice-call/src/manager/twiml.ts
|
|
@@ -316,6 +339,9 @@ function requireConnectedCall(ctx, callId) {
|
|
|
316
339
|
provider: lookup.provider
|
|
317
340
|
};
|
|
318
341
|
}
|
|
342
|
+
function isCurrentCall(ctx, call) {
|
|
343
|
+
return ctx.activeCalls.get(call.callId) === call && !TerminalStates.has(call.state);
|
|
344
|
+
}
|
|
319
345
|
function validateDtmfDigits(digits) {
|
|
320
346
|
return /^[0-9*#wWpP,]+$/.test(digits) ? null : "digits may only contain digits, *, #, comma, w, p";
|
|
321
347
|
}
|
|
@@ -349,7 +375,7 @@ async function initiateCall(ctx, to, sessionKey, options) {
|
|
|
349
375
|
success: false,
|
|
350
376
|
error: "Webhook URL not configured"
|
|
351
377
|
};
|
|
352
|
-
if (ctx.activeCalls.size >= ctx.config.maxConcurrentCalls) return {
|
|
378
|
+
if (ctx.activeCalls.size + ctx.pendingCallAdmissions.size >= ctx.config.maxConcurrentCalls) return {
|
|
353
379
|
callId: "",
|
|
354
380
|
success: false,
|
|
355
381
|
error: `Maximum concurrent calls (${ctx.config.maxConcurrentCalls}) reached`
|
|
@@ -388,9 +414,18 @@ async function initiateCall(ctx, to, sessionKey, options) {
|
|
|
388
414
|
...requesterSessionKey ? { requesterSessionKey } : {}
|
|
389
415
|
}
|
|
390
416
|
};
|
|
391
|
-
|
|
392
|
-
|
|
417
|
+
ctx.pendingCallAdmissions.add(callId);
|
|
418
|
+
try {
|
|
419
|
+
await ctx.mutationQueue.enqueue("state", async () => {
|
|
420
|
+
await persistCallRecord(ctx.storePath, callRecord, ctx.stateRuntime);
|
|
421
|
+
ctx.activeCalls.set(callId, callRecord);
|
|
422
|
+
ctx.pendingCallAdmissions.delete(callId);
|
|
423
|
+
});
|
|
424
|
+
} finally {
|
|
425
|
+
ctx.pendingCallAdmissions.delete(callId);
|
|
426
|
+
}
|
|
393
427
|
try {
|
|
428
|
+
if (ctx.isStopping()) throw new Error("Voice Call manager is stopping");
|
|
394
429
|
let inlineTwiml;
|
|
395
430
|
let preConnectTwiml;
|
|
396
431
|
if (mode === "notify" && initialMessage) {
|
|
@@ -420,22 +455,25 @@ async function initiateCall(ctx, to, sessionKey, options) {
|
|
|
420
455
|
streamAuthToken: streamSession.token
|
|
421
456
|
} : {}
|
|
422
457
|
});
|
|
423
|
-
|
|
424
|
-
callRecord
|
|
458
|
+
await ctx.mutationQueue.enqueue("state", async () => {
|
|
459
|
+
if (!isCurrentCall(ctx, callRecord) || callRecord.providerCallId) return;
|
|
460
|
+
const next = copyCallRecord(callRecord);
|
|
461
|
+
next.providerCallId = result.providerCallId;
|
|
462
|
+
await persistCallRecord(ctx.storePath, next, ctx.stateRuntime);
|
|
463
|
+
Object.assign(callRecord, next);
|
|
425
464
|
ctx.providerCallIdMap.set(result.providerCallId, callId);
|
|
426
|
-
|
|
427
|
-
}
|
|
465
|
+
});
|
|
428
466
|
console.log(`[voice-call] Outbound call initiated: callId=${callId} providerCallId=${callRecord.providerCallId ?? result.providerCallId} mode=${mode} preConnectDtmf=${preConnectTwiml ? "yes" : "no"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
429
467
|
return {
|
|
430
468
|
callId,
|
|
431
469
|
success: true
|
|
432
470
|
};
|
|
433
471
|
} catch (err) {
|
|
434
|
-
finalizeCall({
|
|
472
|
+
await ctx.mutationQueue.enqueue("state", () => finalizeCall({
|
|
435
473
|
ctx,
|
|
436
474
|
call: callRecord,
|
|
437
475
|
endReason: "failed"
|
|
438
|
-
});
|
|
476
|
+
}));
|
|
439
477
|
return {
|
|
440
478
|
callId,
|
|
441
479
|
success: false,
|
|
@@ -450,31 +488,49 @@ async function speak(ctx, callId, text, options) {
|
|
|
450
488
|
error: connected.error
|
|
451
489
|
};
|
|
452
490
|
const { call, providerCallId, provider } = connected;
|
|
491
|
+
let speakingCommitted = false;
|
|
453
492
|
try {
|
|
454
|
-
|
|
493
|
+
let startTimer = false;
|
|
494
|
+
speakingCommitted = await updateCall(ctx, call, (next) => {
|
|
495
|
+
if (!next.answeredAt) {
|
|
496
|
+
next.answeredAt = Date.now();
|
|
497
|
+
startTimer = true;
|
|
498
|
+
}
|
|
499
|
+
transitionState(next, "speaking");
|
|
500
|
+
}, options?.isCurrent);
|
|
501
|
+
if (options?.isCurrent) {
|
|
502
|
+
await ctx.mutationQueue.enqueue("state", async () => void 0);
|
|
503
|
+
if (!options.isCurrent()) throw new Error("Automatic reply superseded");
|
|
504
|
+
}
|
|
505
|
+
if (!speakingCommitted || !isCurrentCall(ctx, call)) return {
|
|
506
|
+
success: false,
|
|
507
|
+
error: "Call has ended"
|
|
508
|
+
};
|
|
509
|
+
if (ctx.isStopping()) throw new Error("Voice Call manager is stopping");
|
|
510
|
+
if (startTimer) startMaxDurationTimer({
|
|
455
511
|
ctx,
|
|
456
|
-
|
|
457
|
-
liveAt: Date.now(),
|
|
512
|
+
callId,
|
|
458
513
|
onTimeout: (id) => endCall(ctx, id, { reason: "timeout" })
|
|
459
514
|
});
|
|
460
|
-
transitionState(call, "speaking");
|
|
461
|
-
persistCallRecord(ctx.storePath, call);
|
|
462
515
|
const numberRouteKey = resolveVoiceCallNumberRouteKeyForCall(call);
|
|
463
516
|
const voice = resolvePreferredTtsVoice(resolveVoiceCallEffectiveConfig(ctx.config, numberRouteKey).config);
|
|
464
517
|
const playbackOptions = options?.listenAfterPlayback ? { listenAfterPlayback: true } : {};
|
|
465
518
|
await provider.playTts({
|
|
466
519
|
callId,
|
|
467
|
-
providerCallId,
|
|
520
|
+
providerCallId: call.providerCallId ?? providerCallId,
|
|
468
521
|
text,
|
|
469
522
|
voice,
|
|
470
523
|
...playbackOptions
|
|
471
524
|
});
|
|
472
|
-
|
|
473
|
-
|
|
525
|
+
if (!await updateCall(ctx, call, (next) => addTranscriptEntry(next, "bot", text))) return {
|
|
526
|
+
success: false,
|
|
527
|
+
error: "Call has ended"
|
|
528
|
+
};
|
|
474
529
|
return { success: true };
|
|
475
530
|
} catch (err) {
|
|
476
|
-
|
|
477
|
-
|
|
531
|
+
if (speakingCommitted) await updateCall(ctx, call, (next) => {
|
|
532
|
+
if (next.state === "speaking") transitionState(next, "listening");
|
|
533
|
+
});
|
|
478
534
|
return {
|
|
479
535
|
success: false,
|
|
480
536
|
error: formatErrorMessage(err)
|
|
@@ -543,30 +599,39 @@ async function speakInitialMessage(ctx, providerCallId) {
|
|
|
543
599
|
console.warn(`[voice-call] Failed to speak initial message: ${result.error}`);
|
|
544
600
|
return;
|
|
545
601
|
}
|
|
546
|
-
if (call
|
|
547
|
-
delete
|
|
548
|
-
|
|
549
|
-
|
|
602
|
+
if (!await updateCall(ctx, call, (next) => {
|
|
603
|
+
if (next.metadata?.initialMessage === initialMessage) delete next.metadata.initialMessage;
|
|
604
|
+
}) || !isCurrentCall(ctx, call)) return;
|
|
605
|
+
if (ctx.isStopping()) throw new Error("Voice Call manager is stopping");
|
|
550
606
|
if (mode === "notify") {
|
|
551
607
|
const delaySec = ctx.config.outbound.notifyHangupDelaySec;
|
|
552
608
|
const delayMs = resolveVoiceCallSecondsTimerDelayMs(delaySec, 0);
|
|
553
609
|
console.log(`[voice-call] Notify mode: auto-hangup in ${delaySec}s for call ${call.callId}`);
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
610
|
+
const previousTimer = ctx.notifyHangupTimers.get(call.callId);
|
|
611
|
+
if (previousTimer) clearTimeout(previousTimer);
|
|
612
|
+
const timer = setTimeout(() => {
|
|
613
|
+
if (ctx.notifyHangupTimers.get(call.callId) !== timer) return;
|
|
614
|
+
ctx.notifyHangupTimers.delete(call.callId);
|
|
615
|
+
const work = (async () => {
|
|
616
|
+
if (!ctx.isStopping() && isCurrentCall(ctx, call)) {
|
|
558
617
|
console.log(`[voice-call] Notify mode: hanging up call ${call.callId}`);
|
|
559
|
-
|
|
560
|
-
|
|
618
|
+
try {
|
|
619
|
+
const endResult = await endCall(ctx, call.callId);
|
|
620
|
+
if (!endResult.success) console.warn(`[voice-call] Notify mode failed to hang up call ${call.callId}: ${endResult.error ?? "unknown error"}`);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
console.warn(`[voice-call] Notify mode failed to hang up call ${call.callId}: ${formatErrorMessage(error)}`);
|
|
623
|
+
}
|
|
561
624
|
}
|
|
562
625
|
})();
|
|
626
|
+
ctx.trackCallWork(work);
|
|
563
627
|
}, delayMs);
|
|
628
|
+
ctx.notifyHangupTimers.set(call.callId, timer);
|
|
564
629
|
} else if (mode === "conversation" && ctx.provider && shouldStartListeningAfterInitialMessage(ctx)) {
|
|
565
|
-
|
|
566
|
-
|
|
630
|
+
if (!await updateCall(ctx, call, (next) => transitionState(next, "listening")) || !isCurrentCall(ctx, call)) return;
|
|
631
|
+
if (ctx.isStopping()) throw new Error("Voice Call manager is stopping");
|
|
567
632
|
await ctx.provider.startListening({
|
|
568
633
|
callId: call.callId,
|
|
569
|
-
providerCallId
|
|
634
|
+
providerCallId: call.providerCallId ?? providerCallId
|
|
570
635
|
});
|
|
571
636
|
}
|
|
572
637
|
} finally {
|
|
@@ -590,14 +655,22 @@ async function continueCall(ctx, callId, prompt) {
|
|
|
590
655
|
try {
|
|
591
656
|
const speakResult = await speak(ctx, callId, prompt);
|
|
592
657
|
if (!speakResult.success) return speakResult;
|
|
593
|
-
|
|
594
|
-
|
|
658
|
+
if (!await updateCall(ctx, call, (next) => transitionState(next, "listening")) || !isCurrentCall(ctx, call)) return {
|
|
659
|
+
success: false,
|
|
660
|
+
error: "Call has ended"
|
|
661
|
+
};
|
|
662
|
+
if (ctx.isStopping()) throw new Error("Voice Call manager is stopping");
|
|
595
663
|
const listenStartedAt = Date.now();
|
|
596
664
|
await provider.startListening({
|
|
597
665
|
callId,
|
|
598
|
-
providerCallId,
|
|
666
|
+
providerCallId: call.providerCallId ?? providerCallId,
|
|
599
667
|
turnToken
|
|
600
668
|
});
|
|
669
|
+
if (ctx.isStopping()) throw new Error("Voice Call manager is stopping");
|
|
670
|
+
if (!isCurrentCall(ctx, call)) return {
|
|
671
|
+
success: false,
|
|
672
|
+
error: "Call has ended"
|
|
673
|
+
};
|
|
601
674
|
const transcript = await waitForFinalTranscript(ctx, callId, turnToken);
|
|
602
675
|
const transcriptReceivedAt = Date.now();
|
|
603
676
|
await provider.stopListening({
|
|
@@ -606,15 +679,19 @@ async function continueCall(ctx, callId, prompt) {
|
|
|
606
679
|
});
|
|
607
680
|
const lastTurnLatencyMs = transcriptReceivedAt - turnStartedAt;
|
|
608
681
|
const lastTurnListenWaitMs = transcriptReceivedAt - listenStartedAt;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
682
|
+
if (!await updateCall(ctx, call, (next) => {
|
|
683
|
+
const turnCount = typeof next.metadata?.turnCount === "number" ? next.metadata.turnCount + 1 : 1;
|
|
684
|
+
next.metadata = {
|
|
685
|
+
...next.metadata,
|
|
686
|
+
turnCount,
|
|
687
|
+
lastTurnLatencyMs,
|
|
688
|
+
lastTurnListenWaitMs,
|
|
689
|
+
lastTurnCompletedAt: transcriptReceivedAt
|
|
690
|
+
};
|
|
691
|
+
})) return {
|
|
692
|
+
success: false,
|
|
693
|
+
error: "Call has ended"
|
|
616
694
|
};
|
|
617
|
-
persistCallRecord(ctx.storePath, call);
|
|
618
695
|
console.log("[voice-call] continueCall latency call=" + call.callId + " totalMs=" + String(lastTurnLatencyMs) + " listenWaitMs=" + String(lastTurnListenWaitMs));
|
|
619
696
|
return {
|
|
620
697
|
success: true,
|
|
@@ -648,11 +725,11 @@ function endCall(ctx, callId, options) {
|
|
|
648
725
|
providerCallId,
|
|
649
726
|
reason
|
|
650
727
|
});
|
|
651
|
-
finalizeCall({
|
|
728
|
+
await ctx.mutationQueue.enqueue("state", () => finalizeCall({
|
|
652
729
|
ctx,
|
|
653
730
|
call,
|
|
654
731
|
endReason: reason
|
|
655
|
-
});
|
|
732
|
+
}));
|
|
656
733
|
return { success: true };
|
|
657
734
|
} catch (err) {
|
|
658
735
|
return {
|
|
@@ -694,7 +771,7 @@ function shouldAcceptInbound(config, from) {
|
|
|
694
771
|
default: return false;
|
|
695
772
|
}
|
|
696
773
|
}
|
|
697
|
-
function createWebhookCall(params) {
|
|
774
|
+
async function createWebhookCall(params) {
|
|
698
775
|
const callId = crypto.randomUUID();
|
|
699
776
|
const effective = resolveVoiceCallEffectiveConfig(params.ctx.config, params.direction === "inbound" ? params.to : void 0);
|
|
700
777
|
const effectiveConfig = effective.config;
|
|
@@ -721,13 +798,13 @@ function createWebhookCall(params) {
|
|
|
721
798
|
...effective.numberRouteKey ? { numberRouteKey: effective.numberRouteKey } : {}
|
|
722
799
|
}
|
|
723
800
|
};
|
|
724
|
-
persistCallRecord(params.ctx.storePath, callRecord);
|
|
801
|
+
await persistCallRecord(params.ctx.storePath, callRecord, params.ctx.stateRuntime);
|
|
725
802
|
params.ctx.activeCalls.set(callId, callRecord);
|
|
726
803
|
params.ctx.providerCallIdMap.set(params.providerCallId, callId);
|
|
727
804
|
log.info(`Created ${params.direction} call record: ${callId} caller=${redactIdentifier(params.from)}`);
|
|
728
805
|
return callRecord;
|
|
729
806
|
}
|
|
730
|
-
function persistRejectedInboundCall(params) {
|
|
807
|
+
async function persistRejectedInboundCall(params) {
|
|
731
808
|
const callId = params.event.callId || params.providerCallId;
|
|
732
809
|
const now = Date.now();
|
|
733
810
|
const rejectedCall = {
|
|
@@ -745,9 +822,12 @@ function persistRejectedInboundCall(params) {
|
|
|
745
822
|
processedEventIds: [params.dedupeKey],
|
|
746
823
|
metadata: { rejectionReason: "inbound-policy" }
|
|
747
824
|
};
|
|
748
|
-
persistCallRecord(params.ctx.storePath, rejectedCall);
|
|
825
|
+
await persistCallRecord(params.ctx.storePath, rejectedCall, params.ctx.stateRuntime);
|
|
749
826
|
}
|
|
750
827
|
function processEvent(ctx, event) {
|
|
828
|
+
return ctx.mutationQueue.enqueue("state", () => processEventInQueue(ctx, event));
|
|
829
|
+
}
|
|
830
|
+
async function processEventInQueue(ctx, event) {
|
|
751
831
|
const dedupeKey = event.dedupeKey || event.id;
|
|
752
832
|
if (ctx.processedEventIds.has(dedupeKey)) return { kind: "ignored" };
|
|
753
833
|
let call = findCall({
|
|
@@ -758,8 +838,8 @@ function processEvent(ctx, event) {
|
|
|
758
838
|
let providerCallId = event.providerCallId;
|
|
759
839
|
let retained;
|
|
760
840
|
if (!call) {
|
|
761
|
-
retained = findCallInStore(ctx.storePath, event.callId);
|
|
762
|
-
if (!retained && providerCallId && providerCallId !== event.callId) retained = findCallInStore(ctx.storePath, providerCallId);
|
|
841
|
+
retained = await findCallInStore(ctx.storePath, event.callId, ctx.stateRuntime);
|
|
842
|
+
if (!retained && providerCallId && providerCallId !== event.callId) retained = await findCallInStore(ctx.storePath, providerCallId, ctx.stateRuntime);
|
|
763
843
|
if (retained && retained.metadata?.rejectionReason !== "inbound-policy") {
|
|
764
844
|
call = ctx.activeCalls.get(retained.callId);
|
|
765
845
|
if (!call) return TerminalStates.has(retained.state) ? { kind: "ignored" } : {
|
|
@@ -769,7 +849,7 @@ function processEvent(ctx, event) {
|
|
|
769
849
|
}
|
|
770
850
|
}
|
|
771
851
|
if (call && providerCallId && providerCallId !== call.providerCallId) {
|
|
772
|
-
if ((providerCallId === event.callId && retained ? retained : findCallInStore(ctx.storePath, providerCallId))?.callId === call.callId) providerCallId = call.providerCallId;
|
|
852
|
+
if ((providerCallId === event.callId && retained ? retained : await findCallInStore(ctx.storePath, providerCallId, ctx.stateRuntime))?.callId === call.callId) providerCallId = call.providerCallId;
|
|
773
853
|
}
|
|
774
854
|
const eventDirection = event.direction === "inbound" || event.direction === "outbound" ? event.direction : void 0;
|
|
775
855
|
if (!call && providerCallId && eventDirection) {
|
|
@@ -781,17 +861,18 @@ function processEvent(ctx, event) {
|
|
|
781
861
|
}
|
|
782
862
|
if (ctx.rejectedProviderCallIds.has(pid)) return { kind: "ignored" };
|
|
783
863
|
const callId = event.callId ?? pid;
|
|
784
|
-
persistRejectedInboundCall({
|
|
864
|
+
await persistRejectedInboundCall({
|
|
785
865
|
ctx,
|
|
786
866
|
event,
|
|
787
867
|
dedupeKey,
|
|
788
868
|
providerCallId: pid
|
|
789
869
|
});
|
|
870
|
+
if (ctx.isStopping()) return { kind: "processed" };
|
|
790
871
|
const rejectionReservation = reserveRejectedProviderCall(ctx.rejectedProviderCallIds, pid);
|
|
791
872
|
if (rejectionReservation === void 0) return { kind: "ignored" };
|
|
792
873
|
rememberManagerReplayKey(ctx.processedEventIds, dedupeKey);
|
|
793
874
|
log.info(`Rejecting inbound call by policy: ${pid}`);
|
|
794
|
-
ctx.provider.hangupCall({
|
|
875
|
+
ctx.trackCallWork(ctx.provider.hangupCall({
|
|
795
876
|
callId,
|
|
796
877
|
providerCallId: pid,
|
|
797
878
|
reason: "hangup-bot"
|
|
@@ -799,10 +880,10 @@ function processEvent(ctx, event) {
|
|
|
799
880
|
releaseRejectedProviderCall(ctx.rejectedProviderCallIds, pid, rejectionReservation);
|
|
800
881
|
const message = formatErrorMessage(err);
|
|
801
882
|
log.warn(`Failed to reject inbound call ${pid}: ${message}`);
|
|
802
|
-
});
|
|
883
|
+
}));
|
|
803
884
|
return { kind: "processed" };
|
|
804
885
|
}
|
|
805
|
-
call = createWebhookCall({
|
|
886
|
+
call = await createWebhookCall({
|
|
806
887
|
ctx,
|
|
807
888
|
providerCallId,
|
|
808
889
|
direction: eventDirection === "outbound" ? "outbound" : "inbound",
|
|
@@ -815,16 +896,8 @@ function processEvent(ctx, event) {
|
|
|
815
896
|
kind: "ignored",
|
|
816
897
|
replayable: true
|
|
817
898
|
};
|
|
818
|
-
const activeCall = call;
|
|
819
|
-
const previousCall = {
|
|
820
|
-
state: activeCall.state,
|
|
821
|
-
providerCallId: activeCall.providerCallId,
|
|
822
|
-
answeredAt: activeCall.answeredAt,
|
|
823
|
-
endedAt: activeCall.endedAt,
|
|
824
|
-
endReason: activeCall.endReason,
|
|
825
|
-
transcriptLength: activeCall.transcript.length,
|
|
826
|
-
processedEventIds: [...activeCall.processedEventIds]
|
|
827
|
-
};
|
|
899
|
+
const activeCall = copyCallRecord(call);
|
|
900
|
+
const previousCall = { providerCallId: call.providerCallId };
|
|
828
901
|
const shouldCommitReplayKey = !(event.type === "call.error" && event.retryable);
|
|
829
902
|
const effects = [];
|
|
830
903
|
let result = { kind: "processed" };
|
|
@@ -848,123 +921,114 @@ function processEvent(ctx, event) {
|
|
|
848
921
|
if (ctx.providerCallIdMap.get(previousCall.providerCallId) === activeCall.callId) ctx.providerCallIdMap.delete(previousCall.providerCallId);
|
|
849
922
|
}
|
|
850
923
|
};
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
924
|
+
if (providerCallId && providerCallId !== activeCall.providerCallId) activeCall.providerCallId = providerCallId;
|
|
925
|
+
if (shouldCommitReplayKey) appendCallReplayKey(activeCall.processedEventIds, dedupeKey);
|
|
926
|
+
switch (event.type) {
|
|
927
|
+
case "call.initiated": {
|
|
928
|
+
transitionState(activeCall, "initiated");
|
|
929
|
+
const inboundProvider = ctx.provider;
|
|
930
|
+
const inboundProviderCallId = activeCall.providerCallId;
|
|
931
|
+
const answerInboundCall = inboundProvider?.answerCall?.bind(inboundProvider);
|
|
932
|
+
if (activeCall.direction === "inbound" && inboundProviderCallId && answerInboundCall) effects.push(() => {
|
|
933
|
+
const inboundStreamSession = ctx.config.realtime?.enabled && inboundProvider?.name === "telnyx" && ctx.streamSessionIssuer ? ctx.streamSessionIssuer({
|
|
934
|
+
providerName: "telnyx",
|
|
935
|
+
callId: activeCall.callId,
|
|
936
|
+
from: activeCall.from,
|
|
937
|
+
to: activeCall.to,
|
|
938
|
+
direction: "inbound"
|
|
939
|
+
}) : void 0;
|
|
940
|
+
ctx.trackCallWork(answerInboundCall({
|
|
941
|
+
callId: activeCall.callId,
|
|
942
|
+
providerCallId: inboundProviderCallId,
|
|
943
|
+
...inboundStreamSession ? {
|
|
944
|
+
streamUrl: inboundStreamSession.streamUrl,
|
|
945
|
+
streamAuthToken: inboundStreamSession.token
|
|
946
|
+
} : {}
|
|
947
|
+
}).catch((err) => {
|
|
948
|
+
const message = formatErrorMessage(err);
|
|
949
|
+
log.warn(`Failed to answer inbound call ${activeCall.providerCallId}: ${message}`);
|
|
950
|
+
}));
|
|
951
|
+
});
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
case "call.ringing":
|
|
955
|
+
transitionState(activeCall, "ringing");
|
|
956
|
+
break;
|
|
957
|
+
case "call.answered":
|
|
958
|
+
activeCall.answeredAt = event.timestamp;
|
|
959
|
+
transitionState(activeCall, "answered");
|
|
960
|
+
effects.push(startDurationTimer, () => ctx.onCallAnswered?.(call));
|
|
961
|
+
break;
|
|
962
|
+
case "call.active":
|
|
963
|
+
transitionState(activeCall, "active");
|
|
964
|
+
break;
|
|
965
|
+
case "call.speaking":
|
|
966
|
+
case "call.assistant-speech":
|
|
967
|
+
prepareLiveDurationTimer();
|
|
968
|
+
transitionState(activeCall, "speaking");
|
|
969
|
+
if (event.type === "call.assistant-speech" && event.transcript.trim()) addTranscriptEntry(activeCall, "bot", event.transcript);
|
|
970
|
+
break;
|
|
971
|
+
case "call.speech":
|
|
972
|
+
if (event.isFinal && event.transcript.trim()) {
|
|
973
|
+
const waiter = ctx.transcriptWaiters.get(activeCall.callId);
|
|
974
|
+
if (waiter?.turnToken && waiter.turnToken !== event.turnToken) {
|
|
975
|
+
log.warn(`Ignoring speech event with mismatched turn token for ${activeCall.callId}`);
|
|
976
|
+
result = { kind: "ignored" };
|
|
977
|
+
break;
|
|
978
|
+
}
|
|
979
|
+
addTranscriptEntry(activeCall, "user", event.transcript);
|
|
980
|
+
const speechResult = {
|
|
981
|
+
kind: "final-speech",
|
|
982
|
+
call,
|
|
983
|
+
transcript: event.transcript,
|
|
984
|
+
waiterResolved: false
|
|
985
|
+
};
|
|
986
|
+
result = speechResult;
|
|
987
|
+
if (waiter) effects.push(() => {
|
|
988
|
+
if (ctx.transcriptWaiters.get(activeCall.callId) === waiter) speechResult.waiterResolved = resolveTranscriptWaiter(ctx, activeCall.callId, event.transcript, event.turnToken);
|
|
879
989
|
});
|
|
880
|
-
break;
|
|
881
990
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
if (waiter?.turnToken && waiter.turnToken !== event.turnToken) {
|
|
903
|
-
log.warn(`Ignoring speech event with mismatched turn token for ${activeCall.callId}`);
|
|
904
|
-
result = { kind: "ignored" };
|
|
905
|
-
break;
|
|
906
|
-
}
|
|
907
|
-
addTranscriptEntry(activeCall, "user", event.transcript);
|
|
908
|
-
result = {
|
|
909
|
-
kind: "final-speech",
|
|
910
|
-
call: activeCall,
|
|
911
|
-
transcript: event.transcript,
|
|
912
|
-
waiterResolved: Boolean(waiter)
|
|
913
|
-
};
|
|
914
|
-
if (waiter) effects.push(() => {
|
|
915
|
-
resolveTranscriptWaiter(ctx, activeCall.callId, event.transcript, event.turnToken);
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
if (event.transcript.trim()) effects.push(() => ctx.onCallerSpeech?.(activeCall));
|
|
919
|
-
prepareLiveDurationTimer();
|
|
920
|
-
transitionState(activeCall, "listening");
|
|
921
|
-
break;
|
|
922
|
-
case "call.silence":
|
|
923
|
-
case "call.dtmf": break;
|
|
924
|
-
case "call.ended":
|
|
925
|
-
finalizeCall({
|
|
991
|
+
if (event.transcript.trim()) effects.push(() => ctx.onCallerSpeech?.(call));
|
|
992
|
+
prepareLiveDurationTimer();
|
|
993
|
+
transitionState(activeCall, "listening");
|
|
994
|
+
break;
|
|
995
|
+
case "call.silence":
|
|
996
|
+
case "call.dtmf": break;
|
|
997
|
+
case "call.ended":
|
|
998
|
+
await finalizeCall({
|
|
999
|
+
ctx,
|
|
1000
|
+
call,
|
|
1001
|
+
preparedCall: activeCall,
|
|
1002
|
+
endReason: event.reason,
|
|
1003
|
+
endedAt: event.timestamp
|
|
1004
|
+
});
|
|
1005
|
+
publishProviderCallId(true);
|
|
1006
|
+
rememberManagerReplayKey(ctx.processedEventIds, dedupeKey);
|
|
1007
|
+
return { kind: "processed" };
|
|
1008
|
+
case "call.error":
|
|
1009
|
+
if (!event.retryable) {
|
|
1010
|
+
await finalizeCall({
|
|
926
1011
|
ctx,
|
|
927
|
-
call
|
|
928
|
-
|
|
929
|
-
|
|
1012
|
+
call,
|
|
1013
|
+
preparedCall: activeCall,
|
|
1014
|
+
endReason: "error",
|
|
1015
|
+
endedAt: event.timestamp,
|
|
1016
|
+
transcriptRejectReason: `Call error: ${event.error}`
|
|
930
1017
|
});
|
|
931
1018
|
publishProviderCallId(true);
|
|
932
1019
|
rememberManagerReplayKey(ctx.processedEventIds, dedupeKey);
|
|
933
1020
|
return { kind: "processed" };
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
endReason: "error",
|
|
940
|
-
endedAt: event.timestamp,
|
|
941
|
-
transcriptRejectReason: `Call error: ${event.error}`
|
|
942
|
-
});
|
|
943
|
-
publishProviderCallId(true);
|
|
944
|
-
rememberManagerReplayKey(ctx.processedEventIds, dedupeKey);
|
|
945
|
-
return { kind: "processed" };
|
|
946
|
-
}
|
|
947
|
-
result = {
|
|
948
|
-
kind: "processed",
|
|
949
|
-
replayable: true
|
|
950
|
-
};
|
|
951
|
-
}
|
|
952
|
-
persistCallRecord(ctx.storePath, activeCall);
|
|
953
|
-
publishProviderCallId();
|
|
954
|
-
if (shouldCommitReplayKey) rememberManagerReplayKey(ctx.processedEventIds, dedupeKey);
|
|
955
|
-
} catch (err) {
|
|
956
|
-
Object.assign(activeCall, {
|
|
957
|
-
state: previousCall.state,
|
|
958
|
-
providerCallId: previousCall.providerCallId,
|
|
959
|
-
answeredAt: previousCall.answeredAt,
|
|
960
|
-
endedAt: previousCall.endedAt,
|
|
961
|
-
endReason: previousCall.endReason
|
|
962
|
-
});
|
|
963
|
-
activeCall.transcript.length = previousCall.transcriptLength;
|
|
964
|
-
activeCall.processedEventIds.splice(0, activeCall.processedEventIds.length, ...previousCall.processedEventIds);
|
|
965
|
-
throw err;
|
|
1021
|
+
}
|
|
1022
|
+
result = {
|
|
1023
|
+
kind: "processed",
|
|
1024
|
+
replayable: true
|
|
1025
|
+
};
|
|
966
1026
|
}
|
|
967
|
-
|
|
1027
|
+
await persistCallRecord(ctx.storePath, activeCall, ctx.stateRuntime);
|
|
1028
|
+
Object.assign(call, activeCall);
|
|
1029
|
+
publishProviderCallId();
|
|
1030
|
+
if (shouldCommitReplayKey) rememberManagerReplayKey(ctx.processedEventIds, dedupeKey);
|
|
1031
|
+
if (!ctx.isStopping()) for (const effect of effects) effect();
|
|
968
1032
|
return result;
|
|
969
1033
|
}
|
|
970
1034
|
//#endregion
|
|
@@ -1002,7 +1066,49 @@ function resolveDefaultStoreBase(config, storePath) {
|
|
|
1002
1066
|
* Manages voice calls: state ownership and delegation to manager helper modules.
|
|
1003
1067
|
*/
|
|
1004
1068
|
var CallManager = class {
|
|
1005
|
-
|
|
1069
|
+
runOperation(operation) {
|
|
1070
|
+
if (this.closing) return Promise.reject(/* @__PURE__ */ new Error("Voice Call manager is stopping"));
|
|
1071
|
+
const pending = this.initialization ? this.initialization.then(() => {
|
|
1072
|
+
if (this.closing) throw new Error("Voice Call manager is stopping");
|
|
1073
|
+
return operation();
|
|
1074
|
+
}) : operation();
|
|
1075
|
+
this.trackCallWork(pending);
|
|
1076
|
+
return pending;
|
|
1077
|
+
}
|
|
1078
|
+
/** Stop is owned by runtime shutdown, after webhook and stream producers have closed. */
|
|
1079
|
+
stop() {
|
|
1080
|
+
if (this.stopPromise) return this.stopPromise;
|
|
1081
|
+
this.closing = true;
|
|
1082
|
+
for (const timers of [this.maxDurationTimers, this.notifyHangupTimers]) {
|
|
1083
|
+
for (const timer of timers.values()) clearTimeout(timer);
|
|
1084
|
+
timers.clear();
|
|
1085
|
+
}
|
|
1086
|
+
for (const waiter of this.transcriptWaiters.values()) {
|
|
1087
|
+
clearTimeout(waiter.timeout);
|
|
1088
|
+
waiter.reject(/* @__PURE__ */ new Error("Voice Call runtime stopped"));
|
|
1089
|
+
}
|
|
1090
|
+
this.transcriptWaiters.clear();
|
|
1091
|
+
this.stopPromise = (async () => {
|
|
1092
|
+
const failures = [];
|
|
1093
|
+
while (this.pendingWork.size > 0) {
|
|
1094
|
+
const results = await Promise.allSettled(this.pendingWork);
|
|
1095
|
+
for (const result of results) if (result.status === "rejected") failures.push(result.reason);
|
|
1096
|
+
}
|
|
1097
|
+
for (const timers of [this.maxDurationTimers, this.notifyHangupTimers]) {
|
|
1098
|
+
for (const timer of timers.values()) clearTimeout(timer);
|
|
1099
|
+
timers.clear();
|
|
1100
|
+
}
|
|
1101
|
+
if (failures.length > 0) throw new AggregateError(failures, "Voice Call work failed during shutdown");
|
|
1102
|
+
})();
|
|
1103
|
+
return this.stopPromise;
|
|
1104
|
+
}
|
|
1105
|
+
/** Serialize transient metadata with persisted updates without adding event-store writes. */
|
|
1106
|
+
updateCallMetadata(call, update) {
|
|
1107
|
+
return this.runOperation(() => this.mutationQueue.enqueue("state", async () => {
|
|
1108
|
+
if (this.activeCalls.get(call.callId) === call && !TerminalStates.has(call.state)) call.metadata = update(call.metadata ? { ...call.metadata } : void 0);
|
|
1109
|
+
}));
|
|
1110
|
+
}
|
|
1111
|
+
constructor(config, storePath, coreSession, stateRuntime) {
|
|
1006
1112
|
this.activeCalls = /* @__PURE__ */ new Map();
|
|
1007
1113
|
this.providerCallIdMap = /* @__PURE__ */ new Map();
|
|
1008
1114
|
this.processedEventIds = /* @__PURE__ */ new Set();
|
|
@@ -1015,25 +1121,48 @@ var CallManager = class {
|
|
|
1015
1121
|
this.maxDurationTimers = /* @__PURE__ */ new Map();
|
|
1016
1122
|
this.initialMessageInFlight = /* @__PURE__ */ new Set();
|
|
1017
1123
|
this.autoResponseOwners = /* @__PURE__ */ new WeakMap();
|
|
1124
|
+
this.mutationQueue = new KeyedAsyncQueue();
|
|
1125
|
+
this.pendingCallAdmissions = /* @__PURE__ */ new Set();
|
|
1126
|
+
this.pendingWork = /* @__PURE__ */ new Set();
|
|
1127
|
+
this.notifyHangupTimers = /* @__PURE__ */ new Map();
|
|
1128
|
+
this.initialization = null;
|
|
1129
|
+
this.closing = false;
|
|
1130
|
+
this.stopPromise = null;
|
|
1131
|
+
this.trackCallWork = (work) => {
|
|
1132
|
+
this.pendingWork.add(work);
|
|
1133
|
+
const settled = () => this.pendingWork.delete(work);
|
|
1134
|
+
work.then(settled, settled);
|
|
1135
|
+
};
|
|
1018
1136
|
this.config = config;
|
|
1019
1137
|
this.coreSession = coreSession;
|
|
1020
1138
|
this.storePath = resolveDefaultStoreBase(config, storePath);
|
|
1139
|
+
this.stateRuntime = stateRuntime;
|
|
1021
1140
|
}
|
|
1022
1141
|
/**
|
|
1023
1142
|
* Initialize the call manager with a provider.
|
|
1024
1143
|
* Verifies persisted calls with the provider and restarts timers.
|
|
1025
1144
|
*/
|
|
1026
|
-
|
|
1145
|
+
initialize(provider, webhookUrl) {
|
|
1146
|
+
if (this.closing) return Promise.reject(/* @__PURE__ */ new Error("Voice Call manager is stopping"));
|
|
1147
|
+
const pending = this.initializeFromStore(provider, webhookUrl);
|
|
1148
|
+
this.initialization = pending;
|
|
1149
|
+
this.trackCallWork(pending);
|
|
1150
|
+
pending.then(() => {
|
|
1151
|
+
if (this.initialization === pending) this.initialization = null;
|
|
1152
|
+
}, () => {});
|
|
1153
|
+
return pending;
|
|
1154
|
+
}
|
|
1155
|
+
async initializeFromStore(provider, webhookUrl) {
|
|
1027
1156
|
this.provider = provider;
|
|
1028
1157
|
this.webhookUrl = webhookUrl;
|
|
1029
1158
|
fs.mkdirSync(this.storePath, { recursive: true });
|
|
1030
|
-
const persisted = loadActiveCallsFromStore(this.storePath);
|
|
1159
|
+
const persisted = await loadActiveCallsFromStore(this.storePath, this.stateRuntime);
|
|
1160
|
+
if (this.closing) return;
|
|
1031
1161
|
this.processedEventIds = persisted.processedEventIds;
|
|
1032
1162
|
this.rejectedProviderCallIds = /* @__PURE__ */ new Map();
|
|
1033
1163
|
const verified = await this.verifyRestoredCalls(provider, persisted.activeCalls);
|
|
1034
|
-
this.
|
|
1035
|
-
|
|
1036
|
-
for (const [callId, call] of verified) if (call.providerCallId) this.providerCallIdMap.set(call.providerCallId, callId);
|
|
1164
|
+
if (this.closing) return;
|
|
1165
|
+
const timers = [];
|
|
1037
1166
|
let skippedAlreadyElapsedTimers = 0;
|
|
1038
1167
|
for (const [callId, call] of verified) {
|
|
1039
1168
|
const maxDurationAnchor = resolveRestoredMaxDurationAnchor(call);
|
|
@@ -1042,23 +1171,32 @@ var CallManager = class {
|
|
|
1042
1171
|
const maxDurationMs = resolveVoiceCallSecondsTimerDelayMs(this.config.maxDurationSeconds);
|
|
1043
1172
|
if (elapsed >= maxDurationMs) {
|
|
1044
1173
|
verified.delete(callId);
|
|
1045
|
-
if (call.providerCallId) this.providerCallIdMap.delete(call.providerCallId);
|
|
1046
1174
|
skippedAlreadyElapsedTimers += 1;
|
|
1047
1175
|
continue;
|
|
1048
1176
|
}
|
|
1049
1177
|
if (call.answeredAt === void 0) {
|
|
1050
1178
|
call.answeredAt = maxDurationAnchor;
|
|
1051
|
-
persistCallRecord(this.storePath, call);
|
|
1179
|
+
await persistCallRecord(this.storePath, call, this.stateRuntime);
|
|
1052
1180
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1181
|
+
if (this.closing) return;
|
|
1182
|
+
timers.push({
|
|
1055
1183
|
callId,
|
|
1056
|
-
|
|
1057
|
-
onTimeout: (id) => this.endCall(id, { reason: "timeout" })
|
|
1184
|
+
deadline: maxDurationAnchor + maxDurationMs
|
|
1058
1185
|
});
|
|
1059
|
-
console.log(`[voice-call] Restarted max-duration timer for restored call ${callId}`);
|
|
1060
1186
|
}
|
|
1061
1187
|
}
|
|
1188
|
+
this.activeCalls = verified;
|
|
1189
|
+
this.providerCallIdMap = /* @__PURE__ */ new Map();
|
|
1190
|
+
for (const [callId, call] of verified) if (call.providerCallId) this.providerCallIdMap.set(call.providerCallId, callId);
|
|
1191
|
+
for (const { callId, deadline } of timers) {
|
|
1192
|
+
startMaxDurationTimer({
|
|
1193
|
+
ctx: this.getContext(),
|
|
1194
|
+
callId,
|
|
1195
|
+
timeoutMs: Math.max(0, deadline - Date.now()),
|
|
1196
|
+
onTimeout: (id) => this.endCall(id, { reason: "timeout" })
|
|
1197
|
+
});
|
|
1198
|
+
console.log(`[voice-call] Restarted max-duration timer for restored call ${callId}`);
|
|
1199
|
+
}
|
|
1062
1200
|
if (skippedAlreadyElapsedTimers > 0) console.log(`[voice-call] Skipped ${skippedAlreadyElapsedTimers} restored call(s) whose max-duration timer already elapsed`);
|
|
1063
1201
|
if (verified.size > 0) console.log(`[voice-call] Restored ${verified.size} active call(s) from store`);
|
|
1064
1202
|
}
|
|
@@ -1079,32 +1217,33 @@ var CallManager = class {
|
|
|
1079
1217
|
let keptVerifiedActive = 0;
|
|
1080
1218
|
let keptUnknownProviderStatus = 0;
|
|
1081
1219
|
let keptVerificationFailures = 0;
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1220
|
+
let admissionFailure;
|
|
1221
|
+
try {
|
|
1222
|
+
for (const [callId, call] of candidates) {
|
|
1223
|
+
if (this.closing) break;
|
|
1224
|
+
if (!call.providerCallId) {
|
|
1225
|
+
skippedNoProviderCallId += 1;
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
if (now - call.startedAt > maxAgeMs) {
|
|
1229
|
+
skippedOlderThanMaxDuration += 1;
|
|
1230
|
+
markRestoredCallSkipped(call, "timeout");
|
|
1231
|
+
await persistCallRecord(this.storePath, call, this.stateRuntime);
|
|
1232
|
+
if (this.closing) break;
|
|
1233
|
+
await provider.hangupCall({
|
|
1234
|
+
callId,
|
|
1235
|
+
providerCallId: call.providerCallId,
|
|
1236
|
+
reason: "timeout"
|
|
1237
|
+
}).catch((err) => {
|
|
1238
|
+
console.warn(`[voice-call] Failed to hang up expired restored call ${callId}:`, err instanceof Error ? err.message : String(err));
|
|
1239
|
+
});
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
const task = provider.getCallStatus({ providerCallId: call.providerCallId }).then(async (result) => {
|
|
1104
1243
|
if (result.isTerminal) {
|
|
1105
1244
|
incrementRestoreStatusCount(skippedTerminalStatuses, result.status);
|
|
1106
1245
|
markRestoredCallSkipped(call, "completed");
|
|
1107
|
-
persistCallRecord(this.storePath, call);
|
|
1246
|
+
await persistCallRecord(this.storePath, call, this.stateRuntime);
|
|
1108
1247
|
} else if (result.isUnknown) {
|
|
1109
1248
|
keptUnknownProviderStatus += 1;
|
|
1110
1249
|
verified.set(callId, call);
|
|
@@ -1112,14 +1251,19 @@ var CallManager = class {
|
|
|
1112
1251
|
keptVerifiedActive += 1;
|
|
1113
1252
|
verified.set(callId, call);
|
|
1114
1253
|
}
|
|
1115
|
-
}
|
|
1254
|
+
}, () => {
|
|
1116
1255
|
keptVerificationFailures += 1;
|
|
1117
1256
|
verified.set(callId, call);
|
|
1118
|
-
})
|
|
1119
|
-
|
|
1120
|
-
|
|
1257
|
+
});
|
|
1258
|
+
task.catch(() => {});
|
|
1259
|
+
verifyTasks.push(task);
|
|
1260
|
+
}
|
|
1261
|
+
} catch (error) {
|
|
1262
|
+
admissionFailure = { error };
|
|
1121
1263
|
}
|
|
1122
|
-
await Promise.allSettled(verifyTasks
|
|
1264
|
+
const outcomes = await Promise.allSettled(verifyTasks);
|
|
1265
|
+
if (admissionFailure) throw admissionFailure.error;
|
|
1266
|
+
for (const outcome of outcomes) if (outcome.status === "rejected") throw outcome.reason;
|
|
1123
1267
|
if (skippedNoProviderCallId > 0) console.log(`[voice-call] Skipped ${skippedNoProviderCallId} restored call(s) with no providerCallId`);
|
|
1124
1268
|
if (skippedOlderThanMaxDuration > 0) console.log(`[voice-call] Skipped ${skippedOlderThanMaxDuration} restored call(s) older than maxDurationSeconds`);
|
|
1125
1269
|
for (const [status, count] of [...skippedTerminalStatuses].toSorted(([a], [b]) => a.localeCompare(b))) console.log(`[voice-call] Skipped ${count} restored call(s) with provider status: ${status}`);
|
|
@@ -1138,40 +1282,45 @@ var CallManager = class {
|
|
|
1138
1282
|
* Initiate an outbound call.
|
|
1139
1283
|
*/
|
|
1140
1284
|
async initiateCall(to, sessionKey, options) {
|
|
1141
|
-
return initiateCall(this.getContext(), to, sessionKey, options);
|
|
1285
|
+
return this.runOperation(() => initiateCall(this.getContext(), to, sessionKey, options));
|
|
1142
1286
|
}
|
|
1143
1287
|
/**
|
|
1144
1288
|
* Speak to user in an active call.
|
|
1145
1289
|
*/
|
|
1146
1290
|
async speak(callId, text, options) {
|
|
1147
|
-
return speak(this.getContext(), callId, text, options);
|
|
1291
|
+
return this.runOperation(() => speak(this.getContext(), callId, text, options));
|
|
1148
1292
|
}
|
|
1149
1293
|
/**
|
|
1150
1294
|
* Send DTMF digits to an active call.
|
|
1151
1295
|
*/
|
|
1152
1296
|
async sendDtmf(callId, digits) {
|
|
1153
|
-
return sendDtmf(this.getContext(), callId, digits);
|
|
1297
|
+
return this.runOperation(() => sendDtmf(this.getContext(), callId, digits));
|
|
1154
1298
|
}
|
|
1155
1299
|
/**
|
|
1156
1300
|
* Speak the initial message for a call (called when media stream connects).
|
|
1157
1301
|
*/
|
|
1158
1302
|
async speakInitialMessage(providerCallId) {
|
|
1159
|
-
return speakInitialMessage(this.getContext(), providerCallId);
|
|
1303
|
+
return this.runOperation(() => speakInitialMessage(this.getContext(), providerCallId));
|
|
1160
1304
|
}
|
|
1161
1305
|
/**
|
|
1162
1306
|
* Continue call: speak prompt, then wait for user's final transcript.
|
|
1163
1307
|
*/
|
|
1164
1308
|
async continueCall(callId, prompt) {
|
|
1165
|
-
return continueCall(this.getContext(), callId, prompt);
|
|
1309
|
+
return this.runOperation(() => continueCall(this.getContext(), callId, prompt));
|
|
1166
1310
|
}
|
|
1167
1311
|
/**
|
|
1168
1312
|
* End an active call.
|
|
1169
1313
|
*/
|
|
1170
1314
|
endCall(callId, options) {
|
|
1171
|
-
return endCall(this.getContext(), callId, options);
|
|
1315
|
+
return this.runOperation(() => endCall(this.getContext(), callId, options));
|
|
1172
1316
|
}
|
|
1173
1317
|
getContext() {
|
|
1174
1318
|
return {
|
|
1319
|
+
mutationQueue: this.mutationQueue,
|
|
1320
|
+
pendingCallAdmissions: this.pendingCallAdmissions,
|
|
1321
|
+
trackCallWork: this.trackCallWork,
|
|
1322
|
+
isStopping: () => this.closing,
|
|
1323
|
+
notifyHangupTimers: this.notifyHangupTimers,
|
|
1175
1324
|
activeCalls: this.activeCalls,
|
|
1176
1325
|
providerCallIdMap: this.providerCallIdMap,
|
|
1177
1326
|
processedEventIds: this.processedEventIds,
|
|
@@ -1180,6 +1329,7 @@ var CallManager = class {
|
|
|
1180
1329
|
config: this.config,
|
|
1181
1330
|
coreSession: this.coreSession,
|
|
1182
1331
|
storePath: this.storePath,
|
|
1332
|
+
stateRuntime: this.stateRuntime,
|
|
1183
1333
|
webhookUrl: this.webhookUrl,
|
|
1184
1334
|
activeTurnCalls: this.activeTurnCalls,
|
|
1185
1335
|
endCallOperations: this.endCallOperations,
|
|
@@ -1197,13 +1347,13 @@ var CallManager = class {
|
|
|
1197
1347
|
* Process a webhook event.
|
|
1198
1348
|
*/
|
|
1199
1349
|
processEvent(event) {
|
|
1200
|
-
return processEvent(this.getContext(), event);
|
|
1350
|
+
return this.runOperation(() => processEvent(this.getContext(), event));
|
|
1201
1351
|
}
|
|
1202
1352
|
createAutoResponseGuard(call) {
|
|
1203
1353
|
const owner = Symbol("automatic response");
|
|
1204
1354
|
this.autoResponseOwners.set(call, owner);
|
|
1205
1355
|
return {
|
|
1206
|
-
isCurrent: () => this.activeCalls.get(call.callId) === call && !TerminalStates.has(call.state) && this.autoResponseOwners.get(call) === owner,
|
|
1356
|
+
isCurrent: () => !this.closing && this.activeCalls.get(call.callId) === call && !TerminalStates.has(call.state) && this.autoResponseOwners.get(call) === owner,
|
|
1207
1357
|
release: () => {
|
|
1208
1358
|
if (this.autoResponseOwners.get(call) === owner) this.autoResponseOwners.delete(call);
|
|
1209
1359
|
}
|
|
@@ -1236,6 +1386,10 @@ var CallManager = class {
|
|
|
1236
1386
|
getCall(callId) {
|
|
1237
1387
|
return this.activeCalls.get(callId);
|
|
1238
1388
|
}
|
|
1389
|
+
/** Await admitted identity updates before resolving a token-bound stream's active call. */
|
|
1390
|
+
getCallForStream(callId) {
|
|
1391
|
+
return this.runOperation(() => this.mutationQueue.enqueue("state", async () => this.closing ? void 0 : this.activeCalls.get(callId)));
|
|
1392
|
+
}
|
|
1239
1393
|
/**
|
|
1240
1394
|
* Get an active call by provider call ID (e.g., Twilio CallSid).
|
|
1241
1395
|
*/
|
|
@@ -1256,13 +1410,13 @@ var CallManager = class {
|
|
|
1256
1410
|
async getCallFromMemoryOrStore(callId) {
|
|
1257
1411
|
const active = this.getCall(callId) ?? this.getCallByProviderCallId(callId);
|
|
1258
1412
|
if (active) return active;
|
|
1259
|
-
return findCallInStore(this.storePath, callId);
|
|
1413
|
+
return this.runOperation(() => findCallInStore(this.storePath, callId, this.stateRuntime));
|
|
1260
1414
|
}
|
|
1261
1415
|
/**
|
|
1262
1416
|
* Get call history (from persisted logs).
|
|
1263
1417
|
*/
|
|
1264
1418
|
async getCallHistory(limit = 50) {
|
|
1265
|
-
return getCallHistoryFromStore(this.storePath, limit);
|
|
1419
|
+
return this.runOperation(() => getCallHistoryFromStore(this.storePath, limit, this.stateRuntime));
|
|
1266
1420
|
}
|
|
1267
1421
|
};
|
|
1268
1422
|
//#endregion
|
|
@@ -2592,7 +2746,7 @@ function normalizeProviderStatus(status) {
|
|
|
2592
2746
|
/** Map terminal provider status strings to OpenClaw end reasons. */
|
|
2593
2747
|
function mapProviderStatusToEndReason(status) {
|
|
2594
2748
|
const normalized = normalizeProviderStatus(status);
|
|
2595
|
-
return TERMINAL_PROVIDER_STATUS_TO_END_REASON[normalized] ?? null;
|
|
2749
|
+
return Object.hasOwn(TERMINAL_PROVIDER_STATUS_TO_END_REASON, normalized) ? TERMINAL_PROVIDER_STATUS_TO_END_REASON[normalized] ?? null : null;
|
|
2596
2750
|
}
|
|
2597
2751
|
/** Return true when a provider status is terminal. */
|
|
2598
2752
|
function isProviderStatusTerminal(status) {
|
|
@@ -2690,19 +2844,19 @@ var StreamDisconnectGrace = class {
|
|
|
2690
2844
|
const MAX_WEBHOOK_BODY_BYTES = WEBHOOK_BODY_READ_DEFAULTS.preAuth.maxBytes;
|
|
2691
2845
|
const WEBHOOK_BODY_TIMEOUT_MS = WEBHOOK_BODY_READ_DEFAULTS.preAuth.timeoutMs;
|
|
2692
2846
|
const MISSING_REMOTE_ADDRESS_IN_FLIGHT_KEY = "__voice_call_no_remote__";
|
|
2693
|
-
const loadRealtimeTranscriptionRuntime = createLazyRuntimeModule(() => import("./realtime-transcription.runtime-CbJAs5t_.
|
|
2694
|
-
const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-
|
|
2695
|
-
function appendRecentTalkEventMetadata(
|
|
2696
|
-
const
|
|
2697
|
-
const recent = Array.isArray(
|
|
2847
|
+
const loadRealtimeTranscriptionRuntime = createLazyRuntimeModule(() => import("./realtime-transcription.runtime-CbJAs5t_.mjs"));
|
|
2848
|
+
const loadResponseGeneratorModule = createLazyRuntimeModule(() => import("./response-generator-DB1nElLO.mjs"));
|
|
2849
|
+
function appendRecentTalkEventMetadata(metadata, event) {
|
|
2850
|
+
const previous = metadata ?? {};
|
|
2851
|
+
const recent = Array.isArray(previous.recentTalkEvents) ? previous.recentTalkEvents.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
|
|
2698
2852
|
recent.push({
|
|
2699
2853
|
at: event.timestamp,
|
|
2700
2854
|
type: event.type,
|
|
2701
2855
|
sessionId: event.sessionId,
|
|
2702
2856
|
turnId: event.turnId
|
|
2703
2857
|
});
|
|
2704
|
-
|
|
2705
|
-
...
|
|
2858
|
+
return {
|
|
2859
|
+
...previous,
|
|
2706
2860
|
lastTalkEventAt: event.timestamp,
|
|
2707
2861
|
lastTalkEventType: event.type,
|
|
2708
2862
|
recentTalkEvents: recent.slice(-10)
|
|
@@ -2771,6 +2925,7 @@ var VoiceCallWebhookServer = class {
|
|
|
2771
2925
|
this.stopStaleCallReaper = null;
|
|
2772
2926
|
this.webhookInFlightLimiter = createWebhookInFlightLimiter();
|
|
2773
2927
|
this.mediaStreamHandler = null;
|
|
2928
|
+
this.streamSpeechGenerations = /* @__PURE__ */ new WeakMap();
|
|
2774
2929
|
this.realtimeHandler = null;
|
|
2775
2930
|
this.replayResponses = /* @__PURE__ */ new Map();
|
|
2776
2931
|
this.replayResponseCacheCalls = 0;
|
|
@@ -2857,8 +3012,11 @@ var VoiceCallWebhookServer = class {
|
|
|
2857
3012
|
interruptStreamReply(providerCallId, streamSid) {
|
|
2858
3013
|
const current = this.getCurrentStream(providerCallId, streamSid);
|
|
2859
3014
|
if (!current || this.shouldSuppressBargeInForInitialMessage(current.call)) return;
|
|
3015
|
+
const generation = Symbol("stream speech");
|
|
3016
|
+
this.streamSpeechGenerations.set(current.call, generation);
|
|
2860
3017
|
this.manager.invalidateAutoResponse(current.call);
|
|
2861
3018
|
current.provider.clearTtsQueue(providerCallId);
|
|
3019
|
+
return generation;
|
|
2862
3020
|
}
|
|
2863
3021
|
/**
|
|
2864
3022
|
* Initialize media streaming with the selected realtime transcription provider.
|
|
@@ -2923,12 +3081,12 @@ var VoiceCallWebhookServer = class {
|
|
|
2923
3081
|
this.logger.info(`Ignoring transcript from inactive stream ${streamSid} (${providerCallId})`);
|
|
2924
3082
|
return;
|
|
2925
3083
|
}
|
|
2926
|
-
const { call
|
|
3084
|
+
const { call } = current;
|
|
2927
3085
|
if (this.shouldSuppressBargeInForInitialMessage(call)) {
|
|
2928
3086
|
this.logger.info(`Ignoring barge transcript while initial message is still playing (${providerCallId})`);
|
|
2929
3087
|
return;
|
|
2930
3088
|
}
|
|
2931
|
-
|
|
3089
|
+
const generation = this.interruptStreamReply(providerCallId, streamSid);
|
|
2932
3090
|
const event = {
|
|
2933
3091
|
id: `stream-transcript-${Date.now()}`,
|
|
2934
3092
|
type: "call.speech",
|
|
@@ -2938,7 +3096,9 @@ var VoiceCallWebhookServer = class {
|
|
|
2938
3096
|
transcript,
|
|
2939
3097
|
isFinal: true
|
|
2940
3098
|
};
|
|
2941
|
-
this.processEventWithAutoResponse(event)
|
|
3099
|
+
this.processEventWithAutoResponse(event, () => this.streamSpeechGenerations.get(call) === generation && this.getCurrentStream(providerCallId, streamSid)?.call === call).catch((err) => {
|
|
3100
|
+
this.logger.error(`Error processing stream transcript: ${String(err)}`);
|
|
3101
|
+
});
|
|
2942
3102
|
},
|
|
2943
3103
|
onSpeechStart: (providerCallId, streamSid) => this.interruptStreamReply(providerCallId, streamSid),
|
|
2944
3104
|
onPartialTranscript: (callId, partial, streamSid) => {
|
|
@@ -2947,7 +3107,9 @@ var VoiceCallWebhookServer = class {
|
|
|
2947
3107
|
},
|
|
2948
3108
|
onTalkEvent: (providerCallId, streamSid, event) => {
|
|
2949
3109
|
const current = this.getCurrentStream(providerCallId, streamSid);
|
|
2950
|
-
if (current)
|
|
3110
|
+
if (current) this.manager.updateCallMetadata(current.call, (metadata) => this.getCurrentStream(providerCallId, streamSid) ? appendRecentTalkEventMetadata(metadata, event) : metadata).catch((error) => {
|
|
3111
|
+
this.logger.warn(`Failed to update stream call metadata: ${String(error)}`);
|
|
3112
|
+
});
|
|
2951
3113
|
},
|
|
2952
3114
|
onConnect: (callId, streamSid) => {
|
|
2953
3115
|
this.logger.info(`Media stream connected: ${callId} -> ${streamSid}`);
|
|
@@ -3001,7 +3163,10 @@ var VoiceCallWebhookServer = class {
|
|
|
3001
3163
|
return;
|
|
3002
3164
|
}
|
|
3003
3165
|
if (this.getUpgradePathname(request) === streamPath && this.mediaStreamHandler) this.mediaStreamHandler?.handleUpgrade(request, socket, head);
|
|
3004
|
-
else
|
|
3166
|
+
else {
|
|
3167
|
+
socket.once("error", () => {});
|
|
3168
|
+
rejectWebSocketUpgrade(socket, { status: 404 });
|
|
3169
|
+
}
|
|
3005
3170
|
});
|
|
3006
3171
|
this.server.on("error", (err) => {
|
|
3007
3172
|
this.server = null;
|
|
@@ -3199,7 +3364,7 @@ var VoiceCallWebhookServer = class {
|
|
|
3199
3364
|
return this.realtimeHandler.buildTwiMLPayload(req, realtimeParams);
|
|
3200
3365
|
}
|
|
3201
3366
|
const parsed = this.provider.parseWebhookEvent(ctx, { verifiedRequestKey: verification.verifiedRequestKey });
|
|
3202
|
-
if (!isReplay && this.processParsedEvents(parsed.events)) verification.releaseReplay?.();
|
|
3367
|
+
if (!isReplay && await this.processParsedEvents(parsed.events)) verification.releaseReplay?.();
|
|
3203
3368
|
return normalizeWebhookResponse(parsed);
|
|
3204
3369
|
};
|
|
3205
3370
|
if (isReplay) return await buildResponse();
|
|
@@ -3313,20 +3478,20 @@ var VoiceCallWebhookServer = class {
|
|
|
3313
3478
|
default: return false;
|
|
3314
3479
|
}
|
|
3315
3480
|
}
|
|
3316
|
-
processParsedEvents(events) {
|
|
3481
|
+
async processParsedEvents(events) {
|
|
3317
3482
|
let replayable = false;
|
|
3318
3483
|
for (const event of events) try {
|
|
3319
|
-
replayable = this.processEventWithAutoResponse(event) || replayable;
|
|
3484
|
+
replayable = await this.processEventWithAutoResponse(event) || replayable;
|
|
3320
3485
|
} catch (err) {
|
|
3321
3486
|
this.logger.error(`Error processing event ${event.type}: ${String(err)}`);
|
|
3322
3487
|
throw err;
|
|
3323
3488
|
}
|
|
3324
3489
|
return replayable;
|
|
3325
3490
|
}
|
|
3326
|
-
processEventWithAutoResponse(event) {
|
|
3327
|
-
const result = this.manager.processEvent(event);
|
|
3491
|
+
async processEventWithAutoResponse(event, isCurrent) {
|
|
3492
|
+
const result = await this.manager.processEvent(event);
|
|
3328
3493
|
if (result.kind !== "final-speech") return result.replayable === true;
|
|
3329
|
-
if (result.waiterResolved) return false;
|
|
3494
|
+
if (result.waiterResolved || isCurrent && !isCurrent()) return false;
|
|
3330
3495
|
const callMode = result.call.metadata?.mode;
|
|
3331
3496
|
if (result.call.direction !== "inbound" && callMode !== "conversation") return false;
|
|
3332
3497
|
this.handleInboundResponse(result.call.callId, result.transcript).catch((err) => {
|
|
@@ -3375,7 +3540,10 @@ var VoiceCallWebhookServer = class {
|
|
|
3375
3540
|
return false;
|
|
3376
3541
|
}
|
|
3377
3542
|
this.logger.info(`AI response queued ${callId} chars=${text.length}`);
|
|
3378
|
-
return (await this.manager.speak(callId, text, {
|
|
3543
|
+
return (await this.manager.speak(callId, text, {
|
|
3544
|
+
listenAfterPlayback: true,
|
|
3545
|
+
isCurrent: response.isCurrent
|
|
3546
|
+
})).success;
|
|
3379
3547
|
};
|
|
3380
3548
|
try {
|
|
3381
3549
|
const { generateVoiceResponse } = await loadResponseGeneratorModule();
|
|
@@ -3417,12 +3585,12 @@ const REALTIME_VOICE_CONSULT_SYSTEM_PROMPT = [
|
|
|
3417
3585
|
"Do not print secret values or dump environment variables; only check whether required configuration is present.",
|
|
3418
3586
|
"Be accurate, brief, and speakable."
|
|
3419
3587
|
].join(" ");
|
|
3420
|
-
const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-
|
|
3421
|
-
const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-
|
|
3422
|
-
const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-
|
|
3423
|
-
const loadMockProvider = createLazyRuntimeModule(() => import("./mock-
|
|
3424
|
-
const loadRealtimeVoiceRuntime = createLazyRuntimeModule(() => import("./realtime-voice.runtime-vtdCOWg-.
|
|
3425
|
-
const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-
|
|
3588
|
+
const loadTelnyxProvider = createLazyRuntimeModule(() => import("./telnyx-BY3ef4Cc.mjs"));
|
|
3589
|
+
const loadTwilioProvider = createLazyRuntimeModule(() => import("./twilio-DWZ4HVmF.mjs"));
|
|
3590
|
+
const loadPlivoProvider = createLazyRuntimeModule(() => import("./plivo-DWYNkAQ3.mjs"));
|
|
3591
|
+
const loadMockProvider = createLazyRuntimeModule(() => import("./mock-CcYEAUhV.mjs"));
|
|
3592
|
+
const loadRealtimeVoiceRuntime = createLazyRuntimeModule(() => import("./realtime-voice.runtime-vtdCOWg-.mjs"));
|
|
3593
|
+
const loadRealtimeHandler = createLazyRuntimeModule(() => import("./realtime-handler-CaoetLrM.mjs"));
|
|
3426
3594
|
function resolveVoiceCallConsultSessionKey(call) {
|
|
3427
3595
|
return resolveVoiceCallSessionKey({
|
|
3428
3596
|
config: call.config,
|
|
@@ -3447,13 +3615,6 @@ function mapVoiceCallConsultTranscript(call, context) {
|
|
|
3447
3615
|
function createRuntimeResourceLifecycle(params) {
|
|
3448
3616
|
let tunnelResult = null;
|
|
3449
3617
|
let stopPromise = null;
|
|
3450
|
-
const runStep = async (step, suppressErrors) => {
|
|
3451
|
-
if (suppressErrors) {
|
|
3452
|
-
await step().catch(() => {});
|
|
3453
|
-
return;
|
|
3454
|
-
}
|
|
3455
|
-
await step();
|
|
3456
|
-
};
|
|
3457
3618
|
return {
|
|
3458
3619
|
setTunnelResult: (result) => {
|
|
3459
3620
|
tunnelResult = result;
|
|
@@ -3462,15 +3623,20 @@ function createRuntimeResourceLifecycle(params) {
|
|
|
3462
3623
|
if (stopPromise) return stopPromise;
|
|
3463
3624
|
const suppressErrors = opts?.suppressErrors ?? false;
|
|
3464
3625
|
stopPromise = (async () => {
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3626
|
+
let failure;
|
|
3627
|
+
for (const step of [
|
|
3628
|
+
async () => {
|
|
3629
|
+
await tunnelResult?.stop();
|
|
3630
|
+
},
|
|
3631
|
+
() => cleanupTailscaleExposure(params.config),
|
|
3632
|
+
() => params.webhookServer.stop(),
|
|
3633
|
+
() => params.manager.stop()
|
|
3634
|
+
]) try {
|
|
3635
|
+
await step();
|
|
3636
|
+
} catch (error) {
|
|
3637
|
+
failure ??= { error };
|
|
3638
|
+
}
|
|
3639
|
+
if (failure && !suppressErrors) throw failure.error;
|
|
3474
3640
|
})();
|
|
3475
3641
|
return stopPromise;
|
|
3476
3642
|
}
|
|
@@ -3583,7 +3749,7 @@ async function createVoiceCallRuntime(params) {
|
|
|
3583
3749
|
if (!validation.valid) throw new Error(`Invalid voice-call config: ${validation.errors.join("; ")}`);
|
|
3584
3750
|
const provider = await resolveProvider(config);
|
|
3585
3751
|
if (stateRuntime) setVoiceCallStateRuntime({ state: stateRuntime });
|
|
3586
|
-
const manager = new CallManager(config, void 0, cfg.session);
|
|
3752
|
+
const manager = new CallManager(config, void 0, cfg.session, stateRuntime);
|
|
3587
3753
|
const realtimeVoiceRuntime = config.realtime.enabled ? await loadRealtimeVoiceRuntime() : null;
|
|
3588
3754
|
const webhookServer = new VoiceCallWebhookServer(config, manager, provider, coreConfig, fullConfig ?? coreConfig, agentRuntime, log);
|
|
3589
3755
|
if (realtimeVoiceRuntime) {
|
|
@@ -3605,12 +3771,15 @@ async function createVoiceCallRuntime(params) {
|
|
|
3605
3771
|
configuredProviderId: effectiveConfig.realtime.provider,
|
|
3606
3772
|
providerConfigs: effectiveConfig.realtime.providers,
|
|
3607
3773
|
cfg,
|
|
3608
|
-
agentId
|
|
3774
|
+
agentId,
|
|
3775
|
+
surface: "gateway-relay",
|
|
3776
|
+
useProviderDefaultModel: true
|
|
3609
3777
|
});
|
|
3610
3778
|
return {
|
|
3611
3779
|
agentId,
|
|
3612
3780
|
provider: resolved.provider,
|
|
3613
3781
|
providerConfig: resolved.providerConfig,
|
|
3782
|
+
capabilities: resolved.capabilities,
|
|
3614
3783
|
instructions: resolveRealtimeInstructions(call)
|
|
3615
3784
|
};
|
|
3616
3785
|
};
|
|
@@ -3692,7 +3861,8 @@ async function createVoiceCallRuntime(params) {
|
|
|
3692
3861
|
}
|
|
3693
3862
|
const lifecycle = createRuntimeResourceLifecycle({
|
|
3694
3863
|
config,
|
|
3695
|
-
webhookServer
|
|
3864
|
+
webhookServer,
|
|
3865
|
+
manager
|
|
3696
3866
|
});
|
|
3697
3867
|
const localUrl = await webhookServer.start();
|
|
3698
3868
|
try {
|