@guidify-ai/vapi-studio 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/agent/AGENTS.md +42 -0
- package/agent/CLAUDE.md +15 -0
- package/agent/claude/rules/ui-and-api-identity.md +9 -0
- package/agent/claude/rules/vapi-studio-best-practices.md +36 -0
- package/agent/cursor/ui-and-api-identity.mdc +16 -0
- package/agent/cursor/vapi-studio-best-practices.mdc +43 -0
- package/dist/adapters/vapi/vapi-sse.compiler.d.ts +61 -0
- package/dist/adapters/vapi/vapi-sse.compiler.d.ts.map +1 -0
- package/dist/adapters/vapi/vapi-sse.compiler.js +396 -0
- package/dist/adapters/vapi/vapi-sse.compiler.js.map +1 -0
- package/dist/analytics/analytics-tags.d.ts +60 -0
- package/dist/analytics/analytics-tags.d.ts.map +1 -0
- package/dist/analytics/analytics-tags.js +27 -0
- package/dist/analytics/analytics-tags.js.map +1 -0
- package/dist/brain/adapters/chatgpt-brain.adapter.d.ts +27 -0
- package/dist/brain/adapters/chatgpt-brain.adapter.d.ts.map +1 -0
- package/dist/brain/adapters/chatgpt-brain.adapter.js +94 -0
- package/dist/brain/adapters/chatgpt-brain.adapter.js.map +1 -0
- package/dist/brain/adapters/claude-brain.adapter.d.ts +24 -0
- package/dist/brain/adapters/claude-brain.adapter.d.ts.map +1 -0
- package/dist/brain/adapters/claude-brain.adapter.js +96 -0
- package/dist/brain/adapters/claude-brain.adapter.js.map +1 -0
- package/dist/brain/adapters/gemini-brain.adapter.d.ts +24 -0
- package/dist/brain/adapters/gemini-brain.adapter.d.ts.map +1 -0
- package/dist/brain/adapters/gemini-brain.adapter.js +106 -0
- package/dist/brain/adapters/gemini-brain.adapter.js.map +1 -0
- package/dist/brain/adapters/grok-brain.adapter.d.ts +24 -0
- package/dist/brain/adapters/grok-brain.adapter.d.ts.map +1 -0
- package/dist/brain/adapters/grok-brain.adapter.js +90 -0
- package/dist/brain/adapters/grok-brain.adapter.js.map +1 -0
- package/dist/brain/adapters/json-llm-brain.base.d.ts +63 -0
- package/dist/brain/adapters/json-llm-brain.base.d.ts.map +1 -0
- package/dist/brain/adapters/json-llm-brain.base.js +511 -0
- package/dist/brain/adapters/json-llm-brain.base.js.map +1 -0
- package/dist/brain/adapters/mock-brain.adapter.d.ts +32 -0
- package/dist/brain/adapters/mock-brain.adapter.d.ts.map +1 -0
- package/dist/brain/adapters/mock-brain.adapter.js +201 -0
- package/dist/brain/adapters/mock-brain.adapter.js.map +1 -0
- package/dist/brain/adapters/mock-provider-brains.adapter.d.ts +22 -0
- package/dist/brain/adapters/mock-provider-brains.adapter.d.ts.map +1 -0
- package/dist/brain/adapters/mock-provider-brains.adapter.js +48 -0
- package/dist/brain/adapters/mock-provider-brains.adapter.js.map +1 -0
- package/dist/brain/brain-clarify.d.ts +75 -0
- package/dist/brain/brain-clarify.d.ts.map +1 -0
- package/dist/brain/brain-clarify.js +146 -0
- package/dist/brain/brain-clarify.js.map +1 -0
- package/dist/brain/brain-config.d.ts +20 -0
- package/dist/brain/brain-config.d.ts.map +1 -0
- package/dist/brain/brain-config.js +20 -0
- package/dist/brain/brain-config.js.map +1 -0
- package/dist/brain/brain-judge.d.ts +68 -0
- package/dist/brain/brain-judge.d.ts.map +1 -0
- package/dist/brain/brain-judge.js +111 -0
- package/dist/brain/brain-judge.js.map +1 -0
- package/dist/brain/brain-ranking.d.ts +41 -0
- package/dist/brain/brain-ranking.d.ts.map +1 -0
- package/dist/brain/brain-ranking.js +103 -0
- package/dist/brain/brain-ranking.js.map +1 -0
- package/dist/brain/brain-usage.tracker.d.ts +48 -0
- package/dist/brain/brain-usage.tracker.d.ts.map +1 -0
- package/dist/brain/brain-usage.tracker.js +106 -0
- package/dist/brain/brain-usage.tracker.js.map +1 -0
- package/dist/brain/brain.port.d.ts +63 -0
- package/dist/brain/brain.port.d.ts.map +1 -0
- package/dist/brain/brain.port.js +7 -0
- package/dist/brain/brain.port.js.map +1 -0
- package/dist/brain/brain.service.d.ts +14 -0
- package/dist/brain/brain.service.d.ts.map +1 -0
- package/dist/brain/brain.service.js +27 -0
- package/dist/brain/brain.service.js.map +1 -0
- package/dist/brain/claude-cheap-models.d.ts +18 -0
- package/dist/brain/claude-cheap-models.d.ts.map +1 -0
- package/dist/brain/claude-cheap-models.js +53 -0
- package/dist/brain/claude-cheap-models.js.map +1 -0
- package/dist/brain/gemini-cheap-models.d.ts +18 -0
- package/dist/brain/gemini-cheap-models.d.ts.map +1 -0
- package/dist/brain/gemini-cheap-models.js +53 -0
- package/dist/brain/gemini-cheap-models.js.map +1 -0
- package/dist/brain/grok-cheap-models.d.ts +18 -0
- package/dist/brain/grok-cheap-models.d.ts.map +1 -0
- package/dist/brain/grok-cheap-models.js +53 -0
- package/dist/brain/grok-cheap-models.js.map +1 -0
- package/dist/brain/llm-model-pricing.d.ts +29 -0
- package/dist/brain/llm-model-pricing.d.ts.map +1 -0
- package/dist/brain/llm-model-pricing.js +38 -0
- package/dist/brain/llm-model-pricing.js.map +1 -0
- package/dist/brain/openai-cheap-models.d.ts +34 -0
- package/dist/brain/openai-cheap-models.d.ts.map +1 -0
- package/dist/brain/openai-cheap-models.js +72 -0
- package/dist/brain/openai-cheap-models.js.map +1 -0
- package/dist/brain/prompt-injection-guard.d.ts +34 -0
- package/dist/brain/prompt-injection-guard.d.ts.map +1 -0
- package/dist/brain/prompt-injection-guard.js +109 -0
- package/dist/brain/prompt-injection-guard.js.map +1 -0
- package/dist/channel/channel-tools.d.ts +72 -0
- package/dist/channel/channel-tools.d.ts.map +1 -0
- package/dist/channel/channel-tools.js +131 -0
- package/dist/channel/channel-tools.js.map +1 -0
- package/dist/conversation/call-turn-queue.d.ts +64 -0
- package/dist/conversation/call-turn-queue.d.ts.map +1 -0
- package/dist/conversation/call-turn-queue.js +156 -0
- package/dist/conversation/call-turn-queue.js.map +1 -0
- package/dist/conversation/conversation-bootstrap.service.d.ts +60 -0
- package/dist/conversation/conversation-bootstrap.service.d.ts.map +1 -0
- package/dist/conversation/conversation-bootstrap.service.js +383 -0
- package/dist/conversation/conversation-bootstrap.service.js.map +1 -0
- package/dist/conversation/conversation-entry.d.ts +38 -0
- package/dist/conversation/conversation-entry.d.ts.map +1 -0
- package/dist/conversation/conversation-entry.js +17 -0
- package/dist/conversation/conversation-entry.js.map +1 -0
- package/dist/conversation/conversation-history.d.ts +31 -0
- package/dist/conversation/conversation-history.d.ts.map +1 -0
- package/dist/conversation/conversation-history.js +53 -0
- package/dist/conversation/conversation-history.js.map +1 -0
- package/dist/conversation/conversation-limits.d.ts +49 -0
- package/dist/conversation/conversation-limits.d.ts.map +1 -0
- package/dist/conversation/conversation-limits.js +44 -0
- package/dist/conversation/conversation-limits.js.map +1 -0
- package/dist/conversation/conversation-resume.service.d.ts +39 -0
- package/dist/conversation/conversation-resume.service.d.ts.map +1 -0
- package/dist/conversation/conversation-resume.service.js +234 -0
- package/dist/conversation/conversation-resume.service.js.map +1 -0
- package/dist/conversation/conversation-schema.d.ts +23 -0
- package/dist/conversation/conversation-schema.d.ts.map +1 -0
- package/dist/conversation/conversation-schema.js +3 -0
- package/dist/conversation/conversation-schema.js.map +1 -0
- package/dist/conversation/listen-expectation.d.ts +145 -0
- package/dist/conversation/listen-expectation.d.ts.map +1 -0
- package/dist/conversation/listen-expectation.js +219 -0
- package/dist/conversation/listen-expectation.js.map +1 -0
- package/dist/conversation/listen-timeout.d.ts +42 -0
- package/dist/conversation/listen-timeout.d.ts.map +1 -0
- package/dist/conversation/listen-timeout.js +57 -0
- package/dist/conversation/listen-timeout.js.map +1 -0
- package/dist/conversation/supervised-conversation.d.ts +64 -0
- package/dist/conversation/supervised-conversation.d.ts.map +1 -0
- package/dist/conversation/supervised-conversation.js +198 -0
- package/dist/conversation/supervised-conversation.js.map +1 -0
- package/dist/conversation/supervised-conversation.registry.d.ts +14 -0
- package/dist/conversation/supervised-conversation.registry.d.ts.map +1 -0
- package/dist/conversation/supervised-conversation.registry.js +47 -0
- package/dist/conversation/supervised-conversation.registry.js.map +1 -0
- package/dist/conversation/types.d.ts +52 -0
- package/dist/conversation/types.d.ts.map +1 -0
- package/dist/conversation/types.js +3 -0
- package/dist/conversation/types.js.map +1 -0
- package/dist/events/conversation-console.d.ts +17 -0
- package/dist/events/conversation-console.d.ts.map +1 -0
- package/dist/events/conversation-console.js +863 -0
- package/dist/events/conversation-console.js.map +1 -0
- package/dist/events/daily-log.driver.d.ts +35 -0
- package/dist/events/daily-log.driver.d.ts.map +1 -0
- package/dist/events/daily-log.driver.js +206 -0
- package/dist/events/daily-log.driver.js.map +1 -0
- package/dist/events/event.service.d.ts +24 -0
- package/dist/events/event.service.d.ts.map +1 -0
- package/dist/events/event.service.js +141 -0
- package/dist/events/event.service.js.map +1 -0
- package/dist/events/route-forensics.d.ts +38 -0
- package/dist/events/route-forensics.d.ts.map +1 -0
- package/dist/events/route-forensics.js +85 -0
- package/dist/events/route-forensics.js.map +1 -0
- package/dist/events/studio-event-bus.d.ts +17 -0
- package/dist/events/studio-event-bus.d.ts.map +1 -0
- package/dist/events/studio-event-bus.js +37 -0
- package/dist/events/studio-event-bus.js.map +1 -0
- package/dist/events/studio-event.d.ts +44 -0
- package/dist/events/studio-event.d.ts.map +1 -0
- package/dist/events/studio-event.js +27 -0
- package/dist/events/studio-event.js.map +1 -0
- package/dist/flow/condition.d.ts +35 -0
- package/dist/flow/condition.d.ts.map +1 -0
- package/dist/flow/condition.js +246 -0
- package/dist/flow/condition.js.map +1 -0
- package/dist/flow/flow-loader.d.ts +71 -0
- package/dist/flow/flow-loader.d.ts.map +1 -0
- package/dist/flow/flow-loader.js +182 -0
- package/dist/flow/flow-loader.js.map +1 -0
- package/dist/forms/form-html.d.ts +30 -0
- package/dist/forms/form-html.d.ts.map +1 -0
- package/dist/forms/form-html.js +130 -0
- package/dist/forms/form-html.js.map +1 -0
- package/dist/forms/form.tokens.d.ts +3 -0
- package/dist/forms/form.tokens.d.ts.map +1 -0
- package/dist/forms/form.tokens.js +6 -0
- package/dist/forms/form.tokens.js.map +1 -0
- package/dist/forms/form.types.d.ts +81 -0
- package/dist/forms/form.types.d.ts.map +1 -0
- package/dist/forms/form.types.js +36 -0
- package/dist/forms/form.types.js.map +1 -0
- package/dist/forms/forms.service.d.ts +52 -0
- package/dist/forms/forms.service.d.ts.map +1 -0
- package/dist/forms/forms.service.js +434 -0
- package/dist/forms/forms.service.js.map +1 -0
- package/dist/forms/noop-form-dispose.adapter.d.ts +12 -0
- package/dist/forms/noop-form-dispose.adapter.d.ts.map +1 -0
- package/dist/forms/noop-form-dispose.adapter.js +27 -0
- package/dist/forms/noop-form-dispose.adapter.js.map +1 -0
- package/dist/forms/twilio-sms-form-dispose.adapter.d.ts +33 -0
- package/dist/forms/twilio-sms-form-dispose.adapter.d.ts.map +1 -0
- package/dist/forms/twilio-sms-form-dispose.adapter.js +125 -0
- package/dist/forms/twilio-sms-form-dispose.adapter.js.map +1 -0
- package/dist/forms/twilio-sms.env.d.ts +62 -0
- package/dist/forms/twilio-sms.env.d.ts.map +1 -0
- package/dist/forms/twilio-sms.env.js +147 -0
- package/dist/forms/twilio-sms.env.js.map +1 -0
- package/dist/forms/twilio-sms.sender.d.ts +27 -0
- package/dist/forms/twilio-sms.sender.d.ts.map +1 -0
- package/dist/forms/twilio-sms.sender.js +75 -0
- package/dist/forms/twilio-sms.sender.js.map +1 -0
- package/dist/identity/email-parse.d.ts +20 -0
- package/dist/identity/email-parse.d.ts.map +1 -0
- package/dist/identity/email-parse.js +102 -0
- package/dist/identity/email-parse.js.map +1 -0
- package/dist/identity/index.d.ts +17 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +23 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/index.d.ts +108 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +300 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/integration-client.d.ts +41 -0
- package/dist/integrations/integration-client.d.ts.map +1 -0
- package/dist/integrations/integration-client.js +152 -0
- package/dist/integrations/integration-client.js.map +1 -0
- package/dist/integrations/jwt-hmac.d.ts +33 -0
- package/dist/integrations/jwt-hmac.d.ts.map +1 -0
- package/dist/integrations/jwt-hmac.js +108 -0
- package/dist/integrations/jwt-hmac.js.map +1 -0
- package/dist/intention/code-intention.d.ts +94 -0
- package/dist/intention/code-intention.d.ts.map +1 -0
- package/dist/intention/code-intention.js +89 -0
- package/dist/intention/code-intention.js.map +1 -0
- package/dist/intention/intention-constants.d.ts +37 -0
- package/dist/intention/intention-constants.d.ts.map +1 -0
- package/dist/intention/intention-constants.js +37 -0
- package/dist/intention/intention-constants.js.map +1 -0
- package/dist/intentions/standard-intentions.d.ts +26 -0
- package/dist/intentions/standard-intentions.d.ts.map +1 -0
- package/dist/intentions/standard-intentions.js +28 -0
- package/dist/intentions/standard-intentions.js.map +1 -0
- package/dist/node/agent-node.d.ts +156 -0
- package/dist/node/agent-node.d.ts.map +1 -0
- package/dist/node/agent-node.js +179 -0
- package/dist/node/agent-node.js.map +1 -0
- package/dist/node/catch-directive.d.ts +33 -0
- package/dist/node/catch-directive.d.ts.map +1 -0
- package/dist/node/catch-directive.js +41 -0
- package/dist/node/catch-directive.js.map +1 -0
- package/dist/output/conversation-output.d.ts +113 -0
- package/dist/output/conversation-output.d.ts.map +1 -0
- package/dist/output/conversation-output.js +100 -0
- package/dist/output/conversation-output.js.map +1 -0
- package/dist/persistence/conversation.entity.d.ts +27 -0
- package/dist/persistence/conversation.entity.d.ts.map +1 -0
- package/dist/persistence/conversation.entity.js +115 -0
- package/dist/persistence/conversation.entity.js.map +1 -0
- package/dist/persistence/conversation.repository.d.ts +82 -0
- package/dist/persistence/conversation.repository.d.ts.map +1 -0
- package/dist/persistence/conversation.repository.js +277 -0
- package/dist/persistence/conversation.repository.js.map +1 -0
- package/dist/persistence/project.entity.d.ts +12 -0
- package/dist/persistence/project.entity.d.ts.map +1 -0
- package/dist/persistence/project.entity.js +46 -0
- package/dist/persistence/project.entity.js.map +1 -0
- package/dist/persistence/project.repository.d.ts +17 -0
- package/dist/persistence/project.repository.d.ts.map +1 -0
- package/dist/persistence/project.repository.js +69 -0
- package/dist/persistence/project.repository.js.map +1 -0
- package/dist/persistence/provider-ingress.entity.d.ts +18 -0
- package/dist/persistence/provider-ingress.entity.d.ts.map +1 -0
- package/dist/persistence/provider-ingress.entity.js +91 -0
- package/dist/persistence/provider-ingress.entity.js.map +1 -0
- package/dist/persistence/provider-ingress.repository.d.ts +21 -0
- package/dist/persistence/provider-ingress.repository.d.ts.map +1 -0
- package/dist/persistence/provider-ingress.repository.js +76 -0
- package/dist/persistence/provider-ingress.repository.js.map +1 -0
- package/dist/studio-ui/assets/index-BGd2OhLv.js +84 -0
- package/dist/studio-ui/assets/index-BGd2OhLv.js.map +1 -0
- package/dist/studio-ui/assets/index-DnJos5x2.css +1 -0
- package/dist/studio-ui/index.html +13 -0
- package/dist/studio-ui-mount/index.d.ts +6 -0
- package/dist/studio-ui-mount/index.d.ts.map +1 -0
- package/dist/studio-ui-mount/index.js +13 -0
- package/dist/studio-ui-mount/index.js.map +1 -0
- package/dist/studio-ui-mount/resolve-studio-ui-root.d.ts +6 -0
- package/dist/studio-ui-mount/resolve-studio-ui-root.d.ts.map +1 -0
- package/dist/studio-ui-mount/resolve-studio-ui-root.js +25 -0
- package/dist/studio-ui-mount/resolve-studio-ui-root.js.map +1 -0
- package/dist/studio-ui-mount/studio-spa.controller.d.ts +18 -0
- package/dist/studio-ui-mount/studio-spa.controller.d.ts.map +1 -0
- package/dist/studio-ui-mount/studio-spa.controller.js +57 -0
- package/dist/studio-ui-mount/studio-spa.controller.js.map +1 -0
- package/dist/studio-ui-mount/studio-ui.module.d.ts +15 -0
- package/dist/studio-ui-mount/studio-ui.module.d.ts.map +1 -0
- package/dist/studio-ui-mount/studio-ui.module.js +47 -0
- package/dist/studio-ui-mount/studio-ui.module.js.map +1 -0
- package/dist/studio-ui-mount/studio-ui.tokens.d.ts +2 -0
- package/dist/studio-ui-mount/studio-ui.tokens.d.ts.map +1 -0
- package/dist/studio-ui-mount/studio-ui.tokens.js +5 -0
- package/dist/studio-ui-mount/studio-ui.tokens.js.map +1 -0
- package/dist/supervisor/supervisor-cascade.d.ts +55 -0
- package/dist/supervisor/supervisor-cascade.d.ts.map +1 -0
- package/dist/supervisor/supervisor-cascade.js +261 -0
- package/dist/supervisor/supervisor-cascade.js.map +1 -0
- package/dist/supervisor/supervisor-engine.d.ts +9 -0
- package/dist/supervisor/supervisor-engine.d.ts.map +1 -0
- package/dist/supervisor/supervisor-engine.js +64 -0
- package/dist/supervisor/supervisor-engine.js.map +1 -0
- package/dist/supervisor/supervisor-limits.d.ts +8 -0
- package/dist/supervisor/supervisor-limits.d.ts.map +1 -0
- package/dist/supervisor/supervisor-limits.js +36 -0
- package/dist/supervisor/supervisor-limits.js.map +1 -0
- package/dist/supervisor/supervisor-node-exec.d.ts +39 -0
- package/dist/supervisor/supervisor-node-exec.d.ts.map +1 -0
- package/dist/supervisor/supervisor-node-exec.js +201 -0
- package/dist/supervisor/supervisor-node-exec.js.map +1 -0
- package/dist/supervisor/supervisor-orchestration.d.ts +24 -0
- package/dist/supervisor/supervisor-orchestration.d.ts.map +1 -0
- package/dist/supervisor/supervisor-orchestration.js +395 -0
- package/dist/supervisor/supervisor-orchestration.js.map +1 -0
- package/dist/supervisor/supervisor-portal.d.ts +75 -0
- package/dist/supervisor/supervisor-portal.d.ts.map +1 -0
- package/dist/supervisor/supervisor-portal.js +320 -0
- package/dist/supervisor/supervisor-portal.js.map +1 -0
- package/dist/supervisor/supervisor-route.d.ts +53 -0
- package/dist/supervisor/supervisor-route.d.ts.map +1 -0
- package/dist/supervisor/supervisor-route.js +308 -0
- package/dist/supervisor/supervisor-route.js.map +1 -0
- package/dist/supervisor/supervisor-special-turns.d.ts +34 -0
- package/dist/supervisor/supervisor-special-turns.d.ts.map +1 -0
- package/dist/supervisor/supervisor-special-turns.js +308 -0
- package/dist/supervisor/supervisor-special-turns.js.map +1 -0
- package/dist/supervisor/supervisor.d.ts +44 -0
- package/dist/supervisor/supervisor.d.ts.map +1 -0
- package/dist/supervisor/supervisor.js +79 -0
- package/dist/supervisor/supervisor.js.map +1 -0
- package/dist/supervisor/supervisor.types.d.ts +71 -0
- package/dist/supervisor/supervisor.types.d.ts.map +1 -0
- package/dist/supervisor/supervisor.types.js +8 -0
- package/dist/supervisor/supervisor.types.js.map +1 -0
- package/dist/tasks/studio-task-queue.d.ts +93 -0
- package/dist/tasks/studio-task-queue.d.ts.map +1 -0
- package/dist/tasks/studio-task-queue.js +226 -0
- package/dist/tasks/studio-task-queue.js.map +1 -0
- package/dist/util/studio-env.d.ts +7 -0
- package/dist/util/studio-env.d.ts.map +1 -0
- package/dist/util/studio-env.js +32 -0
- package/dist/util/studio-env.js.map +1 -0
- package/dist/vapi-studio.module.d.ts +55 -0
- package/dist/vapi-studio.module.d.ts.map +1 -0
- package/dist/vapi-studio.module.js +166 -0
- package/dist/vapi-studio.module.js.map +1 -0
- package/dist/workflow/workflow-handoff.service.d.ts +29 -0
- package/dist/workflow/workflow-handoff.service.d.ts.map +1 -0
- package/dist/workflow/workflow-handoff.service.js +165 -0
- package/dist/workflow/workflow-handoff.service.js.map +1 -0
- package/dist/workflow/workflow-loader.d.ts +48 -0
- package/dist/workflow/workflow-loader.d.ts.map +1 -0
- package/dist/workflow/workflow-loader.js +87 -0
- package/dist/workflow/workflow-loader.js.map +1 -0
- package/docs/README.md +69 -0
- package/docs/assets/deterministic-assistant-flow.svg +128 -0
- package/docs/assets/vapi-studio-stack.svg +26 -0
- package/docs/best-practices/README.md +37 -0
- package/docs/best-practices/brain-and-prompt-injection.md +70 -0
- package/docs/best-practices/conversation-design.md +152 -0
- package/docs/best-practices/debugging-and-observability.md +49 -0
- package/docs/best-practices/documentation-layers.md +31 -0
- package/docs/best-practices/identity-and-pii.md +66 -0
- package/docs/best-practices/nodes-and-listens.md +116 -0
- package/docs/best-practices/ui-and-api-identity.md +51 -0
- package/docs/building-apps/creating-an-app.md +59 -0
- package/docs/building-apps/example-apps.md +23 -0
- package/docs/building-apps/overview.md +27 -0
- package/docs/getting-started/installation.md +52 -0
- package/docs/getting-started/introduction.md +23 -0
- package/docs/getting-started/quick-start.md +23 -0
- package/docs/guide/concepts.md +103 -0
- package/docs/guide/forms.md +102 -0
- package/docs/guide/handbook.md +21 -0
- package/docs/guide/introduction.md +56 -0
- package/docs/guide/module-setup.md +68 -0
- package/docs/guide/vapi-adapter.md +70 -0
- package/docs/guide/workflow-squad.md +59 -0
- package/docs/guides/agents.md +85 -0
- package/docs/guides/docker-compose.events.stub.yaml +27 -0
- package/docs/guides/documentation.md +13 -0
- package/docs/guides/extending-events.md +155 -0
- package/docs/guides/node-conventions.md +59 -0
- package/docs/guides/speckit.md +56 -0
- package/docs/reference/data-model.md +79 -0
- package/docs/reference/environment-variables.md +60 -0
- package/docs/reference/events-and-logging.md +137 -0
- package/docs/reference/flow-schema.md +79 -0
- package/docs/reference/runtime-api.md +708 -0
- package/docs/reference/security.md +41 -0
- package/docs/reference/standard-intentions.md +49 -0
- package/docs/reference/testing.md +15 -0
- package/docs/samples/events/nest-listener.example.ts +17 -0
- package/docs/samples/events/redis-bridge.example.ts +44 -0
- package/package.json +81 -0
- package/scripts/fix-access-modifiers.mjs +85 -0
- package/scripts/install-agent-refs.cjs +196 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Handbook
|
|
2
|
+
|
|
3
|
+
Runtime contracts moved out of the repository README.
|
|
4
|
+
|
|
5
|
+
## Canonical sources
|
|
6
|
+
|
|
7
|
+
| Layer | Path |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| **Entry index** | [README.md](../../README.md) — product intro, tools list, diagram, links |
|
|
10
|
+
| **Runtime API** | [runtime-api.md](../reference/runtime-api.md) — shipped behavior (update with code) |
|
|
11
|
+
| **Documentation site** | [docs/README.md](../README.md) |
|
|
12
|
+
|
|
13
|
+
## Do not
|
|
14
|
+
|
|
15
|
+
- Put application-specific agent steps or customer copy in framework docs
|
|
16
|
+
- Import `@guidify-ai/vapi-studio/src/...` — use public `index.ts` only
|
|
17
|
+
|
|
18
|
+
## Related
|
|
19
|
+
|
|
20
|
+
- [Concepts](./concepts.md)
|
|
21
|
+
- [Best practices](../best-practices/README.md)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Vapi Studio — Introduction
|
|
2
|
+
|
|
3
|
+
**Vapi Studio** is Guidify AI's code-first framework for deterministic voice agents. It ships as `@guidify-ai/vapi-studio` in `vapi-studio/`.
|
|
4
|
+
|
|
5
|
+
## What it is
|
|
6
|
+
|
|
7
|
+
A NestJS module that provides:
|
|
8
|
+
|
|
9
|
+
- **Supervised conversations** — one runtime per call, durable Postgres record
|
|
10
|
+
- **Nodes** — `AgentNode` subclasses with `before` → `listen` → `run` → `after` → `catch`
|
|
11
|
+
- **Flow YAML** — start node, intentions, portals, condition transitions
|
|
12
|
+
- **Brain port** — mock, OpenAI, or your HTTP adapter for intention scan
|
|
13
|
+
- **Output port** — `say`, `sayAndListen`, `endCall`, `transferToHuman`, `handoff`, `continueTo`, `invokeAdvertisedTool`, forms
|
|
14
|
+
- **Vapi adapter** — OpenAI-compatible Custom LLM SSE + webhook helpers
|
|
15
|
+
- **Events & logs** — call forensics (`ROUTE_DECISION`, form sendout, daily files)
|
|
16
|
+
|
|
17
|
+
## What it is not
|
|
18
|
+
|
|
19
|
+
- A no-code bot builder
|
|
20
|
+
- A hosted SaaS
|
|
21
|
+
- A place for customer-specific logic — that belongs in **your application** (separate from this package)
|
|
22
|
+
|
|
23
|
+
## How apps use it
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
VapiStudioModule.forRoot({
|
|
27
|
+
entryPoint: MyConversationEntry,
|
|
28
|
+
nodes: [
|
|
29
|
+
{ className: 'AcknowledgeNode', useClass: AcknowledgeNode },
|
|
30
|
+
{ className: 'GoodbyeNode', useClass: GoodbyeNode },
|
|
31
|
+
],
|
|
32
|
+
intentions: [NeedSmsPhoneIntention],
|
|
33
|
+
brainAdapter: ChatGptBrainAdapter,
|
|
34
|
+
brain: {
|
|
35
|
+
model: 'gpt-4.1-mini',
|
|
36
|
+
confidenceThreshold: 0.4,
|
|
37
|
+
},
|
|
38
|
+
formDisposeAdapter: LinkFormDisposeAdapter,
|
|
39
|
+
eventListeners: [MyEventBuffer],
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Applications own `config/flow.yaml`, node classes, variables/memory types, channel wiring, and `.env`. The framework owns orchestration contracts.
|
|
44
|
+
|
|
45
|
+
## Documentation map
|
|
46
|
+
|
|
47
|
+
| Depth | Where |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| Concepts | [Concepts](./concepts.md) |
|
|
50
|
+
| Wiring | [Module setup](./module-setup.md) |
|
|
51
|
+
| Forms | [Forms](./forms.md) |
|
|
52
|
+
| Vapi | [Vapi adapter](./vapi-adapter.md) |
|
|
53
|
+
| Squads | [Workflow & Squad](./workflow-squad.md) |
|
|
54
|
+
| Full API | [Runtime API](../reference/runtime-api.md) |
|
|
55
|
+
| Conversation design | [Best practices](../best-practices/README.md) |
|
|
56
|
+
| Example app | [Example apps](../building-apps/example-apps.md) (external repos) |
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Module setup
|
|
2
|
+
|
|
3
|
+
The [vapi-studio-project](https://github.com/guidify-ai/vapi-studio-project) starter already depends on `@guidify-ai/vapi-studio` and wires `VapiStudioModule.forRoot`. Use this page when extending that module options block.
|
|
4
|
+
|
|
5
|
+
## Dependency (already in the starter)
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@guidify-ai/vapi-studio": "0.1.0"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## `VapiStudioModule.forRoot` options
|
|
16
|
+
|
|
17
|
+
| Option | Required | Purpose |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| `nodes` | Yes | `{ className, useClass }[]` — every node in `flow.yaml` |
|
|
20
|
+
| `entryPoint` | Yes | `ConversationEntryPoint` — seed variables, `beforeEach` / `afterEach` |
|
|
21
|
+
| `brainAdapter` | Yes | `MockBrainAdapter`, `ChatGptBrainAdapter`, `ClaudeBrainAdapter`, `GeminiBrainAdapter`, `GrokBrainAdapter`, or custom |
|
|
22
|
+
| `brain` | No | `{ model, confidenceThreshold }` for ChatGPT adapter |
|
|
23
|
+
| `intentions` | No | `CodeIntention[]` providers (`INTENTION_CASCADE_PHASE`) |
|
|
24
|
+
| `limits` | No | Always on: `{ maxTurns?, maxDurationMs?, endMessage? }` (defaults 40 / 20m; ceilings 150 / 60m) |
|
|
25
|
+
| `eventListeners` | No | `StudioEventListener[]` |
|
|
26
|
+
| `formDisposeAdapter` | No | Delivers forms (HTML link, Studio modal, Twilio SMS, …) |
|
|
27
|
+
|
|
28
|
+
## Node registration pattern
|
|
29
|
+
|
|
30
|
+
Every node class must be:
|
|
31
|
+
|
|
32
|
+
1. A Nest `@Injectable()` extending `AgentNode<YourSchema>`
|
|
33
|
+
2. Listed in `VapiStudioModule.forRoot({ nodes: [...] })`
|
|
34
|
+
3. Referenced in `config/flow.yaml` by `className`
|
|
35
|
+
|
|
36
|
+
## Conversation entry
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
@Injectable()
|
|
40
|
+
export class MyConversationEntry implements ConversationEntryPoint<MySchema> {
|
|
41
|
+
createVariables(ctx): MyVariables { /* channel, callerId, flags */ }
|
|
42
|
+
async beforeEach(ctx) { /* CRM hydrate, feature flags — not cross-call resume */ }
|
|
43
|
+
async afterEach(ctx) { /* optional */ }
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Flow file location
|
|
48
|
+
|
|
49
|
+
`FlowLoader` reads `config/flow.yaml` relative to `CONFIG_DIR` (default: app `config/` in Docker).
|
|
50
|
+
|
|
51
|
+
## Agent scaffolding
|
|
52
|
+
|
|
53
|
+
`yarn install` in an app runs postinstall:
|
|
54
|
+
|
|
55
|
+
- `.cursor/rules/vapi-studio-best-practices.mdc`
|
|
56
|
+
- `AGENTS.md` stamped block
|
|
57
|
+
|
|
58
|
+
Manual refresh:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
INIT_CWD=$PWD node node_modules/@guidify-ai/vapi-studio/scripts/install-agent-refs.cjs
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Related
|
|
65
|
+
|
|
66
|
+
- [Concepts](./concepts.md)
|
|
67
|
+
- [Runtime API](../reference/runtime-api.md)
|
|
68
|
+
- [Creating an app](../building-apps/creating-an-app.md)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Vapi adapter
|
|
2
|
+
|
|
3
|
+
How Vapi Studio compiles node output for Vapi Custom LLM and webhooks.
|
|
4
|
+
|
|
5
|
+
## Endpoints (app-owned)
|
|
6
|
+
|
|
7
|
+
Typical PoC routes:
|
|
8
|
+
|
|
9
|
+
| Method | Path | Vapi assistant field |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `POST` | `/vapi/webhook` | **Webhook** — assistant-request, status-update, tool-calls |
|
|
12
|
+
| `POST` | `/vapi/chat/completions` | **Conversation** (Custom LLM SSE, single assistant) |
|
|
13
|
+
| `POST` | `/vapi/:moduleId/chat/completions` | **Conversation** per Squad module when workflow loaded |
|
|
14
|
+
|
|
15
|
+
See [Creating an app](../building-apps/creating-an-app.md) for route patterns in your NestJS app.
|
|
16
|
+
|
|
17
|
+
**Routing:** each starter fork is its own deploy (`PUBLIC_BASE_URL` / port). Paths are host-scoped — no project UUID segment. Vapi `assistantId` is forensics only — not used to pick the project.
|
|
18
|
+
|
|
19
|
+
## Correlation
|
|
20
|
+
|
|
21
|
+
- Vapi **call id** (`message.call.id`) maps to supervised runtime via `extractVapiCallId`
|
|
22
|
+
- Framework **conversation id** is canonical — never replace with provider id
|
|
23
|
+
- Lazy bootstrap: first Custom LLM POST may create runtime if webhook order differs
|
|
24
|
+
|
|
25
|
+
## Custom LLM SSE contract
|
|
26
|
+
|
|
27
|
+
1. Open SSE immediately (before Brain HTTP)
|
|
28
|
+
2. Run supervisor turn
|
|
29
|
+
3. Stream `say` chunks via `VapiSseCompiler`
|
|
30
|
+
4. `sayAndListen` — speak then end turn as listening
|
|
31
|
+
5. `endCall` / `transferToHuman` — OpenAI-compatible **tool calls** (names must match Vapi assistant tools)
|
|
32
|
+
6. Duplicate/stale Custom LLM POSTs: replay on that connection — never empty dead air on live stream
|
|
33
|
+
|
|
34
|
+
## Tool names (env)
|
|
35
|
+
|
|
36
|
+
| Variable | Default | Purpose |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `VAPI_END_CALL_TOOL_NAME` | `end_call_tool` | Farewell `endCall` |
|
|
39
|
+
| `VAPI_TRANSFER_CALL_TOOL_NAME` | `transfer_call` | Human transfer (`.env.example` snake_case; live may keep `transferCall`) |
|
|
40
|
+
| `VAPI_HANDOFF_TOOL_NAME` | `handoff` | Squad module handoff |
|
|
41
|
+
| `VAPI_TRANSFER_DESTINATION` | — | E.164 for transfer tool |
|
|
42
|
+
|
|
43
|
+
Function names on the Vapi assistant **must match** these exactly.
|
|
44
|
+
|
|
45
|
+
## Webhook strategies (PoC)
|
|
46
|
+
|
|
47
|
+
| `message.type` | Typical behavior |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `assistant-request` | Bootstrap + return `assistantId` or transient assistant config |
|
|
50
|
+
| `call.started` / `assistant.started` | Bootstrap (saved-assistant path) |
|
|
51
|
+
| `status-update` | Bootstrap on `in-progress`; finalize on `ended` |
|
|
52
|
+
| `tool-calls` | Still-there portal tool → StillThere portal |
|
|
53
|
+
| `user-interrupted` | Record interrupt |
|
|
54
|
+
|
|
55
|
+
Guard: reject messages missing `message.call.id` → `400`.
|
|
56
|
+
|
|
57
|
+
## Channel tools
|
|
58
|
+
|
|
59
|
+
`ctx.tools` — tools advertised on this Custom LLM request
|
|
60
|
+
`ctx.toolResults()` — results from `role: tool` messages (re-entry after tool execution)
|
|
61
|
+
|
|
62
|
+
## Operator setup
|
|
63
|
+
|
|
64
|
+
Full dashboard checklist: implement in **your application** — see [Creating an app](../building-apps/creating-an-app.md).
|
|
65
|
+
|
|
66
|
+
## Related
|
|
67
|
+
|
|
68
|
+
- [Runtime API](../reference/runtime-api.md)
|
|
69
|
+
- [Workflow & Squad](./workflow-squad.md)
|
|
70
|
+
- [Creating an app](../building-apps/creating-an-app.md)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Workflow & Squad
|
|
2
|
+
|
|
3
|
+
Optional multi-assistant deployments. Many apps use **one assistant** and `continueTo` instead.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
| Pattern | Use |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `continueTo({ nodeId })` | Same assistant, same Conversation — lane jumps |
|
|
10
|
+
| `handoff({ moduleId })` | Vapi Squad — switch assistant, shared workflow memory |
|
|
11
|
+
|
|
12
|
+
## `workflow.yaml`
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
version: 1
|
|
16
|
+
workflow:
|
|
17
|
+
id: my-workflow
|
|
18
|
+
entryModule: router
|
|
19
|
+
modules:
|
|
20
|
+
router:
|
|
21
|
+
assistantName: MyRouter
|
|
22
|
+
kind: studio
|
|
23
|
+
flowFile: modules/router.flow.yaml
|
|
24
|
+
entryNode: routerTriage
|
|
25
|
+
identity:
|
|
26
|
+
assistantName: MyIdentity
|
|
27
|
+
kind: studio
|
|
28
|
+
flowFile: modules/identity.flow.yaml
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- `WorkflowLoader` resolves module id ↔ Vapi `assistantName`
|
|
32
|
+
- `WorkflowHandoffService` enriches handoff actions, checkpoints, emits `WORKFLOW_HANDOFF`
|
|
33
|
+
- Handoff does **not** finalize the Conversation
|
|
34
|
+
|
|
35
|
+
## URLs
|
|
36
|
+
|
|
37
|
+
- `POST /vapi/:moduleId/chat/completions`
|
|
38
|
+
- Header `X-Vapi-Studio-Module` also accepted
|
|
39
|
+
|
|
40
|
+
## Vapi handoff tool
|
|
41
|
+
|
|
42
|
+
SSE must call the handoff function with **`destination` as a string** (Squad member name), e.g.:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{ "destination": "MyIdentity" }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Not `{ type, assistantName }` objects — that is assistant config, not tool-call args.
|
|
49
|
+
|
|
50
|
+
## Examples on disk (not loaded by default)
|
|
51
|
+
|
|
52
|
+
Ship example configs in your app repo (e.g. `config/workflow.squad.example.yaml`, `config/vapi-squad.example.json`).
|
|
53
|
+
|
|
54
|
+
Copy to `workflow.yaml` only when deliberately enabling Squad.
|
|
55
|
+
|
|
56
|
+
## Related
|
|
57
|
+
|
|
58
|
+
- [Runtime API](../reference/runtime-api.md) — workflow / handoff
|
|
59
|
+
- [Example apps](../building-apps/example-apps.md) — single-assistant vs squad patterns
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Agents & coding CLIs
|
|
2
|
+
|
|
3
|
+
Guidify AI is built to be **agent-friendly**: one handbook, stamped refs, and always-on rules for Cursor and Claude Code.
|
|
4
|
+
|
|
5
|
+
## Shared handbook
|
|
6
|
+
|
|
7
|
+
| Resource | Purpose |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| [`agent/AGENTS.md`](../../agent/AGENTS.md) | Canonical doctrine (tool-agnostic) |
|
|
10
|
+
| [`docs/best-practices/README.md`](../best-practices/README.md) | Which doctrine guide to open |
|
|
11
|
+
| App `AGENTS.md` | Stamped block from package postinstall |
|
|
12
|
+
|
|
13
|
+
Claude Code does **not** auto-read `AGENTS.md`. Keep the handbook under `agent/` (`AGENTS.md` + `CLAUDE.md`); put a one-line root `CLAUDE.md` that `@agent/CLAUDE.md` so Claude Code discovers it (Anthropic’s documented pattern).
|
|
14
|
+
|
|
15
|
+
This framework package does **not** keep always-on rules under `.cursor/` or `.claude/` in-repo. Edit templates under `agent/`; postinstall copies them into **consumer apps**.
|
|
16
|
+
|
|
17
|
+
## Cursor
|
|
18
|
+
|
|
19
|
+
| Resource | Purpose |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `agent/cursor/*.mdc` | Templates copied into app `.cursor/rules/` |
|
|
22
|
+
| App `.cursor/rules/vapi-studio-best-practices.mdc` | Always-on conversation rules |
|
|
23
|
+
| App `.cursor/rules/ui-and-api-identity.mdc` | UUID / label identity |
|
|
24
|
+
|
|
25
|
+
## Claude Code CLI
|
|
26
|
+
|
|
27
|
+
| Resource | Purpose |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Repo [`agent/CLAUDE.md`](../../agent/CLAUDE.md) | Framework Claude notes (`@AGENTS.md`); root `CLAUDE.md` is discovery-only |
|
|
30
|
+
| `agent/claude/rules/*.md` | Templates copied into **app** `.claude/rules/` on postinstall |
|
|
31
|
+
| App `.claude/rules/vapi-studio-best-practices.md` | Always-on conversation rules |
|
|
32
|
+
| App `.claude/rules/ui-and-api-identity.md` | UUID / label identity |
|
|
33
|
+
| App `CLAUDE.md` | Stamped import of package `agent/AGENTS.md` |
|
|
34
|
+
|
|
35
|
+
| Cursor template (`agent/cursor/`) | Claude template (`agent/claude/rules/`) |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `vapi-studio-best-practices.mdc` | `vapi-studio-best-practices.md` |
|
|
38
|
+
| `ui-and-api-identity.mdc` | `ui-and-api-identity.md` |
|
|
39
|
+
|
|
40
|
+
See [Node conventions](./node-conventions.md) for agent-step naming and lifecycle order (doctrine in [nodes-and-listens.md](../best-practices/nodes-and-listens.md)).
|
|
41
|
+
|
|
42
|
+
## Recommended workflow
|
|
43
|
+
|
|
44
|
+
1. Read app **northern stars** (app repo `README.md`).
|
|
45
|
+
2. Read `agent/AGENTS.md` / `agent/CLAUDE.md` (app: stamped `AGENTS.md` / `CLAUDE.md`).
|
|
46
|
+
3. Open matching [best-practice guide](../best-practices/README.md).
|
|
47
|
+
4. Framework changes → [Runtime API](../reference/runtime-api.md) first.
|
|
48
|
+
5. Update docs in the **same PR** as behavior.
|
|
49
|
+
|
|
50
|
+
## Decision tree: which guide?
|
|
51
|
+
|
|
52
|
+
| Changing… | Read |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| Bot copy / CTA | conversation-design.md |
|
|
55
|
+
| Soft affirmatives / silent handoffs / lane choice | conversation-design.md (+ nodes-and-listens.md) |
|
|
56
|
+
| Mad callers (one re-engage → human) | nodes-and-listens.md · conversation-design.md |
|
|
57
|
+
| New agent step / listen / extract | nodes-and-listens.md |
|
|
58
|
+
| Phone, email, forms | identity-and-pii.md |
|
|
59
|
+
| Studio FE / Nest DTO identity | ui-and-api-identity.md |
|
|
60
|
+
| Analytics funnels / tags | debugging-and-observability.md · events-and-logging.md |
|
|
61
|
+
| Logs / events | debugging-and-observability.md |
|
|
62
|
+
| Limits / public API / env | [Runtime API](../reference/runtime-api.md) |
|
|
63
|
+
| README placement | documentation-layers.md |
|
|
64
|
+
|
|
65
|
+
## Postinstall
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
INIT_CWD=$PWD node node_modules/@guidify-ai/vapi-studio/scripts/install-agent-refs.cjs
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Refreshes **in the consumer app**:
|
|
72
|
+
|
|
73
|
+
- `.cursor/rules/vapi-studio-best-practices.mdc` + `ui-and-api-identity.mdc`
|
|
74
|
+
- `.claude/rules/vapi-studio-best-practices.md` + `ui-and-api-identity.md`
|
|
75
|
+
- stamped blocks in app `AGENTS.md` and `CLAUDE.md`
|
|
76
|
+
|
|
77
|
+
Sources: `agent/cursor/` and `agent/claude/rules/` inside the package. Does not wipe custom sections outside the stamped markers.
|
|
78
|
+
|
|
79
|
+
## SpecKit
|
|
80
|
+
|
|
81
|
+
Greenfield features: [SpecKit guide](./speckit.md) (`.specify/` in this repo).
|
|
82
|
+
|
|
83
|
+
## Related
|
|
84
|
+
|
|
85
|
+
- [Documentation layers](./documentation.md)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Optional compose fragment — Redis + a consumer process only.
|
|
2
|
+
# Use the app's existing `postgres` service; create a second database on it
|
|
3
|
+
# instead of a second Postgres container. Wire your own consumer image/env.
|
|
4
|
+
#
|
|
5
|
+
# EVENT_STORE_DATABASE_URL=postgres://studio:studio@postgres:5432/app_events
|
|
6
|
+
|
|
7
|
+
services:
|
|
8
|
+
redis:
|
|
9
|
+
image: redis:7-alpine
|
|
10
|
+
ports:
|
|
11
|
+
- "${STUDIO_EVENTS_REDIS_HOST_PORT:-16379}:6379"
|
|
12
|
+
healthcheck:
|
|
13
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
14
|
+
interval: 5s
|
|
15
|
+
timeout: 3s
|
|
16
|
+
retries: 10
|
|
17
|
+
|
|
18
|
+
event-consumer:
|
|
19
|
+
image: ${STUDIO_EVENT_CONSUMER_IMAGE:-studio-event-consumer:local}
|
|
20
|
+
environment:
|
|
21
|
+
DATABASE_URL: ${EVENT_STORE_DATABASE_URL:-postgres://studio:studio@postgres:5432/app_events}
|
|
22
|
+
STUDIO_EVENTS_REDIS_URL: ${STUDIO_EVENTS_REDIS_URL:-redis://redis:6379}
|
|
23
|
+
STUDIO_EVENTS_REDIS_STREAM: ${STUDIO_EVENTS_REDIS_STREAM:-studio:events}
|
|
24
|
+
depends_on:
|
|
25
|
+
redis:
|
|
26
|
+
condition: service_healthy
|
|
27
|
+
restart: unless-stopped
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Documentation map
|
|
2
|
+
|
|
3
|
+
| Layer | Location | Purpose |
|
|
4
|
+
| --- | --- | --- |
|
|
5
|
+
| **Package README** | `README.md` | Install + product framing |
|
|
6
|
+
| **Doc site** | `docs/README.md` | Navigation |
|
|
7
|
+
| **Runtime handbook** | `docs/reference/runtime-api.md` | Shipped contracts |
|
|
8
|
+
| **Best practices** | `docs/best-practices/` | Conversation doctrine |
|
|
9
|
+
| **Building apps** | `docs/building-apps/` | Scaffold apps that depend on the package |
|
|
10
|
+
| **Example apps** | `docs/building-apps/example-apps.md` | Links to external sample repos |
|
|
11
|
+
| **App northern stars** | *your app* `README.md` | Goals, triggers — no flow dumps |
|
|
12
|
+
|
|
13
|
+
See [documentation layers](../best-practices/documentation-layers.md).
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Extending Studio events
|
|
2
|
+
|
|
3
|
+
Vapi Studio is **event-driven**. Every meaningful turn can emit structured events
|
|
4
|
+
on an in-process Node bus. The OSS package does **not** lock you into a single
|
|
5
|
+
sink — you attach your own listeners (the same way you attach Postgres).
|
|
6
|
+
|
|
7
|
+
Guidify companion tools (e.g. analytics) subscribe the same way: listen in-process,
|
|
8
|
+
optionally publish to a broker + store. Your app can too.
|
|
9
|
+
|
|
10
|
+
## Mental model
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
Node / Supervisor / Forms / Integrations
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
EventService.emit / persist / persistAnalyticsTag
|
|
17
|
+
│
|
|
18
|
+
├── console + daily file logs
|
|
19
|
+
├── onStudioEvent(...) ← process-wide Node EventEmitter
|
|
20
|
+
└── Nest eventListeners[] ← DI / StudioEventListener
|
|
21
|
+
│
|
|
22
|
+
▼ (your code)
|
|
23
|
+
Redis Streams / queue / HTTP / warehouse / CRM
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Postgres** = durable conversations. **Event bus** = explainability + side effects.
|
|
27
|
+
Neither is Guidify-hosted — both run on your infra.
|
|
28
|
+
|
|
29
|
+
`EventService.log(...)` is **console/file only** — it does **not** hit `onStudioEvent`.
|
|
30
|
+
Use `persist` / `emit` / `persistAnalyticsTag` for anything listeners must see.
|
|
31
|
+
|
|
32
|
+
## Two listener styles
|
|
33
|
+
|
|
34
|
+
### 1. `onStudioEvent` (any process code)
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// main.ts — register BEFORE app.listen
|
|
38
|
+
import { onStudioEvent, STUDIO_EVENTS } from '@guidify-ai/vapi-studio';
|
|
39
|
+
|
|
40
|
+
onStudioEvent(async (event) => {
|
|
41
|
+
if (event.type === 'ROUTE_DECISION') {
|
|
42
|
+
// why this node ran
|
|
43
|
+
}
|
|
44
|
+
if (event.type === STUDIO_EVENTS.OUTBOUND_NOTIFICATION) {
|
|
45
|
+
// SMS / outbound channel
|
|
46
|
+
}
|
|
47
|
+
if (event.type === 'ANALYTICS_TAG') {
|
|
48
|
+
// funnel milestone — payload.tag
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Nest `eventListeners`
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { Injectable } from '@nestjs/common';
|
|
57
|
+
import {
|
|
58
|
+
VapiStudioModule,
|
|
59
|
+
type StudioEvent,
|
|
60
|
+
type StudioEventListener,
|
|
61
|
+
} from '@guidify-ai/vapi-studio';
|
|
62
|
+
|
|
63
|
+
@Injectable()
|
|
64
|
+
export class AuditEventListener implements StudioEventListener {
|
|
65
|
+
async handle(event: StudioEvent): Promise<void> {
|
|
66
|
+
// DI-friendly: inject repos, queues, …
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
VapiStudioModule.forRoot({
|
|
71
|
+
// …
|
|
72
|
+
eventListeners: [AuditEventListener],
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Both styles are first-class.
|
|
77
|
+
|
|
78
|
+
## Sample: Redis Streams broker (like analytics)
|
|
79
|
+
|
|
80
|
+
Framework does **not** open Redis for you. Your app bridges the bus — same
|
|
81
|
+
optional infra pattern as a second Postgres database for an event store.
|
|
82
|
+
|
|
83
|
+
Compose stub: [`docker-compose.events.stub.yaml`](./docker-compose.events.stub.yaml)
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
// src/events/redis-event-bridge.ts — register from main.ts
|
|
87
|
+
import { onStudioEvent, type StudioEvent } from '@guidify-ai/vapi-studio';
|
|
88
|
+
import Redis from 'ioredis'; // your dependency
|
|
89
|
+
|
|
90
|
+
const url = process.env.STUDIO_EVENTS_REDIS_URL?.trim();
|
|
91
|
+
const stream = process.env.STUDIO_EVENTS_REDIS_STREAM?.trim() || 'studio:events';
|
|
92
|
+
|
|
93
|
+
export function registerRedisEventBridge(): void {
|
|
94
|
+
if (!url) {
|
|
95
|
+
console.warn('[events] STUDIO_EVENTS_REDIS_URL unset — bus stays in-process only');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const redis = new Redis(url);
|
|
99
|
+
onStudioEvent(async (event: StudioEvent) => {
|
|
100
|
+
await redis.xadd(
|
|
101
|
+
stream,
|
|
102
|
+
'*',
|
|
103
|
+
'type', event.type,
|
|
104
|
+
'ts', event.ts,
|
|
105
|
+
'conversationId', event.conversationId ?? '',
|
|
106
|
+
'providerCallId', event.providerCallId ?? '',
|
|
107
|
+
'payload', JSON.stringify(event.payload ?? {}),
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
// main.ts
|
|
115
|
+
import { registerRedisEventBridge } from './events/redis-event-bridge';
|
|
116
|
+
|
|
117
|
+
registerRedisEventBridge();
|
|
118
|
+
// … NestFactory.create / listen
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A separate **consumer** process (analytics, warehouse loader, …) reads the stream
|
|
122
|
+
and writes Postgres / ClickHouse / whatever you own. Env presets:
|
|
123
|
+
|
|
124
|
+
| Variable | Purpose |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `STUDIO_EVENTS_REDIS_URL` | Broker URL (app-owned) |
|
|
127
|
+
| `STUDIO_EVENTS_REDIS_STREAM` | Stream name (default `studio:events`) |
|
|
128
|
+
| `EVENT_STORE_DATABASE_URL` | Optional durable store for the consumer |
|
|
129
|
+
|
|
130
|
+
## Sample: emit your own domain events
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// inside a Node
|
|
134
|
+
await ctx.events.persist(ctx.conversationId, 'LEAD_QUALIFIED', {
|
|
135
|
+
companyName: ctx.memory.companyName,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// funnel milestone (payload.tag only — never payload.funnels)
|
|
139
|
+
await ctx.events.persistAnalyticsTag(ctx.conversationId, 'quote_requested');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## What events exist?
|
|
143
|
+
|
|
144
|
+
Canonical catalog: [Events & logging — Event catalog](../reference/events-and-logging.md#event-catalog).
|
|
145
|
+
|
|
146
|
+
Typed constants exported as `STUDIO_EVENTS` (integrations, outbound, tasks). Many
|
|
147
|
+
forensic types are string names (`ROUTE_DECISION`, `FORM_SENDOUT`, …) — filter on
|
|
148
|
+
`event.type`.
|
|
149
|
+
|
|
150
|
+
## Related
|
|
151
|
+
|
|
152
|
+
- [Events & logging](../reference/events-and-logging.md)
|
|
153
|
+
- [Environment variables](../reference/environment-variables.md) · [`.env.example`](../../.env.example)
|
|
154
|
+
- [Debugging and observability](../best-practices/debugging-and-observability.md)
|
|
155
|
+
- [Data model](../reference/data-model.md)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Node conventions
|
|
2
|
+
|
|
3
|
+
Human-readable summary of agent-step conventions. Doctrine: [nodes-and-listens.md](../best-practices/nodes-and-listens.md).
|
|
4
|
+
|
|
5
|
+
## Intention naming
|
|
6
|
+
|
|
7
|
+
- **Actions:** `is{VerbPast}…` — `isCollectedFirstName`, `isConfirmedAddressMatch`
|
|
8
|
+
- **Polarity:** `studio.isPositive`, `studio.isNegative`
|
|
9
|
+
- **Framework standard:** `studio.isGoodbye`, `studio.isStillThere`, …
|
|
10
|
+
|
|
11
|
+
## Node method order
|
|
12
|
+
|
|
13
|
+
Declare in source in **runtime call order**:
|
|
14
|
+
|
|
15
|
+
1. `before()` — CAN gate **and** async prep (auth warm, JWT spawn, lookups needed to authorize). Prefer non-blocking spawn when speech must not wait; `await` only for the gate.
|
|
16
|
+
2. `listen()` — register extract / intentions (before speech completes); no I/O
|
|
17
|
+
3. `run()` — speech + one terminal output only; do not overload with integrations that belong in `before()` / `after()`
|
|
18
|
+
4. `after()` — teardown / non-speech side effects after the terminal action (no TTS)
|
|
19
|
+
5. `catch()` — only when overridden
|
|
20
|
+
|
|
21
|
+
Doctrine: [nodes-and-listens.md](../best-practices/nodes-and-listens.md#prefer-before--after-for-async-work).
|
|
22
|
+
|
|
23
|
+
## Brain (live ChatGPT path)
|
|
24
|
+
|
|
25
|
+
- No Custom LLM listen-hold before scan
|
|
26
|
+
- Scan abort ≤ 3s
|
|
27
|
+
- Target first speech < 1.5s after request
|
|
28
|
+
- Model in `VapiStudioModule.forRoot({ brain })` or `brain.config.ts` — not `.env`
|
|
29
|
+
- `interruptible: false` — queue overlapping POSTs until 3s silence, then one scan
|
|
30
|
+
- End of call: `BRAIN_COST_SUMMARY` when usage tracked
|
|
31
|
+
|
|
32
|
+
## Listed choices
|
|
33
|
+
|
|
34
|
+
After numbered options, always the same closing question pattern via `listedChoiceQuestion` / `listedChoiceListen` — pick N or neither.
|
|
35
|
+
|
|
36
|
+
Soft affirmatives that do **not** pick N (“yeah, why not”, bare “sure”) are not a choice — re-ask which option with cheap `resolveIntention`; do not send them to Brain/unknown ([conversation-design.md](../best-practices/conversation-design.md#do-not-auto-pick-lanes)).
|
|
37
|
+
|
|
38
|
+
## Integrations
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
await ctx.integrations.request({
|
|
42
|
+
name: 'my-api',
|
|
43
|
+
url: 'https://…',
|
|
44
|
+
body: { … },
|
|
45
|
+
secretEnvKey: 'MY_HMAC_SECRET', // env KEY name, not the secret value
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
JWT HS256 in `x-signature`. Events: `INTEGRATION_REQUEST`, `INTEGRATION_RESPONSE`, `INTEGRATION_ERROR`.
|
|
50
|
+
|
|
51
|
+
## Shit in, shit out
|
|
52
|
+
|
|
53
|
+
Do not add Node logic for Vapi stale Custom LLM repeats or “caller repeating previous field.” Unknown / re-ask is enough.
|
|
54
|
+
|
|
55
|
+
## Related
|
|
56
|
+
|
|
57
|
+
- [Standard intentions](../reference/standard-intentions.md)
|
|
58
|
+
- [Nodes and listens (doctrine)](../best-practices/nodes-and-listens.md)
|
|
59
|
+
- [Agents](./agents.md)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SpecKit
|
|
2
|
+
|
|
3
|
+
Workspace tooling for specify → plan → tasks → implement workflows under `specs/`.
|
|
4
|
+
|
|
5
|
+
Config, templates, and scripts live under **`.specify/`** (not under framework-local `.cursor/` — that tree was removed from this package).
|
|
6
|
+
|
|
7
|
+
## Workflows
|
|
8
|
+
|
|
9
|
+
| Workflow | Use |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| specify | Create/update feature spec from description |
|
|
12
|
+
| clarify | Targeted clarification questions → spec |
|
|
13
|
+
| plan | Generate plan from spec template |
|
|
14
|
+
| tasks | Generate `tasks.md` from plan |
|
|
15
|
+
| analyze | Cross-artifact consistency check |
|
|
16
|
+
| checklist | Custom checklist from requirements |
|
|
17
|
+
| implement | Execute tasks from `tasks.md` |
|
|
18
|
+
| converge | Find unbuilt work → append tasks |
|
|
19
|
+
| constitution | Update constitution |
|
|
20
|
+
| taskstoissues | Convert tasks to GitHub issues |
|
|
21
|
+
|
|
22
|
+
Invoke via SpecKit / Specify CLI against `.specify/` (see `.specify/workflows/`, `.specify/templates/`). IDE skills (`.cursor/skills/speckit-*`, `.claude/skills/speckit-*`) are **not** shipped in this framework package — SpecKit here is `.specify/` only. Reinstall SpecKit skills into a local checkout if you need IDE skill discovery.
|
|
23
|
+
|
|
24
|
+
## Artifact layout
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
specs/<feature-id>/
|
|
28
|
+
├── spec.md
|
|
29
|
+
├── plan.md
|
|
30
|
+
├── tasks.md
|
|
31
|
+
├── research.md
|
|
32
|
+
├── quickstart.md
|
|
33
|
+
├── data-model.md
|
|
34
|
+
└── contracts/
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Templates: `.specify/templates/`
|
|
38
|
+
|
|
39
|
+
## When to use SpecKit vs best practices
|
|
40
|
+
|
|
41
|
+
| Work | Start here |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Day-to-day bot nodes / copy | [Best practices](../best-practices/README.md) + [Agents](./agents.md) |
|
|
44
|
+
| Greenfield framework feature | SpecKit specify → plan → tasks |
|
|
45
|
+
| Compliance check | SpecKit analyze after tasks |
|
|
46
|
+
|
|
47
|
+
## Historical artifacts
|
|
48
|
+
|
|
49
|
+
Older SpecKit PoC dumps may exist under a local `archive/` folder (gitignored — not in the repo). Prefer current `docs/` and `docs/reference/runtime-api.md`.
|
|
50
|
+
|
|
51
|
+
**Authority:** root `README.md` and `docs/` over SpecKit contracts.
|
|
52
|
+
|
|
53
|
+
## Related
|
|
54
|
+
|
|
55
|
+
- [Constitution](../reference/principles.md)
|
|
56
|
+
- [Documentation layers](./documentation.md)
|