Files
gsc-ops-api/configs/asterisk/extensions.conf
Claude (gsc-ops-api init) 3847eb2036 Initial import — snapshot from admin host /srv/gosec/gsc-ops-api
This repo had no version control prior to this commit. The import is a
straight snapshot of the working tree at 2026-05-03; the deployed
binary on fihelvop01 was being rebuilt from this source via `make
build` + scp into place, with no upstream review path.

The snapshot already includes one in-flight fix made on 2026-05-03 to
internal/service/persona.go:GetSelfModel — the handler queried
`source` and `strength` columns plus an `is_active = true` filter on
persona.persona_commitments, none of which exist on that table (its
shape is session-bound commitments with `status`, `commitment_meta`,
etc.). The query returned a 500 every time SynapseHub bootstrapped a
persona's self-model, dropping the IdentityConstraints / Commitments /
ConscienceStandards layer from the assembled prompt. The patched
query reads existing columns only (commitment_text, commitment_type),
filters on `status='active'`, and synthesises Source="learned" /
Strength=1.0 to keep the SelfModel response shape stable for callers.

Verified live: `GET /api/v1/personas/70f7cfd9-.../self-model` now
returns 200 with `{identityConstraints:[],commitments:[],
conscienceStandards:[]}` instead of 500.

Future changes go through PRs against this repo — no more bin-only
deploys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:06:02 +02:00

181 lines
6.2 KiB
Plaintext

; Asterisk Dynamic Multi-Tenant Dialplan
; DID/route lookups via func_odbc from PostgreSQL
[general]
static=yes
writeprotect=no
clearglobalvars=no
[globals]
; Defaults — overridden per-tenant via DB lookups
DEFAULT_VM_CONTEXT=default
; ============================================================================
; [from-trunk] — Inbound DID calls from providers via Kamailio
; ============================================================================
[from-trunk]
; Inbound call: look up tenant by DID, then route
exten => _+X.,1,NoOp(Inbound trunk call to ${EXTEN})
same => n,Set(TENANT=${ODBC_TENANT_BY_DID(${EXTEN})})
same => n,GotoIf($["${TENANT}" = ""]?no-tenant,${EXTEN},1)
same => n,Set(CDR(accountcode)=${TENANT})
same => n,Set(ROUTE=${ODBC_INBOUND_ROUTE(${EXTEN})})
same => n,GotoIf($["${ROUTE}" = ""]?no-route,${EXTEN},1)
same => n,Set(DEST_TYPE=${CUT(ROUTE,|,1)})
same => n,Set(DEST_ID=${CUT(ROUTE,|,2)})
same => n,Set(DEST_DATA=${CUT(ROUTE,|,3)})
same => n,Goto(route-${DEST_TYPE},${EXTEN},1)
exten => _X.,1,NoOp(Inbound trunk call to ${EXTEN} - no + prefix)
same => n,Set(TENANT=${ODBC_TENANT_BY_DID(+${EXTEN})})
same => n,GotoIf($["${TENANT}" = ""]?no-tenant,${EXTEN},1)
same => n,Set(CDR(accountcode)=${TENANT})
same => n,Set(ROUTE=${ODBC_INBOUND_ROUTE(+${EXTEN})})
same => n,GotoIf($["${ROUTE}" = ""]?no-route,${EXTEN},1)
same => n,Set(DEST_TYPE=${CUT(ROUTE,|,1)})
same => n,Set(DEST_ID=${CUT(ROUTE,|,2)})
same => n,Set(DEST_DATA=${CUT(ROUTE,|,3)})
same => n,Goto(route-${DEST_TYPE},${EXTEN},1)
; ============================================================================
; Destination handlers — routed by destination_type from inbound_routes
; ============================================================================
; Route to extension
[route-extension]
exten => _X.,1,NoOp(Route to extension ${DEST_DATA})
same => n,Dial(PJSIP/${DEST_DATA},30,tTr)
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
same => n,VoiceMail(${DEST_DATA}@${TENANT},u)
same => n,Hangup()
same => n(busy),VoiceMail(${DEST_DATA}@${TENANT},b)
same => n,Hangup()
; Route to queue
[route-queue]
exten => _X.,1,NoOp(Route to queue ${DEST_DATA})
same => n,Queue(${DEST_DATA},tTr,,,300)
same => n,Hangup()
; Route to IVR
[route-ivr]
exten => _X.,1,NoOp(Route to IVR ${DEST_DATA})
same => n,Goto(ivr-${DEST_DATA},s,1)
same => n,Hangup()
; Route to voicemail
[route-voicemail]
exten => _X.,1,NoOp(Route to voicemail ${DEST_DATA})
same => n,Answer()
same => n,VoiceMail(${DEST_DATA}@${TENANT},u)
same => n,Hangup()
; Route to ring group
[route-ring_group]
exten => _X.,1,NoOp(Route to ring group ${DEST_DATA})
same => n,Dial(PJSIP/${DEST_DATA},30,tTr)
same => n,Hangup()
; Route to conference
[route-conference]
exten => _X.,1,NoOp(Route to conference ${DEST_DATA})
same => n,Answer()
same => n,ConfBridge(${DEST_DATA})
same => n,Hangup()
; Route to external number
[route-external]
exten => _X.,1,NoOp(Route to external number ${DEST_DATA})
same => n,Dial(PJSIP/${DEST_DATA}@kamailio-out,60,tTr)
same => n,Hangup()
; ============================================================================
; [outbound] — Outbound calls from extensions
; ============================================================================
[outbound]
; Outbound: 9 + number (strip 9, look up trunk by tenant)
exten => _9.,1,NoOp(Outbound call from ${CHANNEL(endpoint)} to ${EXTEN:1})
same => n,Set(CDR(accountcode)=${CHANNEL(accountcode)})
same => n,Set(TRUNK_INFO=${ODBC_OUTBOUND_ROUTE(${CDR(accountcode)},${EXTEN:1})})
same => n,GotoIf($["${TRUNK_INFO}" = ""]?no-trunk,${EXTEN},1)
same => n,Set(TRUNK_ID=${CUT(TRUNK_INFO,|,1)})
same => n,Dial(PJSIP/+${EXTEN:1}@kamailio-out,60,tTr)
same => n,Hangup()
; International: 00 + country code
exten => _900.,1,NoOp(International call to +${EXTEN:3})
same => n,Set(CDR(accountcode)=${CHANNEL(accountcode)})
same => n,Set(TRUNK_INFO=${ODBC_OUTBOUND_ROUTE(${CDR(accountcode)},+${EXTEN:3})})
same => n,GotoIf($["${TRUNK_INFO}" = ""]?no-trunk,${EXTEN},1)
same => n,Dial(PJSIP/+${EXTEN:3}@kamailio-out,60,tTr)
same => n,Hangup()
; ============================================================================
; [internal] — Internal extension-to-extension calls
; ============================================================================
[internal]
; Local extensions (4-digit)
exten => _XXXX,1,NoOp(Internal call to ${EXTEN})
same => n,Dial(PJSIP/${EXTEN},30,tTr)
same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
same => n,VoiceMail(${EXTEN}@${CHANNEL(accountcode)},u)
same => n,Hangup()
same => n(busy),VoiceMail(${EXTEN}@${CHANNEL(accountcode)},b)
same => n,Hangup()
; Cross-server extension calls via Kamailio
exten => _XXXXX,1,NoOp(Cross-server call to ${EXTEN})
same => n,Dial(PJSIP/${EXTEN}@kamailio-out,30,tTr)
same => n,Hangup()
; Echo test
exten => 600,1,Answer()
same => n,Echo()
same => n,Hangup()
; Music on hold test
exten => 601,1,Answer()
same => n,MusicOnHold(default,60)
same => n,Hangup()
; Check voicemail
exten => *97,1,Answer()
same => n,VoiceMailMain(${CALLERID(num)}@${CHANNEL(accountcode)})
same => n,Hangup()
; Voicemail direct deposit
exten => *98,1,Answer()
same => n,VoiceMailMain(${EXTEN}@${CHANNEL(accountcode)},s)
same => n,Hangup()
; Include outbound dialing
include => outbound
; ============================================================================
; [from-kamailio] — Entry point for Kamailio-routed calls
; ============================================================================
[from-kamailio]
include => internal
include => from-trunk
; ============================================================================
; Error handlers
; ============================================================================
[no-tenant]
exten => _X.,1,NoOp(No tenant found for DID ${EXTEN})
same => n,Log(WARNING,No tenant found for DID ${EXTEN})
same => n,Playback(ss-noservice)
same => n,Hangup()
[no-route]
exten => _X.,1,NoOp(No route configured for DID ${EXTEN})
same => n,Log(WARNING,No inbound route for DID ${EXTEN} in tenant ${TENANT})
same => n,Playback(ss-noservice)
same => n,Hangup()
[no-trunk]
exten => _X.,1,NoOp(No outbound trunk found)
same => n,Log(WARNING,No outbound trunk for ${EXTEN} in tenant ${CDR(accountcode)})
same => n,Playback(ss-noservice)
same => n,Hangup()