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>
This commit is contained in:
180
configs/asterisk/extensions.conf
Normal file
180
configs/asterisk/extensions.conf
Normal file
@@ -0,0 +1,180 @@
|
||||
; 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()
|
||||
Reference in New Issue
Block a user