TempFS é um projeto que foi desenvolvido inicialmente como um prototipo para contêineres temporarios (tempfs) orquestrado para modelos GGUF usando llama-cpp.
A ideia central é fazer com que modelos GGUF possam interagir em ambientes temproarios de forma eficiente e discreta. Pode notar que o contêiner ubuntu pode facilmente ser usado como playground para testes!
O script llama-server.js espera que um container llama-cpp esteja configurado e pronto para uso. Você pode criá-lo usando o seguinte comando Podman:
podman create \
--name llama-cpp \
--cpus=4 \
--memory=6g \
--memory-swap=7g \
-v llama_models:/models \
-p 8080:8080 \
--entrypoint /bin/sh \
ghcr.io/ggml-org/llama.cpp:full \
-c "sleep infinity"O volume llama_models será usado para armazenar o modelo GGUF (configurado em config.json), que será baixado automaticamente na primeira execução do llama-server.js.
O projeto oferece três exemplos principais de ambientes na pasta EXEMPLOS/:
1. Servidor Llama-CPP (llama-server.js)
Inicia o container llama-cpp (se não estiver rodando), baixa o modelo configurado (se necessário) e fornece um terminal interativo para interagir com o servidor llama.cpp.
node EXEMPLOS/llama-server.js2. Llama CLI (llama-cli.js)
Usa o llama-cli diretamente para interação básica com modelos GGUF. Este exemplo demonstra o uso direto da interface de linha de comando do llama.cpp.
node EXEMPLOS/llama-cli.js3. Ambiente Ubuntu Efêmero (tempfs.js)
Cria um container temporário baseado em ubuntu:24.04 na memória (tempfs). Este ambiente é efêmero e será completamente destruído ao ser encerrado.
node EXEMPLOS/tempfs.jsO projeto agora suporta comandos customizáveis organizados por roles. Você pode criar seus próprios comandos seguindo a estrutura do exemplo ping.js.
- Crie um arquivo
.jsna pasta apropriada dentro determinal/commands/ - Defina as roles do comando para controlar quais containers podem usá-lo
- Siga a estrutura do
ping.jscomo base:
export default {
name: 'seu-comando',
aliases: ['alias1', 'alias2'],
description: 'Descrição do seu comando',
roles: ['role1', 'role2'], // As roles permitem que containers decidam quais comandos usar
async execute(args, container) {
// Lógica do comando aqui
}
}As roles servem para que os containers decidam quais comandos ou grupos de comandos podem usar. Por exemplo:
base: Comandos básicos disponíveis para todos (bash,clear,exit)ping: Comando de exemplo para o container TempFSllama: Comandos específicos para interação com llama.cpp
Ao criar seu container, defina as roles no construtor:
this.roles = ['base', 'ping', 'sua-role-customizada']Os comandos básicos estão disponíveis em todos os terminais:
| Comando | Descrição |
|---|---|
bash |
Entra no shell interativo do container. |
bash <comando> |
Executa um comando no container e retorna a saída. |
clear |
Limpa o terminal. |
exit |
Encerra o processo e limpa o container. |
O sistema de comandos agora suporta:
- Aspas: Argumentos entre aspas são tratados como um único argumento
- Quebra de linha com
\: Use\no final da linha para continuar o comando na próxima linha
Exemplo:
bash echo "Hello World" \
&& echo "Continuação do comando"Limpeza Automática (Processo Monitor)
O projeto implementa um mecanismo de Limpeza Automática essencial para garantir que nenhum recurso fique órfão. Isso é feito através do utils/monitor.js, que atua como um "Processo Zumbi Reverso":
- Monitoramento: O
monitor.jsé iniciado como um processo filho desanexado (detached: true) do processo principal do Node.js. - Vigilância: Ele monitora continuamente o PID do processo pai.
- Limpeza Garantida: Se o processo principal do Node.js morrer (seja por um
exitnormal, um erro não tratado, ou um sinal de interrupção comoCtrl+C), o monitor detecta a morte do pai e executa imediatamente os comandospodman rm -f <container_name>para garantir que o container associado seja parado e removido, limpando o ambiente e evitando containers órfãos.
Essa arquitetura garante que os ambientes efêmeros sejam realmente temporários.
Nota sobre Dependências (npm podman, etc.)
Você notará que este projeto **não utiliza** bibliotecas de terceiros (como `npm podman` ou SDKs) para interagir com o Podman. A comunicação é feita diretamente através da execução de comandos `podman` via `child_process`.Por quê?
- Minimalismo e Controle: Evitar dependências externas reduz a complexidade e o overhead do projeto, dando controle total sobre os comandos executados.
- Foco no Core: O objetivo é simular um ambiente de agente que usa comandos de terminal, e a execução direta de comandos Podman é a forma mais fiel e robusta de alcançar isso.
- Portabilidade: Embora o foco seja Podman, a abordagem de linha de comando facilita a adaptação para Docker ou outras ferramentas de container, bastando trocar o prefixo do comando.
Obrigado pela atenção!
