discoclaw 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.context/voice.md +30 -2
  2. package/.env.example +6 -0
  3. package/dist/cli/dashboard.js +7 -1
  4. package/dist/config.js +7 -0
  5. package/dist/cron/executor.js +72 -1
  6. package/dist/dashboard/api/metrics.js +7 -0
  7. package/dist/dashboard/api/metrics.test.js +16 -0
  8. package/dist/dashboard/api/traces.js +14 -0
  9. package/dist/dashboard/api/traces.test.js +40 -0
  10. package/dist/dashboard/page.js +187 -8
  11. package/dist/dashboard/server.js +81 -14
  12. package/dist/dashboard/server.test.js +120 -4
  13. package/dist/discord/deferred-runner.js +306 -219
  14. package/dist/discord/message-coordinator.js +1 -28
  15. package/dist/discord/reaction-handler.js +81 -3
  16. package/dist/index.js +15 -1
  17. package/dist/observability/trace-store.js +56 -0
  18. package/dist/observability/trace-utils.js +31 -0
  19. package/dist/runtime/codex-cli.js +3 -2
  20. package/dist/runtime/codex-cli.test.js +33 -0
  21. package/dist/runtime/model-tiers.js +1 -1
  22. package/dist/runtime/model-tiers.test.js +9 -0
  23. package/dist/runtime/openai-tool-schemas.js +17 -0
  24. package/dist/voice/audio-pipeline.js +246 -6
  25. package/dist/voice/audio-pipeline.test.js +481 -0
  26. package/dist/voice/audio-receiver.js +8 -0
  27. package/dist/voice/audio-receiver.test.js +16 -0
  28. package/dist/voice/conversation-buffer.js +16 -6
  29. package/dist/voice/providers/gemini-live-provider.js +481 -0
  30. package/dist/voice/providers/gemini-live-provider.test.js +834 -0
  31. package/dist/voice/providers/gemini-live-responder.js +267 -0
  32. package/dist/voice/providers/gemini-live-responder.test.js +615 -0
  33. package/dist/voice/providers/gemini-live-token-estimator.js +100 -0
  34. package/dist/voice/providers/gemini-live-token-estimator.test.js +160 -0
  35. package/dist/voice/providers/gemini-live-types.js +32 -0
  36. package/dist/voice/providers/gemini-tool-mapper.js +91 -0
  37. package/dist/voice/providers/gemini-tool-mapper.test.js +253 -0
  38. package/dist/voice/providers/index.js +3 -0
  39. package/dist/voice/types.test.js +6 -0
  40. package/dist/voice/voice-prompt-builder.js +26 -17
  41. package/dist/voice/voice-prompt-builder.test.js +16 -1
  42. package/package.json +1 -1
  43. package/templates/instructions/SYSTEM_DEFAULTS.md +8 -0
@@ -125,6 +125,21 @@ function estimateSection(chars) {
125
125
  included: safeChars > 0,
126
126
  };
127
127
  }
128
+ function buildVoiceContextSections(parts) {
129
+ const sections = [];
130
+ sections.push(buildPromptPreamble(parts.identity, { skipTrackedTools: true }));
131
+ if (parts.actionsSection) {
132
+ sections.push(parts.actionsSection);
133
+ }
134
+ if (parts.voiceSystemPrompt) {
135
+ sections.push(parts.voiceSystemPrompt);
136
+ }
137
+ sections.push(VOICE_STYLE_INSTRUCTION);
138
+ if (parts.durableMemory) {
139
+ sections.push(`---\nDurable memory (user-specific notes):\n${parts.durableMemory}`);
140
+ }
141
+ return sections;
142
+ }
128
143
  export function buildVoicePromptSectionEstimates(parts) {
129
144
  const charsBySection = {
130
145
  rootPolicy: ROOT_POLICY_CHARS,
@@ -162,28 +177,22 @@ export function buildVoicePromptSectionEstimates(parts) {
162
177
  * 8. User text
163
178
  */
164
179
  export function buildVoicePrompt(parts) {
165
- const sections = [];
166
- // 1. Root policy + identity.
167
- sections.push(buildPromptPreamble(parts.identity, { skipTrackedTools: true }));
168
- // 2. Actions section.
169
- if (parts.actionsSection) {
170
- sections.push(parts.actionsSection);
171
- }
172
- // 3. Voice system prompt (user-configurable).
173
- if (parts.voiceSystemPrompt) {
174
- sections.push(parts.voiceSystemPrompt);
175
- }
176
- // 4. Voice style instruction.
177
- sections.push(VOICE_STYLE_INSTRUCTION);
178
- // 5. Durable memory.
179
- if (parts.durableMemory) {
180
- sections.push(`---\nDurable memory (user-specific notes):\n${parts.durableMemory}`);
181
- }
180
+ const sections = buildVoiceContextSections(parts);
182
181
  // 6. Separator + user text.
183
182
  sections.push(VOICE_INTERNAL_CONTEXT_SEPARATOR);
184
183
  sections.push(parts.userText);
185
184
  return sections.join('\n\n');
186
185
  }
186
+ /**
187
+ * Build the static session instruction used by live voice providers.
188
+ *
189
+ * This contains the same persistent voice context as the classic per-turn
190
+ * prompt, excluding the current user utterance and the internal-context
191
+ * separator that only makes sense for single-shot prompt assembly.
192
+ */
193
+ export function buildVoiceSystemInstruction(parts) {
194
+ return buildVoiceContextSections(parts).join('\n\n');
195
+ }
187
196
  /**
188
197
  * Build a follow-up prompt for voice action result processing.
189
198
  *
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
2
  import fs from 'node:fs/promises';
3
3
  import path from 'node:path';
4
- import { extractSections, extractSoulEssentials, extractUserEssentials, loadVoiceIdentity, buildVoicePrompt, buildVoiceFollowUpPrompt, buildVoicePromptSectionEstimates, VOICE_INTERNAL_CONTEXT_SEPARATOR, VOICE_IDENTITY_MAX_CHARS, } from './voice-prompt-builder.js';
4
+ import { extractSections, extractSoulEssentials, extractUserEssentials, loadVoiceIdentity, buildVoicePrompt, buildVoiceSystemInstruction, buildVoiceFollowUpPrompt, buildVoicePromptSectionEstimates, VOICE_INTERNAL_CONTEXT_SEPARATOR, VOICE_IDENTITY_MAX_CHARS, } from './voice-prompt-builder.js';
5
5
  import { VOICE_STYLE_INSTRUCTION } from './voice-style-prompt.js';
6
6
  import { ROOT_POLICY, TRACKED_DEFAULTS_PREAMBLE, TRACKED_TOOLS_PREAMBLE, buildPromptPreamble, } from '../discord/prompt-common.js';
7
7
  // ---------------------------------------------------------------------------
@@ -180,6 +180,21 @@ describe('loadVoiceIdentity', () => {
180
180
  expect(identityIdx).toBeLessThan(userIdx);
181
181
  });
182
182
  });
183
+ describe('buildVoiceSystemInstruction', () => {
184
+ it('builds the static voice context without the user-turn separator', () => {
185
+ const result = buildVoiceSystemInstruction({
186
+ identity: 'identity block',
187
+ durableMemory: '',
188
+ actionsSection: '',
189
+ voiceSystemPrompt: 'custom voice system prompt',
190
+ });
191
+ expect(result).toContain(buildPromptPreamble('identity block', { skipTrackedTools: true }));
192
+ expect(result).toContain('custom voice system prompt');
193
+ expect(result).toContain(VOICE_STYLE_INSTRUCTION);
194
+ expect(result).not.toContain(VOICE_INTERNAL_CONTEXT_SEPARATOR);
195
+ expect(result).not.toContain('Current user message:');
196
+ });
197
+ });
183
198
  // ---------------------------------------------------------------------------
184
199
  // buildVoicePrompt
185
200
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discoclaw",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "Personal AI orchestrator that turns Discord into a persistent workspace",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -23,6 +23,14 @@ Use tools immediately — Read/Bash/Grep — don't narrate plans. CWD is the wor
23
23
 
24
24
  Before implementing requested functionality, search the codebase to confirm it doesn't already exist. Re-read the actual file content rather than relying on what you recall from earlier in the session — your memory of what you read vs. what you generated can drift.
25
25
 
26
+ ## No Unverified Claims
27
+
28
+ Never tell the user something "is already implemented," "already exists," or "was already done" unless you verified it with a tool call in this turn. If you lack the tools to verify, say "I can't confirm that — I'd need to check." Do not guess.
29
+
30
+ ## Tool Failure Transparency
31
+
32
+ When a tool call fails or returns an error, say so plainly: what you tried, what failed, and what you can't confirm as a result. Never substitute a hallucinated answer for a failed tool call. "I tried to check but the lookup failed" is always better than a fabricated answer.
33
+
26
34
  ## Runtime Registry
27
35
 
28
36
  | Key | Type | Backend |