discoclaw 1.2.4 → 2.0.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.
- package/.context/voice.md +30 -2
- package/.env.example +7 -3
- package/.env.example.full +13 -32
- package/README.md +1 -1
- package/dist/cli/dashboard.js +7 -1
- package/dist/cli/dashboard.test.js +0 -4
- package/dist/cli/init-wizard.js +4 -8
- package/dist/cli/init-wizard.test.js +4 -10
- package/dist/config.js +5 -38
- package/dist/config.test.js +8 -72
- package/dist/cron/executor.js +72 -1
- package/dist/dashboard/api/metrics.js +7 -0
- package/dist/dashboard/api/metrics.test.js +16 -0
- package/dist/dashboard/api/traces.js +14 -0
- package/dist/dashboard/api/traces.test.js +40 -0
- package/dist/dashboard/page.js +187 -8
- package/dist/dashboard/server.js +82 -19
- package/dist/dashboard/server.test.js +123 -10
- package/dist/discord/actions.js +112 -6
- package/dist/discord/actions.test.js +117 -1
- package/dist/discord/deferred-runner.js +306 -219
- package/dist/discord/help-command.js +1 -1
- package/dist/discord/message-coordinator.js +4 -36
- package/dist/discord/models-command.js +1 -1
- package/dist/discord/reaction-handler.js +83 -5
- package/dist/discord/reaction-handler.test.js +55 -0
- package/dist/discord/verify-push.js +31 -36
- package/dist/discord/verify-push.test.js +34 -6
- package/dist/discord/voice-command.js +1 -31
- package/dist/discord/voice-command.test.js +21 -259
- package/dist/discord/voice-status-command.js +3 -22
- package/dist/discord/voice-status-command.test.js +16 -124
- package/dist/discord-followup.test.js +133 -0
- package/dist/health/config-doctor.js +5 -27
- package/dist/health/config-doctor.test.js +1 -4
- package/dist/index.js +15 -28
- package/dist/observability/trace-store.js +56 -0
- package/dist/observability/trace-utils.js +31 -0
- package/dist/runtime/codex-cli.js +3 -2
- package/dist/runtime/codex-cli.test.js +33 -0
- package/dist/runtime/model-tiers.js +1 -1
- package/dist/runtime/model-tiers.test.js +9 -0
- package/dist/runtime/openai-tool-schemas.js +17 -0
- package/dist/runtime-overrides.js +2 -3
- package/dist/runtime-overrides.test.js +27 -193
- package/dist/tasks/store.js +10 -6
- package/dist/tasks/store.test.js +44 -0
- package/dist/tasks/task-action-executor.test.js +162 -50
- package/dist/tasks/task-action-mutations.js +22 -2
- package/dist/tasks/task-action-read-ops.js +7 -1
- package/dist/tasks/task-action-runner-types.js +19 -1
- package/dist/voice/audio-pipeline.js +183 -96
- package/dist/voice/audio-receiver.js +8 -0
- package/dist/voice/audio-receiver.test.js +16 -0
- package/dist/voice/conversation-buffer.js +16 -6
- package/dist/voice/providers/gemini-live-provider.js +481 -0
- package/dist/voice/providers/gemini-live-provider.test.js +834 -0
- package/dist/voice/providers/gemini-live-responder.js +267 -0
- package/dist/voice/providers/gemini-live-responder.test.js +615 -0
- package/dist/voice/providers/gemini-live-token-estimator.js +100 -0
- package/dist/voice/providers/gemini-live-token-estimator.test.js +160 -0
- package/dist/voice/providers/gemini-live-types.js +32 -0
- package/dist/voice/providers/gemini-tool-mapper.js +91 -0
- package/dist/voice/providers/gemini-tool-mapper.test.js +253 -0
- package/dist/voice/providers/index.js +3 -0
- package/dist/voice/voice-prompt-builder.js +26 -17
- package/dist/voice/voice-prompt-builder.test.js +16 -1
- package/docs/configuration.md +4 -9
- package/docs/official-docs.md +6 -9
- package/docs/runtime-switching.md +1 -1
- package/package.json +1 -1
- package/dist/voice/audio-pipeline.test.js +0 -619
- package/dist/voice/stt-deepgram.js +0 -154
- package/dist/voice/stt-deepgram.test.js +0 -275
- package/dist/voice/stt-factory.js +0 -42
- package/dist/voice/stt-factory.test.js +0 -45
- package/dist/voice/stt-openai.js +0 -156
- package/dist/voice/stt-openai.test.js +0 -281
- package/dist/voice/tts-cartesia.js +0 -169
- package/dist/voice/tts-cartesia.test.js +0 -228
- package/dist/voice/tts-deepgram.js +0 -84
- package/dist/voice/tts-deepgram.test.js +0 -220
- package/dist/voice/tts-factory.js +0 -52
- package/dist/voice/tts-factory.test.js +0 -53
- package/dist/voice/tts-openai.js +0 -70
- package/dist/voice/tts-openai.test.js +0 -138
- package/dist/voice/types.test.js +0 -84
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { ChannelType, PermissionFlagsBits } from 'discord.js';
|
|
3
3
|
import { buildUnavailableActionTypesNotice } from './output-common.js';
|
|
4
|
-
import { parseDiscordActions, executeDiscordActions, discordActionsPromptSection, buildTieredDiscordActionsPromptSection, buildDisplayResultLines, buildAllResultLines, withoutRequesterGatedActionFlags, } from './actions.js';
|
|
4
|
+
import { parseDiscordActions, executeDiscordActions, discordActionsPromptSection, buildTieredDiscordActionsPromptSection, buildDisplayResultLines, buildAllResultLines, buildCappedResultLines, withoutRequesterGatedActionFlags, } from './actions.js';
|
|
5
5
|
import { TaskStore } from '../tasks/store.js';
|
|
6
6
|
import { _resetDestructiveConfirmationForTest } from './destructive-confirmation.js';
|
|
7
7
|
import { shouldTriggerFollowUp } from './action-categories.js';
|
|
@@ -892,6 +892,122 @@ describe('buildAllResultLines', () => {
|
|
|
892
892
|
]);
|
|
893
893
|
});
|
|
894
894
|
});
|
|
895
|
+
describe('buildCappedResultLines', () => {
|
|
896
|
+
it('microcompacts multiline readMessages-style payloads to representative id lines', () => {
|
|
897
|
+
const results = [{
|
|
898
|
+
ok: true,
|
|
899
|
+
summary: [
|
|
900
|
+
'Messages in #ops:',
|
|
901
|
+
'[alice] alpha update (id:1001)',
|
|
902
|
+
'[bob] beta update (id:1002)',
|
|
903
|
+
'[carol] gamma update (id:1003)',
|
|
904
|
+
'[dave] delta update (id:1004)',
|
|
905
|
+
'[erin] epsilon update (id:1005)',
|
|
906
|
+
'[frank] zeta update (id:1006)',
|
|
907
|
+
'[grace] eta update (id:1007)',
|
|
908
|
+
'[heidi] theta update (id:1008)',
|
|
909
|
+
'[ivan] iota update (id:1009)',
|
|
910
|
+
].join('\n'),
|
|
911
|
+
}];
|
|
912
|
+
const [line] = buildCappedResultLines(results);
|
|
913
|
+
expect(line).toContain('Done: Messages in #ops:');
|
|
914
|
+
expect(line).toContain('(id:1001)');
|
|
915
|
+
expect(line).toContain('(id:1002)');
|
|
916
|
+
expect(line).toContain('(id:1008)');
|
|
917
|
+
expect(line).toContain('(id:1009)');
|
|
918
|
+
expect(line).toContain('...[omitted 5 lines]');
|
|
919
|
+
expect(line).not.toContain('(id:1005)');
|
|
920
|
+
});
|
|
921
|
+
it('keeps task thread jump URLs in multiline closeout blocks for follow-up reuse', () => {
|
|
922
|
+
const results = [{
|
|
923
|
+
ok: true,
|
|
924
|
+
summary: [
|
|
925
|
+
'Task ws-204 closed',
|
|
926
|
+
'Status: done',
|
|
927
|
+
'Thread: https://discord.com/channels/111111111111111111/222222222222222222/333333333333333333',
|
|
928
|
+
'Project: discoclaw',
|
|
929
|
+
'Assignee: ClawBot',
|
|
930
|
+
'Updated by: @weston',
|
|
931
|
+
'Note: Closeout posted in the linked Discord thread.',
|
|
932
|
+
'Artifacts: /tmp/task-closeout.md',
|
|
933
|
+
'Next action: use taskShow ws-204 if you need the stored linkage later.',
|
|
934
|
+
'Watcher: ops',
|
|
935
|
+
].join('\n'),
|
|
936
|
+
}];
|
|
937
|
+
const [line] = buildCappedResultLines(results);
|
|
938
|
+
expect(line).toContain('Done: Task ws-204 closed');
|
|
939
|
+
expect(line).toContain('Status: done');
|
|
940
|
+
expect(line).toContain('Thread: https://discord.com/channels/111111111111111111/222222222222222222/333333333333333333');
|
|
941
|
+
expect(line).toContain('Artifacts: /tmp/task-closeout.md');
|
|
942
|
+
expect(line).toContain('Next action: use taskShow ws-204 if you need the stored linkage later.');
|
|
943
|
+
expect(line).toContain('...[omitted 4 lines]');
|
|
944
|
+
expect(line).not.toContain('Assignee: ClawBot');
|
|
945
|
+
});
|
|
946
|
+
it('keeps section headings and first values in memoryShow-style blocks', () => {
|
|
947
|
+
const results = [{
|
|
948
|
+
ok: true,
|
|
949
|
+
summary: [
|
|
950
|
+
'**Durable memory:**',
|
|
951
|
+
'- prefers black coffee',
|
|
952
|
+
'- uses fish shell',
|
|
953
|
+
'**By entity:**',
|
|
954
|
+
'- [project] discoclaw migration',
|
|
955
|
+
'**Rolling summary:**',
|
|
956
|
+
'Working on prompt compaction.',
|
|
957
|
+
'**Short-term memory:**',
|
|
958
|
+
'Need task-42 and /tmp/report.md for the next reply.',
|
|
959
|
+
'Extra noisy note A that should be dropped.',
|
|
960
|
+
'Extra noisy note B that should be dropped.',
|
|
961
|
+
'Extra noisy note that should be dropped.',
|
|
962
|
+
].join('\n'),
|
|
963
|
+
}];
|
|
964
|
+
const [line] = buildCappedResultLines(results);
|
|
965
|
+
expect(line).toContain('Done: **Durable memory:**');
|
|
966
|
+
expect(line).toContain('- prefers black coffee');
|
|
967
|
+
expect(line).toContain('**By entity:**');
|
|
968
|
+
expect(line).toContain('- [project] discoclaw migration');
|
|
969
|
+
expect(line).toContain('**Rolling summary:**');
|
|
970
|
+
expect(line).toContain('Working on prompt compaction.');
|
|
971
|
+
expect(line).toContain('**Short-term memory:**');
|
|
972
|
+
expect(line).toContain('Need task-42 and /tmp/report.md for the next reply.');
|
|
973
|
+
expect(line).toContain('...[omitted ');
|
|
974
|
+
expect(line).not.toContain('Extra noisy note B that should be dropped.');
|
|
975
|
+
});
|
|
976
|
+
it('keeps failed prefixes, paths, and actionable error lines in multiline failures', () => {
|
|
977
|
+
const results = [{
|
|
978
|
+
ok: false,
|
|
979
|
+
error: [
|
|
980
|
+
'Forge sync failed while opening workspace state',
|
|
981
|
+
'Workspace: /home/davidmarsh/code/discoclaw/workspace/state.json',
|
|
982
|
+
'Last error: ENOENT: no such file or directory',
|
|
983
|
+
'Stack: at openWorkspaceState (src/discord/actions.ts:400:12)',
|
|
984
|
+
'Stack: at runForgeSync (src/discord/actions.ts:512:8)',
|
|
985
|
+
'Stack: at async executeForgeAction (src/discord/actions.ts:618:3)',
|
|
986
|
+
'Retry hint: recreate the state file, then rerun forge sync',
|
|
987
|
+
'Node: v24.0.0',
|
|
988
|
+
'cwd: /home/davidmarsh/code/discoclaw',
|
|
989
|
+
].join('\n'),
|
|
990
|
+
}];
|
|
991
|
+
const [line] = buildCappedResultLines(results);
|
|
992
|
+
expect(line).toContain('Failed: Forge sync failed while opening workspace state');
|
|
993
|
+
expect(line).toContain('Workspace: /home/davidmarsh/code/discoclaw/workspace/state.json');
|
|
994
|
+
expect(line).toContain('Last error: ENOENT: no such file or directory');
|
|
995
|
+
expect(line).toContain('Retry hint: recreate the state file, then rerun forge sync');
|
|
996
|
+
expect(line).toContain('cwd: /home/davidmarsh/code/discoclaw');
|
|
997
|
+
expect(line).toContain('...[omitted ');
|
|
998
|
+
expect(line).not.toContain('Stack: at runForgeSync');
|
|
999
|
+
});
|
|
1000
|
+
it('falls back to the final hard cap when retained text is still too long', () => {
|
|
1001
|
+
const results = [{
|
|
1002
|
+
ok: true,
|
|
1003
|
+
summary: `Downloaded attachment to /tmp/${'x'.repeat(120)}`,
|
|
1004
|
+
}];
|
|
1005
|
+
const [line] = buildCappedResultLines(results, 60);
|
|
1006
|
+
expect(line.length).toBeLessThanOrEqual(60);
|
|
1007
|
+
expect(line).toContain('Done: Downloaded attachment');
|
|
1008
|
+
expect(line.endsWith('...[truncated]')).toBe(true);
|
|
1009
|
+
});
|
|
1010
|
+
});
|
|
895
1011
|
describe('discordActionsPromptSection', () => {
|
|
896
1012
|
it('always includes the standard guidance when actions are enabled', () => {
|
|
897
1013
|
const flags = {
|