DeepSeek Harness: Logs de Sessão e Trajectory

Última atualização: 2026-08-31

Cada conversa de Agent é uma jornada irreproduzível — modelos têm aleatoriedade, ferramentas têm efeitos colaterais, contexto se acumula. O sistema Trajectory do DSH usa "logs append-only" para registrar completamente cada passo, permitindo que você rastreie, audite, faça fork e restaure o estado da sessão em qualquer ponto no tempo.

💡 Dica: Trajectory não é apenas um visualizador de logs — é o núcleo do gerenciamento de sessão. Você pode criar um branch de fork para experimentar sem afetar a linha principal, ou restaurar a partir de qualquer checkpoint para escolher um caminho diferente.

📋 Pré-requisitos: Ter completado 07-python-sdk.md, familiarizado com noções básicas do SDK

1. O Que Você Vai Aprender

Ciclo de Vida da Sessão


2. Design de Log Append-Only

(1) Por Que Append-Only?

Sistemas de log tradicionais permitem modificação e exclusão, mas logs de sessão de Agent devem ser imutáveis — como um gravador de dados de voo (caixa preta), uma vez que um registro é escrito, não pode ser alterado:

100%
graph LR
    E1[Evento 1] --> E2[Evento 2] --> E3[Evento 3] --> E4[Evento 4] --> E5[Evento 5]
    E5 -.->|Apenas adição| NEW[Evento 6]
    
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9
    style E4 fill:#e8f5e9
    style E5 fill:#e8f5e9
    style NEW fill:#fff3e0

Três princípios do design append-only:

Princípio Descrição Benefício
Imutável Uma vez escritos, logs não podem ser modificados ou excluídos Trilha de auditoria completa
Ordenado Eventos são estritamente ordenados por timestamp Reprodução reversível
Apenas adição Apenas novos eventos podem ser adicionados, sem exclusão Sem conflitos de concorrência

(2) Comparação com Logs Tradicionais

Dimensão Logs Tradicionais Logs Append-Only do DSH
Modificável ✅ Pode modificar/excluir ❌ Não pode modificar
Seguro para concorrência Requer bloqueio Naturalmente seguro (apenas adição)
Capacidade de rollback Depende de backups Restaurar a partir de qualquer ponto
Capacidade de auditoria Pode ser adulterado À prova de adulteração
Eficiência de armazenamento Comprimível Cresce continuamente (requer arquivamento periódico)

(3) Estrutura de Armazenamento de Logs

TEXT 📖 Somente leitura
.dsh/
└── sessions/
    └── sess_abc123/
        ├── events.log          # Log de eventos (append-only)
        ├── snapshots/          # Snapshots de estado
        │   ├── snap_001.json
        │   ├── snap_002.json
        │   └── snap_003.json
        └── metadata.json       # Metadados da sessão

3. Fluxo de Eventos SessionEvent

(1) Tipos de Eventos

Cada operação em uma sessão DSH é registrada como um SessionEvent:

TYPESCRIPT
type SessionEventType =
  | 'session.created'
  | 'session.config_changed'
  | 'user.message'
  | 'agent.message'
  | 'agent.thinking'
  | 'tool.call'
  | 'tool.result'
  | 'tool.approval.requested'
  | 'tool.approval.resolved'
  | 'session.forked'
  | 'session.restored'
  | 'error.occurred';

(2) Estrutura do Evento

Cada SessionEvent contém campos padrão:

TYPESCRIPT
interface SessionEvent {
  id: string;                  // ID único do evento
  type: SessionEventType;      // Tipo do evento
  timestamp: number;           // Timestamp Unix (milissegundos)
  sessionId: string;           // ID da sessão pai
  data: Record<string, unknown>;  // Dados de payload do evento
  parentId?: string;           // ID do evento pai (usado para forks)
}

(3) Descrições Detalhadas dos Eventos

Evento de Mensagem do Usuário:

▶ Exemplo 1:Evento user.message

JSON
{
  "id": "evt_001",
  "type": "user.message",
  "timestamp": 1724486400000,
  "sessionId": "sess_abc123",
  "data": {
    "content": "Me ajude a refatorar o diretório utils",
    "attachments": []
  }
}

Evento de Chamada de Ferramenta:

▶ Exemplo 2:Evento tool.call

JSON
{
  "id": "evt_002",
  "type": "tool.call",
  "timestamp": 1724486401500,
  "sessionId": "sess_abc123",
  "data": {
    "tool": "search",
    "params": {
      "pattern": "utils/*",
      "type": "file"
    },
    "mode": "standard"
  }
}

Evento de Resultado de Ferramenta:

▶ Exemplo 3:Evento tool.result

JSON
{
  "id": "evt_003",
  "type": "tool.result",
  "timestamp": 1724486402300,
  "sessionId": "sess_abc123",
  "data": {
    "toolCallId": "evt_002",
    "status": "success",
    "result": {
      "files": ["utils/format.ts", "utils/validate.ts", "utils/helpers.ts"]
    },
    "duration_ms": 800
  }
}

Evento de Aprovação:

▶ Exemplo 4:Evento tool.approval

JSON
{
  "id": "evt_004",
  "type": "tool.approval.requested",
  "timestamp": 1724486403000,
  "sessionId": "sess_abc123",
  "data": {
    "tool": "file_edit",
    "params": {
      "action": "edit",
      "path": "utils/format.ts"
    },
    "riskLevel": "high"
  }
}
JSON
{
  "id": "evt_005",
  "type": "tool.approval.resolved",
  "timestamp": 1724486405000,
  "sessionId": "sess_abc123",
  "data": {
    "approvalId": "evt_004",
    "decision": "allowed",
    "decidedBy": "user"
  }
}

(4) Exemplo Completo do Fluxo de Eventos

TEXT 📖 Somente leitura
Linha do Tempo              Tipo de Evento
─────────────────────────────────────────
10:00:00.000   session.created
10:00:05.120   user.message          "Me ajude a refatorar o diretório utils"
10:00:06.300   tool.call             search → utils/*
10:00:07.100   tool.result           Encontrados 3 arquivos
10:00:08.200   tool.call             file_edit → read utils/format.ts
10:00:08.500   tool.result           Conteúdo do arquivo retornado
10:00:10.800   agent.thinking        Analisando plano de refatoração...
10:00:12.000   tool.approval.requested   file_edit → edit
10:00:15.000   tool.approval.resolved    → permitido
10:00:15.200   tool.call             file_edit → edit utils/format.ts
10:00:15.600   tool.result           Edição concluída
10:00:17.000   agent.message         "Refatoração concluída!"

4. Visualização Trajectory

(1) O Que É Trajectory?

Trajectory é a interface visual dos logs de sessão, mostrando a "trajetória" completa do Agent:

TEXT 📖 Somente leitura
┌─ Visualização Trajectory ──────────────────────────────────────┐
│                                                         │
│ 10:00  👤 Me ajude a refatorar o diretório utils          │
│ 10:00    🔍 search(utils/*) → 3 arquivos            0.8s  │
│ 10:00    📄 file_edit(read) → utils/format.ts    0.3s  │
│ 10:00    📄 file_edit(read) → utils/validate.ts  0.2s  │
│ 10:00    🤔 Pensando... Analisando plano de refatoração      │
│ 10:00    ⚠️ Aprovação: edit utils/format.ts              │
│ 10:00      → ✅ Permitido                                  │
│ 10:00    📝 file_edit(edit) → utils/format.ts    0.4s  │
│ 10:00    ⚠️ Aprovação: edit utils/validate.ts            │
│ 10:00      → ✅ Permitido                                  │
│ 10:00    📝 file_edit(edit) → utils/validate.ts  0.3s  │
│ 10:00    🤖 Refatoração concluída! Definições de tipo compartilhado extraídas... │
│                                                         │
│ [Fork a partir daqui] [Restaurar até aqui] [Exportar]             │
└─────────────────────────────────────────────────────────┘

(2) Acessando Trajectory na Web UI

Na Web UI, clique no ícone de log na barra de controle superior para abrir a visualização Trajectory:

TEXT 📖 Somente leitura
Barra de controle superior → 📋 → Trajectory

(3) Filtragem e Busca no Trajectory

▶ Exemplo 5:Filtrar por Tipo de Evento

TEXT 📖 Somente leitura
Filtros da Visualização Trajectory:
┌──────────────────────────────────────────┐
│ Filtros:                                 │
│ ☑ user.message    ☑ agent.message        │
│ ☑ tool.call       ☑ tool.result          │
│ ☐ agent.thinking  ☐ eventos de aprovação      │
│                                          │
│ Busca: [Digite palavras-chave...]              │
└──────────────────────────────────────────┘

(4) Acessando Trajectory via SDK

▶ Exemplo 6:Obter Fluxo de Eventos via SDK

PYTHON
from dsh import DSHClient

client = DSHClient(base_url="http://127.0.0.1:3080")
session = client.get_session("sess_abc123")

# Obter todos os eventos
events = session.get_trajectory()

for event in events:
    print(f"[{event.timestamp}] {event.type}: {event.data}")

# Filtrar por tipo
tool_events = session.get_trajectory(event_type="tool.call")

for event in tool_events:
    print(f"Ferramenta: {event.data['tool']}")
    print(f"Parâmetros: {event.data['params']}")

5. Fork e Restauração de Sessão

(1) Conceito de Fork

Fork cria um branch de sessão a partir de um ponto específico no tempo — a linha principal continua avançando enquanto o branch se desenvolve independentemente:

100%
graph LR
    E1[Evento 1] --> E2[Evento 2] --> E3[Evento 3] --> E4[Evento 4]
    E3 -->|fork| F1[Evento Fork 1] --> F2[Evento Fork 2]
    
    E4 --> E5[Evento 5]
    
    style E1 fill:#e8f5e9
    style E2 fill:#e8f5e9
    style E3 fill:#e8f5e9
    style E4 fill:#e8f5e9
    style E5 fill:#e8f5e9
    style F1 fill:#e3f2fd
    style F2 fill:#e3f2fd

(2) Casos de Uso de Fork

Cenário Descrição
Exploração de soluções Testar abordagens diferentes a partir do mesmo nó, comparar resultados
Fallback seguro Fazer fork antes de operações destrutivas; voltar à linha principal se falhar
Teste A/B Comparar a mesma tarefa usando modelos/modos diferentes
Alterações experimentais Quando incerto dos resultados, testar em um branch primeiro

(3) Fazendo Fork na Web UI

Na visualização Trajectory, clique no botão "Fork a partir daqui" ao lado de qualquer evento:

TEXT 📖 Somente leitura
10:00  📝 file_edit(edit) → utils/format.ts  [Fork a partir daqui]
10:00  ⚠️ Aprovação: edit utils/validate.ts    [Fork a partir daqui]
10:00  🤖 Refatoração concluída!               [Fork a partir daqui]

Fork cria uma nova sessão começando a partir do ponto do evento selecionado, copiando todo o contexto anterior àquele ponto.

(4) Fazendo Fork via SDK

▶ Exemplo 7:Operação de Fork via SDK

PYTHON
client = DSHClient(base_url="http://127.0.0.1:3080")
session = client.get_session("sess_abc123")

# Fazer fork a partir do 5º evento
forked = session.fork(after_event="evt_005")

print(f"Sessão com fork: {forked.id}")
print(f"Pai: {forked.parent_id}")
print(f"Ponto de fork: evt_005")

# Continuar conversa no branch do fork
response = forked.send("Tente uma abordagem de refatoração diferente, divida por função")

(5) Restauração

Restauração é diferente de Fork — ela reverte a sessão atual para um ponto de evento especificado, descartando eventos subsequentes:

▶ Exemplo 8:Operação de Restauração via SDK

PYTHON
# Restaurar ao 3º ponto de evento
session.restore(to_event="evt_003")

# Eventos após evt_004, evt_005, etc. são marcados como "restaurados"
# Novos eventos continuam sendo adicionados após evt_003

Nota: Restauração não exclui eventos (princípio append-only), mas marca eventos subsequentes como inválidos e adiciona um evento session.restored.


6. Persistência de Logs

(1) Armazenamento Padrão

Logs de sessão do DSH são armazenados por padrão no diretório .dsh/sessions/ do projeto:

TEXT 📖 Somente leitura
.dsh/
├── sessions/
│   ├── sess_abc123/
│   │   ├── events.log        # Log de eventos
│   │   ├── snapshots/        # Snapshots de estado
│   │   └── metadata.json     # Metadados
│   └── sess_def456/
│       ├── events.log
│       └── ...
├── config.yaml               # Configuração DSH
└── plugins/                  # Diretório de plugins

(2) Configuração de Persistência

YAML
# dsh.config.yaml
storage:
  # Caminho de armazenamento
  base_path: ".dsh/sessions"
  
  # Estratégia de snapshot
  snapshots:
    enabled: true
    interval: 10              # Salvar snapshot a cada 10 eventos
    max_snapshots: 5          # Manter no máximo 5 snapshots
  
  # Rotação de logs
  rotation:
    max_size_mb: 100          # Máx. 100MB por arquivo de log
    max_files: 50             # Manter no máximo 50 sessões
  
  # Arquivamento
  archive:
    enabled: true
    path: ".dsh/archive/"
    after_days: 30            # Auto-arquivar após 30 dias

(3) Exportando Logs de Sessão

▶ Exemplo 9:Exportar como JSON

PYTHON
# Exportar log de sessão completo
session = client.get_session("sess_abc123")
events = session.get_trajectory()

import json
with open("session_export.json", "w") as f:
    json.dump([e.to_dict() for e in events], f, indent=2)

▶ Exemplo 10:Exportar como Markdown

BASH
# Exportação via CLI
dsh session export sess_abc123 --format markdown --output session.md

# Formato de saída
# # Session: sess_abc123
# ## 10:00 - Usuário
# Me ajude a refatorar o diretório utils
# ## 10:00 - Ferramenta: search
# Padrão: utils/* → 3 arquivos encontrados
# ...

(4) Limpeza de Logs

BASH
# Listar todas as sessões (ordenadas por tamanho)
dsh session list --sort size

# Arquivar sessões antigas
dsh session archive --older-than 30d

# Excluir sessões arquivadas (irreversível)
dsh session clean --archived-only

7. Trajectory e Auditoria

(1) Auditoria de Operações

Trajectory registra cada operação do Agent, sendo naturalmente adequado para auditoria:

100%
graph TB
    AUDIT[Necessidade de Auditoria] --> T1[Quem executou?]
    AUDIT --> T2[Quando?]
    AUDIT --> T3[O que foi feito?]
    AUDIT --> T4[Qual foi o resultado?]
    
    T1 --> TRAJ[Fluxo de Eventos Trajectory]
    T2 --> TRAJ
    T3 --> TRAJ
    T4 --> TRAJ

(2) Cenários de Conformidade

Requisito de Conformidade Como Trajectory Atende
Rastreabilidade de operações Cada evento tem ID, timestamp, operador
Alterações à prova de adulteração Log append-only, não pode modificar histórico
Registros de aprovação approval.requested + approval.resolved registro completo
Capacidade de rollback Restaurar a partir de qualquer checkpoint

(3) Gerando Relatórios de Auditoria

▶ Exemplo 11:Gerando um Relatório de Auditoria

PYTHON
session = client.get_session("sess_abc123")
events = session.get_trajectory()

report = {
    "session_id": session.id,
    "duration": events[-1].timestamp - events[0].timestamp,
    "user_messages": len([e for e in events if e.type == "user.message"]),
    "tool_calls": len([e for e in events if e.type == "tool.call"]),
    "approvals_requested": len([e for e in events if e.type == "tool.approval.requested"]),
    "approvals_denied": len([e for e in events if e.type == "tool.approval.resolved" and e.data.get("decision") == "denied"]),
    "files_modified": list(set([
        e.data.get("path") for e in events
        if e.type == "tool.call" and e.data.get("tool") == "file_edit"
    ])),
    "errors": len([e for e in events if e.type == "error.occurred"])
}

import json
print(json.dumps(report, indent=2))

❓ Perguntas Frequentes

P Logs append-only crescem infinitamente?
R Sim, mas o DSH fornece mecanismos de arquivamento e rotação. Configure rotation.max_size_mb e archive.after_days para gerenciamento automático de armazenamento.
P Sessões com fork compartilham dados com a original?
R Fork copia um snapshot do contexto no momento do fork; depois disso, são completamente independentes. Alterações não afetam umas às outras.
P Restauração realmente exclui eventos históricos?
R Não. O princípio append-only garante que eventos nunca são excluídos. Restauração apenas marca eventos subsequentes como inválidos e começa a adicionar novos eventos a partir do ponto de restauração.
P Dados Trajectory podem ser exportados?
R Sim. Suporta exportação em formato JSON, Markdown e CSV. CLI usa dsh session export; SDK usa o método get_trajectory().
P Múltiplos usuários podem ver o Trajectory da mesma sessão?
R O DSH usa modo de usuário único por padrão, então não há problema de compartilhamento multi-usuário. Se usar armazenamento compartilhado (ex.: NFS), múltiplas instâncias DSH podem ler os mesmos logs.
P Como usar Trajectory em CI/CD?
R Use o SDK para exportar o fluxo de eventos, analise contagens de chamadas de ferramentas, taxas de negação de aprovação, taxas de erro, etc., como portas de qualidade.

📖 Resumo


📝 Exercícios

1. ⭐ Básico: Complete uma conversa de Agent (com pelo menos 2 chamadas de ferramentas), abra a visualização Trajectory e liste todos os eventos com seus tipos e timestamps.

2. ⭐⭐ Intermediário: Faça fork de um branch a partir do 3º evento de uma sessão, tente uma abordagem diferente no branch. Compare os resultados finais da linha principal e do branch.

3. ⭐⭐⭐ Desafio: Use o Python SDK para escrever uma ferramenta de análise Trajectory — insira um ID de sessão, gere automaticamente um relatório de auditoria (incluindo estatísticas de operações, registros de aprovação, lista de arquivos modificados, resumo de erros), em formato JSON.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%