2026-02-26T00-00-18_auto_memory/memories.db-wal, memory/memories.db-wal

This commit is contained in:
Nicholai Vogel 2026-02-25 17:00:18 -07:00
parent 442a178d23
commit 80233a715d
8 changed files with 231 additions and 28 deletions

View File

@ -23638,3 +23638,28 @@ hint: See the 'Note about fast-forwards' in 'git push --help' for details.
23:27:43 INFO  [memory] Chunked memory saved {"groupId":"84bcb13d-3767-44a0-a967-1d38f1ceb3bd","chunkCount":0}
23:27:43 INFO  [watcher] Ingested memory file {"path":"/home/nicholai/.agents/memory/2026-02-24-ad-prediction-system-proposal-review.md","chunks":1,"sections":1,"filename":"2026-02-24-ad-prediction-system-proposal-review"}
23:27:43 INFO  [daemon] Imported existing memory files {"files":142,"chunks":320}
23:27:48 INFO  [git] Auto-committed {"message":"2026-02-25T23-27-48_auto_memory/memories.db-wal, memory/memories.db-wal, me","filesChanged":7}
23:28:16 INFO  [secrets] exec_with_secrets completed {"name":"OPENROUTER_API_KEY","code":0}
23:28:24 INFO  [secrets] exec_with_secrets completed {"name":"OPENROUTER_API_KEY","code":0}
23:28:49 INFO  [secrets] exec_with_secrets completed {"name":"OPENROUTER_API_KEY","code":0}
23:29:21 INFO  [secrets] Secret deleted {"name":"OPENROUTER_API_KEY"}
23:29:22 INFO  [secrets] Secret stored {"name":"OPENROUTER_API_KEY"}
23:29:42 INFO  [secrets] exec_with_secrets completed {"name":"OPENROUTER_API_KEY","code":0}
23:30:34 INFO  [secrets] exec_with_secrets completed {"name":"OPENROUTER_API_KEY","code":0}
23:30:56 INFO  [secrets] exec_with_secrets completed {"name":"OPENROUTER_API_KEY","code":0}
23:32:51 INFO  [git] Git push {"commits":789}
23:33:03 INFO  [skills] Fetching skills.sh catalog
23:33:03 INFO  [skills] Fetching ClawHub catalog
23:33:03 INFO  [skills] Cached 600 skills
23:33:04 ERROR [skills] ClawHub catalog fetch failed
Error: ClawHub returned 429
23:37:42 INFO  [git] Git push {"commits":789}
23:42:42 INFO  [git] Git push {"commits":789}
23:47:42 INFO  [git] Git push {"commits":789}
23:52:42 INFO  [git] Git push {"commits":789}
23:57:42 INFO  [git] Git push {"commits":789}
00:00:13 INFO  [scheduler] Executing task: Find a bug and fix it {"taskId":"51f5d597-5c2d-4282-bad1-ac9010862650","runId":"47c819d5-bc20-46de-9c09-afe0ec264eec","harness":"claude-code"}
00:00:13 INFO  [scheduler] Spawning claude-code {"bin":"/home/nicholai/.local/share/../bin/claude","cwd":"/home/nicholai/signet/signetai/"}
00:00:13 INFO  [watcher] File changed {"path":"/home/nicholai/.agents/memory/memories.db-wal"}
00:00:13 INFO  [scheduler] Task Find a bug and fix it failed {"taskId":"51f5d597-5c2d-4282-bad1-ac9010862650","runId":"47c819d5-bc20-46de-9c09-afe0ec264eec","exitCode":1,"timedOut":false}
00:00:13 INFO  [watcher] File changed {"path":"/home/nicholai/.agents/memory/memories.db-wal"}

View File

@ -1,11 +1,6 @@
{
"version": 1,
"secrets": {
"OPENROUTER_API_KEY": {
"ciphertext": "WgC40fXcR4Z/fR+zMeVH8Rl8U5y/BokoGaLeI9Ak4DKoqMS5GYvJ0C1HHw==",
"created": "2026-02-18T21:15:08.588Z",
"updated": "2026-02-18T21:15:08.588Z"
},
"GOOGLE_AI_API_KEY": {
"ciphertext": "1cyAwWgmCqZxQpVGTvPCyyv1C6mt/8YzPfFrTK1crKE2lupmnhCInm0d4PwJeBMAPF6XQbrJZgv4aMZT9utO70+hSkXIZcKPnA4iZYcRew==",
"created": "2026-02-21T07:40:25.875Z",
@ -45,6 +40,11 @@
"ciphertext": "xN8VWOFvMNgmUuCkM44MRFsNf9atDvCvJm6qBis5+FBpJrMlRR9JpmkhSSDd6SZx11/N336IUXQM8LcxtprBiSk6GekDk5COmk3qBin+ry4rF+RZ2NQ2mj6WTnxzxfMgtaK9Gne482zlftCs7CzLLmKcyCW6vrpZzNI8t9CEeThhMJnNcVKbTQHtk/9WD+10bs+jacZe7vsM8RLRsMOI2cUJdiKRCO6b7/o8hzPuCmziUaR54jO0bxdlFBHzJH8hiURlNdZ3ZwQBiWIEcDK15L5FrJSl4hu2oAMCDHTBb5mDzl35fZsH6SPzWhA4FSlvE7SDytOcPQ==",
"created": "2026-02-24T11:00:59.366Z",
"updated": "2026-02-24T11:05:51.951Z"
},
"OPENROUTER_API_KEY": {
"ciphertext": "yCu2nwjkBU+jCYRy9pKDX//fHjlQPaJiWFG5a9sCRXCzGki4oa+2nULx1nzCrHHBaNCne/sXew2x1XhV3No0aVux4mW2kSwcnMzbu6DJM61ENWA9ZJi5R18xVOeQAl9Bs2uI9VuhIvH9Sr9IJWDX91c=",
"created": "2026-02-25T23:29:22.944Z",
"updated": "2026-02-25T23:29:22.944Z"
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1,40 +1,94 @@
#!/usr/bin/env bash
set -euo pipefail
API_KEY=$(signet secret get OPENROUTER_API_KEY 2>/dev/null)
VOICE="${VOICE:-ash}"
FORMAT="${FORMAT:-wav}"
TEXT="$*"
DAEMON="http://localhost:3850"
TMPRAW=$(mktemp /tmp/speak-XXXX.raw)
TMPWAV=$(mktemp /tmp/speak-XXXX.wav)
trap "rm -f $TMPRAW $TMPWAV" EXIT
if [ -z "$TEXT" ]; then
echo "Usage: speak.sh <text to speak>"
exit 1
fi
RESPONSE=$(curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
# The inner command streams the SSE response, extracts base64 audio chunks,
# concatenates and decodes them to raw PCM16.
# We use jq to safely embed the text into the JSON payload.
read -r -d '' INNER_CMD << 'INNEREOF' || true
PAYLOAD=$(jq -n \
--arg text "$SPEAK_TEXT" \
--arg voice "$SPEAK_VOICE" \
'{
model: "openai/gpt-audio-mini",
modalities: ["text", "audio"],
audio: { voice: $voice, format: "pcm16" },
stream: true,
messages: [{ role: "user", content: $text }]
}')
curl -sN https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg text "$TEXT" \
--arg voice "$VOICE" \
--arg fmt "$FORMAT" \
'{
model: "openai/gpt-audio-mini",
modalities: ["text", "audio"],
audio: { voice: $voice, format: $fmt },
messages: [{ role: "user", content: $text }]
}')")
-d "$PAYLOAD" | \
while IFS= read -r line; do
# Strip "data: " prefix from SSE
line="${line#data: }"
[ -z "$line" ] && continue
[ "$line" = "[DONE]" ] && continue
# Extract audio data chunk if present
chunk=$(echo "$line" | jq -r '.choices[0].delta.audio.data // empty' 2>/dev/null)
[ -n "$chunk" ] && printf '%s' "$chunk"
done
INNEREOF
# Extract audio data
AUDIO_DATA=$(echo "$RESPONSE" | jq -r '.choices[0].message.audio.data // empty')
# Execute the streaming command via daemon's exec_with_secrets.
# We pass SPEAK_TEXT and SPEAK_VOICE as additional env vars through the secrets map.
# The exec endpoint injects OPENROUTER_API_KEY; we also set our custom vars in the command.
INNER_WITH_VARS="export SPEAK_TEXT=$(printf '%q' "$TEXT"); export SPEAK_VOICE=$(printf '%q' "$VOICE"); $INNER_CMD"
if [ -z "$AUDIO_DATA" ]; then
echo "Error: No audio in response"
echo "$RESPONSE" | jq '.error // .choices[0].message.content // .' 2>/dev/null
EXEC_RESPONSE=$(curl -s "$DAEMON/api/secrets/OPENROUTER_API_KEY/exec" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg cmd "$INNER_WITH_VARS" '{ command: $cmd }')")
# Extract the concatenated base64 audio from stdout
B64_AUDIO=$(echo "$EXEC_RESPONSE" | jq -r '.stdout // empty')
if [ -z "$B64_AUDIO" ]; then
STDERR=$(echo "$EXEC_RESPONSE" | jq -r '.stderr // empty')
echo "Error: No audio data received"
[ -n "$STDERR" ] && echo "stderr: $STDERR"
exit 1
fi
TMPFILE=$(mktemp /tmp/speak-XXXX.wav)
trap "rm -f $TMPFILE" EXIT
echo "$AUDIO_DATA" | base64 -d > "$TMPFILE"
ffplay -nodisp -autoexit -loglevel quiet "$TMPFILE"
# Decode base64 to raw PCM16
echo "$B64_AUDIO" | base64 -d > "$TMPRAW" 2>/dev/null
RAWSIZE=$(stat -c%s "$TMPRAW" 2>/dev/null || stat -f%z "$TMPRAW" 2>/dev/null)
if [ "$RAWSIZE" -lt 100 ]; then
echo "Error: Audio data too small ($RAWSIZE bytes)"
exit 1
fi
# Wrap raw PCM16 in a WAV header (24kHz, mono, 16-bit LE)
# WAV header is 44 bytes
DATASIZE=$RAWSIZE
FILESIZE=$((DATASIZE + 36))
{
printf 'RIFF'
printf "$(printf '\\x%02x\\x%02x\\x%02x\\x%02x' $((FILESIZE & 0xFF)) $(((FILESIZE >> 8) & 0xFF)) $(((FILESIZE >> 16) & 0xFF)) $(((FILESIZE >> 24) & 0xFF)))"
printf 'WAVEfmt '
printf '\x10\x00\x00\x00' # chunk size 16
printf '\x01\x00' # PCM format
printf '\x01\x00' # mono
printf '\xc0\x5d\x00\x00' # 24000 Hz sample rate
printf '\x80\xbb\x00\x00' # byte rate (24000 * 2)
printf '\x02\x00' # block align
printf '\x10\x00' # 16 bits per sample
printf 'data'
printf "$(printf '\\x%02x\\x%02x\\x%02x\\x%02x' $((DATASIZE & 0xFF)) $(((DATASIZE >> 8) & 0xFF)) $(((DATASIZE >> 16) & 0xFF)) $(((DATASIZE >> 24) & 0xFF)))"
cat "$TMPRAW"
} > "$TMPWAV"
ffplay -nodisp -autoexit -loglevel quiet "$TMPWAV"

BIN
signet-speak.skill Normal file

Binary file not shown.

View File

@ -0,0 +1,36 @@
---
name: signet-speak
description: Speak audibly to the user via text-to-speech using OpenAI's gpt-audio-mini model through OpenRouter. Use when the agent wants to talk out loud, greet the user verbally, deliver information audibly, or when spoken audio output would enhance the interaction. Also triggers when the user asks the agent to "say something", "speak", "talk to me", "use your voice", or "read this aloud".
---
# Signet Speak
Speak out loud via TTS. Uses OpenRouter's `openai/gpt-audio-mini` with Signet daemon's `exec_with_secrets` for secure API key injection.
## Quick Start
```bash
~/.agents/skills/signet-speak/scripts/speak.sh "whatever you want to say"
```
Override voice (default: ash):
```bash
VOICE=coral ~/.agents/skills/signet-speak/scripts/speak.sh "hello there"
```
## Voices
alloy, **ash** (default), ballad, coral, echo, fable, onyx, nova, sage, shimmer, verse, marin, cedar
## Prerequisites
- Signet daemon running (`signet daemon start`)
- `OPENROUTER_API_KEY` in Signet secrets
- `ffplay`, `jq`, `curl` on PATH
## Troubleshooting
- **No audio data**: Check daemon (`signet status`), verify API key
- **401 error**: Re-store key with `signet secret put OPENROUTER_API_KEY`
- **No sound from speakers**: Test with `ffplay -f lavfi -i sine=f=440:d=1 -nodisp -autoexit`

View File

@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -euo pipefail
VOICE="${VOICE:-ash}"
TEXT="$*"
DAEMON="http://localhost:3850"
TMPRAW=$(mktemp /tmp/speak-XXXX.raw)
TMPWAV=$(mktemp /tmp/speak-XXXX.wav)
trap "rm -f $TMPRAW $TMPWAV" EXIT
if [ -z "$TEXT" ]; then
echo "Usage: speak.sh <text to speak>"
exit 1
fi
# Build the inner command that runs with OPENROUTER_API_KEY injected by the daemon
read -r -d '' INNER_CMD << 'INNEREOF' || true
PAYLOAD=$(jq -n \
--arg text "$SPEAK_TEXT" \
--arg voice "$SPEAK_VOICE" \
'{
model: "openai/gpt-audio-mini",
modalities: ["text", "audio"],
audio: { voice: $voice, format: "pcm16" },
stream: true,
messages: [{ role: "user", content: $text }]
}')
curl -sN https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" | \
while IFS= read -r line; do
line="${line#data: }"
[ -z "$line" ] && continue
[ "$line" = "[DONE]" ] && continue
chunk=$(echo "$line" | jq -r '.choices[0].delta.audio.data // empty' 2>/dev/null)
[ -n "$chunk" ] && printf '%s' "$chunk"
done
INNEREOF
# Inject text and voice as shell-safe env vars, then run the inner command
# through the Signet daemon's exec_with_secrets endpoint
INNER_WITH_VARS="export SPEAK_TEXT=$(printf '%q' "$TEXT"); export SPEAK_VOICE=$(printf '%q' "$VOICE"); $INNER_CMD"
EXEC_RESPONSE=$(curl -s "$DAEMON/api/secrets/OPENROUTER_API_KEY/exec" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg cmd "$INNER_WITH_VARS" '{ command: $cmd }')")
# Extract concatenated base64 audio from stdout
B64_AUDIO=$(echo "$EXEC_RESPONSE" | jq -r '.stdout // empty')
if [ -z "$B64_AUDIO" ]; then
STDERR=$(echo "$EXEC_RESPONSE" | jq -r '.stderr // empty')
echo "Error: No audio data received"
[ -n "$STDERR" ] && echo "stderr: $STDERR"
exit 1
fi
# Decode base64 to raw PCM16
echo "$B64_AUDIO" | base64 -d > "$TMPRAW" 2>/dev/null
RAWSIZE=$(stat -c%s "$TMPRAW" 2>/dev/null || stat -f%z "$TMPRAW" 2>/dev/null)
if [ "$RAWSIZE" -lt 100 ]; then
echo "Error: Audio data too small ($RAWSIZE bytes)"
exit 1
fi
# Wrap raw PCM16 in a WAV header (24kHz, mono, 16-bit LE)
DATASIZE=$RAWSIZE
FILESIZE=$((DATASIZE + 36))
{
printf 'RIFF'
printf "$(printf '\\x%02x\\x%02x\\x%02x\\x%02x' $((FILESIZE & 0xFF)) $(((FILESIZE >> 8) & 0xFF)) $(((FILESIZE >> 16) & 0xFF)) $(((FILESIZE >> 24) & 0xFF)))"
printf 'WAVEfmt '
printf '\x10\x00\x00\x00' # chunk size 16
printf '\x01\x00' # PCM format
printf '\x01\x00' # mono
printf '\xc0\x5d\x00\x00' # 24000 Hz
printf '\x80\xbb\x00\x00' # byte rate (24000 * 2)
printf '\x02\x00' # block align
printf '\x10\x00' # 16 bits per sample
printf 'data'
printf "$(printf '\\x%02x\\x%02x\\x%02x\\x%02x' $((DATASIZE & 0xFF)) $(((DATASIZE >> 8) & 0xFF)) $(((DATASIZE >> 16) & 0xFF)) $(((DATASIZE >> 24) & 0xFF)))"
cat "$TMPRAW"
} > "$TMPWAV"
ffplay -nodisp -autoexit -loglevel quiet "$TMPWAV"