feat: add asistente-2 agent with tool-use and E2EE verification
Nuevo agente asistente-2 con herramienta current_time habilitada para demostrar el flujo completo de tool-use (LLM → tool call → resultado → respuesta). Incluye: - agents/asistente2/: reglas puras, config con tool_use.enabled, system prompt - tools/time.go: herramienta current_time (siempre disponible para todos los agentes) - cmd/verify/: comando para subir cross-signing keys y eliminar el warning "Encrypted by a device not verified by its owner" - Registro en runtime.go (current_time) y launcher/main.go (rulesRegistry) El cmd/verify usa mautrix GenerateAndUploadCrossSigningKeysWithPassword para configurar cross-signing via UIA con la password del bot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
|||||||
|
// Package asistente2 defines the pure rules for the asistente-2 bot.
|
||||||
|
// This agent uses tool_use (current_time) to demonstrate the tool-use loop.
|
||||||
|
package asistente2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rules returns the decision rules for the asistente-2 bot.
|
||||||
|
func Rules() []decision.Rule {
|
||||||
|
return []decision.Rule{
|
||||||
|
// !help — explicit help command
|
||||||
|
{
|
||||||
|
Name: "help",
|
||||||
|
Match: decision.MatchCommand("help"),
|
||||||
|
Actions: []decision.Action{{
|
||||||
|
Kind: decision.ActionKindReply,
|
||||||
|
Reply: &decision.ReplyAction{
|
||||||
|
Content: "Soy asistente-2. Puedo responder preguntas y además consultar la hora actual.\n" +
|
||||||
|
"- Pregúntame cualquier cosa\n" +
|
||||||
|
"- Puedo decirte la fecha y hora actual\n\n" +
|
||||||
|
"Escríbeme directamente lo que necesitas.",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Any DM or mention → LLM (with tool-use enabled)
|
||||||
|
{
|
||||||
|
Name: "llm-all",
|
||||||
|
Match: func(ctx decision.MessageContext) bool {
|
||||||
|
return ctx.IsDirectMsg || ctx.IsMention
|
||||||
|
},
|
||||||
|
Actions: []decision.Action{{
|
||||||
|
Kind: decision.ActionKindLLM,
|
||||||
|
LLM: &decision.LLMAction{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
# ============================================
|
||||||
|
# IDENTIDAD
|
||||||
|
# ============================================
|
||||||
|
agent:
|
||||||
|
id: asistente-2
|
||||||
|
name: "Asistente 2"
|
||||||
|
version: "1.0.0"
|
||||||
|
enabled: true
|
||||||
|
description: "Asistente con herramientas. Puede responder preguntas y consultar la hora actual."
|
||||||
|
tags: [assistant, llm, tools]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# PERSONALIDAD Y COMPORTAMIENTO
|
||||||
|
# ============================================
|
||||||
|
personality:
|
||||||
|
tone: friendly
|
||||||
|
verbosity: concise
|
||||||
|
language: es
|
||||||
|
languages_supported: [es, en]
|
||||||
|
emoji_style: minimal
|
||||||
|
prefix: "🛠️"
|
||||||
|
error_style: helpful
|
||||||
|
|
||||||
|
templates:
|
||||||
|
greeting: "Hola, soy asistente-2. ¿En qué puedo ayudarte?"
|
||||||
|
unknown_command: "No entiendo ese comando. Escríbeme directamente lo que necesitas."
|
||||||
|
permission_denied: "No tengo permiso para hacer eso."
|
||||||
|
error: "Algo salió mal: {{.Error}}"
|
||||||
|
success: "{{.Summary}}"
|
||||||
|
busy: "Procesando tu solicitud anterior, dame un momento..."
|
||||||
|
|
||||||
|
behavior:
|
||||||
|
proactive: false
|
||||||
|
ask_confirmation: false
|
||||||
|
show_reasoning: false
|
||||||
|
thread_replies: true
|
||||||
|
typing_indicator: true
|
||||||
|
acknowledge_receipt: false
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# LLM — CONEXIÓN Y RAZONAMIENTO
|
||||||
|
# ============================================
|
||||||
|
llm:
|
||||||
|
primary:
|
||||||
|
provider: openai
|
||||||
|
model: gpt-4o
|
||||||
|
api_key_env: OPENAI_API_KEY
|
||||||
|
base_url: ""
|
||||||
|
max_tokens: 4096
|
||||||
|
temperature: 0.7
|
||||||
|
|
||||||
|
fallback:
|
||||||
|
provider: ""
|
||||||
|
model: ""
|
||||||
|
api_key_env: ""
|
||||||
|
base_url: ""
|
||||||
|
max_tokens: 0
|
||||||
|
temperature: 0
|
||||||
|
|
||||||
|
reasoning:
|
||||||
|
system_prompt_file: "prompts/system.md"
|
||||||
|
context_window: 16384
|
||||||
|
memory_messages: 30
|
||||||
|
|
||||||
|
tool_use:
|
||||||
|
enabled: true # herramientas HABILITADAS
|
||||||
|
max_iterations: 5
|
||||||
|
parallel_calls: false
|
||||||
|
|
||||||
|
rate_limit:
|
||||||
|
requests_per_minute: 60
|
||||||
|
tokens_per_minute: 200000
|
||||||
|
concurrent_requests: 5
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# TOOLS — current_time habilitada
|
||||||
|
# ============================================
|
||||||
|
tools:
|
||||||
|
ssh:
|
||||||
|
enabled: false
|
||||||
|
allowed_targets: []
|
||||||
|
forbidden_commands: []
|
||||||
|
timeout: 0s
|
||||||
|
max_concurrent: 0
|
||||||
|
require_confirmation: []
|
||||||
|
|
||||||
|
http:
|
||||||
|
enabled: false
|
||||||
|
allowed_domains: []
|
||||||
|
timeout: 0s
|
||||||
|
max_retries: 0
|
||||||
|
|
||||||
|
scripts:
|
||||||
|
enabled: false
|
||||||
|
scripts_dir: ""
|
||||||
|
allowed: []
|
||||||
|
timeout: 0s
|
||||||
|
sandbox: false
|
||||||
|
|
||||||
|
file_ops:
|
||||||
|
enabled: false
|
||||||
|
allowed_paths: []
|
||||||
|
read_only: true
|
||||||
|
|
||||||
|
mcp:
|
||||||
|
enabled: false
|
||||||
|
servers: []
|
||||||
|
expose:
|
||||||
|
port: 0
|
||||||
|
tools: []
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# MATRIX — CONEXIÓN Y ROOMS
|
||||||
|
# ============================================
|
||||||
|
matrix:
|
||||||
|
homeserver: "https://matrix-af2f3d.organic-machine.com"
|
||||||
|
user_id: "@asistente-2:matrix-af2f3d.organic-machine.com"
|
||||||
|
access_token_env: MATRIX_TOKEN_ASISTENTE2
|
||||||
|
device_id: "YBFNMNMJIC"
|
||||||
|
|
||||||
|
encryption:
|
||||||
|
enabled: true
|
||||||
|
store_path: "./data/crypto/"
|
||||||
|
trust_mode: tofu
|
||||||
|
|
||||||
|
rooms:
|
||||||
|
listen: []
|
||||||
|
respond: []
|
||||||
|
admin: []
|
||||||
|
|
||||||
|
filters:
|
||||||
|
command_prefix: "!"
|
||||||
|
mention_respond: true
|
||||||
|
dm_respond: true
|
||||||
|
ignore_bots: true
|
||||||
|
ignore_users: []
|
||||||
|
min_power_level: 0
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# COMUNICACIÓN INTER-AGENTES
|
||||||
|
# ============================================
|
||||||
|
agents:
|
||||||
|
peers:
|
||||||
|
- id: assistant-bot
|
||||||
|
capabilities: [general, llm]
|
||||||
|
room: ""
|
||||||
|
|
||||||
|
delegation:
|
||||||
|
enabled: false
|
||||||
|
can_delegate_to: []
|
||||||
|
can_receive_from: [assistant-bot]
|
||||||
|
max_delegation_depth: 1
|
||||||
|
timeout: 30s
|
||||||
|
|
||||||
|
protocol:
|
||||||
|
format: json
|
||||||
|
channel: matrix
|
||||||
|
heartbeat_interval: 60s
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# SSH — no aplica para este bot
|
||||||
|
# ============================================
|
||||||
|
ssh:
|
||||||
|
defaults:
|
||||||
|
user: ""
|
||||||
|
port: 22
|
||||||
|
key_file_env: ""
|
||||||
|
known_hosts: ""
|
||||||
|
keepalive_interval: 0s
|
||||||
|
timeout: 0s
|
||||||
|
targets: {}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# PERMISOS Y SEGURIDAD
|
||||||
|
# ============================================
|
||||||
|
security:
|
||||||
|
roles:
|
||||||
|
admin:
|
||||||
|
users: ["@admin:matrix-af2f3d.organic-machine.com"]
|
||||||
|
actions: ["*"]
|
||||||
|
user:
|
||||||
|
users: ["*"]
|
||||||
|
actions: ["ask", "help", "summarize"]
|
||||||
|
|
||||||
|
audit:
|
||||||
|
enabled: false
|
||||||
|
log_file: "./data/audit.log"
|
||||||
|
log_to_room: ""
|
||||||
|
include: []
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
provider: env
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# SCHEDULING — sin tareas automáticas
|
||||||
|
# ============================================
|
||||||
|
schedules: []
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# OBSERVABILIDAD
|
||||||
|
# ============================================
|
||||||
|
observability:
|
||||||
|
logging:
|
||||||
|
level: info
|
||||||
|
format: json
|
||||||
|
output: stdout
|
||||||
|
file: "./data/asistente2.log"
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
enabled: false
|
||||||
|
port: 9092
|
||||||
|
path: /metrics
|
||||||
|
export: prometheus
|
||||||
|
|
||||||
|
health:
|
||||||
|
enabled: true
|
||||||
|
port: 8082
|
||||||
|
path: /healthz
|
||||||
|
|
||||||
|
tracing:
|
||||||
|
enabled: false
|
||||||
|
provider: ""
|
||||||
|
endpoint: ""
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# RESILIENCIA
|
||||||
|
# ============================================
|
||||||
|
resilience:
|
||||||
|
circuit_breaker:
|
||||||
|
failure_threshold: 5
|
||||||
|
timeout: 30s
|
||||||
|
half_open_max: 2
|
||||||
|
|
||||||
|
retry:
|
||||||
|
max_attempts: 2
|
||||||
|
backoff: exponential
|
||||||
|
initial_delay: 1s
|
||||||
|
max_delay: 10s
|
||||||
|
|
||||||
|
shutdown:
|
||||||
|
timeout: 10s
|
||||||
|
drain_messages: true
|
||||||
|
save_state: false
|
||||||
|
state_file: ""
|
||||||
|
|
||||||
|
queue:
|
||||||
|
enabled: true
|
||||||
|
max_size: 100
|
||||||
|
priority_users: ["@admin:matrix-af2f3d.organic-machine.com"]
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# ALMACENAMIENTO Y ESTADO
|
||||||
|
# ============================================
|
||||||
|
storage:
|
||||||
|
state:
|
||||||
|
backend: sqlite
|
||||||
|
path: "./data/asistente2.db"
|
||||||
|
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
backend: memory
|
||||||
|
ttl: 5m
|
||||||
|
max_entries: 200
|
||||||
|
|
||||||
|
history:
|
||||||
|
backend: sqlite
|
||||||
|
path: "./data/history.db"
|
||||||
|
retention: 168h # 7 días
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Asistente 2 — System Prompt
|
||||||
|
|
||||||
|
Eres un asistente conversacional amigable y directo. Operas en Matrix, respondiendo mensajes directos (DMs) y menciones en rooms.
|
||||||
|
|
||||||
|
## Capacidades
|
||||||
|
- Responder preguntas generales
|
||||||
|
- Resumir texto o documentos pegados en el chat
|
||||||
|
- Redactar textos, emails, documentación
|
||||||
|
- Explicar conceptos técnicos y no técnicos
|
||||||
|
- Ayudar con código: revisar, corregir, explicar
|
||||||
|
- **Consultar la hora y fecha actual** usando la herramienta `current_time`
|
||||||
|
|
||||||
|
## Herramientas disponibles
|
||||||
|
- `current_time`: Devuelve la fecha y hora actual del servidor. Úsala cuando alguien pregunte por la hora, fecha, o necesites contexto temporal.
|
||||||
|
|
||||||
|
## Estilo
|
||||||
|
- Respuestas concisas por defecto. Si necesitas extensión, pregunta primero.
|
||||||
|
- Usa markdown cuando ayude a la legibilidad (listas, código, headers)
|
||||||
|
- Idioma principal: español. Cambia al idioma del usuario si escribe en otro.
|
||||||
|
- Sin emojis excesivos. Uno o dos si aportan contexto.
|
||||||
|
|
||||||
|
## Uso de herramientas
|
||||||
|
- Cuando alguien pregunte por la hora o fecha, usa `current_time` antes de responder.
|
||||||
|
- No inventes datos temporales; siempre consulta la herramienta.
|
||||||
@@ -287,6 +287,10 @@ func buildToolRegistry(cfg *config.AgentConfig, sshExec *ssh.Executor, matrixCli
|
|||||||
logger.Debug("registered file tool")
|
logger.Debug("registered file tool")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// current_time is always available
|
||||||
|
reg.Register(tools.NewCurrentTime())
|
||||||
|
logger.Debug("registered current_time tool")
|
||||||
|
|
||||||
// matrix_send is always available
|
// matrix_send is always available
|
||||||
reg.Register(tools.NewMatrixSend(matrixClient))
|
reg.Register(tools.NewMatrixSend(matrixClient))
|
||||||
logger.Debug("registered matrix tool")
|
logger.Debug("registered matrix tool")
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
|
|
||||||
"github.com/enmanuel/agents/agents"
|
"github.com/enmanuel/agents/agents"
|
||||||
assistantagent "github.com/enmanuel/agents/agents/assistant"
|
assistantagent "github.com/enmanuel/agents/agents/assistant"
|
||||||
|
asistente2agent "github.com/enmanuel/agents/agents/asistente2"
|
||||||
devopsagent "github.com/enmanuel/agents/agents/devops"
|
devopsagent "github.com/enmanuel/agents/agents/devops"
|
||||||
"github.com/enmanuel/agents/internal/config"
|
"github.com/enmanuel/agents/internal/config"
|
||||||
"github.com/enmanuel/agents/pkg/decision"
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
@@ -28,6 +29,7 @@ import (
|
|||||||
// Add a new entry here when you create a new agent package.
|
// Add a new entry here when you create a new agent package.
|
||||||
var rulesRegistry = map[string]func() []decision.Rule{
|
var rulesRegistry = map[string]func() []decision.Rule{
|
||||||
"assistant-bot": assistantagent.Rules,
|
"assistant-bot": assistantagent.Rules,
|
||||||
|
"asistente-2": asistente2agent.Rules,
|
||||||
"devops-bot": devopsagent.Rules,
|
"devops-bot": devopsagent.Rules,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// Command verify sets up cross-signing keys for a Matrix bot user.
|
||||||
|
// This eliminates the "Encrypted by a device not verified by its owner" warning.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// go run -tags goolm ./cmd/verify --homeserver https://... --username asistente-2 --password <pass> --token <access_token>
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"maunium.net/go/mautrix"
|
||||||
|
"maunium.net/go/mautrix/crypto"
|
||||||
|
"maunium.net/go/mautrix/crypto/cryptohelper"
|
||||||
|
"maunium.net/go/mautrix/id"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
homeserver string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
token string
|
||||||
|
storePath string
|
||||||
|
)
|
||||||
|
|
||||||
|
root := &cobra.Command{
|
||||||
|
Use: "verify",
|
||||||
|
Short: "Set up cross-signing keys for a Matrix bot",
|
||||||
|
Long: `Generates and uploads cross-signing keys so the bot's device is verified.
|
||||||
|
This removes the "Encrypted by a device not verified by its owner" warning.
|
||||||
|
|
||||||
|
Requires the bot's access token and password (for UIA during key upload).`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
homeserver = strings.TrimRight(homeserver, "/")
|
||||||
|
serverName := homeserver
|
||||||
|
serverName = strings.TrimPrefix(serverName, "https://")
|
||||||
|
serverName = strings.TrimPrefix(serverName, "http://")
|
||||||
|
|
||||||
|
userID := id.UserID(fmt.Sprintf("@%s:%s", username, serverName))
|
||||||
|
fmt.Printf("→ Setting up cross-signing for %s\n", userID)
|
||||||
|
|
||||||
|
// Create mautrix client
|
||||||
|
client, err := mautrix.NewClient(homeserver, userID, token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Resolve device ID
|
||||||
|
whoami, err := client.Whoami(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("whoami: %w", err)
|
||||||
|
}
|
||||||
|
client.DeviceID = whoami.DeviceID
|
||||||
|
fmt.Printf("→ Device ID: %s\n", client.DeviceID)
|
||||||
|
|
||||||
|
// Initialize crypto
|
||||||
|
sum := sha256.Sum256([]byte(token))
|
||||||
|
pickleKey := sum[:]
|
||||||
|
|
||||||
|
dbPath := filepath.Join(storePath, "crypto.db")
|
||||||
|
if err := os.MkdirAll(filepath.Dir(dbPath), 0700); err != nil {
|
||||||
|
return fmt.Errorf("create store dir: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
helper, err := cryptohelper.NewCryptoHelper(client, pickleKey, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create crypto helper: %w", err)
|
||||||
|
}
|
||||||
|
helper.DBAccountID = username
|
||||||
|
|
||||||
|
if err := helper.Init(ctx); err != nil {
|
||||||
|
return fmt.Errorf("init crypto: %w", err)
|
||||||
|
}
|
||||||
|
defer helper.Close()
|
||||||
|
|
||||||
|
client.Crypto = helper
|
||||||
|
|
||||||
|
// Get the OlmMachine to generate cross-signing keys
|
||||||
|
olmMachine := helper.Machine()
|
||||||
|
if olmMachine == nil {
|
||||||
|
return fmt.Errorf("olm machine not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("→ Generating and uploading cross-signing keys...")
|
||||||
|
_, _, err = olmMachine.GenerateAndUploadCrossSigningKeysWithPassword(ctx, password, "")
|
||||||
|
if err != nil {
|
||||||
|
// If keys already exist, try to just sign our device
|
||||||
|
fmt.Printf(" Note: %v\n", err)
|
||||||
|
fmt.Println("→ Attempting to sign own device with existing keys...")
|
||||||
|
return signOwnDevice(ctx, olmMachine, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("✓ Cross-signing keys uploaded successfully")
|
||||||
|
fmt.Printf("✓ Device %s is now verified by %s\n", client.DeviceID, userID)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
root.Flags().StringVar(&homeserver, "homeserver", "", "Matrix homeserver URL")
|
||||||
|
root.Flags().StringVar(&username, "username", "", "Bot username (without @ or server)")
|
||||||
|
root.Flags().StringVar(&password, "password", "", "Bot password (for UIA auth)")
|
||||||
|
root.Flags().StringVar(&token, "token", "", "Bot access token")
|
||||||
|
root.Flags().StringVar(&storePath, "store", "./data/verify-crypto/", "Crypto store path")
|
||||||
|
_ = root.MarkFlagRequired("homeserver")
|
||||||
|
_ = root.MarkFlagRequired("username")
|
||||||
|
_ = root.MarkFlagRequired("password")
|
||||||
|
_ = root.MarkFlagRequired("token")
|
||||||
|
|
||||||
|
if err := root.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func signOwnDevice(ctx context.Context, mach *crypto.OlmMachine, client *mautrix.Client) error {
|
||||||
|
device := &id.Device{
|
||||||
|
UserID: client.UserID,
|
||||||
|
DeviceID: client.DeviceID,
|
||||||
|
}
|
||||||
|
err := mach.SignOwnDevice(ctx, device)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("sign own device: %w", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("✓ Device %s signed with cross-signing key\n", client.DeviceID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
moderncsqlite "modernc.org/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// mautrix dbutil opens sqlite as "sqlite3"; register the pure-Go driver under that name.
|
||||||
|
sql.Register("sqlite3", &moderncsqlite.Driver{})
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCurrentTime creates a current_time tool that returns the current date and time.
|
||||||
|
// Useful for agents that need temporal awareness.
|
||||||
|
func NewCurrentTime() Tool {
|
||||||
|
return Tool{
|
||||||
|
Def: Def{
|
||||||
|
Name: "current_time",
|
||||||
|
Description: "Returns the current date and time in the server's timezone. Use this when you need to know the current time or date.",
|
||||||
|
Parameters: []Param{
|
||||||
|
{Name: "format", Type: "string", Description: "Optional Go time format string. Defaults to RFC3339 if empty.", Required: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Exec: func(ctx context.Context, args map[string]any) Result {
|
||||||
|
layout := getString(args, "format")
|
||||||
|
if layout == "" {
|
||||||
|
layout = time.RFC3339
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
output := fmt.Sprintf("Current time: %s\nTimezone: %s", now.Format(layout), now.Location().String())
|
||||||
|
return Result{Output: output}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user