asmpkg / guiche
Core PHP para assistentes conversacionais orientados a Tools, Plugins, estado, segurança, persistência e runtime de conversação.
Requires
- php: ^8.4
- vlucas/phpdotenv: ^5.6
Requires (Dev)
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v1.6.1
- v1.6.0
- v1.5.0
- v1.4.0
- v1.3.0
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.2
- v1.0.1
- v1.0.0
- v0.9.0
- v0.8.0
- v0.7.0
- v0.6.0
- v0.5.1
- v0.5.0
- v0.4.0
- v0.3.0
- v0.2.0
- dev-feature/v1.5.0-loaders-multitenant
- dev-feature/v1.1.0-contexto-dinamico-multitenant
- dev-feature/v1.0.1-clinical-chat-ci
- dev-hotfix/v1.0.1-clinical-chat
- dev-feature/v1.0-stable
- dev-feature/v0.9-release-candidate
- dev-feature/v0.8-clinical-example
- dev-feature/v0.7-developer-experience
- dev-feature/v0.6-test-suite-static-analysis
- dev-feature/v0.5.1-conversation-runtime
- dev-feature/v0.5-persistence-observability
- dev-feature/v0.4-safety-layer
This package is auto-updated.
Last update: 2026-11-01 05:57:20 UTC
README
Guichê é um Core PHP para construir assistentes conversacionais orientados a Tools, Plugins, estado, segurança, persistência e runtime de conversação sem acoplar o Core a um domínio específico.
O projeto evoluiu de um piloto clínico para uma biblioteca reutilizável. Domínios como clínica, atendimento, vendas ou suporte são integrações construídas sobre os mesmos contratos públicos do Core.
Versão documentada: v1.6.1 — Stable
O que o Guichê oferece
A linha v1 reúne:
- Tools e Plugins extensíveis;
- estado estruturado e persistência por
ContextStoreInterface; - contexto confiável multi-tenant;
bindIdentity()para identidade externa autenticada;- Trusted Parameter Binding;
- ToolPolicy e hard Execution Gate;
- proteção de WRITE, idempotência e Result Projection;
- prompts globais, dinâmicos e por tenant;
- loaders de Tools/Plugins e DI explícita;
- Operational State;
- lifecycle de sessão com TTL;
- Conversation Runtime, scheduler e follow-up experimental;
- provider OpenAI Responses;
- Prompt Caching otimizado na v1.6.1.
Requisitos
- PHP
^8.4; - Composer;
- uma chave de API para o provider usado em conversas reais.
O exemplo oficial usa OpenAI, mas os contratos do Core não dependem de um domínio específico.
O quality gate e os testes automatizados não dependem de OpenAI real, banco real, Clinsoft, Internet ou side effects reais.
Instalação
Instale a linha estável atual:
composer require asmpkg/guiche:^1.6
Para trabalhar diretamente com o clone:
git clone git@github.com:alexsmonte/guiche.git guiche
cd guiche
composer install
Quick Start — primeira conversa
1. Crie um projeto vazio
mkdir meu-guiche
cd meu-guiche
composer require asmpkg/guiche:^1.6
2. Inicialize o projeto
vendor/bin/guiche init
O comando cria, sem sobrescrever arquivos existentes:
.env
guiche.prompt.md # compatibilidade
guiche.php # Composition Root
prompts/
└── comportamento.md # prompt global
src/
├── Tool/
└── Plugin/
storage/
└── conversations/
Quando existe composer.json, o init também garante o mapeamento PSR-4:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
Se o prefixo tiver sido adicionado, regenere o autoload:
composer dump-autoload
Um App\\ já existente com outro caminho é preservado e reportado pelo doctor, em vez de ser sobrescrito silenciosamente.
3. Configure o provider
Edite .env:
AI_API_KEY=sua-chave AI_MODEL=gpt-5.6-luna
AI_MODEL possui valor padrão. Por compatibilidade, OPENAI_API_KEY e OPENAI_MODEL continuam aceitos como aliases legados.
4. Personalize o prompt
O padrão atual usa:
prompts/comportamento.md
Para um tenant confiável acme, você pode adicionar:
prompts/acme.md
A composição será:
prompts/comportamento.md
+
prompts/acme.md
A prioridade de resolução é:
$app['prompt_resolver']
↓
GUICHE_PROMPT_FILE
↓
GUICHE_PROMPT
↓
prompts/comportamento.md + prompts/{tenant_id}.md
↓
guiche.prompt.md legado
O tenant_id precisa vir do contexto confiável da sessão. Mensagem do usuário, state livre e argumentos de Tool não podem selecionar o arquivo de tenant.
5. Verifique o ambiente
vendor/bin/guiche doctor
O doctor valida PHP, extensões, .env, configuração de IA, prompt global, App\\ => src/, diretórios de loaders e storage/conversations, sem fazer chamada de rede ao provider.
6. Converse
Modo interativo:
vendor/bin/guiche chat
Mensagem única:
vendor/bin/guiche chat "Olá, tudo bem?"
Sessão explícita:
vendor/bin/guiche chat --session=cliente-123 "Olá"
No modo interativo:
/contextmostra o contexto salvo;/usagemostra o uso registrado na sessão;/toolsmostra as Tools disponíveis;/resetreinicia a sessão;/sairencerra a CLI.
Esses comandos são tratados localmente e não são enviados à IA.
Também é possível consultar usage fora do chat:
vendor/bin/guiche usage --session=cliente-123
Como o Guichê funciona
Fluxo conceitual simplificado:
Host / aplicação
↓
Guiche
↓
Prompt + contexto estruturado + ToolPolicy
↓
AiProvider
↓
Tool call
↓
ExecutionGate
↓
Tool
↓
State / Result Projection / continuação
A chamada de uma Tool pela IA não equivale a autorização de execução. O ExecutionGate continua sendo a autoridade final antes do side effect real.
Conceitos principais
Tool
Uma Tool implementa ToolInterface e declara:
- nome;
- descrição;
- schema de argumentos;
- execução.
Tools podem ser classificadas como READ ou WRITE. Operações de escrita possuem requisitos adicionais de segurança e idempotência.
Quando a execução depende de contexto confiável da sessão, a Tool pode implementar ContextAwareToolInterface.
Plugin
Um Plugin implementa PluginInterface e registra capacidades pelo GuicheBuilder, como:
- Tools;
- Presenters;
- State Manager;
- Policies;
- instruction fragments;
- completion guards;
- result projections.
State e Operational State
O contexto estruturado da conversa pode ser persistido por uma implementação de ContextStoreInterface.
O Core não precisa conhecer detalhes do domínio para manter:
- intenção;
- estado operacional;
- histórico de Tools;
- lifecycle da sessão;
- usage;
- contexto confiável de execução.
O domínio continua responsável por interpretar seu próprio estado por meio de Plugins e State Managers.
Contexto confiável e multi-tenant
O fluxo recomendado é:
SESSION
↓
execution_context.identity
↓
TenantResolver
↓
execution_context.tenant_id
↓
ToolExecutionContext
↓
ContextAwareToolInterface::executeWithContext()
tenant_id não deve ser aceito da IA como fonte de autoridade.
Para aplicações externas, vincule a identidade autenticada antes de processar a mensagem:
$guiche->bindIdentity( $sessionId, [ 'provider' => 'custom-crm', 'account_id' => $accountId, 'conversation_id' => $conversationId, ] ); $response = $guiche->handle( $sessionId, $message );
bindIdentity() é write-once por sessão, idempotente para o mesmo binding e falha fechado em tentativa de troca.
A autenticação do request/webhook pertence ao host. Somente depois de estabelecer confiança o host deve chamar bindIdentity().
Veja:
docs/multitenancy.md;docs/trusted-external-identity.md;examples/chatwoot/;examples/external-host/.
Prompts e Composition Root
O vendor/bin/guiche init cria guiche.php, o Composition Root do consumidor:
$factory = require __DIR__ . '/guiche.php'; $guiche = $factory();
Fontes públicas de prompt incluem:
StaticPromptResolver;FilePromptResolver;CallbackPromptResolver;FallbackPromptResolver;TenantPromptResolver;CompositePromptResolver.
Fluxo confiável:
SESSION
↓
bindIdentity()
↓
TenantResolver
↓
tenant_id
↓
PromptContext
↓
PromptResolver
↓
prompt
Mensagem do usuário, state livre e argumentos de Tool não são fonte de autoridade para selecionar tenant ou prompt.
Veja:
docs/dynamic-prompts.md;examples/prompt-sources/;examples/framework-integration/.
Tools, Plugins, loaders e DI
A API explícita permanece disponível:
$builder->registerTool(new MinhaTool()); $builder->registerPlugin(new MeuPlugin());
Também é possível usar loaders por convenção:
$builder ->loadTools('InformacoesEmpresa', 'ConsultarPedido') ->loadPlugins('Clinica');
Convenções:
InformacoesEmpresa
→ App\Tool\InformacoesEmpresaTool
Clinica
→ App\Plugin\ClinicaPlugin
FQCN também é aceito.
Não existe scanning de diretório, glob, require dinâmico ou autowiring recursivo.
Dependências precisam ser registradas explicitamente:
$builder ->setService(MinhaConexao::class, $conexao) ->loadTool('InformacoesEmpresa');
No Composition Root:
$guiche = $factory([ 'services' => [ MinhaConexao::class => $conexao, ], 'tools' => [ 'InformacoesEmpresa', $toolLegada, ], 'plugins' => [ 'Clinica', $pluginLegado, ], ]);
GuicheBuilder::loadCapabilities() também permite carregar services, tools e plugins de forma declarativa.
Os nomes enviados a loadTool(), loadPlugin() e loaders equivalentes são configuração de bootstrap confiável. Nunca use mensagem, saída da IA ou argumentos livres do usuário para escolher classe a carregar.
Safety Layer
A execução de Tools passa por regras estruturadas de segurança.
Entre os mecanismos disponíveis:
- classificação READ/WRITE;
- validação de argumentos;
- ToolPolicy;
- estágios permitidos;
- preconditions de estado;
- Trusted Parameter Binding;
- confirmação explícita;
- hard Execution Gate;
- proteção de idempotência para WRITE;
- bloqueio de duplicate writes;
- Result Projection;
- revalidação de chamadas stale.
Fluxo resumido:
ToolRegistry
↓
ToolPolicy
↓
subconjunto permitido
↓
AiProvider
↓
Tool call
↓
ExecutionGate
↓
execução real
Mesmo que uma Tool seja forjada, fique stale entre chamadas ou seja produzida fora do estágio permitido, o ExecutionGate revalida a operação imediatamente antes da execução.
OpenAI Responses e Prompt Caching — v1.6.1
O provider OpenAiResponsesProvider usa a Responses API e, na v1.6.1, foi otimizado para Prompt Caching.
A estratégia separa:
PREFIXO ESTÁVEL
- instructions
- schemas completos das Tools
- breakpoint explícito
- TTL de 12h
CONTEXTO DINÂMICO
- runtime
- intenção
- state
- lifecycle da sessão
- resultados incrementais
- TTL de 30m
Dados mutáveis não ficam no prefixo estável. Isso evita invalidar o cache por mudanças de horário, sessão, intenção ou estado.
Schemas estáveis e allowed_tools
Para manter os schemas estáveis entre turnos, o Guichê não precisa remover fisicamente definições de Tools a cada mudança de estágio.
A ToolPolicy calcula o subconjunto permitido e o provider OpenAI o traduz para tool_choice.allowed_tools.
schemas completos e estáveis
+
ToolPolicy
↓
allowed_tools
↓
modelo
Essa otimização não substitui a Safety Layer.
O ExecutionGate continua revalidando a Tool antes da execução real, inclusive contra estado atualizado.
Cache incremental após Tools
Nas continuations, o Guichê reaproveita o prefixo já cacheado e escreve somente os incrementos necessários da conversa.
Isso reduz reprocessamento de tokens em fluxos multi-Tool sem alterar a API pública da linha v1.
Session Lifecycle
O GuicheBuilder suporta configuração de TTL por meio de withSessionTtl().
O lifecycle expõe estados como:
new
active
expired
Mudanças de lifecycle fazem parte do contexto dinâmico da conversa e não precisam invalidar o prefixo estável do provider OpenAI.
Conversation Runtime
O runtime cobre responsabilidades como:
- incoming events;
- buffer/debounce;
- turn;
- sequence;
- scheduler;
- claim/lease;
- stale-event protection;
- follow-up;
- recovery.
A divisão conceitual é:
ConversationRuntime = quando processar
Guiche = como processar/raciocinar o turno
FollowUpRuntime e partes do Conversation Runtime permanecem API experimental até promoção explícita.
Exemplo básico
O exemplo oficial de Developer Experience fica em:
examples/basic/
Ele contém:
BasicPlugin;- Tool local
CatalogSearch; - catálogo determinístico em memória;
- operação somente READ;
- nenhum MySQL;
- nenhuma API privada;
- nenhum side effect.
O exemplo deve permanecer pequeno, legível, neutro de domínio e executável como primeira experiência com o framework.
Veja Quick Start detalhado.
Exemplo clínico avançado
A biblioteca mantém o Core genérico em src/ e disponibiliza um exemplo completo de agendamento em examples/clinica-piloto/.
Para executar o exemplo pela primeira vez, use o Fake Mode, que não depende de banco, IA ou APIs externas:
cp examples/clinica-piloto/.env.example examples/clinica-piloto/.env php examples/clinica-piloto/fake-smoke.php
Veja o guia de instalação e isolamento em examples/clinica-piloto/INSTALL.md.
O namespace do exemplo não pertence ao autoload público do pacote.
Desenvolvimento
Instale as dependências:
composer install
Execute o quality gate:
composer check
O quality gate inclui:
- PHPUnit;
- PHPStan;
- cobertura mínima definida pelo projeto;
- acceptance legado;
- freeze da API pública.
Na v1.6.1, o gate validado permanece com 391 testes, PHPStan sem erros e coverage acima do threshold de 70%.
Arquitetura e documentação
Referências principais:
- Quick Start:
docs/quick-start.md; - arquitetura:
docs/architecture.md; - Tools:
docs/tools.md; - Plugins:
docs/plugins.md; - State:
docs/state.md; - contexto multi-tenant:
docs/multitenancy.md; - identidade externa confiável:
docs/trusted-external-identity.md; - prompts dinâmicos:
docs/dynamic-prompts.md; - segurança:
docs/security.md; - estabilidade de API:
docs/api-stability.md; - suporte PHP:
docs/php-support.md; - changelog:
CHANGELOG.md; - release v1.6.0:
docs/release-v1.6.0.md; - release v1.6.1:
docs/release-v1.6.1.md.
Documentos de migração permanecem disponíveis em docs/migration-*.
Status e compatibilidade
A linha atual é v1.6.x Stable.
A evolução principal da linha v1 inclui:
v1.0 API pública estável
v1.1 contexto multi-tenant
v1.2 CLI e bootstrap
v1.3 identidade externa confiável
v1.4 Composition Root e prompts dinâmicos
v1.5 loaders, DI explícita e prompts por tenant
v1.6 Operational State & Runtime DX
v1.6.1 Prompt Caching otimizado no provider OpenAI
O compromisso da linha v1 inclui:
- API
publicprotegida por SemVer/BC; - suporte oficial a PHP 8.4 e PHP 8.5;
- hard Execution Gate antes de side effects;
- idempotência explícita para WRITE;
- extensibilidade por Tools, Plugins, ContextStore e AiProvider;
- instalação e uso em consumidor Composer externo;
- Conversation Runtime experimental fora do compromisso BC estável até promoção explícita.
Pontos de extensão públicos centrais:
ToolInterface;PluginInterface;ContextStoreInterface;AiProviderInterface;ToolRegistration;GuicheBuilder.
O principal critério de aceite permanece:
Em um projeto vazio, um desenvolvedor deve conseguir seguir somente este README e obter uma conversa funcional.
Licença
Consulte o arquivo de licença do repositório.