Skip to content

Commit 9fef551

Browse files
docs(blog): add Pi Agent integration article in Portuguese (Brazil)
Add comprehensive blog post about integrating Pi Agent into HagiCode in pt-BR locale. Covers thin adapter pattern, architecture design, core component implementation, and frontend-backend adaptation details. Co-Authored-By: Hagicode <noreply@hagicode.com> Signed-off-by: newbe36524 <newbe36524@qq.com>
1 parent a1b2827 commit 9fef551

1 file changed

Lines changed: 320 additions & 0 deletions

File tree

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
---
2+
title: Caminho Prático para Integrar Pi Agent ao HagiCode
3+
date: 2026-06-08
4+
tags: [ai-integration, hagicode, pi-agent, thin-adapter, cli]
5+
---
6+
7+
## Caminho Prático para Integrar Pi Agent ao HagiCode
8+
9+
> Este artigo compartilha nossa experiência prática na integração do Pi agent como um ponto de entrada de fluxo de trabalho de primeira classe no projeto HagiCode, incluindo design de arquitetura, implementação de componentes principais e detalhes de adaptação frontend e backend.
10+
11+
## Contexto
12+
13+
Tudo começou com aquela pergunta: no projeto HagiCode Mono, embora `repos/Hagicode.Libs` já tenha implementado o `PiProvider` reutilizável, `repos/hagicode-core` e `repos/web` ainda não elevaram o Pi a um Agent CLI de primeira classe em nível de projeto. É como ter um bom par de sapatos mas ainda não ter amarrado os cadarços — você consegue caminhar, mas sempre sente que falta algo.
14+
15+
O `PiProvider` existente está localizado em `HagiCode.Libs/src/HagiCode.Libs.Providers/Pi/PiProvider.cs`, ele implementa o protocolo de comunicação CLI baseado em JSON delimitado por linhas (`--mode json --print`), suportando gerenciamento de sessão, chamada de ferramentas e saída em streaming. Este código está bem escrito, apenas está lá adormecido, esperando ser acionado.
16+
17+
Esta situação criou uma lacuna: as capacidades subjacentes do Pi estão completas, mas o caminho de integração em nível de projeto (da configuração do usuário ao monitoramento de execução) está ausente. É como ter pintado um bom quadro, mas não tê-lo pendurado na parede para apreciação. Portanto, precisamos integrar o Pi como um novo provider ativo `PiCli` em todo o sistema, tornando-o um ponto de entrada de fluxo de trabalho de primeira classe igual a outros Agentes CLI.
18+
19+
Afinal, queremos uma experiência completa, não fragmentos dispersos.
20+
21+
## Sobre HagiCode
22+
23+
A solução compartilhada neste artigo vem de nossa experiência prática no projeto [HagiCode](https://hagicode.com). HagiCode é um projeto de assistente de código inteligente, e durante o desenvolvimento precisamos integrar múltiplos provedores de capacidades de IA. A solução de integração do Pi agent descrita neste artigo é exatamente um padrão de integração reutilizável que resumimos em nossa prática, com valor de referência para cenários semelhantes de integração de múltiplos providers. O endereço GitHub do projeto é [github.com/HagiCode-org/site](https://github.com/HagiCode-org/site).
24+
25+
## Design de Arquitetura
26+
27+
A integração do Pi agent adotou o **padrão thin adapter**, em vez de reimplementar o protocolo de processo Pi na camada core. Esta decisão de design não tem nada de complexa, é apenas pensar: por que reinventar a roda?
28+
29+
Afinal:
30+
31+
1. **Evitar reimplementação**: A lógica de construção de parâmetros, inicialização de processo, análise de JSON e tratamento de erros no `PiProvider` já está completa, reimplementar criaria duas fontes de comportamento e duas matrizes de teste. Tudo bem, mas a manutenção será problemática.
32+
2. **Manter consistência**: Mantém consistência com a forma de integração de CLIs existentes como Kimi, Gemini, Reasonix, DeepAgents, todos delegando para implementações na camada libs através de thin adapter. Todo mundo faz assim, só seguir o fluxo.
33+
3. **Separação de responsabilidades**: `hagicode-core` foca em contratos de runtime e lógica de negócio, detalhes de processo são deixados para `HagiCode.Libs` processar. Cada um com sua responsabilidade, não é perfeito?
34+
35+
Este design permite que HagiCode mantenha a camada core concisa enquanto integra rapidamente novos provedores de capacidades de IA. Afinal, simplicidade é beleza, eficiência é dinheiro.
36+
37+
## Implementação de Componentes Principais
38+
39+
### Enumeração e Factory do Provider
40+
41+
Em `hagicode-core/src/PCode.Models/AIProviderType.cs` foi adicionado o valor de enumeração `PiCli = 13`:
42+
43+
```csharp
44+
public enum AIProviderType
45+
{
46+
ClaudeCodeCli = 0,
47+
// ... outros providers
48+
PiCli = 13,
49+
}
50+
```
51+
52+
Este valor de enumeração é a raiz da identidade do provider, afetará a enumeração frontend `PCode_Models_AIProviderType.ts` gerada pelo OpenAPI, o branch de criação do `AIProviderFactory`, bem como a lógica de análise de Provider e julgamento de provider ativo. Registrando o novo branch de criação no `AIProviderFactory`:
53+
54+
```csharp
55+
case AIProviderType.PiCli:
56+
provider = new PiCliProvider(
57+
logger,
58+
configuration,
59+
providerFactory.GetRequiredService<ICliProvider<PiOptions>>(),
60+
providerFactory.GetService<IAgentCliRuntimeEnvironmentResolver>());
61+
break;
62+
```
63+
64+
Na verdade, este código não tem nada de especial, é apenas uma enumeração e um switch case. Mas eles são importantes, como notas em uma partitura, adicionadas uma por uma para tocar a melodia completa.
65+
66+
### Implementação do Thin Adapter
67+
68+
`PiCliProvider.cs` é o thin adapter central, ele implementa as interfaces `IAIProvider`, `IVersionedAIProvider` e `IAsyncDisposable`. Através do construtor recebe `ICliProvider<PiOptions>` (de `HagiCode.Libs`), mapeia `AIRequest` / `ProviderConfiguration` para `PiOptions`, depois delega execução, ping, consulta de versão e outras operações para o provider subjacente.
69+
70+
O ponto chave é tratar o fluxo de eventos JSON específico do Pi, incluindo eventos como `assistant.thought`, `assistant`, `terminal.completed`, etc. Estes eventos precisam ser corretamente analisados e convertidos para o formato padrão do sistema durante o processo de saída em streaming. É um pouco como tradução, traduzir de um idioma para outro, o significado precisa ser transmitido adequadamente.
71+
72+
### Preset de Profissão Principal
73+
74+
Em `main-professions.yaml` foi adicionada a entrada de profissão principal `profession-pi`:
75+
76+
```yaml
77+
- Id: "profession-pi"
78+
Name: "Pi"
79+
Family: "pi"
80+
Summary: "hero.professionCopy.primary.pi.summary"
81+
Icon: "executor-avatar:Pi"
82+
SourceLabel: "hero.professionCopy.sources.aiProvidersPiCli"
83+
ProviderType: "PiCli"
84+
SortOrder: 59
85+
DefaultEnabled: true
86+
DefaultParameters:
87+
binary: "pi"
88+
provider: "omniroute"
89+
thinking: "balanced"
90+
```
91+
92+
Isso garante que o snapshot backend e o diretório fallback frontend tenham identidade Pi consistente, podem gerenciar configuração Pi através do editor Hero existente, e a adição do Pi não quebrará a consumibilidade das entradas de profissão principal existentes. Afinal, não queremos quebrar as coisas existentes por adicionar uma nova funcionalidade, isso seria perder o essencial pelo trivial.
93+
94+
### Registro de Monitoramento
95+
96+
`AgentCliMonitoringRegistry` precisa adicionar o descriptor de monitoramento do Pi, permitindo que o sistema resolva caminhos executáveis, exiba nomes de marca, faça health checks, e exiba status do Pi na barra de status e detalhes de saúde:
97+
98+
```csharp
99+
new AgentCliMonitoringDescriptor(
100+
CliId: "pi",
101+
DisplayName: "Pi",
102+
ProviderType: AIProviderType.PiCli,
103+
DisplayOrder: 13,
104+
Strategy: AgentCliMonitoringStrategy.Grain,
105+
NotConfiguredMessage: "Pi CLI is not configured or executable not found.",
106+
EnabledPaths: [],
107+
ExecutablePathConfigPaths: ["Hero:PrimaryProfessions:Pi:ExecutablePath"],
108+
DefaultExecutablePath: "pi")
109+
```
110+
111+
O sistema de monitoramento é como um painel de instrumentos, mostrando como o carro está rodando. O status do Pi fica claro a um olhar, para que os usuários saibam se tudo está normal.
112+
113+
## Adaptação Frontend
114+
115+
### Adaptação de Tipo de Executor
116+
117+
O frontend precisa atualizar `executorTypeAdapter.ts`, adicionando lógica de identificação de tipo do Pi:
118+
119+
```typescript
120+
const PI_IDS = new Set<string>([
121+
PCode_Models_AIProviderType.PI_CLI,
122+
'Pi',
123+
'PiCli',
124+
'pi',
125+
'picli',
126+
'pi-cli',
127+
]);
128+
129+
export function isPi(value: string): boolean {
130+
const normalized = normalize(value);
131+
const normalizedLower = normalized.toLowerCase();
132+
return PI_IDS.has(normalized)
133+
|| normalizedLower.includes('pi-cli')
134+
|| normalizedLower.includes('picli')
135+
|| normalizedLower === 'pi';
136+
}
137+
```
138+
139+
É como dar ao Pi vários nomes, não importa como você o chama, ele sabe que você está chamando ele. Afinal, o nome não é importante, o importante é saber quem você é.
140+
141+
### Diretório Fallback do Hero
142+
143+
Em `hero.ts` adicionar entrada fallback do Pi, garantindo que mesmo se os dados backend não forem carregados, o frontend possa exibir normalmente a configuração Pi:
144+
145+
```typescript
146+
{
147+
id: "profession-pi",
148+
name: "Pi",
149+
family: "pi",
150+
summary: "hero.professionCopy.primary.pi.summary",
151+
icon: "executor-avatar:Pi",
152+
sourceLabel: "hero.professionCopy.sources.aiProvidersPiCli",
153+
providerType: AIProviderType.PI_CLI,
154+
sortOrder: 59,
155+
isReadOnly: true,
156+
managedParameterKeys: {
157+
// chaves de parâmetro suportadas na primeira versão
158+
},
159+
defaultParameters: {
160+
binary: "pi",
161+
provider: "omniroute",
162+
thinking: "balanced",
163+
},
164+
}
165+
```
166+
167+
Fallback é como um plano de contingência, caso o backend caia ou os dados não sejam carregados, o frontend ainda pode funcionar normalmente. Afinal, ninguém quer entrar em pânico quando isso acontecer.
168+
169+
### Textos Localizados e Formulários
170+
171+
Em `locales/*/common/{hero,settings}.yml` adicionar traduções relacionadas ao Pi, e em `HeroCliEquipmentForm.tsx` adicionar seção de campos de configuração para o Pi, suportando campos binary, provider, thinking, sessionDirectory e chaves de ferramenta/sessão.
172+
173+
A primeira versão do Pi expõe apenas campos minimamente necessários, funcionalidades complexas como allowlist/denylist de ferramentas e editor de variáveis de ambiente foram explicitamente adiadas para mudanças subsequentes. Afinal, não se deve comer tudo de uma vez, devagar se vai mais longe.
174+
175+
## Exemplos de Configuração
176+
177+
### Configuração Backend
178+
179+
Configurar parâmetros do Pi em `appsettings.yml`:
180+
181+
```yaml
182+
Hero:
183+
PrimaryProfessions:
184+
Pi:
185+
ExecutablePath: /usr/local/bin/pi
186+
Provider: omniroute
187+
Thinking: balanced
188+
SessionDirectory: ~/.pi/sessions
189+
NoSession: false
190+
DisableAllTools: false
191+
DisableBuiltinTools: false
192+
```
193+
194+
### Configuração Frontend
195+
196+
Configurar profissão do Pi no editor Hero:
197+
198+
```typescript
199+
{
200+
id: "my-pi-profession",
201+
name: "My Pi Profession",
202+
family: "pi",
203+
providerType: AIProviderType.PI_CLI,
204+
primaryModel: {
205+
provider: "PiCli",
206+
model: "glm-4.7",
207+
providerSettings: {
208+
provider: "omniroute",
209+
thinking: "balanced",
210+
sessionDirectory: "/Users/username/.pi/sessions",
211+
noSession: false,
212+
disableAllTools: false,
213+
disableBuiltinTools: false,
214+
},
215+
},
216+
}
217+
```
218+
219+
Arquivos de configuração são como receitas, seguindo você faz um bom prato. Às vezes, mesmo seguindo a receita, você pode queimar a comida... mas desta vez a configuração está clara, não deve haver problemas.
220+
221+
## Validação e Testes
222+
223+
### Validação Backend
224+
225+
Validar preset de profissão principal em testes:
226+
227+
```csharp
228+
var snapshot = await presetProvider.GetSnapshotAsync();
229+
var piProfession = snapshot.FindById("profession-pi");
230+
piProfession.ShouldNotBeNull();
231+
piProfession.ProviderType.ShouldBe(AIProviderType.PiCli);
232+
piProfession.Family.ShouldBe("pi");
233+
```
234+
235+
Também precisa validar disponibilidade do Pi e health check:
236+
237+
```bash
238+
# Verificar executável do Pi
239+
which pi
240+
pi --version
241+
242+
# Validar registro do provider backend
243+
curl http://localhost:35168/api/health/agent-cli/pi
244+
```
245+
246+
Testes são como exames, passar prova que você realmente sabe. Às vezes, mesmo passando no exame não significa que você realmente entende, mas pelo menos mostra que você consegue acertar as questões.
247+
248+
### Validação Frontend
249+
250+
```typescript
251+
// Validar análise de tipo e nome de exibição
252+
expect(resolveExecutorVisualType('pi-cli')).toBe('Pi');
253+
expect(resolveExecutorVisualType(PCode_Models_AIProviderType.PI_CLI)).toBe('Pi');
254+
expect(resolveExecutorDisplayName('PiCli')).toBe('Pi');
255+
256+
// Validar diretório fallback
257+
const piFallback = findFallbackProfessionById('profession-pi');
258+
expect(piFallback?.providerType).toBe(AIProviderType.PI_CLI);
259+
```
260+
261+
Estes casos de teste cobrem os principais caminhos lógicos, garantindo que o Pi possa ser corretamente identificado e exibido. Afinal, o que é exibido aos usuários não pode ter erros.
262+
263+
## Resolução de Problemas Comuns
264+
265+
### Executável do Pi Não Encontrado
266+
267+
Se o health check retornar "Pi executable was not found.", precisa verificar se o pi está no PATH, ou confirmar se o caminho configurado está correto. A solução é garantir que `pi` esteja instalado e no PATH, ou configurar o `ExecutablePath` correto em `appsettings.yml`.
268+
269+
É como não encontrar a chave de casa, precisa pensar se colocou no lugar errado. Na verdade, a solução é simples, ou colocar a chave de volta no lugar original, ou trocar a fechadura.
270+
271+
### Campos de Configuração Não Reconhecidos
272+
273+
Se durante a inicialização for lançado o erro "PiCli runtime settings [...] are not supported", verificar se estão usando apenas campos de configuração suportados na primeira versão. Os campos suportados na primeira versão são: `provider`, `thinking`, `sessionDirectory`, `noSession`, `disableAllTools`, `disableBuiltinTools`.
274+
275+
Às vezes é ganância, querer muitas funcionalidades, resultado o sistema não suporta. Na verdade, as funcionalidades da primeira versão já são suficientes, querer demais é ineficiente.
276+
277+
### Não Conseguir Selecionar Pi no Frontend
278+
279+
Se não houver opção Pi no editor Hero, verificar se executou `npm run generate:api` para regenerar as enumerações frontend, se há entrada `profession-pi` em `hero.ts`, e se os textos localizados foram corretamente adicionados.
280+
281+
Resolver problemas é como procurar objetos perdidos, precisa ser passo a passo. Afinal, procurar aleatoriamente não encontra, precisa ter lógica.
282+
283+
## Melhores Práticas
284+
285+
1. **Usar padrão thin adapter**: Não reimplemente protocolos de processo na camada core, delegue para providers da camada libs. Isso evita reimplementação, mantém consistência de código. Afinal, reinventar a roda não é apenas cansativo, também propenso a problemas.
286+
287+
2. **Manter consistência de nomenclatura**: Use convenções de nomenclatura unificadas entre frontend e backend, evitando confusão. Enumeração Provider usa `PiCli`, CLI ID usa `"pi"`, nome de exibição usa `"Pi"`. Bons nomes reduzem custos de comunicação.
288+
289+
3. **Priorizar presets**: A primeira versão deve ser baseada no preset `profession-pi`, em vez de exigir configuração manual dos usuários. Isso permite que os usuários comecem rapidamente, reduzindo complexidade de configuração. Usuários gostam de coisas simples, deixem o complexo para mim.
290+
291+
4. **Focar em mensagens de erro**: Garanta que mensagens de erro sejam claras e acionáveis, ajudando os usuários a localizar rapidamente os problemas. Mensagens de erro bem escritas impedem que os usuários entrem em pânico por um erro.
292+
293+
5. **Compatibilidade de versão**: Considerando a estabilidade de serialização dos valores de enumeração `AIProviderType`, mudanças precisam ser tratadas com cautela. O valor de enumeração `AIProviderType.PiCli = 13` não pode ser facilmente modificado. Afinal, mudar este valor pode quebrar compatibilidade reversa, o que seria problemático.
294+
295+
## Conclusão
296+
297+
Através do padrão thin adapter, integramos com sucesso o Pi agent no sistema HagiCode, tornando-o um ponto de entrada de fluxo de trabalho de primeira classe igual a outros Agentes CLI. As vantagens principais desta solução são:
298+
299+
- Evita reimplementação, reutiliza o `PiProvider` existente na camada libs
300+
- Mantém forma de integração consistente com providers existentes, reduzindo custos de manutenção
301+
- Implementa o caminho completo da configuração do usuário ao monitoramento de execução
302+
303+
Esta prática do HagiCode prova que o padrão thin adapter é uma solução eficaz para integrar provedores de capacidades de IA. Ele nos permite suportar rapidamente novos agentes, mantendo estabilidade e capacidade de manutenção do sistema.
304+
305+
Na verdade, fazer tecnologia é assim, encontrar um bom padrão, então reutilizá-lo. Assim você pode avançar rapidamente sem se perder. É como caminhar, encontrou um bom caminho, continua seguindo, apenas ocasionalmente para para apreciar a paisagem...
306+
307+
Se você também está fazendo integração de capacidades de IA de múltiplos providers, espero que esta solução possa te dar alguma inspiração. Se você está interessado no projeto HagiCode, bem-vindo ao GitHub para trocar ideias. Afinal, tecnologia é algo que progredimos mais com troca.
308+
309+
## Referências
310+
311+
- [Repositório GitHub do HagiCode](https://github.com/HagiCode-org/site)
312+
- [Site Oficial do HagiCode](https://hagicode.com)
313+
- [Guia de Instalação do HagiCode](https://docs.hagicode.com/installation/docker-compose)
314+
- [Documentação do Pi Agent](https://github.com/earendil-works/pi-coding-agent)
315+
316+
## Conclusão
317+
318+
Em torno de "Caminho Prático para Integrar Pi Agent ao HagiCode", uma forma mais estável de avanço é primeiro fazer funcionar progressivamente configurações críticas, limites de dependência e caminhos de implementação, depois completar detalhes de otimização.
319+
320+
Quando os objetivos, passos e pontos de aceitação estão claros, este tipo de solução geralmente pode entrar mais suavemente na entrega real.

0 commit comments

Comments
 (0)